Skip to content

Commit 7d2231a

Browse files
committed
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.
1 parent 049de3f commit 7d2231a

File tree

10 files changed

+113
-25
lines changed

10 files changed

+113
-25
lines changed

src/compiletest/runtest.rs

+13
Original file line numberDiff line numberDiff line change
@@ -979,13 +979,25 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
979979
// is the ending point, and * represents ANSI color codes.
980980
for line in proc_res.stderr.lines() {
981981
let mut was_expected = false;
982+
let mut prev = 0;
982983
for (i, ee) in expected_errors.iter().enumerate() {
983984
if !found_flags[i] {
984985
debug!("prefix={} ee.kind={} ee.msg={} line={}",
985986
prefixes[i],
986987
ee.kind,
987988
ee.msg,
988989
line);
990+
// Suggestions have no line number in their output, so take on the line number of
991+
// the previous expected error
992+
if ee.kind == "suggestion" {
993+
assert!(expected_errors[prev].kind == "help",
994+
"SUGGESTIONs must be preceded by a HELP");
995+
if line.contains(&ee.msg) {
996+
found_flags[i] = true;
997+
was_expected = true;
998+
break;
999+
}
1000+
}
9891001
if (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
9901002
line.contains(&ee.kind) &&
9911003
line.contains(&ee.msg) {
@@ -994,6 +1006,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
9941006
break;
9951007
}
9961008
}
1009+
prev = i;
9971010
}
9981011

9991012
// ignore this msg which gets printed at the end

src/librustc_resolve/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3138,7 +3138,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
31383138
uses it like a function name",
31393139
path_name));
31403140

3141-
let msg = format!("Did you mean to write: \
3141+
let msg = format!("did you mean to write: \
31423142
`{} {{ /* fields */ }}`?",
31433143
path_name);
31443144
if self.emit_errors {
@@ -3179,7 +3179,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
31793179
uses it like a function name",
31803180
path_name));
31813181

3182-
let msg = format!("Did you mean to write: \
3182+
let msg = format!("did you mean to write: \
31833183
`{} {{ /* fields */ }}`?",
31843184
path_name);
31853185
if self.emit_errors {

src/librustc_typeck/astconv.rs

+26-15
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use std::iter::repeat;
6666
use std::rc::Rc;
6767
use std::slice;
6868
use syntax::{abi, ast, ast_util};
69-
use syntax::codemap::Span;
69+
use syntax::codemap::{Span, Pos};
7070
use syntax::parse::token;
7171
use syntax::print::pprust;
7272

@@ -975,21 +975,32 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
975975
span_err!(this.tcx().sess, ty.span, E0178,
976976
"expected a path on the left-hand side of `+`, not `{}`",
977977
pprust::ty_to_string(ty));
978-
match ty.node {
979-
ast::TyRptr(None, ref mut_ty) => {
980-
fileline_help!(this.tcx().sess, ty.span,
981-
"perhaps you meant `&{}({} +{})`? (per RFC 438)",
982-
ppaux::mutability_to_string(mut_ty.mutbl),
983-
pprust::ty_to_string(&*mut_ty.ty),
984-
pprust::bounds_to_string(bounds));
978+
let hi = bounds.iter().map(|x| match *x {
979+
ast::TraitTyParamBound(ref tr, _) => tr.span.hi,
980+
ast::RegionTyParamBound(ref r) => r.span.hi,
981+
}).max_by(|x| x.to_usize());
982+
let full_span = hi.map(|hi| Span {
983+
lo: ty.span.lo,
984+
hi: hi,
985+
expn_id: ty.span.expn_id,
986+
});
987+
match (&ty.node, full_span) {
988+
(&ast::TyRptr(None, ref mut_ty), Some(full_span)) => {
989+
this.tcx().sess
990+
.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
991+
format!("&{}({} +{})",
992+
ppaux::mutability_to_string(mut_ty.mutbl),
993+
pprust::ty_to_string(&*mut_ty.ty),
994+
pprust::bounds_to_string(bounds)));
985995
}
986-
ast::TyRptr(Some(ref lt), ref mut_ty) => {
987-
fileline_help!(this.tcx().sess, ty.span,
988-
"perhaps you meant `&{} {}({} +{})`? (per RFC 438)",
989-
pprust::lifetime_to_string(lt),
990-
ppaux::mutability_to_string(mut_ty.mutbl),
991-
pprust::ty_to_string(&*mut_ty.ty),
992-
pprust::bounds_to_string(bounds));
996+
(&ast::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
997+
this.tcx().sess
998+
.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
999+
format!("&{} {}({} +{})",
1000+
pprust::lifetime_to_string(lt),
1001+
ppaux::mutability_to_string(mut_ty.mutbl),
1002+
pprust::ty_to_string(&*mut_ty.ty),
1003+
pprust::bounds_to_string(bounds)));
9931004
}
9941005

9951006
_ => {

src/librustc_typeck/check/mod.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -1071,15 +1071,32 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
10711071
ast::MutImmutable => ""
10721072
};
10731073
if ty::type_is_trait(t_1) {
1074-
span_help!(fcx.tcx().sess, t_span, "did you mean `&{}{}`?", mtstr, tstr);
1074+
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
1075+
Ok(s) => {
1076+
fcx.tcx().sess.span_suggestion(t_span,
1077+
"try casting to a reference instead:",
1078+
format!("&{}{}", mtstr, s));
1079+
},
1080+
Err(_) =>
1081+
span_help!(fcx.tcx().sess, t_span,
1082+
"did you mean `&{}{}`?", mtstr, tstr),
1083+
}
10751084
} else {
10761085
span_help!(fcx.tcx().sess, span,
10771086
"consider using an implicit coercion to `&{}{}` instead",
10781087
mtstr, tstr);
10791088
}
10801089
}
10811090
ty::ty_uniq(..) => {
1082-
span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr);
1091+
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
1092+
Ok(s) => {
1093+
fcx.tcx().sess.span_suggestion(t_span,
1094+
"try casting to a `Box` instead:",
1095+
format!("Box<{}>", s));
1096+
},
1097+
Err(_) =>
1098+
span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr),
1099+
}
10831100
}
10841101
_ => {
10851102
span_help!(fcx.tcx().sess, e_span,

src/libsyntax/parse/parser.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,9 @@ impl<'a> Parser<'a> {
972972
pub fn span_help(&self, sp: Span, m: &str) {
973973
self.sess.span_diagnostic.span_help(sp, m)
974974
}
975+
pub fn span_suggestion(&self, sp: Span, m: &str, n: String) {
976+
self.sess.span_diagnostic.span_suggestion(sp, m, n)
977+
}
975978
pub fn fileline_help(&self, sp: Span, m: &str) {
976979
self.sess.span_diagnostic.fileline_help(sp, m)
977980
}
@@ -2594,6 +2597,7 @@ impl<'a> Parser<'a> {
25942597
}
25952598

25962599
let lo = self.span.lo;
2600+
let box_hi = self.span.hi;
25972601

25982602
try!(self.bump());
25992603

@@ -2610,9 +2614,10 @@ impl<'a> Parser<'a> {
26102614
self.span_err(span,
26112615
&format!("expected expression, found `{}`",
26122616
this_token_to_string));
2613-
let box_span = mk_sp(lo, self.last_span.hi);
2614-
self.span_help(box_span,
2615-
"perhaps you meant `box() (foo)` instead?");
2617+
let box_span = mk_sp(lo, box_hi);
2618+
self.span_suggestion(box_span,
2619+
"try using `box()` instead:",
2620+
"box()".to_string());
26162621
self.abort_if_errors();
26172622
}
26182623
let subexpression = try!(self.parse_prefix_expr());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
&1 as Copy;
13+
//~^ ERROR cast to unsized type
14+
//~| HELP try casting to a reference instead:
15+
//~| SUGGESTION &1 as &Copy;
16+
Box::new(1) as Copy;
17+
//~^ ERROR cast to unsized type
18+
//~| HELP try casting to a `Box` instead:
19+
//~| SUGGESTION Box::new(1) as Box<Copy>;
20+
}

src/test/compile-fail/issue-17441.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fn main() {
1616
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
1717
let _bar = Box::new(1_usize) as std::fmt::Debug;
1818
//~^ ERROR cast to unsized type: `Box<usize>` as `core::fmt::Debug`
19-
//~^^ HELP did you mean `Box<core::fmt::Debug>`?
19+
//~^^ HELP try casting to a `Box` instead
2020

2121
let _baz = 1_usize as std::fmt::Debug;
2222
//~^ ERROR cast to unsized type: `usize` as `core::fmt::Debug`

src/test/compile-fail/issue-6702.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ struct Monster {
1515

1616
fn main() {
1717
let _m = Monster(); //~ ERROR `Monster` is a structure name, but
18-
//~^ HELP Did you mean to write: `Monster { /* fields */ }`?
18+
//~^ HELP did you mean to write: `Monster { /* fields */ }`?
1919
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let _: &Copy + 'static;
13+
//~^ ERROR expected a path
14+
//~| HELP try adding parentheses
15+
//~| SUGGESTION let _: &(Copy + 'static);
16+
let _: &'static Copy + 'static;
17+
//~^ ERROR expected a path
18+
//~| HELP try adding parentheses
19+
//~| SUGGESTION let _: &'static (Copy + 'static);
20+
}

src/test/parse-fail/parenthesized-box-expr-message.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
// except according to those terms.
1010

1111
fn main() {
12-
box(1 + 1) //~ HELP perhaps you meant `box() (foo)` instead?
12+
box (1 + 1)
13+
//~^ HELP try using `box()` instead:
14+
//~| SUGGESTION box() (1 + 1)
1315
; //~ ERROR expected expression, found `;`
1416
}

0 commit comments

Comments
 (0)