Skip to content

Use the proper term when using non-existing variant #46024

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

Merged
merged 4 commits into from
Nov 23, 2017
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
16 changes: 16 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,15 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}
}

pub fn is_enum(&self) -> bool {
match self.sty {
TyAdt(adt_def, _) => {
adt_def.is_enum()
}
_ => false,
}
}

pub fn is_closure(&self) -> bool {
match self.sty {
TyClosure(..) => true,
Expand All @@ -1233,6 +1242,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}
}

pub fn is_fresh_ty(&self) -> bool {
match self.sty {
TyInfer(FreshTy(_)) => true,
_ => false,
}
}

pub fn is_fresh(&self) -> bool {
match self.sty {
TyInfer(FreshTy(_)) => true,
Expand Down
80 changes: 52 additions & 28 deletions src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,41 +164,63 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};

match error {
MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
unsatisfied_predicates,
out_of_scope_traits,
lev_candidate,
mode,
.. }) => {
MethodError::NoMatch(NoMatchData {
static_candidates: static_sources,
unsatisfied_predicates,
out_of_scope_traits,
lev_candidate,
mode,
..
}) => {
let tcx = self.tcx;

let actual = self.resolve_type_vars_if_possible(&rcvr_ty);
let ty_string = self.ty_to_string(actual);
let is_method = mode == Mode::MethodCall;
let type_str = if is_method {
"method"
} else if actual.is_enum() {
"variant"
} else {
match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
(Some(name), false) if name.is_lowercase() => {
"function or associated item"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add tests for all these new variations of diagnostics?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
(Some(_), false) => "associated item",
(Some(_), true) | (None, false) => {
"variant or associated item"
}
(None, true) => "variant",
}
};
let mut err = if !actual.references_error() {
struct_span_err!(tcx.sess, span, E0599,
"no {} named `{}` found for type `{}` in the \
current scope",
if mode == Mode::MethodCall {
"method"
} else {
match item_name.as_str().chars().next() {
Some(name) => {
if name.is_lowercase() {
"function or associated item"
} else {
"associated item"
}
},
None => {
""
},
}
},
item_name,
self.ty_to_string(actual))
struct_span_err!(
tcx.sess,
span,
E0599,
"no {} named `{}` found for type `{}` in the current scope",
type_str,
item_name,
ty_string
)
} else {
self.tcx.sess.diagnostic().struct_dummy()
tcx.sess.diagnostic().struct_dummy()
};

if let Some(def) = actual.ty_adt_def() {
if let Some(full_sp) = tcx.hir.span_if_local(def.did) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oli-obk I don't know if this will actually do what I want it to do. After the test suite runs I'll see. If the output is still suboptimal, I'll leave the PR with only the first commit for merging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks on travis like it's doing the right thing now

let def_sp = tcx.sess.codemap().def_span(full_sp);
err.span_label(def_sp, format!("{} `{}` not found {}",
type_str,
item_name,
if def.is_enum() && !is_method {
"here"
} else {
"for this"
}));
}
}

// If the method name is the name of a field with a function or closure type,
// give a helping note that it has to be called as (x.f)(...).
if let Some(expr) = rcvr_expr {
Expand Down Expand Up @@ -240,6 +262,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => {}
}
}
} else {
err.span_label(span, format!("{} not found in `{}`", type_str, ty_string));
}

