diff options
| author | bors <bors@rust-lang.org> | 2021-01-12 14:42:37 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-01-12 14:42:37 +0000 |
| commit | 497c9a256b1c2961e91565ccc6e0dd3a87a031ed (patch) | |
| tree | c8c21ff5de2701b2668fd6e790836bdcad3cce5b /src/test/ui | |
| parent | fc9944fe84a683f0450c0921a935456e51b1c3ae (diff) | |
| parent | d46c3e3411b4971e31c9ead8126cc95114388b3b (diff) | |
| download | rust-497c9a256b1c2961e91565ccc6e0dd3a87a031ed.tar.gz rust-497c9a256b1c2961e91565ccc6e0dd3a87a031ed.zip | |
Auto merge of #80517 - wabain:issue-77880-infer-error-try-conversion-msg, r=davidtwco
Enhance type inference errors involving the `?` operator This patch adds a special-cased note on type inference errors when the error span points to a `?` return. It also makes the primary label for such errors "cannot infer type of `?` error" in cases where before we would have only said "cannot infer type". One beneficiary of this change is async blocks, where we can't explicitly annotate the return type and so may not generate any other help (#77880); this lets us at least print the error type we're converting from and anything we know about the type we can't fully infer. More generally, it signposts that an implicit conversion is happening that may have impeded type inference the user was expecting. We already do something similar for [mismatched type errors](https://github.com/rust-lang/rust/blob/2987785df3d46d5ff144a5c67fbb8f5cca798d78/src/test/ui/try-block/try-block-bad-type.stderr#L7). The check for a relevant `?` operator is built into the existing HIR traversal which looks for places that could be annotated to resolve the error. That means we could identify `?` uses anywhere in the function that output the type we can't infer, but this patch just sticks to adding the note if the primary span given for the error has the operator; if there are other expressions where the type occurs and one of them is selected for the error instead, it's more likely that the `?` operator's implicit conversion isn't the sole cause of the inference failure and that adding an additional diagnostic would just be noise. I added a ui test for one such case. The data about the `?` conversion is passed around in a `UseDiagnostic` enum that in theory could be used to add more of this kind of note in the future. It was also just easier to pass around than something with a more specific name. There are some follow-up refactoring commits for the code that generates the error label, which was already pretty involved and made a bit more complicated by this change.
Diffstat (limited to 'src/test/ui')
7 files changed, 68 insertions, 3 deletions
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr index 2f630c2c9ad..2875cef6801 100644 --- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr +++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr @@ -13,7 +13,9 @@ error[E0282]: type annotations needed for `impl Future` LL | let fut = async { | --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified LL | make_unit()?; - | ^ cannot infer type + | ^ cannot infer type of error for `?` operator + | + = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/inference/cannot-infer-async.stderr b/src/test/ui/inference/cannot-infer-async.stderr index 92a9045f6db..282bc13e9e7 100644 --- a/src/test/ui/inference/cannot-infer-async.stderr +++ b/src/test/ui/inference/cannot-infer-async.stderr @@ -4,7 +4,9 @@ error[E0282]: type annotations needed LL | let fut = async { | --- consider giving `fut` a type LL | make_unit()?; - | ^ cannot infer type + | ^ cannot infer type of error for `?` operator + | + = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>` error: aborting due to previous error diff --git a/src/test/ui/inference/cannot-infer-closure-circular.rs b/src/test/ui/inference/cannot-infer-closure-circular.rs new file mode 100644 index 00000000000..a3b957179b1 --- /dev/null +++ b/src/test/ui/inference/cannot-infer-closure-circular.rs @@ -0,0 +1,14 @@ +fn main() { + // Below we call the closure with its own return as the argument, unifying + // its inferred input and return types. We want to make sure that the generated + // error handles this gracefully, and in particular doesn't generate an extra + // note about the `?` operator in the closure body, which isn't relevant to + // the inference. + let x = |r| { + //~^ ERROR type annotations needed + let v = r?; + Ok(v) + }; + + let _ = x(x(Ok(()))); +} diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr new file mode 100644 index 00000000000..5efb400a4c7 --- /dev/null +++ b/src/test/ui/inference/cannot-infer-closure-circular.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed for `std::result::Result<(), E>` + --> $DIR/cannot-infer-closure-circular.rs:7:14 + | +LL | let x = |r| { + | ^ consider giving this closure parameter the explicit type `std::result::Result<(), E>`, with the type parameters specified + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/inference/cannot-infer-closure.stderr b/src/test/ui/inference/cannot-infer-closure.stderr index d5366e422db..475ed00d107 100644 --- a/src/test/ui/inference/cannot-infer-closure.stderr +++ b/src/test/ui/inference/cannot-infer-closure.stderr @@ -2,8 +2,9 @@ error[E0282]: type annotations needed for the closure `fn((), ()) -> std::result --> $DIR/cannot-infer-closure.rs:3:15 | LL | Err(a)?; - | ^ cannot infer type + | ^ cannot infer type of error for `?` operator | + = note: `?` implicitly converts the error value into a type implementing `From<()>` help: give this closure an explicit return type without `_` placeholders | LL | let x = |a: (), b: ()| -> std::result::Result<(), _> { diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.rs b/src/test/ui/inference/cannot-infer-partial-try-return.rs new file mode 100644 index 00000000000..e1058e96cef --- /dev/null +++ b/src/test/ui/inference/cannot-infer-partial-try-return.rs @@ -0,0 +1,22 @@ +struct QualifiedError<E>(E); + +impl<E, T> From<E> for QualifiedError<T> +where + E: std::error::Error, + T: From<E>, +{ + fn from(e: E) -> QualifiedError<T> { + QualifiedError(e.into()) + } +} + +fn infallible() -> Result<(), std::convert::Infallible> { + Ok(()) +} + +fn main() { + let x = || -> Result<_, QualifiedError<_>> { + infallible()?; //~ERROR type annotations needed + Ok(()) + }; +} diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr new file mode 100644 index 00000000000..a64503fa667 --- /dev/null +++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed for the closure `fn() -> std::result::Result<(), QualifiedError<_>>` + --> $DIR/cannot-infer-partial-try-return.rs:19:9 + | +LL | infallible()?; + | ^^^^^^^^^^^^^ cannot infer type of error for `?` operator + | + = note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From<Infallible>` +help: give this closure an explicit return type without `_` placeholders + | +LL | let x = || -> std::result::Result<(), QualifiedError<_>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. |
