Skip to content

Commit cd93b16

Browse files
authored
Rollup merge of rust-lang#56188 - zackmdavis:if_i_may_suggest, r=davidtwco
enum type instead of variant suggestion unification Fixes rust-lang#56028. Weirdly, we were deciding between a help note and a structured suggestion based on whether the import candidate span was a dummy—but we weren't using that span in any case! The dummy-ness of the span (which appears to be a matter of this-crate vs. other-crate definition) isn't the right criterion by which we should decide whether it's germane to mention that "there is an enum variant"; instead, let's use the someness of `def` (which is used as the `has_unexpected_resolution` argument to `error_code`). Since `import_candidate_to_paths` has no other callers, we are free to stop returning the span and rename the function. By using `span_suggestions_`, we leverage the max-suggestions output limit already built in to the emitter, thus resolving rust-lang#56028. In the matter of message wording, "you can" is redundant (and perhaps too informal); prefer the imperative. In a second commit, we do some unprincipled special-casing to correct and beautify suggestions for `Option` and `Result` (where the existing code was being confused by their being reexported in the prelude). r? @davidtwco
2 parents ddab10a + 64ad3e2 commit cd93b16

10 files changed

+133
-58
lines changed

src/librustc_resolve/lib.rs

+38-18
Original file line numberDiff line numberDiff line change
@@ -3213,23 +3213,43 @@ impl<'a> Resolver<'a> {
32133213
let enum_candidates =
32143214
this.lookup_import_candidates(ident, ns, is_enum_variant);
32153215
let mut enum_candidates = enum_candidates.iter()
3216-
.map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
3216+
.map(|suggestion| {
3217+
import_candidate_to_enum_paths(&suggestion)
3218+
}).collect::<Vec<_>>();
32173219
enum_candidates.sort();
3218-
for (sp, variant_path, enum_path) in enum_candidates {
3219-
if sp.is_dummy() {
3220-
let msg = format!("there is an enum variant `{}`, \
3221-
try using `{}`?",
3222-
variant_path,
3223-
enum_path);
3224-
err.help(&msg);
3220+
3221+
if !enum_candidates.is_empty() {
3222+
// contextualize for E0412 "cannot find type", but don't belabor the point
3223+
// (that it's a variant) for E0573 "expected type, found variant"
3224+
let preamble = if def.is_none() {
3225+
let others = match enum_candidates.len() {
3226+
1 => String::new(),
3227+
2 => " and 1 other".to_owned(),
3228+
n => format!(" and {} others", n)
3229+
};
3230+
format!("there is an enum variant `{}`{}; ",
3231+
enum_candidates[0].0, others)
32253232
} else {
3226-
err.span_suggestion_with_applicability(
3227-
span,
3228-
"you can try using the variant's enum",
3229-
enum_path,
3230-
Applicability::MachineApplicable,
3231-
);
3232-
}
3233+
String::new()
3234+
};
3235+
let msg = format!("{}try using the variant's enum", preamble);
3236+
3237+
err.span_suggestions_with_applicability(
3238+
span,
3239+
&msg,
3240+
enum_candidates.into_iter()
3241+
.map(|(_variant_path, enum_ty_path)| enum_ty_path)
3242+
// variants reëxported in prelude doesn't mean `prelude::v1` is the
3243+
// type name! FIXME: is there a more principled way to do this that
3244+
// would work for other reëxports?
3245+
.filter(|enum_ty_path| enum_ty_path != "std::prelude::v1")
3246+
// also say `Option` rather than `std::prelude::v1::Option`
3247+
.map(|enum_ty_path| {
3248+
// FIXME #56861: DRYer prelude filtering
3249+
enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned()
3250+
}),
3251+
Applicability::MachineApplicable,
3252+
);
32333253
}
32343254
}
32353255
if path.len() == 1 && this.self_type_is_available(span) {
@@ -5128,8 +5148,8 @@ fn path_names_to_string(path: &Path) -> String {
51285148
.collect::<Vec<_>>())
51295149
}
51305150

5131-
/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant.
5132-
fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) {
5151+
/// Get the stringified path for an enum from an `ImportSuggestion` for an enum variant.
5152+
fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
51335153
let variant_path = &suggestion.path;
51345154
let variant_path_string = path_names_to_string(variant_path);
51355155

@@ -5140,7 +5160,7 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St
51405160
};
51415161
let enum_path_string = path_names_to_string(&enum_path);
51425162

5143-
(suggestion.path.span, variant_path_string, enum_path_string)
5163+
(variant_path_string, enum_path_string)
51445164
}
51455165

51465166

