Skip to content

Commit 12af256

Browse files
committed
Point at method call when type annotations are needed
1 parent 7dbfb0a commit 12af256

13 files changed

+108
-44
lines changed

src/librustc/infer/error_reporting/need_type_info.rs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::infer::type_variable::TypeVariableOriginKind;
66
use crate::ty::{self, Ty, Infer, TyVar};
77
use crate::ty::print::Print;
88
use syntax::source_map::DesugaringKind;
9+
use syntax::symbol::kw;
910
use syntax_pos::Span;
1011
use errors::{Applicability, DiagnosticBuilder};
1112

@@ -19,6 +20,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
1920
found_arg_pattern: Option<&'tcx Pat>,
2021
found_ty: Option<Ty<'tcx>>,
2122
found_closure: Option<&'tcx ExprKind>,
23+
found_method_call: Option<&'tcx ExprKind>,
2224
}
2325

2426
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
@@ -35,6 +37,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
3537
found_arg_pattern: None,
3638
found_ty: None,
3739
found_closure: None,
40+
found_method_call: None,
3841
}
3942
}
4043

@@ -93,11 +96,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
9396
}
9497

9598
fn visit_expr(&mut self, expr: &'tcx Expr) {
96-
if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
97-
&expr.kind,
98-
self.node_matches_type(expr.hir_id),
99-
) {
100-
self.found_closure = Some(&expr.kind);
99+
if self.node_matches_type(expr.hir_id).is_some() {
100+
match expr.kind {
101+
ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
102+
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr.kind),
103+
_ => {}
104+
}
101105
}
102106
intravisit::walk_expr(self, expr);
103107
}
@@ -157,7 +161,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
157161
let ty_vars = self.type_variables.borrow();
158162
let var_origin = ty_vars.var_origin(ty_vid);
159163
if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
160-
return (name.to_string(), Some(var_origin.span));
164+
if name != kw::SelfUpper {
165+
return (name.to_string(), Some(var_origin.span));
166+
}
161167
}
162168
}
163169

@@ -175,6 +181,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
175181
body_id: Option<hir::BodyId>,
176182
span: Span,
177183
ty: Ty<'tcx>,
184+
is_projection: bool,
178185
) -> DiagnosticBuilder<'tcx> {
179186
let ty = self.resolve_vars_if_possible(&ty);
180187
let (name, name_sp) = self.extract_type_name(&ty, None);
@@ -210,6 +217,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
210217
// 3 | let _ = x.sum() as f64;
211218
// | ^^^ cannot infer type for `S`
212219
span
220+
} else if let Some(ExprKind::MethodCall(_, call_span, _)) = local_visitor.found_method_call {
221+
// Point at the call instead of the whole expression:
222+
// error[E0284]: type annotations needed
223+
// --> file.rs:2:5
224+
// |
225+
// 2 | vec![Ok(2)].into_iter().collect()?;
226+
// | ^^^^^^^ cannot infer type
227+
// |
228+
// = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
229+
if span.contains(*call_span) {
230+
*call_span
231+
} else {
232+
span
233+
}
213234
} else {
214235
span
215236
};
@@ -247,13 +268,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
247268
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
248269
// | the type parameter `E` is specified
249270
// ```
250-
let mut err = struct_span_err!(
251-
self.tcx.sess,
252-
err_span,
253-
E0282,
254-
"type annotations needed{}",
255-
ty_msg,
256-
);
271+
let mut err = if is_projection {
272+
struct_span_err!(self.tcx.sess, err_span, E0284, "type annotations needed{}", ty_msg)
273+
} else {
274+
struct_span_err!(self.tcx.sess, err_span, E0282, "type annotations needed{}", ty_msg)
275+
};
257276

258277
let suffix = match local_visitor.found_ty {
259278
Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => {
@@ -334,6 +353,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
334353
format!("consider giving this pattern {}", suffix)
335354
};
336355
err.span_label(pattern.span, msg);
356+
} else if let Some(ExprKind::MethodCall(segment, ..)) = local_visitor.found_method_call {
357+
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(segment.ident.span) {
358+
if segment.args.is_none() {
359+
err.span_suggestion(
360+
segment.ident.span,
361+
"consider specifying the type argument in the method call",
362+
// FIXME: we don't know how many type arguments should be set here.
363+
format!("{}::<_>", snippet),
364+
Applicability::HasPlaceholders,
365+
);
366+
}
367+
}
337368
}
338369
// Instead of the following:
339370
// error[E0282]: type annotations needed
@@ -351,7 +382,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
351382
// | ^^^ cannot infer type for `S`
352383
// |
353384
// = note: type must be known at this point
354-
let span = name_sp.unwrap_or(span);
385+
let span = name_sp.unwrap_or(err_span);
355386
if !err.span.span_labels().iter().any(|span_label| {
356387
span_label.label.is_some() && span_label.span == span
357388
}) && local_visitor.found_arg_pattern.is_none()

src/librustc/traits/error_reporting.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,7 +1989,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
19891989
self.tcx.lang_items().sized_trait()
19901990
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
19911991
{
1992-
self.need_type_info_err(body_id, span, self_ty).emit();
1992+
self.need_type_info_err(body_id, span, self_ty, false).emit();
19931993
} else {
19941994
let mut err = struct_span_err!(
19951995
self.tcx.sess,
@@ -2007,7 +2007,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
20072007
// Same hacky approach as above to avoid deluging user
20082008
// with error messages.
20092009
if !ty.references_error() && !self.tcx.sess.has_errors() {
2010-
self.need_type_info_err(body_id, span, ty).emit();
2010+
let mut err = self.need_type_info_err(body_id, span, ty, false);
2011+
self.note_obligation_cause(&mut err, obligation);
2012+
err.emit();
20112013
}
20122014
}
20132015

@@ -2018,21 +2020,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
20182020
let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
20192021
// both must be type variables, or the other would've been instantiated
20202022
assert!(a.is_ty_var() && b.is_ty_var());
2021-
self.need_type_info_err(body_id,
2022-
obligation.cause.span,
2023-
a).emit();
2023+
let mut err = self.need_type_info_err(body_id, span, a, false);
2024+
self.note_obligation_cause(&mut err, obligation);
2025+
err.emit();
2026+
}
2027+
}
2028+
ty::Predicate::Projection(ref data) => {
2029+
let trait_ref = data.to_poly_trait_ref(self.tcx);
2030+
let self_ty = trait_ref.self_ty();
2031+
if predicate.references_error() {
2032+
return;
20242033
}
2034+
let mut err = self.need_type_info_err(body_id, span, self_ty, true);
2035+
err.note(&format!("cannot resolve `{}`", predicate));
2036+
self.note_obligation_cause(&mut err, obligation);
2037+
err.emit();
20252038
}
20262039

20272040
_ => {
20282041
if !self.tcx.sess.has_errors() {
20292042
let mut err = struct_span_err!(
20302043
self.tcx.sess,
2031-
obligation.cause.span,
2044+
span,
20322045
E0284,
20332046
"type annotations needed: cannot resolve `{}`",
20342047
predicate,
20352048
);
2049+
err.span_label(span, &format!("cannot resolve `{}`", predicate));
20362050
self.note_obligation_cause(&mut err, obligation);
20372051
err.emit();
20382052
}

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5359,7 +5359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
53595359
ty
53605360
} else {
53615361
if !self.is_tainted_by_errors() {
5362-
self.need_type_info_err((**self).body_id, sp, ty)
5362+
self.need_type_info_err((**self).body_id, sp, ty, false)
53635363
.note("type must be known at this point")
53645364
.emit();
53655365
}

src/librustc_typeck/check/writeback.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
717717
fn report_error(&self, t: Ty<'tcx>) {
718718
if !self.tcx.sess.has_errors() {
719719
self.infcx
720-
.need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t)
720+
.need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, false)
721721
.emit();
722722
}
723723
}
Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1-
error[E0284]: type annotations needed: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
1+
error[E0284]: type annotations needed
22
--> $DIR/associated-types-overridden-binding.rs:4:1
33
|
44
LL | trait Foo: Iterator<Item = i32> {}
55
| ------------------------------- required by `Foo`
66
LL | trait Bar: Foo<Item = u32> {}
7-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self`
8+
|
9+
= note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
810

9-
error[E0282]: type annotations needed
11+
error[E0284]: type annotations needed
1012
--> $DIR/associated-types-overridden-binding.rs:7:1
1113
|
14+
LL | trait I32Iterator = Iterator<Item = i32>;
15+
| ----------------------------------------- required by `I32Iterator`
1216
LL | trait U32Iterator = I32Iterator<Item = u32>;
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self`
18+
|
19+
= note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
1420

