Skip to content

Commit

Permalink
Rollup merge of rust-lang#55253 - zackmdavis:some_suggestion, r=pnkfelix
Browse files Browse the repository at this point in the history
only issue "variant of the expected type" suggestion for enums

This suggestion (introduced in pull-request rust-lang#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`).

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](rust-lang@b0d3d3b9?w=1).

Resolves rust-lang#55250.

r? @pnkfelix
  • Loading branch information
pietroalbini authored Oct 25, 2018
2 parents 823244a + b0d3d3b commit f46ee04
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 27 deletions.
53 changes: 27 additions & 26 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,34 +111,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);

// If the expected type is an enum with any variants whose sole
// field is of the found type, suggest such variants. See Issue
// #42764.
// If the expected type is an enum (Issue #55250) with any variants whose
// sole field is of the found type, suggest such variants. (Issue #42764)
if let ty::Adt(expected_adt, substs) = expected.sty {
let mut compatible_variants = expected_adt.variants
.iter()
.filter(|variant| variant.fields.len() == 1)
.filter_map(|variant| {
let sole_field = &variant.fields[0];
let sole_field_ty = sole_field.ty(self.tcx, substs);
if self.can_coerce(expr_ty, sole_field_ty) {
let variant_path = self.tcx.item_path_str(variant.did);
Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
} else {
None
if expected_adt.is_enum() {
let mut compatible_variants = expected_adt.variants
.iter()
.filter(|variant| variant.fields.len() == 1)
.filter_map(|variant| {
let sole_field = &variant.fields[0];
let sole_field_ty = sole_field.ty(self.tcx, substs);
if self.can_coerce(expr_ty, sole_field_ty) {
let variant_path = self.tcx.item_path_str(variant.did);
Some(variant_path.trim_left_matches("std::prelude::v1::").to_string())
} else {
None
}
}).peekable();

if compatible_variants.peek().is_some() {
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
let suggestions = compatible_variants
.map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
err.span_suggestions_with_applicability(
expr.span,
"try using a variant of the expected type",
suggestions,
Applicability::MaybeIncorrect,
);
}
}).peekable();

if compatible_variants.peek().is_some() {
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
let suggestions = compatible_variants.map(|v|
format!("{}({})", v, expr_text)).collect::<Vec<_>>();
err.span_suggestions_with_applicability(
expr.span,
"try using a variant of the expected type",
suggestions,
Applicability::MaybeIncorrect,
);
}
}

Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/did_you_mean/issue-42764.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,20 @@ fn main() {
let n: usize = 42;
this_function_expects_a_double_option(n);
//~^ 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
}
11 changes: 10 additions & 1 deletion src/test/ui/did_you_mean/issue-42764.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ LL | this_function_expects_a_double_option(DoubleOption::FirstSome(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`.

0 comments on commit f46ee04

Please sign in to comment.