Rollup merge of #55253 - zackmdavis:some_suggestion, r=pnkfelix
only issue "variant of the expected type" suggestion for enums This suggestion (introduced in pull-request #43178 /eac74104
) 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`). 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](b0d3d3b9
). Resolves #55250. r? @pnkfelix
This commit is contained in:
commit
f46ee0482f
3 changed files with 53 additions and 27 deletions
|
@ -111,34 +111,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
|
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
|
||||||
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
|
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
|
||||||
|
|
||||||
// If the expected type is an enum with any variants whose sole
|
// If the expected type is an enum (Issue #55250) with any variants whose
|
||||||
// field is of the found type, suggest such variants. See Issue
|
// sole field is of the found type, suggest such variants. (Issue #42764)
|
||||||
// #42764.
|
|
||||||
if let ty::Adt(expected_adt, substs) = expected.sty {
|
if let ty::Adt(expected_adt, substs) = expected.sty {
|
||||||
let mut compatible_variants = expected_adt.variants
|
if expected_adt.is_enum() {
|
||||||
.iter()
|
let mut compatible_variants = expected_adt.variants
|
||||||
.filter(|variant| variant.fields.len() == 1)
|
.iter()
|
||||||
.filter_map(|variant| {
|
.filter(|variant| variant.fields.len() == 1)
|
||||||
let sole_field = &variant.fields[0];
|
.filter_map(|variant| {
|
||||||
let sole_field_ty = sole_field.ty(self.tcx, substs);
|
let sole_field = &variant.fields[0];
|
||||||
if self.can_coerce(expr_ty, sole_field_ty) {
|
let sole_field_ty = sole_field.ty(self.tcx, substs);
|
||||||
let variant_path = self.tcx.item_path_str(variant.did);
|
if self.can_coerce(expr_ty, sole_field_ty) {
|
||||||
Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
|
let variant_path = self.tcx.item_path_str(variant.did);
|
||||||
} else {
|
Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
|
||||||
None
|
} else {
|
||||||
}
|
None
|
||||||
}).peekable();
|
}
|
||||||
|
}).peekable();
|
||||||
|
|
||||||
if compatible_variants.peek().is_some() {
|
if compatible_variants.peek().is_some() {
|
||||||
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
|
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
|
||||||
let suggestions = compatible_variants.map(|v|
|
let suggestions = compatible_variants
|
||||||
format!("{}({})", v, expr_text)).collect::<Vec<_>>();
|
.map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
|
||||||
err.span_suggestions_with_applicability(
|
err.span_suggestions_with_applicability(
|
||||||
expr.span,
|
expr.span,
|
||||||
"try using a variant of the expected type",
|
"try using a variant of the expected type",
|
||||||
suggestions,
|
suggestions,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,4 +20,20 @@ fn main() {
|
||||||
let n: usize = 42;
|
let n: usize = 42;
|
||||||
this_function_expects_a_double_option(n);
|
this_function_expects_a_double_option(n);
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
|
//~| HELP try using a variant of the expected type
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// But don't issue the "try using a variant" help if the one-"variant" ADT is
|
||||||
|
// actually a one-field struct.
|
||||||
|
|
||||||
|
struct Payload;
|
||||||
|
|
||||||
|
struct Wrapper { payload: Payload }
|
||||||
|
|
||||||
|
struct Context { wrapper: Wrapper }
|
||||||
|
|
||||||
|
fn overton() {
|
||||||
|
let _c = Context { wrapper: Payload{} };
|
||||||
|
//~^ ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,15 @@ LL | this_function_expects_a_double_option(DoubleOption::FirstSome(n));
|
||||||
LL | this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
|
LL | this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-42764.rs:37:33
|
||||||
|
|
|
||||||
|
LL | let _c = Context { wrapper: Payload{} };
|
||||||
|
| ^^^^^^^^^ expected struct `Wrapper`, found struct `Payload`
|
||||||
|
|
|
||||||
|
= note: expected type `Wrapper`
|
||||||
|
found type `Payload`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue