Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 77 additions & 21 deletions src/librustc/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,9 +36,13 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
}
_ => false,
}
})
}) {
Some(ty)
} else {
None
}
}
None => false,
None => None,
}
}
}
Expand All @@ -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);
Expand Down Expand Up @@ -98,21 +108,59 @@ 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,
target_ty: ty,
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 {
let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id);
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 in `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 type `std::result::Result<i32, E>` with the type
// | parameter `E` specified
// ```
let (ty_msg, suffix) = match &local_visitor.found_ty {
Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
let ty = ty_to_string(ty);
(format!(" in `{}`", ty),
format!( "the type `{}` with the type parameter `{}` specified", ty, name))
}
_ => (String::new(), "a type".to_owned()),
};
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name, &ty_msg))];

if let Some(pattern) = local_visitor.found_arg_pattern {
err_span = pattern.span;
// We don't want to show the default label for closures.
Expand All @@ -128,31 +176,39 @@ 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(),
)),
_ => {}
}
} 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);
Expand All @@ -173,15 +229,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
span,
E0698,
"type inside generator must be known in this context");
err.span_label(span, InferCtxt::missing_type_msg(&name));
err.span_label(span, InferCtxt::missing_type_msg(&name, ""));
err
}

fn missing_type_msg(type_name: &str) -> String {
fn missing_type_msg(type_name: &str, postfix: &str) -> String {
if type_name == "_" {
"cannot infer type".to_owned()
} else {
format!("cannot infer type for `{}`", type_name)
format!("cannot infer type for `{}`{}", type_name, postfix)
}
}
}
23 changes: 22 additions & 1 deletion src/librustc/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably override this in FmtPrinter's print_ty tbh, instead of adding infer_ty_name.

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) => {
Expand Down Expand Up @@ -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>>,
Expand Down Expand Up @@ -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>>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please cc me on ty::print changes - but also, I have a few questions, such as "why is this a Box<&dyn Trait>?" - you can just remove the Box and everything would still work.

}

impl<F> Deref for FmtPrinter<'a, 'gcx, 'tcx, F> {
Expand All @@ -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,
}))
}
}
Expand Down Expand Up @@ -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))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a Deref impl, you don't need to write self.0.

}

fn print_value_path(
mut self,
def_id: DefId,
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-12187-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ fn new<T>() -> &'static T {

fn main() {
let &v = new();
//~^ ERROR type annotations needed [E0282]
//~^ ERROR type annotations needed
}
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-12187-1.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `&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 type `&T` with the type parameter `_` specified

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-12187-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ fn new<'r, T>() -> &'r T {

fn main() {
let &v = new();
//~^ ERROR type annotations needed [E0282]
//~^ ERROR type annotations needed
}
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-12187-2.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `&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 type `&T` with the type parameter `_` specified

error: aborting due to previous error

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-17551.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `B<T>`
--> $DIR/issue-17551.rs:6:15
|
LL | let foo = B(marker::PhantomData);
| --- ^ cannot infer type for `T`
| --- ^ cannot infer type for `T` in `B<T>`
| |
| consider giving `foo` a type
| consider giving `foo` the type `B<T>` with the type parameter `T` specified

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-20261.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `&(_,)`
--> $DIR/issue-20261.rs:4:11
|
LL | for (ref i,) in [].iter() {
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-23046.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `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 type `Expr<'_, VAR>` with the type parameter `VAR` specified

error: aborting due to previous error

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-25368.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `(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 type `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)` with the type parameter `T` specified
...
LL | tx.send(Foo{ foo: PhantomData });
| ^^^ cannot infer type for `T`
| ^^^ cannot infer type for `T` in `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`

error: aborting due to previous error

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-7813.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `&[_; 0]`
--> $DIR/issue-7813.rs:2:13
|
LL | let v = &[];
| - ^^^ cannot infer type
| |
| consider giving `v` a type
| consider giving `v` the type `&[_; 0]` with the type parameter `_` specified

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `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`
| ----- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<T>`
| |
| consider giving `x` a type
| consider giving `x` the type `std::vec::Vec<T>` with the type parameter `T` specified

error[E0308]: mismatched types
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/span/issue-42234-unknown-receiver-type.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0282]: type annotations needed
error[E0282]: type annotations needed in `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 type `std::option::Option<_>` with the type parameter `T` specified
LL | x.unwrap().method_that_could_exist_on_some_type();
| ^^^^^^^^^^ cannot infer type for `T`
| ^^^^^^^^^^ cannot infer type for `T` in `std::option::Option<_>`
|
= note: type must be known at this point

Expand Down
Loading