Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change a few error messages to give code suggestions #24683

Merged
merged 1 commit into from
Apr 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/compiletest/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,13 +979,25 @@ 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={}",
prefixes[i],
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) {
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
41 changes: 26 additions & 15 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)));
}

_ => {
Expand Down
21 changes: 19 additions & 2 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,15 +1071,32 @@ 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",
mtstr, tstr);
}
}
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,
Expand Down
11 changes: 8 additions & 3 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -2594,6 +2597,7 @@ impl<'a> Parser<'a> {
}

let lo = self.span.lo;
let box_hi = self.span.hi;

try!(self.bump());

Expand All @@ -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());
Expand Down
20 changes: 20 additions & 0 deletions src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs
Original file line number Diff line number Diff line change
@@ -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>;
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-17441.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-6702.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 */ }`?
}
Original file line number Diff line number Diff line change
@@ -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);
}
4 changes: 3 additions & 1 deletion src/test/parse-fail/parenthesized-box-expr-message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `;`
}