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.
This commit is contained in:
commit
4cadff61ef
@ -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
|
||||
|
67
src/test/compile-fail/issue-35675.rs
Normal file
67
src/test/compile-fail/issue-35675.rs
Normal file
@ -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 {},
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user