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.
This commit is contained in:
parent
049de3fe7f
commit
7d2231aa22
10 changed files with 113 additions and 25 deletions
|
@ -979,6 +979,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||||
// is the ending point, and * represents ANSI color codes.
|
// is the ending point, and * represents ANSI color codes.
|
||||||
for line in proc_res.stderr.lines() {
|
for line in proc_res.stderr.lines() {
|
||||||
let mut was_expected = false;
|
let mut was_expected = false;
|
||||||
|
let mut prev = 0;
|
||||||
for (i, ee) in expected_errors.iter().enumerate() {
|
for (i, ee) in expected_errors.iter().enumerate() {
|
||||||
if !found_flags[i] {
|
if !found_flags[i] {
|
||||||
debug!("prefix={} ee.kind={} ee.msg={} line={}",
|
debug!("prefix={} ee.kind={} ee.msg={} line={}",
|
||||||
|
@ -986,6 +987,17 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||||
ee.kind,
|
ee.kind,
|
||||||
ee.msg,
|
ee.msg,
|
||||||
line);
|
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)) &&
|
if (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
|
||||||
line.contains(&ee.kind) &&
|
line.contains(&ee.kind) &&
|
||||||
line.contains(&ee.msg) {
|
line.contains(&ee.msg) {
|
||||||
|
@ -994,6 +1006,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
prev = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore this msg which gets printed at the end
|
// ignore this msg which gets printed at the end
|
||||||
|
|
|
@ -3138,7 +3138,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
uses it like a function name",
|
uses it like a function name",
|
||||||
path_name));
|
path_name));
|
||||||
|
|
||||||
let msg = format!("Did you mean to write: \
|
let msg = format!("did you mean to write: \
|
||||||
`{} {{ /* fields */ }}`?",
|
`{} {{ /* fields */ }}`?",
|
||||||
path_name);
|
path_name);
|
||||||
if self.emit_errors {
|
if self.emit_errors {
|
||||||
|
@ -3179,7 +3179,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
uses it like a function name",
|
uses it like a function name",
|
||||||
path_name));
|
path_name));
|
||||||
|
|
||||||
let msg = format!("Did you mean to write: \
|
let msg = format!("did you mean to write: \
|
||||||
`{} {{ /* fields */ }}`?",
|
`{} {{ /* fields */ }}`?",
|
||||||
path_name);
|
path_name);
|
||||||
if self.emit_errors {
|
if self.emit_errors {
|
||||||
|
|
|
@ -66,7 +66,7 @@ use std::iter::repeat;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use syntax::{abi, ast, ast_util};
|
use syntax::{abi, ast, ast_util};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::{Span, Pos};
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::print::pprust;
|
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,
|
span_err!(this.tcx().sess, ty.span, E0178,
|
||||||
"expected a path on the left-hand side of `+`, not `{}`",
|
"expected a path on the left-hand side of `+`, not `{}`",
|
||||||
pprust::ty_to_string(ty));
|
pprust::ty_to_string(ty));
|
||||||
match ty.node {
|
let hi = bounds.iter().map(|x| match *x {
|
||||||
ast::TyRptr(None, ref mut_ty) => {
|
ast::TraitTyParamBound(ref tr, _) => tr.span.hi,
|
||||||
fileline_help!(this.tcx().sess, ty.span,
|
ast::RegionTyParamBound(ref r) => r.span.hi,
|
||||||
"perhaps you meant `&{}({} +{})`? (per RFC 438)",
|
}).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),
|
ppaux::mutability_to_string(mut_ty.mutbl),
|
||||||
pprust::ty_to_string(&*mut_ty.ty),
|
pprust::ty_to_string(&*mut_ty.ty),
|
||||||
pprust::bounds_to_string(bounds));
|
pprust::bounds_to_string(bounds)));
|
||||||
}
|
}
|
||||||
ast::TyRptr(Some(ref lt), ref mut_ty) => {
|
(&ast::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
|
||||||
fileline_help!(this.tcx().sess, ty.span,
|
this.tcx().sess
|
||||||
"perhaps you meant `&{} {}({} +{})`? (per RFC 438)",
|
.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
|
||||||
|
format!("&{} {}({} +{})",
|
||||||
pprust::lifetime_to_string(lt),
|
pprust::lifetime_to_string(lt),
|
||||||
ppaux::mutability_to_string(mut_ty.mutbl),
|
ppaux::mutability_to_string(mut_ty.mutbl),
|
||||||
pprust::ty_to_string(&*mut_ty.ty),
|
pprust::ty_to_string(&*mut_ty.ty),
|
||||||
pprust::bounds_to_string(bounds));
|
pprust::bounds_to_string(bounds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -1071,7 +1071,16 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
ast::MutImmutable => ""
|
ast::MutImmutable => ""
|
||||||
};
|
};
|
||||||
if ty::type_is_trait(t_1) {
|
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 {
|
} else {
|
||||||
span_help!(fcx.tcx().sess, span,
|
span_help!(fcx.tcx().sess, span,
|
||||||
"consider using an implicit coercion to `&{}{}` instead",
|
"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(..) => {
|
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,
|
span_help!(fcx.tcx().sess, e_span,
|
||||||
|
|
|
@ -972,6 +972,9 @@ impl<'a> Parser<'a> {
|
||||||
pub fn span_help(&self, sp: Span, m: &str) {
|
pub fn span_help(&self, sp: Span, m: &str) {
|
||||||
self.sess.span_diagnostic.span_help(sp, m)
|
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) {
|
pub fn fileline_help(&self, sp: Span, m: &str) {
|
||||||
self.sess.span_diagnostic.fileline_help(sp, m)
|
self.sess.span_diagnostic.fileline_help(sp, m)
|
||||||
}
|
}
|
||||||
|
@ -2594,6 +2597,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
|
let box_hi = self.span.hi;
|
||||||
|
|
||||||
try!(self.bump());
|
try!(self.bump());
|
||||||
|
|
||||||
|
@ -2610,9 +2614,10 @@ impl<'a> Parser<'a> {
|
||||||
self.span_err(span,
|
self.span_err(span,
|
||||||
&format!("expected expression, found `{}`",
|
&format!("expected expression, found `{}`",
|
||||||
this_token_to_string));
|
this_token_to_string));
|
||||||
let box_span = mk_sp(lo, self.last_span.hi);
|
let box_span = mk_sp(lo, box_hi);
|
||||||
self.span_help(box_span,
|
self.span_suggestion(box_span,
|
||||||
"perhaps you meant `box() (foo)` instead?");
|
"try using `box()` instead:",
|
||||||
|
"box()".to_string());
|
||||||
self.abort_if_errors();
|
self.abort_if_errors();
|
||||||
}
|
}
|
||||||
let subexpression = try!(self.parse_prefix_expr());
|
let subexpression = try!(self.parse_prefix_expr());
|
||||||
|
|
|
@ -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>;
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ fn main() {
|
||||||
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
|
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
|
||||||
let _bar = Box::new(1_usize) as std::fmt::Debug;
|
let _bar = Box::new(1_usize) as std::fmt::Debug;
|
||||||
//~^ ERROR cast to unsized type: `Box<usize>` as `core::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;
|
let _baz = 1_usize as std::fmt::Debug;
|
||||||
//~^ ERROR cast to unsized type: `usize` as `core::fmt::Debug`
|
//~^ ERROR cast to unsized type: `usize` as `core::fmt::Debug`
|
||||||
|
|
|
@ -15,5 +15,5 @@ struct Monster {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _m = Monster(); //~ ERROR `Monster` is a structure name, but
|
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 */ }`?
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -9,6 +9,8 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
fn main() {
|
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 `;`
|
; //~ ERROR expected expression, found `;`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue