diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 8ae3639318291..91550ae746157 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -979,6 +979,7 @@ fn check_expected_errors(expected_errors: Vec , // 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 , 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 , 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 0058b31088b92..d300045c0ec01 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 171c83d00e465..78797d086c677 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 fa76dc167f2ab..348846b8ad401 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 0515d1ae945bd..ae396d7c4e6d2 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 0000000000000..4e6ae96e3fc75 --- /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 or the MIT license +// , 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; +} diff --git a/src/test/compile-fail/issue-17441.rs b/src/test/compile-fail/issue-17441.rs index 68ddef6718878..46a64f99354c6 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` as `core::fmt::Debug` - //~^^ HELP did you mean `Box`? + //~^^ 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 d035c615ec378..e464ddf54c2d9 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 0000000000000..fc2ed83b2724d --- /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 or the MIT license +// , 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 05bbaec37af02..28c64dbc7531d 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 `;` }