struct FindHirNodeVisitor<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
target: GenericArg<'tcx>,
+ target_span: Span,
found_node_ty: Option<Ty<'tcx>>,
found_local_pattern: Option<&'tcx Pat<'tcx>>,
found_arg_pattern: Option<&'tcx Pat<'tcx>>,
found_closure: Option<&'tcx Expr<'tcx>>,
found_method_call: Option<&'tcx Expr<'tcx>>,
+ found_exact_method_call: Option<&'tcx Expr<'tcx>>,
}
impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
- fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self {
+ fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
Self {
infcx,
target,
+ target_span,
found_node_ty: None,
found_local_pattern: None,
found_arg_pattern: None,
found_closure: None,
found_method_call: None,
+ found_exact_method_call: None,
}
}
.infcx
.inner
.borrow_mut()
- .type_variables
+ .type_variables()
.sub_unified(a_vid, b_vid),
_ => false,
}
}
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
+ if call_span == self.target_span
+ && Some(self.target)
+ == self.infcx.in_progress_tables.and_then(|tables| {
+ tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into)
+ })
+ {
+ self.found_exact_method_call = Some(&expr);
+ return;
+ }
+ }
if self.node_ty_contains_target(expr.hir_id).is_some() {
match expr.kind {
ExprKind::Closure(..) => self.found_closure = Some(&expr),
highlight: Option<ty::print::RegionHighlightMode>,
) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind {
- let ty_vars = &self.inner.borrow().type_variables;
+ let mut inner = self.inner.borrow_mut();
+ let ty_vars = &inner.type_variables();
let var_origin = ty_vars.var_origin(ty_vid);
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind {
let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
.get_opt_name()
.map(|parent_symbol| parent_symbol.to_string());
- let type_parent_desc = self
- .tcx
- .def_kind(parent_def_id)
- .map(|parent_def_kind| parent_def_kind.descr(parent_def_id));
-
- (parent_name, type_parent_desc)
+ (parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)))
} else {
(None, None)
};
let ty = self.resolve_vars_if_possible(&ty);
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
- let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into());
+ let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
let ty_to_string = |ty: Ty<'tcx>| -> String {
let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
- let ty_vars = &self.inner.borrow().type_variables;
+ let mut inner = self.inner.borrow_mut();
+ let ty_vars = inner.type_variables();
let getter = move |ty_vid| {
let var_origin = ty_vars.var_origin(ty_vid);
if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
None
};
printer.name_resolver = Some(Box::new(&getter));
- let _ = ty.print(printer);
+ let _ = if let ty::FnDef(..) = ty.kind {
+ // We don't want the regular output for `fn`s because it includes its path in
+ // invalid pseduo-syntax, we want the `fn`-pointer output instead.
+ ty.fn_sig(self.tcx).print(printer)
+ } else {
+ ty.print(printer)
+ };
s
};
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
};
- let ty_msg = match local_visitor.found_node_ty {
- Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
+ let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
+ (_, Some(_)) => String::new(),
+ (Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => {
let fn_sig = substs.as_closure().sig();
let args = closure_args(&fn_sig);
let ret = fn_sig.output().skip_binder().to_string();
format!(" for the closure `fn({}) -> {}`", args, ret)
}
- Some(ty) if is_named_and_not_impl_trait(ty) => {
+ (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
let ty = ty_to_string(ty);
format!(" for `{}`", ty)
}
_ => "a type".to_string(),
};
- if let Some(pattern) = local_visitor.found_arg_pattern {
+ if let Some(e) = local_visitor.found_exact_method_call {
+ if let ExprKind::MethodCall(segment, ..) = &e.kind {
+ // Suggest specifying 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);
+ }
+ } else if let Some(pattern) = local_visitor.found_arg_pattern {
// We don't want to show the default label for closures.
//
// So, before clearing, the output would look something like this: