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 2 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
78 changes: 50 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,61 @@ 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 type_str = if mode == Mode::MethodCall {
"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() {
let full_sp = tcx.def_span(def.did);
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() {
"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 +260,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
3 changes: 2 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,12 @@


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
}
}
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
}
4 changes: 2 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,11 @@
// 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`
}

fn main() {}
3 changes: 2 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,10 @@
// except according to those terms.

enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ }
//~^ NOTE variant `Homura` not found here

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`
}
4 changes: 2 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,9 @@
// 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`
}

fn main() {}
5 changes: 3 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,14 @@

// 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`
_ => (),
}
});
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
Loading