Skip to content

Commit 4cadff6

Browse files
committed
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.
2 parents 3178d43 + 2b2eeda commit 4cadff6

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

src/librustc_resolve/lib.rs

+32
Original file line numberDiff line numberDiff line change
@@ -2222,6 +2222,7 @@ impl<'a> Resolver<'a> {
22222222
-> PathResolution {
22232223
let ns = source.namespace();
22242224
let is_expected = &|def| source.is_expected(def);
2225+
let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false };
22252226

22262227
// Base error is amended with one short label and possibly some longer helps/notes.
22272228
let report_errors = |this: &mut Self, def: Option<Def>| {
@@ -2272,6 +2273,21 @@ impl<'a> Resolver<'a> {
22722273
if !candidates.is_empty() {
22732274
// Report import candidates as help and proceed searching for labels.
22742275
show_candidates(&mut err, &candidates, def.is_some());
2276+
} else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
2277+
let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant);
2278+
let mut enum_candidates = enum_candidates.iter()
2279+
.map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
2280+
enum_candidates.sort();
2281+
for (sp, variant_path, enum_path) in enum_candidates {
2282+
let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?",
2283+
variant_path,
2284+
enum_path);
2285+
if sp == DUMMY_SP {
2286+
err.help(&msg);
2287+
} else {
2288+
err.span_help(sp, &msg);
2289+
}
2290+
}
22752291
}
22762292
if path.len() == 1 && this.self_type_is_available() {
22772293
if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
@@ -3424,6 +3440,22 @@ fn path_names_to_string(path: &Path) -> String {
34243440
names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>())
34253441
}
34263442

3443+
/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant.
3444+
fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) {
3445+
let variant_path = &suggestion.path;
3446+
let variant_path_string = path_names_to_string(variant_path);
3447+
3448+
let path_len = suggestion.path.segments.len();
3449+
let enum_path = ast::Path {
3450+
span: suggestion.path.span,
3451+
segments: suggestion.path.segments[0..path_len - 1].to_vec(),
3452+
};
3453+
let enum_path_string = path_names_to_string(&enum_path);
3454+
3455+
(suggestion.path.span, variant_path_string, enum_path_string)
3456+
}
3457+
3458+
34273459
/// When an entity with a given name is not available in scope, we search for
34283460
/// entities with that name in all crates. This method allows outputting the
34293461
/// results of this search in a programmer-friendly way

src/test/compile-fail/issue-35675.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
enum Fruit {
12+
Apple(i64),
13+
//~^ HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`?
14+
//~| HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`?
15+
Orange(i64),
16+
}
17+
18+
fn should_return_fruit() -> Apple {
19+
//~^ ERROR cannot find type `Apple` in this scope
20+
//~| NOTE not found in this scope
21+
Apple(5)
22+
//~^ ERROR cannot find function `Apple` in this scope
23+
//~| NOTE not found in this scope
24+
//~| HELP possible candidate is found in another module, you can import it into scope
25+
}
26+
27+
fn should_return_fruit_too() -> Fruit::Apple {
28+
//~^ ERROR expected type, found variant `Fruit::Apple`
29+
//~| NOTE not a type
30+
Apple(5)
31+
//~^ ERROR cannot find function `Apple` in this scope
32+
//~| NOTE not found in this scope
33+
//~| HELP possible candidate is found in another module, you can import it into scope
34+
}
35+
36+
fn foo() -> Ok {
37+
//~^ ERROR expected type, found variant `Ok`
38+
//~| NOTE not a type
39+
//~| HELP there is an enum variant
40+
//~| HELP there is an enum variant
41+
Ok(())
42+
}
43+
44+
fn bar() -> Variant3 {
45+
//~^ ERROR cannot find type `Variant3` in this scope
46+
//~| NOTE not found in this scope
47+
}
48+
49+
fn qux() -> Some {
50+
//~^ ERROR expected type, found variant `Some`
51+
//~| NOTE not a type
52+
//~| HELP there is an enum variant
53+
//~| HELP there is an enum variant
54+
Some(1)
55+
}
56+
57+
fn main() {}
58+
59+
mod x {
60+
enum Enum {
61+
Variant1,
62+
Variant2(),
63+
Variant3(usize),
64+
//~^ HELP there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`?
65+
Variant4 {},
66+
}
67+
}

0 commit comments

Comments
 (0)