tracing/tracing-attributes/tests/ui/async_instrument.rs
Michael Goulet 39a2068a45
attributes: add fake return to improve span on type error (#2270)
## Motivation

Return type errors on instrumented async functions are a bit vague,
since the type error originates within the macro itself due to the
indirection of additional `async {}` blocks generated in the proc-macro
(and due to the way that inference propagates around in Rust). 

This leads to a pretty difficult to understand error. For example:

```rust
#[instrument]
async fn foo() -> String {
  ""
}
```

results in...

```
error[E0308]: mismatched types
 --> src/main.rs:1:1
  |
1 | #[tracing::instrument]
  | ^^^^^^^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
  | |
  | expected struct `String`, found `&str`
```

## Solution

Installs a fake `return` statement as the first thing that happens in
the auto-generated block of an instrumented async function. 

This causes the coercion machinery within rustc to infer the right
return type (matching the the outer function) eagerly, as opposed to
after the `async {}` block has been type-checked. 

This will cause us to both be able to point out the return type span
correctly, and properly suggest fixes on the expressions that cause the
type mismatch. 

After this change, the example code above compiles to:

```
error[E0308]: mismatched types
  --> src/main.rs:3:5
   |
3  |     ""
   |     ^^- help: try using a conversion method: `.to_string()`
   |     |
   |     expected struct `String`, found `&str`
   |
note: return type inferred to be `String` here
  --> src/main.rs:2:20
   |
2  | async fn foo() -> String {
   |                   ^^^^^^
```
2022-08-19 16:00:56 -07:00

46 lines
709 B
Rust

#![allow(unreachable_code)]
#[tracing::instrument]
async fn unit() {
""
}
#[tracing::instrument]
async fn simple_mismatch() -> String {
""
}
// FIXME: this span is still pretty poor
#[tracing::instrument]
async fn opaque_unsatisfied() -> impl std::fmt::Display {
("",)
}
struct Wrapper<T>(T);
#[tracing::instrument]
async fn mismatch_with_opaque() -> Wrapper<impl std::fmt::Display> {
""
}
#[tracing::instrument]
async fn early_return_unit() {
if true {
return "";
}
}
#[tracing::instrument]
async fn early_return() -> String {
if true {
return "";
}
String::new()
}
#[tracing::instrument]
async fn extra_semicolon() -> i32 {
1;
}
fn main() {}