if self.is_fn_ty(&rcvr_ty, span) {
Expand Down
5 changes: 4 additions & 1 deletion src/test/compile-fail/bogus-tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@


enum color { rgb(isize, isize, isize), rgba(isize, isize, isize, isize), }
//~^ NOTE variant `hsl` not found here

fn main() {
let red: color = color::rgb(255, 0, 0);
match red {
color::rgb(r, g, b) => { println!("rgb"); }
color::hsl(h, s, l) => { println!("hsl"); } //~ ERROR no function
color::hsl(h, s, l) => { println!("hsl"); }
//~^ ERROR no variant
//~| NOTE variant not found in `color`
}
}
4 changes: 2 additions & 2 deletions src/test/compile-fail/empty-struct-braces-expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ fn main() {

let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1`
let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1`
let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type
let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type
let xe3 = XE::Empty3; //~ ERROR no variant named `Empty3` found for type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this context nothing suggests for sure that Empty3 is a variant and not an associated constant or method.
At the same time, in other contexts like tuple struct patterns match { E::X(..) => {} } we can say for sure that X is a variant, but in this PR diagnostics are not context-dependent, only guessing based on case etc is used.
What I'd want to see is a context-dependent message worded and formatted uniformly with other "expected, (not) found" resolution diagnostics.
This is a bit vague and this PR is still an improvement, so I won't block this PR on these changes.

(I'm basically adding a "rewrite this from scratch" item in my TODO list now.)

let xe3 = XE::Empty3(); //~ ERROR no variant named `Empty3` found for type
}
5 changes: 3 additions & 2 deletions src/test/compile-fail/issue-22933-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum Delicious {
enum Delicious { //~ NOTE variant `PIE` not found here
Pie = 0x1,
Apple = 0x2,
ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
//~^ ERROR no associated item named `PIE` found for type `Delicious`
//~^ ERROR no variant named `PIE` found for type `Delicious`
//~| NOTE variant not found in `Delicious`
}

fn main() {}
20 changes: 19 additions & 1 deletion src/test/compile-fail/issue-23173.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,27 @@
// except according to those terms.

enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ }
//~^ NOTE variant `Homura` not found here
struct Struct {
//~^ NOTE function or associated item `method` not found for this
//~| NOTE function or associated item `method` not found for this
//~| NOTE associated item `Assoc` not found for this
a: usize,
}

fn use_token(token: &Token) { unimplemented!() }

fn main() {
use_token(&Token::Homura); //~ ERROR no associated item named
use_token(&Token::Homura);
//~^ ERROR no variant named `Homura`
//~| NOTE variant not found in `Token`
Struct::method();
//~^ ERROR no function or associated item named `method` found for type
//~| NOTE function or associated item not found in `Struct`
Struct::method;
//~^ ERROR no function or associated item named `method` found for type
//~| NOTE function or associated item not found in `Struct`
Struct::Assoc;
//~^ ERROR no associated item named `Assoc` found for type `Struct` in
//~| NOTE associated item not found in `Struct`
}
5 changes: 3 additions & 2 deletions src/test/compile-fail/issue-23217.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub enum SomeEnum {
pub enum SomeEnum { //~ NOTE variant `A` not found here
B = SomeEnum::A,
//~^ ERROR no associated item named `A` found for type `SomeEnum`
//~^ ERROR no variant named `A` found for type `SomeEnum`
//~| NOTE variant not found in `SomeEnum`
}

fn main() {}
6 changes: 4 additions & 2 deletions src/test/compile-fail/issue-28971.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@

// This should not cause an ICE

enum Foo {
enum Foo { //~ NOTE variant `Baz` not found here
Bar(u8)
}
fn main(){
foo(|| {
match Foo::Bar(1) {
Foo::Baz(..) => (), //~ ERROR no associated
Foo::Baz(..) => (),
//~^ ERROR no variant named `Baz` found for type `Foo`
//~| NOTE variant not found in `Foo`
_ => (),
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
error[E0599]: no method named `foo` found for type `Bar` in the current scope
--> $DIR/issue-21659-show-relevant-trait-impls-3.rs:30:8
|
23 | struct Bar;
| ----------- method `foo` not found for this
...
30 | f1.foo(1usize);
| ^^^
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
error[E0599]: no method named `is_empty` found for type `Foo` in the current scope
--> $DIR/method-suggestion-no-duplication.rs:19:15
|
14 | struct Foo;
| ----------- method `is_empty` not found for this
...
19 | foo(|s| s.is_empty());
| ^^^^^^^^
|
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/impl-trait/no-method-suggested-traits.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::box
error[E0599]: no method named `method` found for type `Foo` in the current scope
--> $DIR/no-method-suggested-traits.rs:62:9
|
14 | struct Foo;
| ----------- method `method` not found for this
...
62 | Foo.method();
| ^^^^^^
|
Expand Down Expand Up @@ -157,6 +160,9 @@ error[E0599]: no method named `method2` found for type `std::rc::Rc<&mut std::bo
error[E0599]: no method named `method3` found for type `Foo` in the current scope
--> $DIR/no-method-suggested-traits.rs:107:9
|
14 | struct Foo;
| ----------- method `method3` not found for this
...
107 | Foo.method3();
| ^^^^^^^
|
Expand All @@ -177,6 +183,9 @@ error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::bo
error[E0599]: no method named `method3` found for type `Bar` in the current scope
--> $DIR/no-method-suggested-traits.rs:115:12
|
15 | enum Bar { X }
| -------- method `method3` not found for this
...
115 | Bar::X.method3();
| ^^^^^^^
|
Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/method-call-err-msg.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ error[E0061]: this function takes 2 parameters but 1 parameter was supplied
error[E0599]: no method named `take` found for type `Foo` in the current scope
--> $DIR/method-call-err-msg.rs:34:7
|
13 | pub struct Foo;
| --------------- method `take` not found for this
...
34 | .take() //~ ERROR no method named `take` found for type `Foo` in the current scope
| ^^^^
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0599]: no associated item named `XXX` found for type `u32` in the current
--> $DIR/no-double-error.rs:18:9
|
18 | u32::XXX => { }
| ^^^^^^^^
| ^^^^^^^^ associated item not found in `u32`

error: aborting due to previous error

3 changes: 3 additions & 0 deletions src/test/ui/span/issue-7575.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ note: candidate #3 is defined in the trait `UnusedTrait`
error[E0599]: no method named `fff` found for type `Myisize` in the current scope
--> $DIR/issue-7575.rs:74:30
|
48 | struct Myisize(isize);
| ---------------------- method `fff` not found for this
...
74 | u.f8(42) + u.f9(342) + m.fff(42)
| ^^^
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
error[E0599]: no method named `closure` found for type `Obj<[closure@$DIR/issue-18343.rs:16:28: 16:33]>` in the current scope
--> $DIR/issue-18343.rs:17:7
|
11 | struct Obj<F> where F: FnMut() -> u32 {
| ------------------------------------- method `closure` not found for this
...
17 | o.closure();
| ^^^^^^^ field, not a method
|
Expand Down
Loading