Auto merge of #43178 - zackmdavis:some_suggestion, r=eddyb
suggest one-argument enum variant to fix type mismatch when applicable Following @est31's [suggestion](https://github.com/rust-lang/rust/issues/42764#issuecomment-309680886). ![some_suggestion](https://user-images.githubusercontent.com/1076988/28101064-ee83f51e-667a-11e7-9e4f-d8f9eb2fb6c3.png) Resolves #42764.
This commit is contained in:
commit
582af6e1ad
3 changed files with 68 additions and 0 deletions
|
@ -16,6 +16,7 @@ use rustc::traits::ObligationCause;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::{self, Span};
|
use syntax_pos::{self, Span};
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
use rustc::hir::print;
|
||||||
use rustc::hir::def::Def;
|
use rustc::hir::def::Def;
|
||||||
use rustc::ty::{self, Ty, AssociatedItem};
|
use rustc::ty::{self, Ty, AssociatedItem};
|
||||||
use errors::{DiagnosticBuilder, CodeMapper};
|
use errors::{DiagnosticBuilder, CodeMapper};
|
||||||
|
@ -94,6 +95,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let cause = self.misc(expr.span);
|
let cause = self.misc(expr.span);
|
||||||
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
|
||||||
|
// field is of the found type, suggest such variants. See Issue
|
||||||
|
// #42764.
|
||||||
|
if let ty::TyAdt(expected_adt, substs) = expected.sty {
|
||||||
|
let mut compatible_variants = vec![];
|
||||||
|
for variant in &expected_adt.variants {
|
||||||
|
if variant.fields.len() == 1 {
|
||||||
|
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 mut variant_path = self.tcx.item_path_str(variant.did);
|
||||||
|
variant_path = variant_path.trim_left_matches("std::prelude::v1::")
|
||||||
|
.to_string();
|
||||||
|
compatible_variants.push(variant_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !compatible_variants.is_empty() {
|
||||||
|
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
|
||||||
|
let suggestions = compatible_variants.iter()
|
||||||
|
.map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
|
||||||
|
err.span_suggestions(expr.span,
|
||||||
|
"perhaps you meant to use a variant of the expected type",
|
||||||
|
suggestions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(suggestion) = self.check_ref(expr,
|
if let Some(suggestion) = self.check_ref(expr,
|
||||||
checked_ty,
|
checked_ty,
|
||||||
expected) {
|
expected) {
|
||||||
|
|
22
src/test/ui/did_you_mean/issue-42764.rs
Normal file
22
src/test/ui/did_you_mean/issue-42764.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
enum DoubleOption<T> {
|
||||||
|
FirstSome(T),
|
||||||
|
AlternativeSome(T),
|
||||||
|
Nothing,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn this_function_expects_a_double_option<T>(d: DoubleOption<T>) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let n: usize = 42;
|
||||||
|
this_function_expects_a_double_option(n);
|
||||||
|
}
|
17
src/test/ui/did_you_mean/issue-42764.stderr
Normal file
17
src/test/ui/did_you_mean/issue-42764.stderr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-42764.rs:21:43
|
||||||
|
|
|
||||||
|
21 | this_function_expects_a_double_option(n);
|
||||||
|
| ^ expected enum `DoubleOption`, found usize
|
||||||
|
|
|
||||||
|
= note: expected type `DoubleOption<_>`
|
||||||
|
found type `usize`
|
||||||
|
help: perhaps you meant to use a variant of the expected type
|
||||||
|
|
|
||||||
|
21 | this_function_expects_a_double_option(DoubleOption::FirstSome(n));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
21 | this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Reference in a new issue