Use the appropriate number of type arguments in suggestion
This commit is contained in:
parent
cca4b6d42a
commit
33b06362fa
@ -20,7 +20,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
|
|||||||
found_arg_pattern: Option<&'tcx Pat>,
|
found_arg_pattern: Option<&'tcx Pat>,
|
||||||
found_ty: Option<Ty<'tcx>>,
|
found_ty: Option<Ty<'tcx>>,
|
||||||
found_closure: Option<&'tcx ExprKind>,
|
found_closure: Option<&'tcx ExprKind>,
|
||||||
found_method_call: Option<&'tcx ExprKind>,
|
found_method_call: Option<&'tcx Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
|
||||||
@ -99,7 +99,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
|
|||||||
if self.node_matches_type(expr.hir_id).is_some() {
|
if self.node_matches_type(expr.hir_id).is_some() {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
|
ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
|
||||||
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr.kind),
|
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,8 +211,8 @@ pub fn need_type_info_err(
|
|||||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
||||||
let ty_vars = self.type_variables.borrow();
|
let ty_vars = self.type_variables.borrow();
|
||||||
let getter = move |ty_vid| {
|
let getter = move |ty_vid| {
|
||||||
if let TypeVariableOriginKind::TypeParameterDefinition(name) =
|
let var_origin = ty_vars.var_origin(ty_vid);
|
||||||
ty_vars.var_origin(ty_vid).kind {
|
if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
|
||||||
return Some(name.to_string());
|
return Some(name.to_string());
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -238,7 +238,7 @@ pub fn need_type_info_err(
|
|||||||
span
|
span
|
||||||
} else if let Some(
|
} else if let Some(
|
||||||
ExprKind::MethodCall(_, call_span, _),
|
ExprKind::MethodCall(_, call_span, _),
|
||||||
) = local_visitor.found_method_call {
|
) = local_visitor.found_method_call.map(|e| &e.kind) {
|
||||||
// Point at the call instead of the whole expression:
|
// Point at the call instead of the whole expression:
|
||||||
// error[E0284]: type annotations needed
|
// error[E0284]: type annotations needed
|
||||||
// --> file.rs:2:5
|
// --> file.rs:2:5
|
||||||
@ -375,16 +375,48 @@ pub fn need_type_info_err(
|
|||||||
format!("consider giving this pattern {}", suffix)
|
format!("consider giving this pattern {}", suffix)
|
||||||
};
|
};
|
||||||
err.span_label(pattern.span, msg);
|
err.span_label(pattern.span, msg);
|
||||||
} else if let Some(ExprKind::MethodCall(segment, ..)) = local_visitor.found_method_call {
|
} else if let Some(e) = local_visitor.found_method_call {
|
||||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(segment.ident.span) {
|
if let ExprKind::MethodCall(segment, _call_sp, _args) = &e.kind {
|
||||||
if segment.args.is_none() {
|
if let (Ok(snippet), Some(tables), None) = (
|
||||||
err.span_suggestion(
|
self.tcx.sess.source_map().span_to_snippet(segment.ident.span),
|
||||||
segment.ident.span,
|
self.in_progress_tables,
|
||||||
"consider specifying the type argument in the method call",
|
&segment.args,
|
||||||
// FIXME: we don't know how many type arguments should be set here.
|
) {
|
||||||
format!("{}::<_>", snippet),
|
let borrow = tables.borrow();
|
||||||
Applicability::HasPlaceholders,
|
let sigs = borrow.node_method_sig();
|
||||||
);
|
if let Some(sig) = sigs.get(e.hir_id) {
|
||||||
|
let mut params = vec![];
|
||||||
|
for arg in sig.inputs_and_output().skip_binder().iter() {
|
||||||
|
if let ty::Param(param) = arg.kind {
|
||||||
|
if param.name != kw::SelfUpper {
|
||||||
|
let name = param.name.to_string();
|
||||||
|
if !params.contains(&name) {
|
||||||
|
params.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !params.is_empty() {
|
||||||
|
err.span_suggestion(
|
||||||
|
segment.ident.span,
|
||||||
|
&format!(
|
||||||
|
"consider specifying the type argument{} in the method call",
|
||||||
|
if params.len() > 1 {
|
||||||
|
"s"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
},
|
||||||
|
),
|
||||||
|
format!("{}::<{}>", snippet, params.join(", ")),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.span_label(e.span, &format!(
|
||||||
|
"this method call resolves to `{:?}`",
|
||||||
|
sig.output().skip_binder(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,6 +338,8 @@ pub struct TypeckTables<'tcx> {
|
|||||||
/// typeck::check::fn_ctxt for details.
|
/// typeck::check::fn_ctxt for details.
|
||||||
node_types: ItemLocalMap<Ty<'tcx>>,
|
node_types: ItemLocalMap<Ty<'tcx>>,
|
||||||
|
|
||||||
|
node_method_sig: ItemLocalMap<ty::PolyFnSig<'tcx>>,
|
||||||
|
|
||||||
/// Stores the type parameters which were substituted to obtain the type
|
/// Stores the type parameters which were substituted to obtain the type
|
||||||
/// of this node. This only applies to nodes that refer to entities
|
/// of this node. This only applies to nodes that refer to entities
|
||||||
/// parameterized by type parameters, such as generic fns, types, or
|
/// parameterized by type parameters, such as generic fns, types, or
|
||||||
@ -442,6 +444,7 @@ pub fn empty(local_id_root: Option<DefId>) -> TypeckTables<'tcx> {
|
|||||||
user_provided_types: Default::default(),
|
user_provided_types: Default::default(),
|
||||||
user_provided_sigs: Default::default(),
|
user_provided_sigs: Default::default(),
|
||||||
node_types: Default::default(),
|
node_types: Default::default(),
|
||||||
|
node_method_sig: Default::default(),
|
||||||
node_substs: Default::default(),
|
node_substs: Default::default(),
|
||||||
adjustments: Default::default(),
|
adjustments: Default::default(),
|
||||||
pat_binding_modes: Default::default(),
|
pat_binding_modes: Default::default(),
|
||||||
@ -542,6 +545,20 @@ pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn node_method_sig(&self) -> LocalTableInContext<'_, ty::PolyFnSig<'tcx>> {
|
||||||
|
LocalTableInContext {
|
||||||
|
local_id_root: self.local_id_root,
|
||||||
|
data: &self.node_method_sig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn node_method_sig_mut(&mut self) -> LocalTableInContextMut<'_, ty::PolyFnSig<'tcx>> {
|
||||||
|
LocalTableInContextMut {
|
||||||
|
local_id_root: self.local_id_root,
|
||||||
|
data: &mut self.node_method_sig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
|
pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
|
||||||
self.node_type_opt(id).unwrap_or_else(||
|
self.node_type_opt(id).unwrap_or_else(||
|
||||||
bug!("node_type: no type for node `{}`",
|
bug!("node_type: no type for node `{}`",
|
||||||
@ -748,6 +765,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
|
|||||||
ref user_provided_types,
|
ref user_provided_types,
|
||||||
ref user_provided_sigs,
|
ref user_provided_sigs,
|
||||||
ref node_types,
|
ref node_types,
|
||||||
|
ref node_method_sig,
|
||||||
ref node_substs,
|
ref node_substs,
|
||||||
ref adjustments,
|
ref adjustments,
|
||||||
ref pat_binding_modes,
|
ref pat_binding_modes,
|
||||||
@ -774,6 +792,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
|
|||||||
user_provided_types.hash_stable(hcx, hasher);
|
user_provided_types.hash_stable(hcx, hasher);
|
||||||
user_provided_sigs.hash_stable(hcx, hasher);
|
user_provided_sigs.hash_stable(hcx, hasher);
|
||||||
node_types.hash_stable(hcx, hasher);
|
node_types.hash_stable(hcx, hasher);
|
||||||
|
node_method_sig.hash_stable(hcx, hasher);
|
||||||
node_substs.hash_stable(hcx, hasher);
|
node_substs.hash_stable(hcx, hasher);
|
||||||
adjustments.hash_stable(hcx, hasher);
|
adjustments.hash_stable(hcx, hasher);
|
||||||
pat_binding_modes.hash_stable(hcx, hasher);
|
pat_binding_modes.hash_stable(hcx, hasher);
|
||||||
|
@ -871,6 +871,27 @@ fn check_method_call(
|
|||||||
|
|
||||||
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
|
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
|
||||||
Ok(method) => {
|
Ok(method) => {
|
||||||
|
let sig = self.tcx.fn_sig(method.def_id);
|
||||||
|
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
|
||||||
|
// trigger this codepath causing `structuraly_resolved_type` to emit an error.
|
||||||
|
|
||||||
|
// We could do this only when type params are present in the method to reducte
|
||||||
|
// memory usage, but doing it unconditionally lets us also point at the method
|
||||||
|
// expression and state the resolved return value:
|
||||||
|
// ```
|
||||||
|
// error[E0282]: type annotations needed
|
||||||
|
// --> $DIR/issue-65611.rs:59:20
|
||||||
|
// |
|
||||||
|
// LL | let x = buffer.last().unwrap().0.clone();
|
||||||
|
// | -------^^^^--
|
||||||
|
// | | |
|
||||||
|
// | | cannot infer type for `T`
|
||||||
|
// | this method call resolves to `std::option::Option<&T>`
|
||||||
|
// |
|
||||||
|
// = note: type must be known at this point
|
||||||
|
// ```
|
||||||
|
self.tables.borrow_mut().node_method_sig_mut().insert(expr.hir_id, sig);
|
||||||
|
|
||||||
self.write_method_call(expr.hir_id, method);
|
self.write_method_call(expr.hir_id, method);
|
||||||
Ok(method)
|
Ok(method)
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@ error[E0282]: type annotations needed
|
|||||||
--> $DIR/issue-65611.rs:59:20
|
--> $DIR/issue-65611.rs:59:20
|
||||||
|
|
|
|
||||||
LL | let x = buffer.last().unwrap().0.clone();
|
LL | let x = buffer.last().unwrap().0.clone();
|
||||||
| ^^^^
|
| -------^^^^--
|
||||||
| |
|
| | |
|
||||||
| cannot infer type for `T`
|
| | cannot infer type for `T`
|
||||||
| help: consider specifying the type argument in the method call: `last::<_>`
|
| this method call resolves to `std::option::Option<&T>`
|
||||||
|
|
|
|
||||||
= note: type must be known at this point
|
= note: type must be known at this point
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ LL | l.iter().map(f).collect()?
|
|||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
| |
|
| |
|
||||||
| cannot infer type
|
| cannot infer type
|
||||||
| help: consider specifying the type argument in the method call: `collect::<_>`
|
| help: consider specifying the type argument in the method call: `collect::<B>`
|
||||||
|
|
|
|
||||||
= note: cannot resolve `<_ as std::ops::Try>::Ok == _`
|
= note: cannot resolve `<_ as std::ops::Try>::Ok == _`
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ LL | let _ = (vec![1,2,3]).into_iter().sum() as f64;
|
|||||||
| ^^^
|
| ^^^
|
||||||
| |
|
| |
|
||||||
| cannot infer type for `S`
|
| cannot infer type for `S`
|
||||||
| help: consider specifying the type argument in the method call: `sum::<_>`
|
| help: consider specifying the type argument in the method call: `sum::<S>`
|
||||||
|
|
|
|
||||||
= note: type must be known at this point
|
= note: type must be known at this point
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user