Auto merge of #61361 - estebank:infer-type, r=varkor
Add more detail to type inference error When encountering code where type inference fails, add more actionable information: ``` fn main() { let foo = Vec::new(); } ``` ``` error[E0282]: type annotations needed in `std::vec::Vec<T>` --> $DIR/vector-no-ann.rs:2:16 | LL | let foo = Vec::new(); | --- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<T>` | | | consider giving `foo` a type ``` Fix #25633.
This commit is contained in:
commit
d59dcb261e
@ -15,17 +15,18 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
hir_map: &'a hir::map::Map<'gcx>,
|
||||
found_local_pattern: Option<&'gcx Pat>,
|
||||
found_arg_pattern: Option<&'gcx Pat>,
|
||||
found_ty: Option<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
|
||||
fn node_matches_type(&mut self, hir_id: HirId) -> bool {
|
||||
fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
|
||||
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
|
||||
tables.borrow().node_type_opt(hir_id)
|
||||
});
|
||||
match ty_opt {
|
||||
Some(ty) => {
|
||||
let ty = self.infcx.resolve_vars_if_possible(&ty);
|
||||
ty.walk().any(|inner_ty| {
|
||||
if ty.walk().any(|inner_ty| {
|
||||
inner_ty == self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
|
||||
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
|
||||
self.infcx
|
||||
@ -35,9 +36,13 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}) {
|
||||
Some(ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None => false,
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,16 +53,21 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: &'gcx Local) {
|
||||
if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) {
|
||||
if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) {
|
||||
self.found_local_pattern = Some(&*local.pat);
|
||||
self.found_ty = Some(ty);
|
||||
}
|
||||
intravisit::walk_local(self, local);
|
||||
}
|
||||
|
||||
fn visit_body(&mut self, body: &'gcx Body) {
|
||||
for argument in &body.arguments {
|
||||
if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) {
|
||||
if let (None, Some(ty)) = (
|
||||
self.found_arg_pattern,
|
||||
self.node_matches_type(argument.hir_id),
|
||||
) {
|
||||
self.found_arg_pattern = Some(&*argument.pat);
|
||||
self.found_ty = Some(ty);
|
||||
}
|
||||
}
|
||||
intravisit::walk_body(self, body);
|
||||
@ -98,7 +108,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
let name = self.extract_type_name(&ty, None);
|
||||
|
||||
let mut err_span = span;
|
||||
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
|
||||
|
||||
let mut local_visitor = FindLocalByTypeVisitor {
|
||||
infcx: &self,
|
||||
@ -106,6 +115,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
hir_map: &self.tcx.hir(),
|
||||
found_local_pattern: None,
|
||||
found_arg_pattern: None,
|
||||
found_ty: None,
|
||||
};
|
||||
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.type_variables.borrow();
|
||||
let getter = move |ty_vid| {
|
||||
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
|
||||
*ty_vars.var_origin(ty_vid) {
|
||||
return Some(name.to_string());
|
||||
}
|
||||
None
|
||||
};
|
||||
printer.name_resolver = Some(Box::new(&getter));
|
||||
let _ = ty.print(printer);
|
||||
s
|
||||
};
|
||||
|
||||
if let Some(body_id) = body_id {
|
||||
@ -113,6 +138,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
local_visitor.visit_expr(expr);
|
||||
}
|
||||
|
||||
// When `name` corresponds to a type argument, show the path of the full type we're
|
||||
// trying to infer. In the following example, `ty_msg` contains
|
||||
// " in `std::result::Result<i32, E>`":
|
||||
// ```
|
||||
// error[E0282]: type annotations needed for `std::result::Result<i32, E>`
|
||||
// --> file.rs:L:CC
|
||||
// |
|
||||
// L | let b = Ok(4);
|
||||
// | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
|
||||
// | |
|
||||
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
|
||||
// | the type parameter `E` is specified
|
||||
// ```
|
||||
let (ty_msg, suffix) = match &local_visitor.found_ty {
|
||||
Some(ty) if &ty.to_string() != "_" && name == "_" => {
|
||||
let ty = ty_to_string(ty);
|
||||
(format!(" for `{}`", ty),
|
||||
format!("the explicit type `{}`, with the type parameters specified", ty))
|
||||
}
|
||||
Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
|
||||
let ty = ty_to_string(ty);
|
||||
(format!(" for `{}`", ty),
|
||||
format!(
|
||||
"the explicit type `{}`, where the type parameter `{}` is specified",
|
||||
ty,
|
||||
name,
|
||||
))
|
||||
}
|
||||
_ => (String::new(), "a type".to_owned()),
|
||||
};
|
||||
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
|
||||
|
||||
if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||
err_span = pattern.span;
|
||||
// We don't want to show the default label for closures.
|
||||
@ -128,16 +185,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// After clearing, it looks something like this:
|
||||
// ```
|
||||
// let x = |_| { };
|
||||
// ^ consider giving this closure parameter a type
|
||||
// ^ consider giving this closure parameter the type `[_; 0]`
|
||||
// with the type parameter `_` specified
|
||||
// ```
|
||||
labels.clear();
|
||||
labels.push(
|
||||
(pattern.span, "consider giving this closure parameter a type".to_owned()));
|
||||
labels.push((
|
||||
pattern.span,
|
||||
format!("consider giving this closure parameter {}", suffix),
|
||||
));
|
||||
} else if let Some(pattern) = local_visitor.found_local_pattern {
|
||||
if let Some(simple_ident) = pattern.simple_ident() {
|
||||
match pattern.span.compiler_desugaring_kind() {
|
||||
None => labels.push((pattern.span,
|
||||
format!("consider giving `{}` a type", simple_ident))),
|
||||
None => labels.push((
|
||||
pattern.span,
|
||||
format!("consider giving `{}` {}", simple_ident, suffix),
|
||||
)),
|
||||
Some(CompilerDesugaringKind::ForLoop) => labels.push((
|
||||
pattern.span,
|
||||
"the element type for this iterator is not specified".to_owned(),
|
||||
@ -145,14 +207,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
labels.push((pattern.span, "consider giving the pattern a type".to_owned()));
|
||||
labels.push((pattern.span, format!("consider giving this pattern {}", suffix)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
err_span,
|
||||
E0282,
|
||||
"type annotations needed");
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
err_span,
|
||||
E0282,
|
||||
"type annotations needed{}",
|
||||
ty_msg,
|
||||
);
|
||||
|
||||
for (target_span, label_message) in labels {
|
||||
err.span_label(target_span, label_message);
|
||||
|
@ -483,7 +483,17 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
|
||||
ty::FnPtr(ref bare_fn) => {
|
||||
p!(print(bare_fn))
|
||||
}
|
||||
ty::Infer(infer_ty) => p!(write("{}", infer_ty)),
|
||||
ty::Infer(infer_ty) => {
|
||||
if let ty::TyVar(ty_vid) = infer_ty {
|
||||
if let Some(name) = self.infer_ty_name(ty_vid) {
|
||||
p!(write("{}", name))
|
||||
} else {
|
||||
p!(write("{}", infer_ty))
|
||||
}
|
||||
} else {
|
||||
p!(write("{}", infer_ty))
|
||||
}
|
||||
},
|
||||
ty::Error => p!(write("[type error]")),
|
||||
ty::Param(ref param_ty) => p!(write("{}", param_ty)),
|
||||
ty::Bound(debruijn, bound_ty) => {
|
||||
@ -681,6 +691,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn pretty_print_dyn_existential(
|
||||
mut self,
|
||||
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
|
||||
@ -931,6 +945,8 @@ pub struct FmtPrinterData<'a, 'gcx, 'tcx, F> {
|
||||
binder_depth: usize,
|
||||
|
||||
pub region_highlight_mode: RegionHighlightMode,
|
||||
|
||||
pub name_resolver: Option<Box<&'a dyn Fn(ty::sty::TyVid) -> Option<String>>>,
|
||||
}
|
||||
|
||||
impl<F> Deref for FmtPrinter<'a, 'gcx, 'tcx, F> {
|
||||
@ -957,6 +973,7 @@ impl<F> FmtPrinter<'a, 'gcx, 'tcx, F> {
|
||||
region_index: 0,
|
||||
binder_depth: 0,
|
||||
region_highlight_mode: RegionHighlightMode::default(),
|
||||
name_resolver: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -1206,6 +1223,10 @@ impl<F: fmt::Write> Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
|
||||
}
|
||||
|
||||
impl<F: fmt::Write> PrettyPrinter<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
|
||||
fn infer_ty_name(&self, id: ty::TyVid) -> Option<String> {
|
||||
self.0.name_resolver.as_ref().and_then(|func| func(id))
|
||||
}
|
||||
|
||||
fn print_value_path(
|
||||
mut self,
|
||||
def_id: DefId,
|
||||
|
@ -4,5 +4,5 @@ fn new<T>() -> &'static T {
|
||||
|
||||
fn main() {
|
||||
let &v = new();
|
||||
//~^ ERROR type annotations needed [E0282]
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `&T`
|
||||
--> $DIR/issue-12187-1.rs:6:10
|
||||
|
|
||||
LL | let &v = new();
|
||||
| -^
|
||||
| ||
|
||||
| |cannot infer type
|
||||
| consider giving the pattern a type
|
||||
| consider giving this pattern the explicit type `&T`, with the type parameters specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -4,5 +4,5 @@ fn new<'r, T>() -> &'r T {
|
||||
|
||||
fn main() {
|
||||
let &v = new();
|
||||
//~^ ERROR type annotations needed [E0282]
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `&T`
|
||||
--> $DIR/issue-12187-2.rs:6:10
|
||||
|
|
||||
LL | let &v = new();
|
||||
| -^
|
||||
| ||
|
||||
| |cannot infer type
|
||||
| consider giving the pattern a type
|
||||
| consider giving this pattern the explicit type `&T`, with the type parameters specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `B<T>`
|
||||
--> $DIR/issue-17551.rs:6:15
|
||||
|
|
||||
LL | let foo = B(marker::PhantomData);
|
||||
| --- ^ cannot infer type for `T`
|
||||
| |
|
||||
| consider giving `foo` a type
|
||||
| consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `&(_,)`
|
||||
--> $DIR/issue-20261.rs:4:11
|
||||
|
|
||||
LL | for (ref i,) in [].iter() {
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `Expr<'_, VAR>`
|
||||
--> $DIR/issue-23046.rs:17:15
|
||||
|
|
||||
LL | let ex = |x| {
|
||||
| ^ consider giving this closure parameter a type
|
||||
| ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
|
||||
--> $DIR/issue-25368.rs:11:17
|
||||
|
|
||||
LL | let (tx, rx) = channel();
|
||||
| -------- consider giving the pattern a type
|
||||
| -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
|
||||
...
|
||||
LL | tx.send(Foo{ foo: PhantomData });
|
||||
| ^^^ cannot infer type for `T`
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `&[_; 0]`
|
||||
--> $DIR/issue-7813.rs:2:13
|
||||
|
|
||||
LL | let v = &[];
|
||||
| - ^^^ cannot infer type
|
||||
| |
|
||||
| consider giving `v` a type
|
||||
| consider giving `v` the explicit type `&[_; 0]`, with the type parameters specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -22,7 +22,7 @@ impl Foo for Vec<isize> {
|
||||
fn m1() {
|
||||
// we couldn't infer the type of the vector just based on calling foo()...
|
||||
let mut x = Vec::new();
|
||||
//~^ ERROR type annotations needed [E0282]
|
||||
//~^ ERROR type annotations needed
|
||||
x.foo();
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `std::vec::Vec<T>`
|
||||
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
|
||||
|
|
||||
LL | let mut x = Vec::new();
|
||||
| ----- ^^^^^^^^ cannot infer type for `T`
|
||||
| |
|
||||
| consider giving `x` a type
|
||||
| consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `std::option::Option<_>`
|
||||
--> $DIR/issue-42234-unknown-receiver-type.rs:7:5
|
||||
|
|
||||
LL | let x: Option<_> = None;
|
||||
| - consider giving `x` a type
|
||||
| - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified
|
||||
LL | x.unwrap().method_that_could_exist_on_some_type();
|
||||
| ^^^^^^^^^^ cannot infer type for `T`
|
||||
|
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `[_; 0]`
|
||||
--> $DIR/cannot_infer_local_or_array.rs:2:13
|
||||
|
|
||||
LL | let x = [];
|
||||
| - ^^ cannot infer type
|
||||
| |
|
||||
| consider giving `x` a type
|
||||
| consider giving `x` the explicit type `[_; 0]`, with the type parameters specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `std::vec::Vec<T>`
|
||||
--> $DIR/cannot_infer_local_or_vec.rs:2:13
|
||||
|
|
||||
LL | let x = vec![];
|
||||
| - ^^^^^^ cannot infer type for `T`
|
||||
| |
|
||||
| consider giving `x` a type
|
||||
| consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
|
||||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `(std::vec::Vec<T>,)`
|
||||
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
|
||||
|
|
||||
LL | let (x, ) = (vec![], );
|
||||
| ----- ^^^^^^ cannot infer type for `T`
|
||||
| |
|
||||
| consider giving the pattern a type
|
||||
| consider giving this pattern the explicit type `(std::vec::Vec<T>,)`, where the type parameter `T` is specified
|
||||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `std::option::Option<T>`
|
||||
--> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32
|
||||
|
|
||||
LL | let mut closure0 = None;
|
||||
| ------------ consider giving `closure0` a type
|
||||
| ------------ consider giving `closure0` the explicit type `std::option::Option<T>`, with the type parameters specified
|
||||
...
|
||||
LL | return c();
|
||||
| ^^^ cannot infer type
|
||||
|
@ -1,4 +1,4 @@
|
||||
fn main() {
|
||||
let _foo = Vec::new();
|
||||
//~^ ERROR type annotations needed [E0282]
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0282]: type annotations needed for `std::vec::Vec<T>`
|
||||
--> $DIR/vector-no-ann.rs:2:16
|
||||
|
|
||||
LL | let _foo = Vec::new();
|
||||
| ---- ^^^^^^^^ cannot infer type for `T`
|
||||
| |
|
||||
| consider giving `_foo` a type
|
||||
| consider giving `_foo` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user