From 99aae9b834604788b58da8eac9156cc3715426e1 Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Wed, 28 Sep 2016 19:27:23 +1000 Subject: [PATCH] Improve error message and snippet for "did you mean `x`" - Fixes #36164 - Part of #35233 - handles unknown fields - uses UI-style tests - update all related tests (cfail, ui, incremental) --- src/librustc_typeck/check/mod.rs | 14 ++++++++------ .../compile-fail/attempted-access-non-fatal.rs | 4 ++-- src/test/compile-fail/cast-rfc0401.rs | 2 +- .../compile-fail/derived-errors/issue-30580.rs | 2 +- src/test/compile-fail/issue-11004.rs | 4 ++-- src/test/compile-fail/issue-14721.rs | 3 +-- src/test/compile-fail/issue-19244-2.rs | 2 +- src/test/compile-fail/issue-23253.rs | 2 +- src/test/compile-fail/issue-24363.rs | 2 +- src/test/compile-fail/issue-24365.rs | 6 +++--- src/test/compile-fail/issue-31011.rs | 2 +- src/test/compile-fail/no-type-for-node-ice.rs | 2 +- src/test/compile-fail/struct-fields-typo.rs | 4 ++-- .../compile-fail/struct-pat-derived-error.rs | 2 +- .../compile-fail/union/union-suggest-field.rs | 4 ++-- src/test/compile-fail/unsafe-fn-autoderef.rs | 2 +- .../incremental/struct_change_field_name.rs | 4 ++-- src/test/ui/did_you_mean/issue-36798.rs | 18 ++++++++++++++++++ src/test/ui/did_you_mean/issue-36798.stderr | 8 ++++++++ .../did_you_mean/issue-36798_unknown_field.rs | 18 ++++++++++++++++++ .../issue-36798_unknown_field.stderr | 8 ++++++++ .../macro-backtrace-invalid-internals.stderr | 12 ++++++------ 22 files changed, 89 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-36798.rs create mode 100644 src/test/ui/did_you_mean/issue-36798.stderr create mode 100644 src/test/ui/did_you_mean/issue-36798_unknown_field.rs create mode 100644 src/test/ui/did_you_mean/issue-36798_unknown_field.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ee00cb2f5a3e4..1345bffca7580 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2959,18 +2959,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .emit(); self.tcx().types.err } else { - let mut err = self.type_error_struct(expr.span, |actual| { - format!("attempted access of field `{}` on type `{}`, \ - but no field with that name was found", + let mut err = self.type_error_struct(field.span, |actual| { + format!("no field `{}` on type `{}`", field.node, actual) }, expr_t); match expr_t.sty { ty::TyAdt(def, _) if !def.is_enum() => { if let Some(suggested_field_name) = Self::suggest_field_name(def.struct_variant(), field, vec![]) { - err.span_help(field.span, - &format!("did you mean `{}`?", suggested_field_name)); - }; + err.span_label(field.span, + &format!("did you mean `{}`?", suggested_field_name)); + } else { + err.span_label(field.span, + &format!("unknown field")); + }; } ty::TyRawPtr(..) => { err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ diff --git a/src/test/compile-fail/attempted-access-non-fatal.rs b/src/test/compile-fail/attempted-access-non-fatal.rs index 1d9249bc17b1f..fe8e793ed781a 100644 --- a/src/test/compile-fail/attempted-access-non-fatal.rs +++ b/src/test/compile-fail/attempted-access-non-fatal.rs @@ -11,6 +11,6 @@ // Check that bogus field access is non-fatal fn main() { let x = 0; - let _ = x.foo; //~ ERROR attempted access of field - let _ = x.bar; //~ ERROR attempted access of field + let _ = x.foo; //~ no field `foo` on type `{integer}` + let _ = x.bar; //~ no field `bar` on type `{integer}` } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index b6e81504a9d24..ee622a17ab12c 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -112,7 +112,7 @@ fn main() //~| NOTE required for the cast to the object type `Foo` // check no error cascade - let _ = main.f as *const u32; //~ ERROR attempted access of field + let _ = main.f as *const u32; //~ no field `f` on type `fn() {main}` let cf: *const Foo = &0; let _ = cf as *const [u16]; diff --git a/src/test/compile-fail/derived-errors/issue-30580.rs b/src/test/compile-fail/derived-errors/issue-30580.rs index 88d4aef6d9ddc..553ad0a33410b 100644 --- a/src/test/compile-fail/derived-errors/issue-30580.rs +++ b/src/test/compile-fail/derived-errors/issue-30580.rs @@ -19,7 +19,7 @@ impl<'a, 'tcx> Pass<'a, 'tcx> pub fn tcx(&self) -> &'a &'tcx () { self.1 } fn lol(&mut self, b: &Foo) { - b.c; //~ ERROR no field with that name was found + b.c; //~ ERROR no field `c` on type `&Foo` self.tcx(); } } diff --git a/src/test/compile-fail/issue-11004.rs b/src/test/compile-fail/issue-11004.rs index 308be46271531..069883424222e 100644 --- a/src/test/compile-fail/issue-11004.rs +++ b/src/test/compile-fail/issue-11004.rs @@ -14,9 +14,9 @@ struct A { x: i32, y: f64 } #[cfg(not(works))] unsafe fn access(n:*mut A) -> (i32, f64) { - let x : i32 = n.x; //~ ERROR attempted access of field `x` + let x : i32 = n.x; //~ no field `x` on type `*mut A` //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).x` - let y : f64 = n.y; //~ ERROR attempted access of field `y` + let y : f64 = n.y; //~ no field `y` on type `*mut A` //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).y` (x, y) } diff --git a/src/test/compile-fail/issue-14721.rs b/src/test/compile-fail/issue-14721.rs index 92add18f9413c..58e8e10ee37ac 100644 --- a/src/test/compile-fail/issue-14721.rs +++ b/src/test/compile-fail/issue-14721.rs @@ -10,6 +10,5 @@ fn main() { let foo = "str"; - println!("{}", foo.desc); //~ ERROR attempted access of field `desc` on type `&str`, - // but no field with that name was found + println!("{}", foo.desc); //~ no field `desc` on type `&str` } diff --git a/src/test/compile-fail/issue-19244-2.rs b/src/test/compile-fail/issue-19244-2.rs index 7d7d7d7c8ce4d..864f8f6b54e7c 100644 --- a/src/test/compile-fail/issue-19244-2.rs +++ b/src/test/compile-fail/issue-19244-2.rs @@ -13,5 +13,5 @@ const STRUCT: MyStruct = MyStruct { field: 42 }; fn main() { let a: [isize; STRUCT.nonexistent_field]; - //~^ ERROR attempted access of field `nonexistent_field` + //~^ no field `nonexistent_field` on type `MyStruct` } diff --git a/src/test/compile-fail/issue-23253.rs b/src/test/compile-fail/issue-23253.rs index e977cd135ab67..626604a87a72c 100644 --- a/src/test/compile-fail/issue-23253.rs +++ b/src/test/compile-fail/issue-23253.rs @@ -12,5 +12,5 @@ enum Foo { Bar } fn main() { Foo::Bar.a; - //~^ ERROR: attempted access of field `a` on type `Foo`, but no field with that name was found + //~^ no field `a` on type `Foo` } diff --git a/src/test/compile-fail/issue-24363.rs b/src/test/compile-fail/issue-24363.rs index 590c464371c06..03cae6e64ef5e 100644 --- a/src/test/compile-fail/issue-24363.rs +++ b/src/test/compile-fail/issue-24363.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - 1.create_a_type_error[ //~ ERROR attempted access of field + 1.create_a_type_error[ //~ no field `create_a_type_error` on type `{integer}` ()+() //~ ERROR binary operation `+` cannot be applied // ^ ensure that we typeck the inner expression ^ ]; diff --git a/src/test/compile-fail/issue-24365.rs b/src/test/compile-fail/issue-24365.rs index a4df42a8c70f2..72df6fb59990f 100644 --- a/src/test/compile-fail/issue-24365.rs +++ b/src/test/compile-fail/issue-24365.rs @@ -17,13 +17,13 @@ pub enum Foo { } fn test(a: Foo) { - println!("{}", a.b); //~ ERROR attempted access of field + println!("{}", a.b); //~ no field `b` on type `Foo` } fn main() { let x = Attribute::Code { attr_name_idx: 42, }; - let z = (&x).attr_name_idx; //~ ERROR attempted access of field - let y = x.attr_name_idx; //~ ERROR attempted access of field + let z = (&x).attr_name_idx; //~ no field `attr_name_idx` on type `&Attribute` + let y = x.attr_name_idx; //~ no field `attr_name_idx` on type `Attribute` } diff --git a/src/test/compile-fail/issue-31011.rs b/src/test/compile-fail/issue-31011.rs index b828b11030d71..716b0bbe77294 100644 --- a/src/test/compile-fail/issue-31011.rs +++ b/src/test/compile-fail/issue-31011.rs @@ -11,7 +11,7 @@ macro_rules! log { ( $ctx:expr, $( $args:expr),* ) => { if $ctx.trace { - //~^ ERROR attempted access of field `trace` on type `&T`, but no field with that name + //~^ no field `trace` on type `&T` println!( $( $args, )* ); } } diff --git a/src/test/compile-fail/no-type-for-node-ice.rs b/src/test/compile-fail/no-type-for-node-ice.rs index aab4db6eadfd6..f049f69e4bba2 100644 --- a/src/test/compile-fail/no-type-for-node-ice.rs +++ b/src/test/compile-fail/no-type-for-node-ice.rs @@ -11,5 +11,5 @@ // Related issues: #20401, #20506, #20614, #20752, #20829, #20846, #20885, #20886 fn main() { - "".homura[""]; //~ ERROR no field with that name was found + "".homura[""]; //~ no field `homura` on type `&'static str` } diff --git a/src/test/compile-fail/struct-fields-typo.rs b/src/test/compile-fail/struct-fields-typo.rs index c897dc55204b1..0e30c1e86e4f2 100644 --- a/src/test/compile-fail/struct-fields-typo.rs +++ b/src/test/compile-fail/struct-fields-typo.rs @@ -18,7 +18,7 @@ fn main() { foo: 0, bar: 0.5, }; - let x = foo.baa;//~ ERROR attempted access of field `baa` on type `BuildData` - //~^ HELP did you mean `bar`? + let x = foo.baa;//~ no field `baa` on type `BuildData` + //~^ did you mean `bar`? println!("{}", x); } diff --git a/src/test/compile-fail/struct-pat-derived-error.rs b/src/test/compile-fail/struct-pat-derived-error.rs index 4b65292340fa1..f525ec373753d 100644 --- a/src/test/compile-fail/struct-pat-derived-error.rs +++ b/src/test/compile-fail/struct-pat-derived-error.rs @@ -15,7 +15,7 @@ struct a { impl a { fn foo(&self) { - let a { x, y } = self.d; //~ ERROR attempted access of field `d` + let a { x, y } = self.d; //~ ERROR no field `d` on type `&a` //~^ ERROR struct `a` does not have a field named `x` //~^^ ERROR struct `a` does not have a field named `y` //~^^^ ERROR pattern does not mention field `b` diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs index ce421428d883b..3c355989b82f0 100644 --- a/src/test/compile-fail/union/union-suggest-field.rs +++ b/src/test/compile-fail/union/union-suggest-field.rs @@ -22,8 +22,8 @@ fn main() { let u = U { principle: 0 }; //~^ ERROR union `U` has no field named `principle` //~| NOTE field does not exist - did you mean `principal`? - let w = u.principial; //~ ERROR attempted access of field `principial` on type `U` - //~^ HELP did you mean `principal`? + let w = u.principial; //~ ERROR no field `principial` on type `U` + //~^ did you mean `principal`? let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U` //~^ HELP maybe a `()` to call it is missing? diff --git a/src/test/compile-fail/unsafe-fn-autoderef.rs b/src/test/compile-fail/unsafe-fn-autoderef.rs index 97a7bf147105a..15b304c69baf5 100644 --- a/src/test/compile-fail/unsafe-fn-autoderef.rs +++ b/src/test/compile-fail/unsafe-fn-autoderef.rs @@ -26,7 +26,7 @@ fn f(p: *const Rec) -> isize { // are prohibited by various checks, such as that the enum is // instantiable and so forth). - return p.f; //~ ERROR attempted access of field `f` on type `*const Rec` + return p.f; //~ ERROR no field `f` on type `*const Rec` } fn main() { diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index c27294442e7a4..cb43d12740584 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -39,13 +39,13 @@ pub fn use_X() -> u32 { let x: X = X { x: 22 }; //[cfail2]~^ ERROR struct `X` has no field named `x` x.x as u32 - //[cfail2]~^ ERROR attempted access of field `x` + //[cfail2]~^ ERROR no field `x` on type `X` } #[rustc_dirty(label="TypeckItemBody", cfg="cfail2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 - //[cfail2]~^ ERROR attempted access of field `x` + //[cfail2]~^ ERROR no field `x` on type `X` } #[rustc_clean(label="TypeckItemBody", cfg="cfail2")] diff --git a/src/test/ui/did_you_mean/issue-36798.rs b/src/test/ui/did_you_mean/issue-36798.rs new file mode 100644 index 0000000000000..cd0d0951abf8a --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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. + +struct Foo { + bar: u8 +} + +fn main() { + let f = Foo { bar: 22 }; + f.baz; +} diff --git a/src/test/ui/did_you_mean/issue-36798.stderr b/src/test/ui/did_you_mean/issue-36798.stderr new file mode 100644 index 0000000000000..c124747c801d8 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798.stderr @@ -0,0 +1,8 @@ +error: no field `baz` on type `Foo` + --> $DIR/issue-36798.rs:17:7 + | +17 | f.baz; + | ^^^ did you mean `bar`? + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-36798_unknown_field.rs b/src/test/ui/did_you_mean/issue-36798_unknown_field.rs new file mode 100644 index 0000000000000..2970a325a6af8 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798_unknown_field.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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. + +struct Foo { + bar: u8 +} + +fn main() { + let f = Foo { bar: 22 }; + f.zz; +} diff --git a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr new file mode 100644 index 0000000000000..4e02f8bd0cfb2 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr @@ -0,0 +1,8 @@ +error: no field `zz` on type `Foo` + --> $DIR/issue-36798_unknown_field.rs:17:7 + | +17 | f.zz; + | ^^ unknown field + +error: aborting due to previous error + diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index 82000a59bfb17..48f9bac906ecf 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -7,11 +7,11 @@ error: no method named `fake` found for type `{integer}` in the current scope 50 | fake_method_stmt!(); | -------------------- in this macro invocation -error: attempted access of field `fake` on type `{integer}`, but no field with that name was found - --> $DIR/macro-backtrace-invalid-internals.rs:21:11 +error: no field `fake` on type `{integer}` + --> $DIR/macro-backtrace-invalid-internals.rs:21:13 | 21 | 1.fake - | ^^^^^^ + | ^^^^ ... 51 | fake_field_stmt!(); | ------------------- in this macro invocation @@ -34,11 +34,11 @@ error: no method named `fake` found for type `{integer}` in the current scope 54 | let _ = fake_method_expr!(); | ------------------- in this macro invocation -error: attempted access of field `fake` on type `{integer}`, but no field with that name was found - --> $DIR/macro-backtrace-invalid-internals.rs:39:11 +error: no field `fake` on type `{integer}` + --> $DIR/macro-backtrace-invalid-internals.rs:39:13 | 39 | 1.fake - | ^^^^^^ + | ^^^^ ... 55 | let _ = fake_field_expr!(); | ------------------ in this macro invocation