Skip to content

Commit b0d3d3b

Browse files
committed
only issue "variant of the expected type" suggestion for enums
Felix S. Klock II pointed out that this suggestion (introduced in pull-request #43178 / eac7410) was being issued for one-field-struct expected types (in which case it is misleading and outright wrong), even though it was only intended for one-field enum-variants (most notably, `Some`). Particularly tender-hearted code-historians may be inclined to show mercy towards the author of #43178 on the grounds that it's somewhat confusing that struct field definitions are given in a type called `ty::VariantDef`. Add a conditional to adhere to the original intent. (It would be possible to generalize to structs, but not obviously net desirable.) This adds a level of indentation, so the diff here is going to be easier to read in ignore-whitespace mode (`-w`). Resolves #55250.
1 parent 22cc2ae commit b0d3d3b

File tree

3 files changed

+53
-27
lines changed

3 files changed

+53
-27
lines changed

src/librustc_typeck/check/demand.rs

+27-26
Original file line numberDiff line numberDiff line change
@@ -111,34 +111,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
111111
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
112112
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
113113

114-
// If the expected type is an enum with any variants whose sole
115-
// field is of the found type, suggest such variants. See Issue
116-
// #42764.
114+
// If the expected type is an enum (Issue #55250) with any variants whose
115+
// sole field is of the found type, suggest such variants. (Issue #42764)
117116
if let ty::Adt(expected_adt, substs) = expected.sty {
118-
let mut compatible_variants = expected_adt.variants
119-
.iter()
120-
.filter(|variant| variant.fields.len() == 1)
121-
.filter_map(|variant| {
122-
let sole_field = &variant.fields[0];
123-
let sole_field_ty = sole_field.ty(self.tcx, substs);
124-
if self.can_coerce(expr_ty, sole_field_ty) {
125-
let variant_path = self.tcx.item_path_str(variant.did);
126-
Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
127-
} else {
128-
None
117+
if expected_adt.is_enum() {
118+
let mut compatible_variants = expected_adt.variants
119+
.iter()
120+
.filter(|variant| variant.fields.len() == 1)
121+
.filter_map(|variant| {
122+
let sole_field = &variant.fields[0];
123+
let sole_field_ty = sole_field.ty(self.tcx, substs);
124+
if self.can_coerce(expr_ty, sole_field_ty) {
125+
let variant_path = self.tcx.item_path_str(variant.did);
126+
Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
127+
} else {
128+
None
129+
}
130+
}).peekable();
131+
132+
if compatible_variants.peek().is_some() {
133+
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
134+
let suggestions = compatible_variants
135+
.map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
136+
err.span_suggestions_with_applicability(
137+
expr.span,
138+
"try using a variant of the expected type",
139+
suggestions,
140+
Applicability::MaybeIncorrect,
141+
);
129142
}
130-
}).peekable();
131-
132-
if compatible_variants.peek().is_some() {
133-
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
134-
let suggestions = compatible_variants.map(|v|
135-
format!("{}({})", v, expr_text)).collect::<Vec<_>>();
136-
err.span_suggestions_with_applicability(
137-
expr.span,
138-
"try using a variant of the expected type",
139-
suggestions,
140-
Applicability::MaybeIncorrect,
141-
);
142143
}
143144
}
144145

src/test/ui/did_you_mean/issue-42764.rs

+16
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,20 @@ fn main() {
2020
let n: usize = 42;
2121
this_function_expects_a_double_option(n);
2222
//~^ ERROR mismatched types
23+
//~| HELP try using a variant of the expected type
24+
}
25+
26+
27+
// But don't issue the "try using a variant" help if the one-"variant" ADT is
28+
// actually a one-field struct.
29+
30+
struct Payload;
31+
32+
struct Wrapper { payload: Payload }
33+
34+
struct Context { wrapper: Wrapper }
35+
36+
fn overton() {
37+
let _c = Context { wrapper: Payload{} };
38+
//~^ ERROR mismatched types
2339
}

src/test/ui/did_you_mean/issue-42764.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ LL | this_function_expects_a_double_option(DoubleOption::FirstSome(n));
1313
LL | this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1515

16-
error: aborting due to previous error
16+
error[E0308]: mismatched types
17+
--> $DIR/issue-42764.rs:37:33
18+
|
19+
LL | let _c = Context { wrapper: Payload{} };
20+
| ^^^^^^^^^ expected struct `Wrapper`, found struct `Payload`
21+
|
22+
= note: expected type `Wrapper`
23+
found type `Payload`
24+
25+
error: aborting due to 2 previous errors
1726

1827
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)