src/librustc_typeck/check/demand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
123123
let sole_field_ty = sole_field.ty(self.tcx, substs);
124124
if self.can_coerce(expr_ty, sole_field_ty) {
125125
let variant_path = self.tcx.item_path_str(variant.did);
126+
// FIXME #56861: DRYer prelude filtering
126127
Some(variant_path.trim_start_matches("std::prelude::v1::").to_string())
127128
} else {
128129
None
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
enum PutDown { Set }
2+
enum AffixHeart { Set }
3+
enum CauseToBe { Set }
4+
enum Determine { Set }
5+
enum TableDishesAction { Set }
6+
enum Solidify { Set }
7+
enum UnorderedCollection { Set }
8+
9+
fn setup() -> Set { Set }
10+
//~^ ERROR cannot find type `Set` in this scope
11+
//~| ERROR cannot find value `Set` in this scope
12+
13+
fn main() {
14+
setup();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error[E0412]: cannot find type `Set` in this scope
2+
--> $DIR/issue-56028-there-is-an-enum-variant.rs:9:15
3+
|
4+
LL | fn setup() -> Set { Set }
5+
| ^^^ not found in this scope
6+
help: there is an enum variant `AffixHeart::Set` and 7 others; try using the variant's enum
7+
|
8+
LL | fn setup() -> AffixHeart { Set }
9+
| ^^^^^^^^^^
10+
LL | fn setup() -> CauseToBe { Set }
11+
| ^^^^^^^^^
12+
LL | fn setup() -> Determine { Set }
13+
| ^^^^^^^^^
14+
LL | fn setup() -> PutDown { Set }
15+
| ^^^^^^^
16+
and 3 other candidates
17+
18+
error[E0425]: cannot find value `Set` in this scope
19+
--> $DIR/issue-56028-there-is-an-enum-variant.rs:9:21
20+
|
21+
LL | fn setup() -> Set { Set }
22+
| ^^^ not found in this scope
23+
help: possible candidates are found in other modules, you can import them into scope
24+
|
25+
LL | use AffixHeart::Set;
26+
|
27+
LL | use CauseToBe::Set;
28+
|
29+
LL | use Determine::Set;
30+
|
31+
LL | use PutDown::Set;
32+
|
33+
and 3 other candidates
34+
35+
error: aborting due to 2 previous errors
36+
37+
Some errors occurred: E0412, E0425.
38+
For more information about an error, try `rustc --explain E0412`.

src/test/ui/enum/enum-variant-type-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | fn foo(x: Foo::Bar) {} //~ ERROR expected type, found variant `Foo::Bar`
55
| ^^^^^^^^
66
| |
77
| not a type
8-
| help: you can try using the variant's enum: `Foo`
8+
| help: try using the variant's enum: `Foo`
99

1010
error: aborting due to previous error
1111

src/test/ui/issues/issue-17546.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | fn new() -> NoResult<MyEnum, String> {
55
| --------^^^^^^^^^^^^^^^^
66
| |
77
| did you mean `Result`?
8-
| help: you can try using the variant's enum: `foo::MyEnum`
8+
| help: try using the variant's enum: `foo::MyEnum`
99

1010
error[E0573]: expected type, found variant `Result`
1111
--> $DIR/issue-17546.rs:32:17
@@ -48,7 +48,7 @@ LL | fn newer() -> NoResult<foo::MyEnum, String> {
4848
| --------^^^^^^^^^^^^^^^^^^^^^
4949
| |
5050
| did you mean `Result`?
51-
| help: you can try using the variant's enum: `foo::MyEnum`
51+
| help: try using the variant's enum: `foo::MyEnum`
5252

5353
error: aborting due to 4 previous errors
5454

src/test/ui/issues/issue-30535.stderr

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ error[E0573]: expected type, found variant `foo::Foo::FooV`
22
--> $DIR/issue-30535.rs:16:8
33
|
44
LL | _: foo::Foo::FooV //~ ERROR expected type, found variant `foo::Foo::FooV`
5-
| ^^^^^^^^^^^^^^ not a type
6-
|
7-
= help: there is an enum variant `foo::Foo::FooV`, try using `foo::Foo`?
5+
| ^^^^^^^^^^^^^^
6+
| |
7+
| not a type
8+
| help: try using the variant's enum: `foo::Foo`
89

910
error: aborting due to previous error
1011

src/test/ui/issues/issue-35075.stderr

+10-8
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@ error[E0412]: cannot find type `Foo` in this scope
22
--> $DIR/issue-35075.rs:12:12
33
|
44
LL | inner: Foo<T> //~ ERROR cannot find type `Foo` in this scope
5-
| ^^^---
6-
| |
7-
| not found in this scope
8-
| help: you can try using the variant's enum: `Baz`
5+
| ^^^ not found in this scope
6+
help: there is an enum variant `Baz::Foo`; try using the variant's enum
7+
|
8+
LL | inner: Baz //~ ERROR cannot find type `Foo` in this scope
9+
| ^^^
910

1011
error[E0412]: cannot find type `Foo` in this scope
1112
--> $DIR/issue-35075.rs:16:9
1213
|
1314
LL | Foo(Foo<T>) //~ ERROR cannot find type `Foo` in this scope
14-
| ^^^---
15-
| |
16-
| not found in this scope
17-
| help: you can try using the variant's enum: `Baz`
15+
| ^^^ not found in this scope
16+
help: there is an enum variant `Baz::Foo`; try using the variant's enum
17+
|
18+
LL | Foo(Baz) //~ ERROR cannot find type `Foo` in this scope
19+
| ^^^
1820

1921
error: aborting due to 2 previous errors
2022

src/test/ui/issues/issue-35675.stderr

+18-16
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ error[E0412]: cannot find type `Apple` in this scope
22
--> $DIR/issue-35675.rs:17:29
33
|
44
LL | fn should_return_fruit() -> Apple {
5+
| ^^^^^ not found in this scope
6+
help: there is an enum variant `Fruit::Apple`; try using the variant's enum
7+
|
8+
LL | fn should_return_fruit() -> Fruit {
59
| ^^^^^
6-
| |
7-
| not found in this scope
8-
| help: you can try using the variant's enum: `Fruit`
910

1011
error[E0425]: cannot find function `Apple` in this scope
1112
--> $DIR/issue-35675.rs:19:5
@@ -24,7 +25,7 @@ LL | fn should_return_fruit_too() -> Fruit::Apple {
2425
| ^^^^^^^^^^^^
2526
| |
2627
| not a type
27-
| help: you can try using the variant's enum: `Fruit`
28+
| help: try using the variant's enum: `Fruit`
2829

2930
error[E0425]: cannot find function `Apple` in this scope
3031
--> $DIR/issue-35675.rs:25:5
@@ -40,28 +41,29 @@ error[E0573]: expected type, found variant `Ok`
4041
--> $DIR/issue-35675.rs:29:13
4142
|
4243
LL | fn foo() -> Ok {
43-
| ^^ not a type
44-
|
45-
= help: there is an enum variant `std::prelude::v1::Ok`, try using `std::prelude::v1`?
46-
= help: there is an enum variant `std::result::Result::Ok`, try using `std::result::Result`?
44+
| ^^
45+
| |
46+
| not a type
47+
| help: try using the variant's enum: `std::result::Result`
4748

4849
error[E0412]: cannot find type `Variant3` in this scope
4950
--> $DIR/issue-35675.rs:34:13
5051
|
5152
LL | fn bar() -> Variant3 {
52-
| ^^^^^^^^
53-
| |
54-
| not found in this scope
55-
| help: you can try using the variant's enum: `x::Enum`
53+
| ^^^^^^^^ not found in this scope
54+
help: there is an enum variant `x::Enum::Variant3`; try using the variant's enum
55+
|
56+
LL | fn bar() -> x::Enum {
57+
| ^^^^^^^
5658

5759
error[E0573]: expected type, found variant `Some`
5860
--> $DIR/issue-35675.rs:38:13
5961
|
6062
LL | fn qux() -> Some {
61-
| ^^^^ not a type
62-
|
63-
= help: there is an enum variant `std::prelude::v1::Option::Some`, try using `std::prelude::v1::Option`?
64-
= help: there is an enum variant `std::prelude::v1::Some`, try using `std::prelude::v1`?
63+
| ^^^^
64+
| |
65+
| not a type
66+
| help: try using the variant's enum: `Option`
6567

6668
error: aborting due to 7 previous errors
6769

src/test/ui/variants/variant-used-as-type.stderr

+6-10
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,24 @@ error[E0573]: expected type, found variant `Ty::A`
33
|
44
LL | B(Ty::A),
55
| ^^^^^ not a type
6-
help: you can try using the variant's enum
7-
|
8-
LL | B(Ty),
9-
| ^^
10-
help: you can try using the variant's enum
6+
help: try using the variant's enum
117
|
128
LL | B(E),
139
| ^
10+
LL | B(Ty),
11+
| ^^
1412

1513
error[E0573]: expected type, found variant `E::A`
1614
--> $DIR/variant-used-as-type.rs:27:6
1715
|
1816
LL | impl E::A {}
1917
| ^^^^ not a type
20-
help: you can try using the variant's enum
21-
|
22-
LL | impl Ty {}
23-
| ^^
24-
help: you can try using the variant's enum
18+
help: try using the variant's enum
2519
|
2620
LL | impl E {}
2721
| ^
22+
LL | impl Ty {}
23+
| ^^
2824

2925
error: aborting due to 2 previous errors
3026

0 commit comments

Comments
 (0)