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

Error "cannot infer type" when using '?' in async block + bad diagnostic #63502

Open
russelltg opened this issue Aug 12, 2019 · 11 comments
Open
Labels
A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. D-papercut Diagnostics: An error or lint that needs small tweaks. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@russelltg
Copy link

russelltg commented Aug 12, 2019

This seems related to #42424, except I don't see an obvious workaround like in #42424.

#![feature(async_await)]

use std::io::Error;

fn make_unit() -> Result<(), Error> { 
    Ok(())
}

fn main() {
    let fut = async {
        make_unit()?;
        
        Ok(())
    };
}

Fails with the error

error[E0282]: type annotations needed for `impl std::future::Future`
  --> src/main.rs:11:9
   |
10 |     let fut = async {
   |         --- consider giving `fut` the explicit type `impl std::future::Future`, with the type parameters specified
11 |         make_unit()?;
   |         ^^^^^^^^^^^^ cannot infer type

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=ea7e5f7b6e1637f6a39aee0b8209c99e

First of all, it seems like this shouldn't be an error--it should be able to deduce that the return type is Result<(), io::Error>, but also the diagnostic does not work. If you try to add impl std::future::Future<Output=Result<(), Error>> as a type annotation, it also fails to compile because impl Trait is only allowed as return types and argument types.

Playground link

@jonas-schievink jonas-schievink added A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints C-bug Category: This is a bug. F-async_await T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. requires-nightly This issue requires a nightly compiler in some way. labels Aug 12, 2019
@Centril Centril added the AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. label Aug 12, 2019
@estebank estebank added A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. A-inference Area: Type inference labels Aug 12, 2019
@estebank
Copy link
Contributor

Opened #63504 for the incorrect suggestion. For the main issue, ? interacts in non-obvious ways with type inference because it does implicit conversion. In this case, because fut doesn't explicitly constraint what the expected type is, rustc doesn't know what Result<(), std::io:Error> should be converted to.

There are other similar tickets filed about these kind of type inference issues: #49391, #38508, #46333, #46680, #48089, #61152, #58517 and #63082.

(larger work around ? tracked in #31436)

@cramertj
Copy link
Member

I don't see an obvious workaround

The workaround is this:

use std::io::Error;

fn make_unit() -> Result<(), Error> { 
    Ok(())
}

fn main() {
    let fut = async {
        make_unit()?;
        
        Ok::<(), Error>(())
    };
}

Centril added a commit to Centril/rust that referenced this issue Aug 14, 2019
…ntril

When needing type annotations in local bindings, account for impl Trait and closures

Fix rust-lang#46680, fix rust-lang#63504, fix rust-lang#63506, fix rust-lang#40014, cc rust-lang#63502.
@nikomatsakis
Copy link
Contributor

Discussing as part of a "triage effort". A few notes:

  • This isn't (necessarily) an inference failure: the original code snippet is somewhat underspecified, in that the return type of the async block can be any error type E that the Error value can be Into'd into.
  • What's needed is probably (a) a syntax to conveniently specify the error type and (b) a diagnostic that suggests said syntax.

We lack a syntax. So maybe we can give a better diagnostic that at least hints at the solution. Or maybe an extended error code description.

@estebank
Copy link
Contributor

estebank commented Aug 28, 2019

For this case, we probably could suggest a temporary local binding with an explicit type:

    let fut = async {
        let x: Result<_, Error> = make_unit();
        x?;
        Ok(())
    };

As for the syntax, we could borrow the closure syntax and allow something like async -> Result<(), Error> {} or async::<Result<(), Error> {}, but those are uuuugly.

CC #62570, as it is not the same error, but it is similar enough code that these two errors will likely happen in short temporal distance of each other.

@cramertj
Copy link
Member

@estebank did you mean to include the ? after the x in your example above?

@estebank
Copy link
Contributor

Yes, but was missing the final expr Ok(()) to be correctly equivalent the original code. Just updated it.

@cramertj
Copy link
Member

cramertj commented Aug 28, 2019

@estebank That code still would not compile-- the error type annotation doesn't help there because it gets .into()'d in the ? usage. To make it work, you need to annotate the type of the final Ok value.

@estebank
Copy link
Contributor

You're absolutely right. Need more coffee.

@programmerjake
Copy link
Member

doesn't ? still use From rather than Into, or did I miss some happy RFC?

@estebank estebank added the D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. label Oct 5, 2019
@estebank estebank removed the requires-nightly This issue requires a nightly compiler in some way. label Nov 12, 2019
bors added a commit that referenced this issue Dec 11, 2019
Point at method call when type annotations are needed

- Point at method call instead of whole expression when type annotations are needed.
- Suggest use of turbofish on function and methods.

Fix #49391, fix #46333, fix #48089. CC #58517, #63502, #63082.

r? @nikomatsakis
bors added a commit that referenced this issue Dec 13, 2019
Point at method call when type annotations are needed

- Point at method call instead of whole expression when type annotations are needed.
- Suggest use of turbofish on function and methods.

Fix #49391, fix #46333, fix #48089. CC #58517, #63502, #63082.

Fixes #40015

r? @nikomatsakis
@Dylan-DPC
Copy link
Member

Current output:

error[[E0282]](https://doc.rust-lang.org/nightly/error_codes/E0282.html): type annotations needed
  --> src/main.rs:11:9
   |
11 |         Ok(())
   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
   |
help: consider specifying the generic arguments
   |
11 |         Ok::<(), E>(())
   |           +++++++++

@estebank
Copy link
Contributor

The only thing left is for inference to detect that E could have been Error and suggest that.

@estebank estebank added the D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. label Aug 4, 2023
@estebank estebank added D-papercut Diagnostics: An error or lint that needs small tweaks. and removed C-bug Category: This is a bug. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. labels Oct 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. D-papercut Diagnostics: An error or lint that needs small tweaks. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

8 participants