about summary refs log tree commit diff
diff options
context:
space:
mode:
authorP1start <rewi-github@whanau.org>2015-04-21 21:13:42 +1200
committerP1start <rewi-github@whanau.org>2015-04-21 21:13:42 +1200
commit7d2231aa22c80f47deea5b482ae03ae0cb2ae827 (patch)
treeb1057862dda83f6ae22c876e94955456ebebbb39
parent049de3fe7f61d6ae5e6079981ed8e0e7701ea28e (diff)
downloadrust-7d2231aa22c80f47deea5b482ae03ae0cb2ae827.tar.gz
rust-7d2231aa22c80f47deea5b482ae03ae0cb2ae827.zip
Change a few error messages to give code suggestions
PR #24242 added the ability to the compiler to directly give suggestions about
how to modify code to fix an error. The new errors look like this:

    foobar.rs:5:12: 5:25 error: expected a path on the left-hand side of `+`,
                                not `&'static Copy` [E0178]
    foobar.rs:5     let x: &'static Copy + 'static;
                           ^~~~~~~~~~~~~
    foobar.rs:5:12: 5:35 help: try adding parentheses (per RFC 438):
    foobar.rs:      let x: &'static (Copy + 'static);

    foobar.rs:2:13: 2:23 error: cast to unsized type: `&_` as `core::marker::Copy`
    foobar.rs:2     let x = &1 as Copy;
                            ^~~~~~~~~~
    foobar.rs:2:19: 2:23 help: try casting to a reference instead:
    foobar.rs:      let x = &1 as &Copy;

    foobar.rs:7:24: 7:25 error: expected expression, found `;`
    foobar.rs:7     let x = box (1 + 1);
                                       ^
    foobar.rs:7:13: 7:16 help: try using `box()` instead:
    foobar.rs:      let x = box() (1 + 1);

This also modifies compiletest to give the ability to directly test suggestions
given by error messages.
-rw-r--r--src/compiletest/runtest.rs13
-rw-r--r--src/librustc_resolve/lib.rs4
-rw-r--r--src/librustc_typeck/astconv.rs41
-rw-r--r--src/librustc_typeck/check/mod.rs21
-rw-r--r--src/libsyntax/parse/parser.rs11
-rw-r--r--src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs20
-rw-r--r--src/test/compile-fail/issue-17441.rs2
-rw-r--r--src/test/compile-fail/issue-6702.rs2
-rw-r--r--src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs20
-rw-r--r--src/test/parse-fail/parenthesized-box-expr-message.rs4
10 files changed, 113 insertions, 25 deletions
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index 8ae36393182..91550ae7461 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -979,6 +979,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
     // is the ending point, and * represents ANSI color codes.
     for line in proc_res.stderr.lines() {
         let mut was_expected = false;
+        let mut prev = 0;
         for (i, ee) in expected_errors.iter().enumerate() {
             if !found_flags[i] {
                 debug!("prefix={} ee.kind={} ee.msg={} line={}",
@@ -986,6 +987,17 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
                        ee.kind,
                        ee.msg,
                        line);
+                // Suggestions have no line number in their output, so take on the line number of
+                // the previous expected error
+                if ee.kind == "suggestion" {
+                    assert!(expected_errors[prev].kind == "help",
+                            "SUGGESTIONs must be preceded by a HELP");
+                    if line.contains(&ee.msg) {
+                        found_flags[i] = true;
+                        was_expected = true;
+                        break;
+                    }
+                }
                 if (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
                     line.contains(&ee.kind) &&
                     line.contains(&ee.msg) {
@@ -994,6 +1006,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
                     break;
                 }
             }
+            prev = i;
         }
 
         // ignore this msg which gets printed at the end
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 0058b31088b..d300045c0ec 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -3138,7 +3138,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                           uses it like a function name",
                                          path_name));
 
-                        let msg = format!("Did you mean to write: \
+                        let msg = format!("did you mean to write: \
                                            `{} {{ /* fields */ }}`?",
                                           path_name);
                         if self.emit_errors {
@@ -3179,7 +3179,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                 uses it like a function name",
                                                 path_name));
 
-                                let msg = format!("Did you mean to write: \
+                                let msg = format!("did you mean to write: \
                                                      `{} {{ /* fields */ }}`?",
                                                     path_name);
                                 if self.emit_errors {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 171c83d00e4..78797d086c6 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -66,7 +66,7 @@ use std::iter::repeat;
 use std::rc::Rc;
 use std::slice;
 use syntax::{abi, ast, ast_util};
-use syntax::codemap::Span;
+use syntax::codemap::{Span, Pos};
 use syntax::parse::token;
 use syntax::print::pprust;
 
@@ -975,21 +975,32 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
             span_err!(this.tcx().sess, ty.span, E0178,
                       "expected a path on the left-hand side of `+`, not `{}`",
                       pprust::ty_to_string(ty));
-            match ty.node {
-                ast::TyRptr(None, ref mut_ty) => {
-                    fileline_help!(this.tcx().sess, ty.span,
-                               "perhaps you meant `&{}({} +{})`? (per RFC 438)",
-                               ppaux::mutability_to_string(mut_ty.mutbl),
-                               pprust::ty_to_string(&*mut_ty.ty),
-                               pprust::bounds_to_string(bounds));
+            let hi = bounds.iter().map(|x| match *x {
+                ast::TraitTyParamBound(ref tr, _) => tr.span.hi,
+                ast::RegionTyParamBound(ref r) => r.span.hi,
+            }).max_by(|x| x.to_usize());
+            let full_span = hi.map(|hi| Span {
+                lo: ty.span.lo,
+                hi: hi,
+                expn_id: ty.span.expn_id,
+            });
+            match (&ty.node, full_span) {
+                (&ast::TyRptr(None, ref mut_ty), Some(full_span)) => {
+                    this.tcx().sess
+                        .span_suggestion(full_span, "try adding parentheses (per RFC 438):",
+                                         format!("&{}({} +{})",
+                                                 ppaux::mutability_to_string(mut_ty.mutbl),
+                                                 pprust::ty_to_string(&*mut_ty.ty),
+                                                 pprust::bounds_to_string(bounds)));
                 }
-               ast::TyRptr(Some(ref lt), ref mut_ty) => {
-                    fileline_help!(this.tcx().sess, ty.span,
-                               "perhaps you meant `&{} {}({} +{})`? (per RFC 438)",
-                               pprust::lifetime_to_string(lt),
-                               ppaux::mutability_to_string(mut_ty.mutbl),
-                               pprust::ty_to_string(&*mut_ty.ty),
-                               pprust::bounds_to_string(bounds));
+                (&ast::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
+                    this.tcx().sess
+                        .span_suggestion(full_span, "try adding parentheses (per RFC 438):",
+                                         format!("&{} {}({} +{})",
+                                                 pprust::lifetime_to_string(lt),
+                                                 ppaux::mutability_to_string(mut_ty.mutbl),
+                                                 pprust::ty_to_string(&*mut_ty.ty),
+                                                 pprust::bounds_to_string(bounds)));
                 }
 
                 _ => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fa76dc167f2..348846b8ad4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1071,7 +1071,16 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 ast::MutImmutable => ""
             };
             if ty::type_is_trait(t_1) {
-                span_help!(fcx.tcx().sess, t_span, "did you mean `&{}{}`?", mtstr, tstr);
+                match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
+                    Ok(s) => {
+                        fcx.tcx().sess.span_suggestion(t_span,
+                                                       "try casting to a reference instead:",
+                                                       format!("&{}{}", mtstr, s));
+                    },
+                    Err(_) =>
+                        span_help!(fcx.tcx().sess, t_span,
+                                   "did you mean `&{}{}`?", mtstr, tstr),
+                }
             } else {
                 span_help!(fcx.tcx().sess, span,
                            "consider using an implicit coercion to `&{}{}` instead",
@@ -1079,7 +1088,15 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             }
         }
         ty::ty_uniq(..) => {
-            span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr);
+            match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
+                Ok(s) => {
+                    fcx.tcx().sess.span_suggestion(t_span,
+                                                   "try casting to a `Box` instead:",
+                                                   format!("Box<{}>", s));
+                },
+                Err(_) =>
+                    span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr),
+            }
         }
         _ => {
             span_help!(fcx.tcx().sess, e_span,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0515d1ae945..ae396d7c4e6 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -972,6 +972,9 @@ impl<'a> Parser<'a> {
     pub fn span_help(&self, sp: Span, m: &str) {
         self.sess.span_diagnostic.span_help(sp, m)
     }
+    pub fn span_suggestion(&self, sp: Span, m: &str, n: String) {
+        self.sess.span_diagnostic.span_suggestion(sp, m, n)
+    }
     pub fn fileline_help(&self, sp: Span, m: &str) {
         self.sess.span_diagnostic.fileline_help(sp, m)
     }
@@ -2594,6 +2597,7 @@ impl<'a> Parser<'a> {
             }
 
             let lo = self.span.lo;
+            let box_hi = self.span.hi;
 
             try!(self.bump());
 
@@ -2610,9 +2614,10 @@ impl<'a> Parser<'a> {
                         self.span_err(span,
                                       &format!("expected expression, found `{}`",
                                               this_token_to_string));
-                        let box_span = mk_sp(lo, self.last_span.hi);
-                        self.span_help(box_span,
-                                       "perhaps you meant `box() (foo)` instead?");
+                        let box_span = mk_sp(lo, box_hi);
+                        self.span_suggestion(box_span,
+                                             "try using `box()` instead:",
+                                             "box()".to_string());
                         self.abort_if_errors();
                     }
                     let subexpression = try!(self.parse_prefix_expr());
diff --git a/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs b/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs
new file mode 100644
index 00000000000..4e6ae96e3fc
--- /dev/null
+++ b/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    &1 as Copy;
+    //~^ ERROR cast to unsized type
+    //~| HELP try casting to a reference instead:
+    //~| SUGGESTION &1 as &Copy;
+    Box::new(1) as Copy;
+    //~^ ERROR cast to unsized type
+    //~| HELP try casting to a `Box` instead:
+    //~| SUGGESTION Box::new(1) as Box<Copy>;
+}
diff --git a/src/test/compile-fail/issue-17441.rs b/src/test/compile-fail/issue-17441.rs
index 68ddef67188..46a64f99354 100644
--- a/src/test/compile-fail/issue-17441.rs
+++ b/src/test/compile-fail/issue-17441.rs
@@ -16,7 +16,7 @@ fn main() {
     // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
     let _bar = Box::new(1_usize) as std::fmt::Debug;
     //~^ ERROR cast to unsized type: `Box<usize>` as `core::fmt::Debug`
-    //~^^ HELP did you mean `Box<core::fmt::Debug>`?
+    //~^^ HELP try casting to a `Box` instead
 
     let _baz = 1_usize as std::fmt::Debug;
     //~^ ERROR cast to unsized type: `usize` as `core::fmt::Debug`
diff --git a/src/test/compile-fail/issue-6702.rs b/src/test/compile-fail/issue-6702.rs
index d035c615ec3..e464ddf54c2 100644
--- a/src/test/compile-fail/issue-6702.rs
+++ b/src/test/compile-fail/issue-6702.rs
@@ -15,5 +15,5 @@ struct Monster {
 
 fn main() {
     let _m = Monster(); //~ ERROR `Monster` is a structure name, but
-    //~^ HELP Did you mean to write: `Monster { /* fields */ }`?
+    //~^ HELP did you mean to write: `Monster { /* fields */ }`?
 }
diff --git a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs
new file mode 100644
index 00000000000..fc2ed83b272
--- /dev/null
+++ b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let _: &Copy + 'static;
+    //~^ ERROR expected a path
+    //~| HELP try adding parentheses
+    //~| SUGGESTION let _: &(Copy + 'static);
+    let _: &'static Copy + 'static;
+    //~^ ERROR expected a path
+    //~| HELP try adding parentheses
+    //~| SUGGESTION let _: &'static (Copy + 'static);
+}
diff --git a/src/test/parse-fail/parenthesized-box-expr-message.rs b/src/test/parse-fail/parenthesized-box-expr-message.rs
index 05bbaec37af..28c64dbc753 100644
--- a/src/test/parse-fail/parenthesized-box-expr-message.rs
+++ b/src/test/parse-fail/parenthesized-box-expr-message.rs
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 fn main() {
-    box(1 + 1) //~ HELP perhaps you meant `box() (foo)` instead?
+    box (1 + 1)
+    //~^ HELP try using `box()` instead:
+    //~| SUGGESTION box() (1 + 1)
     ; //~ ERROR expected expression, found `;`
 }