Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Type annotations needed" error is shown in a misleading wrong location #72690

Closed
Ran4 opened this issue May 28, 2020 · 10 comments · Fixed by #73027
Closed

"Type annotations needed" error is shown in a misleading wrong location #72690

Ran4 opened this issue May 28, 2020 · 10 comments · Fixed by #73027
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference C-bug Category: This is a bug. D-confusing Diagnostics: Confusing error or lint that should be reworked. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Ran4
Copy link

Ran4 commented May 28, 2020

This compiles just fine:

fn main() {
    // vec!["hello"]
    //     .iter_mut()
    //     .map(|x| String::from(x.as_ref()))
    //     .collect::<Vec<String>>();

    vec![String::from("First"), String::from("Second")]
        .iter()
        .find(|s| *s == "Second");
}

But this gives a compiler error:

fn main() {
    vec!["hello"]
        .iter_mut()
        .map(|x| String::from(x.as_ref()))
        .collect::<Vec<String>>();

    vec![String::from("First"), String::from("Second")]
        .iter()
        .find(|s| *s == "Second");
}
error[E0283]: type annotations needed for `&&std::string::String`
 --> src/main.rs:9:16
  |
9 |         .find(|s| *s == "Second");
  |                ^ consider giving this closure parameter the explicit type `&&std::string::String`, where the type parameter `std::string::String` is specified
  |
  = note: cannot resolve `std::string::String: std::convert::From<&_>`
  = note: required by `std::convert::From::from`

error: aborting due to previous error

error: could not compile `programname`.

To learn more, run the command again with --verbose.

It seems really weird that the second statement is affected like this?

Meta

$ rustc --version --verbose
rustc 1.43.1 (8d69840ab 2020-05-04)
binary: rustc
commit-hash: 8d69840ab92ea7f4d323420088dd8c9775f180cd
commit-date: 2020-05-04
host: x86_64-unknown-linux-gnu
release: 1.43.1
LLVM version: 9.0

Empty project (created with cargo new), unmodified Cargo.toml (so no extra dependencies):

[package]
name = "programname"
version = "0.1.0"
authors = ["..."]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

This issue has been assigned to @doctorn via this comment.

@Ran4 Ran4 added the C-bug Category: This is a bug. label May 28, 2020
@wwylele
Copy link
Contributor

wwylele commented May 28, 2020

It is actually that the first statement has type error, but somehow the error is reported to the second statement.

The first statement alone reports the error correctly

fn main() {
    vec!["hello"]
        .iter_mut()
        .map(|x| String::from(x.as_ref()))
        .collect::<Vec<String>>();

    //vec![String::from("First"), String::from("Second")]
    //    .iter()
    //    .find(|s| *s == "Second");
}
error[E0283]: type annotations needed
 --> src/main.rs:4:18
  |
4 |         .map(|x| String::from(x.as_ref()))
  |          ---     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
  |          |
  |          help: consider specifying the type arguments in the method call: `map::<B, F>`
  |
  = note: cannot resolve `std::string::String: std::convert::From<&_>`
  = note: required by `std::convert::From::from`

and by fixing the error, the following compiles fine

fn main() {
    vec!["hello"]
        .iter_mut()
        .map(|x| String::from(*x))
        .collect::<Vec<String>>();

    vec![String::from("First"), String::from("Second")]
        .iter()
        .find(|s| *s == "Second");
}

@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 28, 2020
@estebank estebank added A-inference Area: Type inference D-confusing Diagnostics: Confusing error or lint that should be reworked. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. labels May 28, 2020
@shaleh
Copy link

shaleh commented May 31, 2020

This happens on Nightly and on Stable.

@dtolnay dtolnay added the regression-from-stable-to-stable Performance or correctness regression from one stable version to another. label Jun 1, 2020
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 1, 2020
@dtolnay
Copy link
Member

dtolnay commented Jun 1, 2020

Labeling as this was a regression introduced by 1.41.0.

@dtolnay dtolnay added the E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc label Jun 1, 2020
@LeSeulArtichaut LeSeulArtichaut added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jun 3, 2020
@LeSeulArtichaut
Copy link
Contributor

@doctorn
Copy link
Contributor

doctorn commented Jun 3, 2020

Problem seems to be that we always assume the last closure was the source of the inference failure

fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
if call_span == self.target_span
&& Some(self.target)
== self.infcx.in_progress_tables.and_then(|tables| {
tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into)
})
{
self.found_exact_method_call = Some(&expr);
return;
}
}
if self.node_ty_contains_target(expr.hir_id).is_some() {
match expr.kind {
ExprKind::Closure(..) => self.found_closure = Some(&expr),
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
_ => {}
}
}
intravisit::walk_expr(self, expr);
}

@doctorn
Copy link
Contributor

doctorn commented Jun 3, 2020

Just sticking a return after

ExprKind::Closure(..) => self.found_closure = Some(&expr),
is enough to get the correct diagnostic in this specific instance. However, we clearly need to be smarter than that, as in a sequence of closures, any of them could be the source of an inference error (current implementation always assumes last, just adding a return always assumes first).

@doctorn
Copy link
Contributor

doctorn commented Jun 4, 2020

Ok, I'm doing some more investigation and I think it might actually be safe to assume the first compatible closure is the source of the inference error because of the way node_ty_contains_target is implemented.

Definitely not the case - looking into some alternative fixes.

@rustbot claim

@rustbot rustbot assigned rustbot and unassigned rustbot Jun 4, 2020
@doctorn
Copy link
Contributor

doctorn commented Jun 4, 2020

Ok this is even more subtle than I first thought. There's just far too much ambiguity here for this diagnostic code to produce a sensible suggestion. Any time a sub-expression/local pattern/argument pattern/closure's type contains the inference target it immediately becomes a candidate for suggesting on. In this case though, the inference target is std::string::String, so any code that has anything to do with strings will trip the diagnostic...

@doctorn
Copy link
Contributor

doctorn commented Jun 4, 2020

fn main() {
    vec!["hello"]
        .iter_mut()
        .map(|x| String::from(x.as_ref()))
        .collect::<Vec<String>>();

    format!("Hello");
}

Compiling the above results in this - clearly the format! has nothing to do with the error...

error[E0283]: type annotations needed for `std::string::String`
 --> src/main.rs:4:18
  |
4 |         .map(|x| String::from(x.as_ref()))
  |                  ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
...
7 |     format!("Hello");
  |     ----------------- consider giving `res` a type
  |
  = note: cannot resolve `std::string::String: std::convert::From<&_>`
  = note: required by `std::convert::From::from`

@dtolnay dtolnay changed the title Type inference bug? "Type annotations needed" error is shown in a misleading wrong location Jun 16, 2020
@bors bors closed this as completed in 2d1bd57 Jun 20, 2020
@alper
Copy link
Contributor

alper commented Dec 7, 2020

I have a similar message to:

cannot infer type for struct std::string::String

But what I don't understand is: why does it complain it can't infer the type if it clearly knows the type?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference C-bug Category: This is a bug. D-confusing Diagnostics: Confusing error or lint that should be reworked. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants