Auto merge of #38099 - GuillaumeGomez:cast_suggestions, r=nikomatsakis · rust-lang/rust@439c312 (original) (raw)
`@@ -14,8 +14,13 @@ use rustc::ty::Ty;
`
14
14
`use rustc::infer::{InferOk};
`
15
15
`use rustc::traits::ObligationCause;
`
16
16
``
17
``
`-
use syntax_pos::Span;
`
``
17
`+
use syntax::ast;
`
``
18
`+
use syntax_pos::{self, Span};
`
18
19
`use rustc::hir;
`
``
20
`+
use rustc::hir::def::Def;
`
``
21
`+
use rustc::ty::{self, AssociatedItem};
`
``
22
+
``
23
`+
use super::method::probe;
`
19
24
``
20
25
`impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
`
21
26
`// Requires that the two types unify, and prints an error message if
`
`@@ -27,7 +32,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
`
27
32
`self.register_predicates(obligations);
`
28
33
`},
`
29
34
`Err(e) => {
`
30
``
`-
self.report_mismatched_types(&cause, expected, actual, e);
`
``
35
`+
self.report_mismatched_types(&cause, expected, actual, e).emit();
`
31
36
`}
`
32
37
`}
`
33
38
`}
`
`@@ -46,7 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
`
46
51
`self.register_predicates(obligations);
`
47
52
`},
`
48
53
`Err(e) => {
`
49
``
`-
self.report_mismatched_types(cause, expected, actual, e);
`
``
54
`+
self.report_mismatched_types(cause, expected, actual, e).emit();
`
50
55
`}
`
51
56
`}
`
52
57
`}
`
`@@ -57,7 +62,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
`
57
62
`if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
`
58
63
`let cause = self.misc(expr.span);
`
59
64
`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>()
`
``
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,
`
61
124
`}
`
62
125
`}
`
63
126
`}
`