Point at method call when type annotations are needed
This commit is contained in:
parent
7dbfb0a8ca
commit
12af2561e9
@ -6,6 +6,7 @@ use crate::infer::type_variable::TypeVariableOriginKind;
|
||||
use crate::ty::{self, Ty, Infer, TyVar};
|
||||
use crate::ty::print::Print;
|
||||
use syntax::source_map::DesugaringKind;
|
||||
use syntax::symbol::kw;
|
||||
use syntax_pos::Span;
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
|
||||
@ -19,6 +20,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
found_arg_pattern: Option<&'tcx Pat>,
|
||||
found_ty: Option<Ty<'tcx>>,
|
||||
found_closure: Option<&'tcx ExprKind>,
|
||||
found_method_call: Option<&'tcx ExprKind>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
@ -35,6 +37,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
found_arg_pattern: None,
|
||||
found_ty: None,
|
||||
found_closure: None,
|
||||
found_method_call: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,11 +96,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr) {
|
||||
if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
|
||||
&expr.kind,
|
||||
self.node_matches_type(expr.hir_id),
|
||||
) {
|
||||
self.found_closure = Some(&expr.kind);
|
||||
if self.node_matches_type(expr.hir_id).is_some() {
|
||||
match expr.kind {
|
||||
ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
|
||||
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr.kind),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
@ -157,7 +161,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let ty_vars = self.type_variables.borrow();
|
||||
let var_origin = ty_vars.var_origin(ty_vid);
|
||||
if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
|
||||
return (name.to_string(), Some(var_origin.span));
|
||||
if name != kw::SelfUpper {
|
||||
return (name.to_string(), Some(var_origin.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +181,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
body_id: Option<hir::BodyId>,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
is_projection: bool,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let ty = self.resolve_vars_if_possible(&ty);
|
||||
let (name, name_sp) = self.extract_type_name(&ty, None);
|
||||
@ -210,6 +217,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// 3 | let _ = x.sum() as f64;
|
||||
// | ^^^ cannot infer type for `S`
|
||||
span
|
||||
} else if let Some(ExprKind::MethodCall(_, call_span, _)) = local_visitor.found_method_call {
|
||||
// Point at the call instead of the whole expression:
|
||||
// error[E0284]: type annotations needed
|
||||
// --> file.rs:2:5
|
||||
// |
|
||||
// 2 | vec![Ok(2)].into_iter().collect()?;
|
||||
// | ^^^^^^^ cannot infer type
|
||||
// |
|
||||
// = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
|
||||
if span.contains(*call_span) {
|
||||
*call_span
|
||||
} else {
|
||||
span
|
||||
}
|
||||
} else {
|
||||
span
|
||||
};
|
||||
@ -247,13 +268,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
|
||||
// | the type parameter `E` is specified
|
||||
// ```
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
err_span,
|
||||
E0282,
|
||||
"type annotations needed{}",
|
||||
ty_msg,
|
||||
);
|
||||
let mut err = if is_projection {
|
||||
struct_span_err!(self.tcx.sess, err_span, E0284, "type annotations needed{}", ty_msg)
|
||||
} else {
|
||||
struct_span_err!(self.tcx.sess, err_span, E0282, "type annotations needed{}", ty_msg)
|
||||
};
|
||||
|
||||
let suffix = match local_visitor.found_ty {
|
||||
Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => {
|
||||
@ -334,6 +353,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
format!("consider giving this pattern {}", suffix)
|
||||
};
|
||||
err.span_label(pattern.span, msg);
|
||||
} else if let Some(ExprKind::MethodCall(segment, ..)) = local_visitor.found_method_call {
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(segment.ident.span) {
|
||||
if segment.args.is_none() {
|
||||
err.span_suggestion(
|
||||
segment.ident.span,
|
||||
"consider specifying the type argument in the method call",
|
||||
// FIXME: we don't know how many type arguments should be set here.
|
||||
format!("{}::<_>", snippet),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Instead of the following:
|
||||
// error[E0282]: type annotations needed
|
||||
@ -351,7 +382,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// | ^^^ cannot infer type for `S`
|
||||
// |
|
||||
// = note: type must be known at this point
|
||||
let span = name_sp.unwrap_or(span);
|
||||
let span = name_sp.unwrap_or(err_span);
|
||||
if !err.span.span_labels().iter().any(|span_label| {
|
||||
span_label.label.is_some() && span_label.span == span
|
||||
}) && local_visitor.found_arg_pattern.is_none()
|
||||
|
@ -1989,7 +1989,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
self.tcx.lang_items().sized_trait()
|
||||
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
|
||||
{
|
||||
self.need_type_info_err(body_id, span, self_ty).emit();
|
||||
self.need_type_info_err(body_id, span, self_ty, false).emit();
|
||||
} else {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
@ -2007,7 +2007,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// Same hacky approach as above to avoid deluging user
|
||||
// with error messages.
|
||||
if !ty.references_error() && !self.tcx.sess.has_errors() {
|
||||
self.need_type_info_err(body_id, span, ty).emit();
|
||||
let mut err = self.need_type_info_err(body_id, span, ty, false);
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2018,21 +2020,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
|
||||
// both must be type variables, or the other would've been instantiated
|
||||
assert!(a.is_ty_var() && b.is_ty_var());
|
||||
self.need_type_info_err(body_id,
|
||||
obligation.cause.span,
|
||||
a).emit();
|
||||
let mut err = self.need_type_info_err(body_id, span, a, false);
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
let trait_ref = data.to_poly_trait_ref(self.tcx);
|
||||
let self_ty = trait_ref.self_ty();
|
||||
if predicate.references_error() {
|
||||
return;
|
||||
}
|
||||
let mut err = self.need_type_info_err(body_id, span, self_ty, true);
|
||||
err.note(&format!("cannot resolve `{}`", predicate));
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
_ => {
|
||||
if !self.tcx.sess.has_errors() {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
obligation.cause.span,
|
||||
span,
|
||||
E0284,
|
||||
"type annotations needed: cannot resolve `{}`",
|
||||
predicate,
|
||||
);
|
||||
err.span_label(span, &format!("cannot resolve `{}`", predicate));
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
|
@ -5359,7 +5359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty
|
||||
} else {
|
||||
if !self.is_tainted_by_errors() {
|
||||
self.need_type_info_err((**self).body_id, sp, ty)
|
||||
self.need_type_info_err((**self).body_id, sp, ty, false)
|
||||
.note("type must be known at this point")
|
||||
.emit();
|
||||
}
|
||||
|
@ -717,7 +717,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
||||
fn report_error(&self, t: Ty<'tcx>) {
|
||||
if !self.tcx.sess.has_errors() {
|
||||
self.infcx
|
||||
.need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t)
|
||||
.need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, false)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,23 @@
|
||||
error[E0284]: type annotations needed: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
|
||||
error[E0284]: type annotations needed
|
||||
--> $DIR/associated-types-overridden-binding.rs:4:1
|
||||
|
|
||||
LL | trait Foo: Iterator<Item = i32> {}
|
||||
| ------------------------------- required by `Foo`
|
||||
LL | trait Bar: Foo<Item = u32> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self`
|
||||
|
|
||||
= note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
error[E0284]: type annotations needed
|
||||
--> $DIR/associated-types-overridden-binding.rs:7:1
|
||||
|
|
||||
LL | trait I32Iterator = Iterator<Item = i32>;
|
||||
| ----------------------------------------- required by `I32Iterator`
|
||||
LL | trait U32Iterator = I32Iterator<Item = u32>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self`
|
||||
|
|
||||
= note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0282, E0284.
|
||||
For more information about an error, try `rustc --explain E0282`.
|
||||
For more information about this error, try `rustc --explain E0284`.
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0284]: type annotations needed: cannot resolve `<_ as Foo>::A == _`
|
||||
error[E0284]: type annotations needed
|
||||
--> $DIR/associated-types-unconstrained.rs:14:20
|
||||
|
|
||||
LL | let x: isize = Foo::bar();
|
||||
| ^^^^^^^^
|
||||
| ^^^^^^^^ cannot infer type
|
||||
|
|
||||
= note: cannot resolve `<_ as Foo>::A == _`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0284]: type annotations needed: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
|
||||
error[E0284]: type annotations needed
|
||||
--> $DIR/issue-12028.rs:27:14
|
||||
|
|
||||
LL | self.input_stream(&mut stream);
|
||||
| ^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^ cannot infer type for `H`
|
||||
|
|
||||
= note: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,7 +2,10 @@ error[E0282]: type annotations needed
|
||||
--> $DIR/issue-65611.rs:59:20
|
||||
|
|
||||
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::<_>`
|
||||
|
|
||||
= note: type must be known at this point
|
||||
|
||||
|
@ -9,7 +9,7 @@ fn f(x: &i32) -> Result<i32, ()> {
|
||||
|
||||
fn g() -> Result<Vec<i32>, ()> {
|
||||
let l = [1, 2, 3, 4];
|
||||
l.iter().map(f).collect()? //~ ERROR type annotations needed: cannot resolve
|
||||
l.iter().map(f).collect()? //~ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -1,8 +1,13 @@
|
||||
error[E0284]: type annotations needed: cannot resolve `<_ as std::ops::Try>::Ok == _`
|
||||
--> $DIR/question-mark-type-infer.rs:12:5
|
||||
error[E0284]: type annotations needed
|
||||
--> $DIR/question-mark-type-infer.rs:12:21
|
||||
|
|
||||
LL | l.iter().map(f).collect()?
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^
|
||||
| |
|
||||
| cannot infer type
|
||||
| help: consider specifying the type argument in the method call: `collect::<_>`
|
||||
|
|
||||
= note: cannot resolve `<_ as std::ops::Try>::Ok == _`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -9,8 +9,8 @@ fn shines_a_beacon_through_the_darkness() {
|
||||
}
|
||||
|
||||
fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
|
||||
data.iter() //~ ERROR type annotations needed
|
||||
.sum::<_>()
|
||||
data.iter()
|
||||
.sum::<_>() //~ ERROR type annotations needed
|
||||
.to_string()
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,10 @@ LL | x.unwrap().method_that_could_exist_on_some_type();
|
||||
= note: type must be known at this point
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/issue-42234-unknown-receiver-type.rs:12:5
|
||||
--> $DIR/issue-42234-unknown-receiver-type.rs:13:10
|
||||
|
|
||||
LL | / data.iter()
|
||||
LL | | .sum::<_>()
|
||||
| |___________________^ cannot infer type
|
||||
LL | .sum::<_>()
|
||||
| ^^^ cannot infer type
|
||||
|
|
||||
= note: type must be known at this point
|
||||
|
||||
|
@ -2,7 +2,10 @@ error[E0282]: type annotations needed
|
||||
--> $DIR/type-annotations-needed-expr.rs:2:39
|
||||
|
|
||||
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::<_>`
|
||||
|
|
||||
= note: type must be known at this point
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user