1521
error: aborting due to 2 previous errors
1622

17-
Some errors have detailed explanations: E0282, E0284.
18-
For more information about an error, try `rustc --explain E0282`.
23+
For more information about this error, try `rustc --explain E0284`.

src/test/ui/associated-types/associated-types-unconstrained.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
error[E0284]: type annotations needed: cannot resolve `<_ as Foo>::A == _`
1+
error[E0284]: type annotations needed
22
--> $DIR/associated-types-unconstrained.rs:14:20
33
|
44
LL | let x: isize = Foo::bar();
5-
| ^^^^^^^^
5+
| ^^^^^^^^ cannot infer type
6+
|
7+
= note: cannot resolve `<_ as Foo>::A == _`
68

79
error: aborting due to previous error
810

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
error[E0284]: type annotations needed: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
1+
error[E0284]: type annotations needed
22
--> $DIR/issue-12028.rs:27:14
33
|
44
LL | self.input_stream(&mut stream);
5-
| ^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^ cannot infer type for `H`
6+
|
7+
= note: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
68

79
error: aborting due to previous error
810

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +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-
| ^^^^ cannot infer type for `T`
5+
| ^^^^
6+
| |
7+
| cannot infer type for `T`
8+
| help: consider specifying the type argument in the method call: `last::<_>`
69
|
710
= note: type must be known at this point
811

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fn f(x: &i32) -> Result<i32, ()> {
99

1010
fn g() -> Result<Vec<i32>, ()> {
1111
let l = [1, 2, 3, 4];
12-
l.iter().map(f).collect()? //~ ERROR type annotations needed: cannot resolve
12+
l.iter().map(f).collect()? //~ ERROR type annotations needed
1313
}
1414

1515
fn main() {

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
error[E0284]: type annotations needed: cannot resolve `<_ as std::ops::Try>::Ok == _`
2-
--> $DIR/question-mark-type-infer.rs:12:5
1+
error[E0284]: type annotations needed
2+
--> $DIR/question-mark-type-infer.rs:12:21
33
|
44
LL | l.iter().map(f).collect()?
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^
6+
| |
7+
| cannot infer type
8+
| help: consider specifying the type argument in the method call: `collect::<_>`
9+
|
10+
= note: cannot resolve `<_ as std::ops::Try>::Ok == _`
611

712
error: aborting due to previous error
813

src/test/ui/span/issue-42234-unknown-receiver-type.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ fn shines_a_beacon_through_the_darkness() {
99
}
1010

1111
fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
12-
data.iter() //~ ERROR type annotations needed
13-
.sum::<_>()
12+
data.iter()
13+
.sum::<_>() //~ ERROR type annotations needed
1414
.to_string()
1515
}
1616

src/test/ui/span/issue-42234-unknown-receiver-type.stderr

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ LL | x.unwrap().method_that_could_exist_on_some_type();
99
= note: type must be known at this point
1010

1111
error[E0282]: type annotations needed
12-
--> $DIR/issue-42234-unknown-receiver-type.rs:12:5
12+
--> $DIR/issue-42234-unknown-receiver-type.rs:13:10
1313
|
14-
LL | / data.iter()
15-
LL | | .sum::<_>()
16-
| |___________________^ cannot infer type
14+
LL | .sum::<_>()
15+
| ^^^ cannot infer type
1716
|
1817
= note: type must be known at this point
1918

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error[E0282]: type annotations needed
22
--> $DIR/type-annotations-needed-expr.rs:2:39
33
|
44
LL | let _ = (vec![1,2,3]).into_iter().sum() as f64;
5-
| ^^^ cannot infer type for `S`
5+
| ^^^
6+
| |
7+
| cannot infer type for `S`
8+
| help: consider specifying the type argument in the method call: `sum::<_>`
69
|
710
= note: type must be known at this point
811

0 commit comments

Comments
 (0)