diff options
| author | bors <bors@rust-lang.org> | 2017-04-08 09:23:28 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-04-08 09:23:28 +0000 |
| commit | 4cadff61ef395f3937d950e35304969ced2ea0b0 (patch) | |
| tree | 1b2004649c34ad8c3056aaf1d433dfc2e7a86bd5 | |
| parent | 3178d4318c669eb0a7bf985e2d603a8e9e1917e7 (diff) | |
| parent | 2b2eeda0831401935a45c70667cf4c3eaedafe7d (diff) | |
| download | rust-4cadff61ef395f3937d950e35304969ced2ea0b0.tar.gz rust-4cadff61ef395f3937d950e35304969ced2ea0b0.zip | |
Auto merge of #40775 - estebank:variant-as-type, r=petrochenkov
Suggest using enum when a variant is used as a type
Given a file:
```rust
enum Fruit {
Apple(i64),
Orange(i64),
}
fn should_return_fruit() -> Apple {
Apple(5)
}
```
Provide the following output:
```rust
error[E0412]: cannot find type `Apple` in this scope
--> file.rs:16:29
|
16 | fn should_return_fruit() -> Apple {
| ^^^^^ not found in this scope
|
help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`?
--> file.rs:12:5
|
12 | Apple(i64),
| ^^^^^^^^^^
error[E0425]: cannot find function `Apple` in this scope
--> file.rs:17:5
|
17 | Apple(5)
| ^^^^^ not found in this scope
|
= help: possible candidate is found in another module, you can import it into scope:
`use Fruit::Apple;`
```
Fix #35675.
| -rw-r--r-- | src/librustc_resolve/lib.rs | 32 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-35675.rs | 67 |
2 files changed, 99 insertions, 0 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d9900340a2e..c94f63329d1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2222,6 +2222,7 @@ impl<'a> Resolver<'a> { -> PathResolution { let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); + let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; // Base error is amended with one short label and possibly some longer helps/notes. let report_errors = |this: &mut Self, def: Option<Def>| { @@ -2272,6 +2273,21 @@ impl<'a> Resolver<'a> { if !candidates.is_empty() { // Report import candidates as help and proceed searching for labels. show_candidates(&mut err, &candidates, def.is_some()); + } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { + let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); + let mut enum_candidates = enum_candidates.iter() + .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>(); + enum_candidates.sort(); + for (sp, variant_path, enum_path) in enum_candidates { + let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", + variant_path, + enum_path); + if sp == DUMMY_SP { + err.help(&msg); + } else { + err.span_help(sp, &msg); + } + } } if path.len() == 1 && this.self_type_is_available() { if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) { @@ -3424,6 +3440,22 @@ fn path_names_to_string(path: &Path) -> String { names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>()) } +/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) { + let variant_path = &suggestion.path; + let variant_path_string = path_names_to_string(variant_path); + + let path_len = suggestion.path.segments.len(); + let enum_path = ast::Path { + span: suggestion.path.span, + segments: suggestion.path.segments[0..path_len - 1].to_vec(), + }; + let enum_path_string = path_names_to_string(&enum_path); + + (suggestion.path.span, variant_path_string, enum_path_string) +} + + /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/test/compile-fail/issue-35675.rs b/src/test/compile-fail/issue-35675.rs new file mode 100644 index 00000000000..f990c2c42fe --- /dev/null +++ b/src/test/compile-fail/issue-35675.rs @@ -0,0 +1,67 @@ +// Copyright 2017 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. + +enum Fruit { + Apple(i64), + //~^ HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + //~| HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + Orange(i64), +} + +fn should_return_fruit() -> Apple { + //~^ ERROR cannot find type `Apple` in this scope + //~| NOTE not found in this scope + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn should_return_fruit_too() -> Fruit::Apple { + //~^ ERROR expected type, found variant `Fruit::Apple` + //~| NOTE not a type + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn foo() -> Ok { + //~^ ERROR expected type, found variant `Ok` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Ok(()) +} + +fn bar() -> Variant3 { + //~^ ERROR cannot find type `Variant3` in this scope + //~| NOTE not found in this scope +} + +fn qux() -> Some { + //~^ ERROR expected type, found variant `Some` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + //~^ HELP there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + Variant4 {}, + } +} |
