Skip to content

Commit 3ae974f

Browse files
committed
fix misleading type annotation diagonstics
This solves the method call part of issue rust-lang#69455 I added a `target_span` field so as to pin down the exact location of the error. We need a dedicated field `found_exact_method_call` to prioritize situations like the test case `issue-69455.rs`. If we reuse `found_method_call`, `found_local_pattern` will show up first. We can not move `found_method_call` up, it is undesirable in various situations.
1 parent 39b6253 commit 3ae974f

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed

src/librustc_infer/infer/error_reporting/need_type_info.rs

+52-6
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,27 @@ use std::borrow::Cow;
1717
struct FindHirNodeVisitor<'a, 'tcx> {
1818
infcx: &'a InferCtxt<'a, 'tcx>,
1919
target: GenericArg<'tcx>,
20+
target_span: Span,
2021
found_node_ty: Option<Ty<'tcx>>,
2122
found_local_pattern: Option<&'tcx Pat<'tcx>>,
2223
found_arg_pattern: Option<&'tcx Pat<'tcx>>,
2324
found_closure: Option<&'tcx Expr<'tcx>>,
2425
found_method_call: Option<&'tcx Expr<'tcx>>,
26+
found_exact_method_call: Option<&'tcx Expr<'tcx>>,
2527
}
2628

2729
impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
28-
fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self {
30+
fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
2931
Self {
3032
infcx,
3133
target,
34+
target_span,
3235
found_node_ty: None,
3336
found_local_pattern: None,
3437
found_arg_pattern: None,
3538
found_closure: None,
3639
found_method_call: None,
40+
found_exact_method_call: None,
3741
}
3842
}
3943

@@ -103,6 +107,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
103107
}
104108

105109
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
110+
if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
111+
if call_span == self.target_span
112+
&& Some(self.target)
113+
== self.infcx.in_progress_tables.and_then(|tables| {
114+
tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into)
115+
})
116+
{
117+
self.found_exact_method_call = Some(&expr);
118+
return;
119+
}
120+
}
106121
if self.node_ty_contains_target(expr.hir_id).is_some() {
107122
match expr.kind {
108123
ExprKind::Closure(..) => self.found_closure = Some(&expr),
@@ -234,7 +249,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
234249
let ty = self.resolve_vars_if_possible(&ty);
235250
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
236251

237-
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into());
252+
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
238253
let ty_to_string = |ty: Ty<'tcx>| -> String {
239254
let mut s = String::new();
240255
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
@@ -287,14 +302,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
287302
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
288303
};
289304

290-
let ty_msg = match local_visitor.found_node_ty {
291-
Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
305+
let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
306+
(_, Some(_)) => String::new(),
307+
(Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => {
292308
let fn_sig = substs.as_closure().sig();
293309
let args = closure_args(&fn_sig);
294310
let ret = fn_sig.output().skip_binder().to_string();
295311
format!(" for the closure `fn({}) -> {}`", args, ret)
296312
}
297-
Some(ty) if is_named_and_not_impl_trait(ty) => {
313+
(Some(ty), _) if is_named_and_not_impl_trait(ty) => {
298314
let ty = ty_to_string(ty);
299315
format!(" for `{}`", ty)
300316
}
@@ -370,7 +386,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
370386
_ => "a type".to_string(),
371387
};
372388

373-
if let Some(pattern) = local_visitor.found_arg_pattern {
389+
if let Some(e) = local_visitor.found_exact_method_call {
390+
if let ExprKind::MethodCall(segment, ..) = &e.kind {
391+
// Suggest specifying type params or point out the return type of the call:
392+
//
393+
// error[E0282]: type annotations needed
394+
// --> $DIR/type-annotations-needed-expr.rs:2:39
395+
// |
396+
// LL | let _ = x.into_iter().sum() as f64;
397+
// | ^^^
398+
// | |
399+
// | cannot infer type for `S`
400+
// | help: consider specifying the type argument in
401+
// | the method call: `sum::<S>`
402+
// |
403+
// = note: type must be known at this point
404+
//
405+
// or
406+
//
407+
// error[E0282]: type annotations needed
408+
// --> $DIR/issue-65611.rs:59:20
409+
// |
410+
// LL | let x = buffer.last().unwrap().0.clone();
411+
// | -------^^^^--
412+
// | | |
413+
// | | cannot infer type for `T`
414+
// | this method call resolves to `std::option::Option<&T>`
415+
// |
416+
// = note: type must be known at this point
417+
self.annotate_method_call(segment, e, &mut err);
418+
}
419+
} else if let Some(pattern) = local_visitor.found_arg_pattern {
374420
// We don't want to show the default label for closures.
375421
//
376422
// So, before clearing, the output would look something like this:

src/test/ui/issues/issue-69455.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Regression test for #69455: projection predicate was not satisfied.
2+
// Compiler should indicate the correct location of the
3+
// unsatisfied projection predicate
4+
5+
pub trait Test<Rhs = Self> {
6+
type Output;
7+
8+
fn test(self, rhs: Rhs) -> Self::Output;
9+
}
10+
11+
impl Test<u32> for u64 {
12+
type Output = u64;
13+
14+
fn test(self, other: u32) -> u64 {
15+
self + (other as u64)
16+
}
17+
}
18+
19+
impl Test<u64> for u64 {
20+
type Output = u64;
21+
22+
fn test(self, other: u64) -> u64 {
23+
(self + other) as u64
24+
}
25+
}
26+
27+
fn main() {
28+
let xs: Vec<u64> = vec![1, 2, 3];
29+
println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed [E0284]
30+
}

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

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0284]: type annotations needed
2+
--> $DIR/issue-69455.rs:29:26
3+
|
4+
LL | type Output;
5+
| ------------ `<Self as Test<Rhs>>::Output` defined here
6+
...
7+
LL | println!("{}", 23u64.test(xs.iter().sum()));
8+
| ------^^^^-----------------
9+
| | |
10+
| | cannot infer type for type `u64`
11+
| this method call resolves to `<Self as Test<Rhs>>::Output`
12+
|
13+
= note: cannot satisfy `<u64 as Test<_>>::Output == _`
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0284`.

0 commit comments

Comments
 (0)