Use generics_of instead of incorrectly inspecting FnSig arguments

This commit is contained in:
Esteban Küber 2019-12-10 11:05:16 -08:00
parent 6b76d82b13
commit 5d1adbb629
3 changed files with 48 additions and 27 deletions

View File

@ -377,7 +377,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_label(pattern.span, msg);
} else if let Some(e) = local_visitor.found_method_call {
if let ExprKind::MethodCall(segment, ..) = &e.kind {
// Suggest specifiying type params or point out the return type of the call.
// Suggest specifiying type params or point out the return type of the call:
//
// error[E0282]: type annotations needed
// --> $DIR/type-annotations-needed-expr.rs:2:39
// |
// LL | let _ = x.into_iter().sum() as f64;
// | ^^^
// | |
// | cannot infer type for `S`
// | help: consider specifying the type argument in
// | the method call: `sum::<S>`
// |
// = note: type must be known at this point
//
// or
//
// 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.annotate_method_call(segment, e, &mut err);
}
}
@ -422,34 +447,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&segment.args,
) {
let borrow = tables.borrow();
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() {
let method_defs = borrow.node_method_def_id();
if let Some(did) = method_defs.get(e.hir_id) {
let generics = self.tcx.generics_of(*did);
if !generics.params.is_empty() {
err.span_suggestion(
segment.ident.span,
&format!(
"consider specifying the type argument{} in the method call",
if params.len() > 1 {
if generics.params.len() > 1 {
"s"
} else {
""
},
),
format!("{}::<{}>", snippet, params.join(", ")),
format!("{}::<{}>", snippet, generics.params.iter()
.map(|p| p.name.to_string())
.collect::<Vec<String>>()
.join(", ")),
Applicability::HasPlaceholders,
);
} else {
let sig = self.tcx.fn_sig(*did);
err.span_label(e.span, &format!(
"this method call resolves to `{:?}`",
sig.output().skip_binder(),

View File

@ -338,7 +338,7 @@ pub struct TypeckTables<'tcx> {
/// typeck::check::fn_ctxt for details.
node_types: ItemLocalMap<Ty<'tcx>>,
node_method_sig: ItemLocalMap<ty::PolyFnSig<'tcx>>,
node_method_def_id: ItemLocalMap<DefId>,
/// Stores the type parameters which were substituted to obtain the type
/// of this node. This only applies to nodes that refer to entities
@ -444,7 +444,7 @@ impl<'tcx> TypeckTables<'tcx> {
user_provided_types: Default::default(),
user_provided_sigs: Default::default(),
node_types: Default::default(),
node_method_sig: Default::default(),
node_method_def_id: Default::default(),
node_substs: Default::default(),
adjustments: Default::default(),
pat_binding_modes: Default::default(),
@ -545,17 +545,17 @@ impl<'tcx> TypeckTables<'tcx> {
}
}
pub fn node_method_sig(&self) -> LocalTableInContext<'_, ty::PolyFnSig<'tcx>> {
pub fn node_method_def_id(&self) -> LocalTableInContext<'_, DefId> {
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.node_method_sig
data: &self.node_method_def_id
}
}
pub fn node_method_sig_mut(&mut self) -> LocalTableInContextMut<'_, ty::PolyFnSig<'tcx>> {
pub fn node_method_def_id_mut(&mut self) -> LocalTableInContextMut<'_, DefId> {
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.node_method_sig
data: &mut self.node_method_def_id
}
}
@ -765,7 +765,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
ref user_provided_types,
ref user_provided_sigs,
ref node_types,
ref node_method_sig,
ref node_method_def_id,
ref node_substs,
ref adjustments,
ref pat_binding_modes,
@ -792,7 +792,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
user_provided_types.hash_stable(hcx, hasher);
user_provided_sigs.hash_stable(hcx, hasher);
node_types.hash_stable(hcx, hasher);
node_method_sig.hash_stable(hcx, hasher);
node_method_def_id.hash_stable(hcx, hasher);
node_substs.hash_stable(hcx, hasher);
adjustments.hash_stable(hcx, hasher);
pat_binding_modes.hash_stable(hcx, hasher);

View File

@ -871,7 +871,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
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.
@ -890,7 +889,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// |
// = note: type must be known at this point
// ```
self.tables.borrow_mut().node_method_sig_mut().insert(expr.hir_id, sig);
self.tables.borrow_mut().node_method_def_id_mut().insert(
expr.hir_id,
method.def_id,
);
self.write_method_call(expr.hir_id, method);
Ok(method)