Skip to content

Commit 439c312

Browse files
committed
Auto merge of #38099 - GuillaumeGomez:cast_suggestions, r=nikomatsakis
Cast suggestions r? @nikomatsakis
2 parents 92d4600 + 28e2c6a commit 439c312

File tree

13 files changed

+401
-100
lines changed

13 files changed

+401
-100
lines changed

src/librustc/infer/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1367,9 +1367,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
13671367
cause: &ObligationCause<'tcx>,
13681368
expected: Ty<'tcx>,
13691369
actual: Ty<'tcx>,
1370-
err: TypeError<'tcx>) {
1370+
err: TypeError<'tcx>)
1371+
-> DiagnosticBuilder<'tcx> {
13711372
let trace = TypeTrace::types(cause, true, expected, actual);
1372-
self.report_and_explain_type_error(trace, &err).emit();
1373+
self.report_and_explain_type_error(trace, &err)
13731374
}
13741375

13751376
pub fn report_conflicting_default_types(&self,

src/librustc/ty/sty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ pub struct ProjectionTy<'tcx> {
543543
pub struct BareFnTy<'tcx> {
544544
pub unsafety: hir::Unsafety,
545545
pub abi: abi::Abi,
546+
/// Signature (inputs and output) of this function type.
546547
pub sig: PolyFnSig<'tcx>,
547548
}
548549

src/librustc_typeck/check/_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
481481
} else {
482482
(result_ty, arm_ty)
483483
};
484-
self.report_mismatched_types(&cause, expected, found, e);
484+
self.report_mismatched_types(&cause, expected, found, e).emit();
485485
self.tcx.types.err
486486
}
487487
};

src/librustc_typeck/check/autoderef.rs

+8
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,18 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
131131
Some(self.fcx.resolve_type_vars_if_possible(&normalized.value))
132132
}
133133

134+
/// Returns the final type, generating an error if it is an
135+
/// unresolved inference variable.
134136
pub fn unambiguous_final_ty(&self) -> Ty<'tcx> {
135137
self.fcx.structurally_resolved_type(self.span, self.cur_ty)
136138
}
137139

140+
/// Returns the final type we ended up with, which may well be an
141+
/// inference variable (we will resolve it first, if possible).
142+
pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
143+
self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
144+
}
145+
138146
pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
139147
where I: IntoIterator<Item = &'b hir::Expr>
140148
{

src/librustc_typeck/check/demand.rs

+67-4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ use rustc::ty::Ty;
1414
use rustc::infer::{InferOk};
1515
use rustc::traits::ObligationCause;
1616

17-
use syntax_pos::Span;
17+
use syntax::ast;
18+
use syntax_pos::{self, Span};
1819
use rustc::hir;
20+
use rustc::hir::def::Def;
21+
use rustc::ty::{self, AssociatedItem};
22+
23+
use super::method::probe;
1924

2025
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2126
// Requires that the two types unify, and prints an error message if
@@ -27,7 +32,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2732
self.register_predicates(obligations);
2833
},
2934
Err(e) => {
30-
self.report_mismatched_types(&cause, expected, actual, e);
35+
self.report_mismatched_types(&cause, expected, actual, e).emit();
3136
}
3237
}
3338
}
@@ -46,7 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4651
self.register_predicates(obligations);
4752
},
4853
Err(e) => {
49-
self.report_mismatched_types(cause, expected, actual, e);
54+
self.report_mismatched_types(cause, expected, actual, e).emit();
5055
}
5156
}
5257
}
@@ -57,7 +62,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5762
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
5863
let cause = self.misc(expr.span);
5964
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
60-
self.report_mismatched_types(&cause, expected, expr_ty, e);
65+
let mode = probe::Mode::MethodCall;
66+
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
67+
mode,
68+
expected,
69+
checked_ty,
70+
ast::DUMMY_NODE_ID);
71+
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
72+
if suggestions.len() > 0 {
73+
err.help(&format!("here are some functions which \
74+
might fulfill your needs:\n - {}",
75+
self.get_best_match(&suggestions)));
76+
};
77+
err.emit();
78+
}
79+
}
80+
81+
fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
82+
format!(".{}({})",
83+
method.name,
84+
if self.has_no_input_arg(method) {
85+
""
86+
} else {
87+
"..."
88+
})
89+
}
90+
91+
fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> String {
92+
methods.iter()
93+
.take(5)
94+
.map(|method| self.format_method_suggestion(&*method))
95+
.collect::<Vec<String>>()
96+
.join("\n - ")
97+
}
98+
99+
fn get_best_match(&self, methods: &[AssociatedItem]) -> String {
100+
let no_argument_methods: Vec<_> =
101+
methods.iter()
102+
.filter(|ref x| self.has_no_input_arg(&*x))
103+
.map(|x| x.clone())
104+
.collect();
105+
if no_argument_methods.len() > 0 {
106+
self.display_suggested_methods(&no_argument_methods)
107+
} else {
108+
self.display_suggested_methods(&methods)
109+
}
110+
}
111+
112+
// This function checks if the method isn't static and takes other arguments than `self`.
113+
fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
114+
match method.def() {
115+
Def::Method(def_id) => {
116+
match self.tcx.item_type(def_id).sty {
117+
ty::TypeVariants::TyFnDef(_, _, fty) => {
118+
fty.sig.skip_binder().inputs().len() == 1
119+
}
120+
_ => false,
121+
}
122+
}
123+
_ => false,
61124
}
62125
}
63126
}

src/librustc_typeck/check/method/mod.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ pub use self::CandidateSource::*;
3030
pub use self::suggest::AllTraitsVec;
3131

3232
mod confirm;
33-
mod probe;
33+
pub mod probe;
3434
mod suggest;
3535

36+
use self::probe::IsSuggestion;
37+
3638
pub enum MethodError<'tcx> {
3739
// Did not find an applicable method, but we did find various near-misses that may work.
3840
NoMatch(NoMatchData<'tcx>),
@@ -91,7 +93,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
9193
allow_private: bool)
9294
-> bool {
9395
let mode = probe::Mode::MethodCall;
94-
match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
96+
match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
97+
self_ty, call_expr_id) {
9598
Ok(..) => true,
9699
Err(NoMatch(..)) => false,
97100
Err(Ambiguity(..)) => true,
@@ -130,7 +133,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
130133

131134
let mode = probe::Mode::MethodCall;
132135
let self_ty = self.resolve_type_vars_if_possible(&self_ty);
133-
let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
136+
let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
137+
self_ty, call_expr.id)?;
134138

135139
if let Some(import_id) = pick.import_id {
136140
self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -328,7 +332,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
328332
expr_id: ast::NodeId)
329333
-> Result<Def, MethodError<'tcx>> {
330334
let mode = probe::Mode::Path;
331-
let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
335+
let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
336+
self_ty, expr_id)?;
332337

333338
if let Some(import_id) = pick.import_id {
334339
self.tcx.used_trait_imports.borrow_mut().insert(import_id);

0 commit comments

Comments
 (0)