Skip to content

Commit 33b0636

Browse files
committed
Use the appropriate number of type arguments in suggestion
1 parent cca4b6d commit 33b0636

File tree

6 files changed

+93
-21
lines changed

6 files changed

+93
-21
lines changed

src/librustc/infer/error_reporting/need_type_info.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
2020
found_arg_pattern: Option<&'tcx Pat>,
2121
found_ty: Option<Ty<'tcx>>,
2222
found_closure: Option<&'tcx ExprKind>,
23-
found_method_call: Option<&'tcx ExprKind>,
23+
found_method_call: Option<&'tcx Expr>,
2424
}
2525

2626
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
@@ -99,7 +99,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
9999
if self.node_matches_type(expr.hir_id).is_some() {
100100
match expr.kind {
101101
ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
102-
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr.kind),
102+
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
103103
_ => {}
104104
}
105105
}
@@ -211,8 +211,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
211211
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
212212
let ty_vars = self.type_variables.borrow();
213213
let getter = move |ty_vid| {
214-
if let TypeVariableOriginKind::TypeParameterDefinition(name) =
215-
ty_vars.var_origin(ty_vid).kind {
214+
let var_origin = ty_vars.var_origin(ty_vid);
215+
if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
216216
return Some(name.to_string());
217217
}
218218
None
@@ -238,7 +238,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
238238
span
239239
} else if let Some(
240240
ExprKind::MethodCall(_, call_span, _),
241-
) = local_visitor.found_method_call {
241+
) = local_visitor.found_method_call.map(|e| &e.kind) {
242242
// Point at the call instead of the whole expression:
243243
// error[E0284]: type annotations needed
244244
// --> file.rs:2:5
@@ -375,16 +375,48 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
375375
format!("consider giving this pattern {}", suffix)
376376
};
377377
err.span_label(pattern.span, msg);
378-
} else if let Some(ExprKind::MethodCall(segment, ..)) = local_visitor.found_method_call {
379-
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(segment.ident.span) {
380-
if segment.args.is_none() {
381-
err.span_suggestion(
382-
segment.ident.span,
383-
"consider specifying the type argument in the method call",
384-
// FIXME: we don't know how many type arguments should be set here.
385-
format!("{}::<_>", snippet),
386-
Applicability::HasPlaceholders,
387-
);
378+
} else if let Some(e) = local_visitor.found_method_call {
379+
if let ExprKind::MethodCall(segment, _call_sp, _args) = &e.kind {
380+
if let (Ok(snippet), Some(tables), None) = (
381+
self.tcx.sess.source_map().span_to_snippet(segment.ident.span),
382+
self.in_progress_tables,
383+
&segment.args,
384+
) {
385+
let borrow = tables.borrow();
386+
let sigs = borrow.node_method_sig();
387+
if let Some(sig) = sigs.get(e.hir_id) {
388+
let mut params = vec![];
389+
for arg in sig.inputs_and_output().skip_binder().iter() {
390+
if let ty::Param(param) = arg.kind {
391+
if param.name != kw::SelfUpper {
392+
let name = param.name.to_string();
393+
if !params.contains(&name) {
394+
params.push(name);
395+
}
396+
}
397+
}
398+
}
399+
if !params.is_empty() {
400+
err.span_suggestion(
401+
segment.ident.span,
402+
&format!(
403+
"consider specifying the type argument{} in the method call",
404+
if params.len() > 1 {
405+
"s"
406+
} else {
407+
""
408+
},
409+
),
410+
format!("{}::<{}>", snippet, params.join(", ")),
411+
Applicability::HasPlaceholders,
412+
);
413+
} else {
414+
err.span_label(e.span, &format!(
415+
"this method call resolves to `{:?}`",
416+
sig.output().skip_binder(),
417+
));
418+
}
419+
}
388420
}
389421
}
390422
}

src/librustc/ty/context.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ pub struct TypeckTables<'tcx> {
338338
/// typeck::check::fn_ctxt for details.
339339
node_types: ItemLocalMap<Ty<'tcx>>,
340340

341+
node_method_sig: ItemLocalMap<ty::PolyFnSig<'tcx>>,
342+
341343
/// Stores the type parameters which were substituted to obtain the type
342344
/// of this node. This only applies to nodes that refer to entities
343345
/// parameterized by type parameters, such as generic fns, types, or
@@ -442,6 +444,7 @@ impl<'tcx> TypeckTables<'tcx> {
442444
user_provided_types: Default::default(),
443445
user_provided_sigs: Default::default(),
444446
node_types: Default::default(),
447+
node_method_sig: Default::default(),
445448
node_substs: Default::default(),
446449
adjustments: Default::default(),
447450
pat_binding_modes: Default::default(),
@@ -542,6 +545,20 @@ impl<'tcx> TypeckTables<'tcx> {
542545
}
543546
}
544547

548+
pub fn node_method_sig(&self) -> LocalTableInContext<'_, ty::PolyFnSig<'tcx>> {
549+
LocalTableInContext {
550+
local_id_root: self.local_id_root,
551+
data: &self.node_method_sig
552+
}
553+
}
554+
555+
pub fn node_method_sig_mut(&mut self) -> LocalTableInContextMut<'_, ty::PolyFnSig<'tcx>> {
556+
LocalTableInContextMut {
557+
local_id_root: self.local_id_root,
558+
data: &mut self.node_method_sig
559+
}
560+
}
561+
545562
pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
546563
self.node_type_opt(id).unwrap_or_else(||
547564
bug!("node_type: no type for node `{}`",
@@ -748,6 +765,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
748765
ref user_provided_types,
749766
ref user_provided_sigs,
750767
ref node_types,
768+
ref node_method_sig,
751769
ref node_substs,
752770
ref adjustments,
753771
ref pat_binding_modes,
@@ -774,6 +792,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
774792
user_provided_types.hash_stable(hcx, hasher);
775793
user_provided_sigs.hash_stable(hcx, hasher);
776794
node_types.hash_stable(hcx, hasher);
795+
node_method_sig.hash_stable(hcx, hasher);
777796
node_substs.hash_stable(hcx, hasher);
778797
adjustments.hash_stable(hcx, hasher);
779798
pat_binding_modes.hash_stable(hcx, hasher);

src/librustc_typeck/check/expr.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
871871

872872
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
873873
Ok(method) => {
874+
let sig = self.tcx.fn_sig(method.def_id);
875+
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
876+
// trigger this codepath causing `structuraly_resolved_type` to emit an error.
877+
878+
// We could do this only when type params are present in the method to reducte
879+
// memory usage, but doing it unconditionally lets us also point at the method
880+
// expression and state the resolved return value:
881+
// ```
882+
// error[E0282]: type annotations needed
883+
// --> $DIR/issue-65611.rs:59:20
884+
// |
885+
// LL | let x = buffer.last().unwrap().0.clone();
886+
// | -------^^^^--
887+
// | | |
888+
// | | cannot infer type for `T`
889+
// | this method call resolves to `std::option::Option<&T>`
890+
// |
891+
// = note: type must be known at this point
892+
// ```
893+
self.tables.borrow_mut().node_method_sig_mut().insert(expr.hir_id, sig);
894+
874895
self.write_method_call(expr.hir_id, method);
875896
Ok(method)
876897
}

src/test/ui/issues/issue-65611.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ error[E0282]: type annotations needed
22
--> $DIR/issue-65611.rs:59:20
33
|
44
LL | let x = buffer.last().unwrap().0.clone();
5-
| ^^^^
6-
| |
7-
| cannot infer type for `T`
8-
| help: consider specifying the type argument in the method call: `last::<_>`
5+
| -------^^^^--
6+
| | |
7+
| | cannot infer type for `T`
8+
| this method call resolves to `std::option::Option<&T>`
99
|
1010
= note: type must be known at this point
1111

src/test/ui/question-mark-type-infer.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | l.iter().map(f).collect()?
55
| ^^^^^^^
66
| |
77
| cannot infer type
8-
| help: consider specifying the type argument in the method call: `collect::<_>`
8+
| help: consider specifying the type argument in the method call: `collect::<B>`
99
|
1010
= note: cannot resolve `<_ as std::ops::Try>::Ok == _`
1111

src/test/ui/span/type-annotations-needed-expr.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let _ = (vec![1,2,3]).into_iter().sum() as f64;
55
| ^^^
66
| |
77
| cannot infer type for `S`
8-
| help: consider specifying the type argument in the method call: `sum::<_>`
8+
| help: consider specifying the type argument in the method call: `sum::<S>`
99
|
1010
= note: type must be known at this point
1111

0 commit comments

Comments
 (0)