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

Add fake return to improve span on type error in tracing::instrument #2270

Merged
merged 8 commits into from Aug 19, 2022

Conversation

compiler-errors
Copy link
Contributor

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:

#[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 {
   |                   ^^^^^^

@compiler-errors
Copy link
Contributor Author

compiler-errors commented Aug 8, 2022

Note:

Is it possible to provide a UI test (like https://github.com/dtolnay/trybuild) for tracing macros? Otherwise, any recommendations on how to provide a test for this change, since all affected code is not expected to compile (and thus probably doesn't work with a traditional unit test)?

@hawkw
Copy link
Member

hawkw commented Aug 8, 2022

Note:

Is it possible to provide a UI test (like https://github.com/dtolnay/trybuild) for tracing macros? Otherwise, any recommendations on how to provide a test for this change, since all affected code is not expected to compile (and thus probably doesn't work with a traditional unit test)?

it's fine to introduce a dev dependency on trybuild for testing this.

@compiler-errors
Copy link
Contributor Author

it's fine to introduce a dev dependency on trybuild for testing this.

@davidbarsky just told me to do the same -- will do!

@compiler-errors compiler-errors force-pushed the return-span branch 2 times, most recently from cd2f3a1 to b4dcdcb Compare August 8, 2022 22:42
@compiler-errors
Copy link
Contributor Author

Okay, think this is ready for review. Sorry for the force-pushes, wanted to make sure the history was clean.

tracing-attributes/tests/ui.rs Outdated Show resolved Hide resolved
tracing-attributes/src/expand.rs Outdated Show resolved Hide resolved
tracing-attributes/src/expand.rs Outdated Show resolved Hide resolved
tracing-attributes/src/expand.rs Outdated Show resolved Hide resolved
@hawkw
Copy link
Member

hawkw commented Aug 8, 2022

(as a side note, you don't need to force push to branches, as all pull requests will be merged by squashing. see https://github.com/tokio-rs/tracing/blob/master/CONTRIBUTING.md#commit-squashing for details.)

@compiler-errors
Copy link
Contributor Author

Good to know. Guess I really should've read the contributing guide first, my bad.

@compiler-errors
Copy link
Contributor Author

(sorry, that force push is because I am dumb and don't know how to use git)

@hawkw
Copy link
Member

hawkw commented Aug 8, 2022

no worries, it's nto a big deal!

@davidbarsky
Copy link
Member

mercurial + the diff tool encourages the equivalent of force pushes, but github punishes you for it, so no worries.

@compiler-errors
Copy link
Contributor Author

also used to force-pushing when working on rustc because bors doesn't auto-squash 😸

@hawkw
Copy link
Member

hawkw commented Aug 15, 2022

CI failure is a new clippy warning, unrelated to this change: https://github.com/tokio-rs/tracing/runs/7842367961?check_suite_focus=true I'll fix that on main.

@hawkw hawkw enabled auto-merge (squash) August 19, 2022 23:00
@hawkw hawkw merged commit 39a2068 into tokio-rs:master Aug 19, 2022
davidbarsky pushed a commit that referenced this pull request Sep 8, 2022
## 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 {
   |                   ^^^^^^
```
hawkw pushed a commit that referenced this pull request Sep 19, 2022
## 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 {
   |                   ^^^^^^
```
hawkw pushed a commit that referenced this pull request Sep 19, 2022
## 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 {
   |                   ^^^^^^
```
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.23 (October 6, 2022)

This release of `tracing-attributes` fixes a bug where compiler
diagnostic spans for type errorsin `#[instrument]`ed `async fn`s have
the location of the `#[instrument]` attribute rather than the location
of the actual error, and a bug where inner attributes in
`#[instrument]`ed functions would cause a compiler error.
### Fixed

- Fix incorrect handling of inner attributes in `#[instrument]`ed
  functions ([#2307])
- Add fake return to improve spans generated for type errors in `async
  fn`s ([#2270])
- Updated `syn` dependency to fix compilation with `-Z minimal-versions`
  ([#2246])

Thanks to new contributors @compiler-errors and @e-nomem, as well as
@CAD97, for contributing to this release!

[#2307]: #2307
[#2270]: #2270
[#2246]: #2246
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.23 (October 6, 2022)

This release of `tracing-attributes` fixes a bug where compiler
diagnostic spans for type errors in `#[instrument]`ed `async fn`s have
the location of the `#[instrument]` attribute rather than the location
of the actual error, and a bug where inner attributes in
`#[instrument]`ed functions would cause a compiler error.

### Fixed

- Fix incorrect handling of inner attributes in `#[instrument]`ed
  functions ([#2307])
- Add fake return to improve spans generated for type errors in `async
  fn`s ([#2270])
- Updated `syn` dependency to fix compilation with `-Z minimal-versions`
  ([#2246])

Thanks to new contributors @compiler-errors and @e-nomem, as well as
@CAD97, for contributing to this release!

[#2307]: #2307
[#2270]: #2270
[#2246]: #2246
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.37 (October 6, 2022)

This release of `tracing` incorporates changes from `tracing-core`
[v0.1.30][core-0.1.30] and `tracing-attributes` [v0.1.23][0.1.23],
including the new `Subscriber::on_register_dispatch` method for
performing late initialization after a `Subscriber` is registered as a
`Dispatch`, and bugfixes for the `#[instrument]` attribute.
Additionally, it fixes instances of the `bare_trait_objects` lint, which
is now a warning on `tracing`'s MSRV and will become an error in the
next edition.

### Fixed

- **attributes**: Incorrect handling of inner attributes in
  `#[instrument]`ed functions (#2307)
- **attributes**: Incorrect location of compiler diagnostic spans
  generated for type errors in `#[instrument]`ed `async fn`s (#2270)
- **attributes**: Updated `syn` dependency to fix compilation with `-Z
  minimal-versions` (#2246)
- `bare_trait_objects` warning in `valueset!` macro expansion (#2308)

### Added

- **core**: `Subscriber::on_register_dispatch` method (#2269)
- **core**: `WeakDispatch` type and `Dispatch::downgrade()` function
  (#2293)

### Changed

- `tracing-core`: updated to [0.1.30][core-0.1.30]
- `tracing-attributes`: updated to [0.1.23][attrs-0.1.23]

### Documented

- Added [`tracing-web`] and [`reqwest-tracing`] to related crates
  (#2283], [#2331)

Thanks to new contributors @compiler-errors, @e-nomem, @WorldSEnder,
@Xiami2012, and @tl-rodrigo-gryzinski, as well as @jswrenn and @CAD97,
for contributing to this release!

[core-0.1.30]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.30
[attrs-0.1.23]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.23
[`tracing-web`]: https://crates.io/crates/tracing-web/
[`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing/
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.37 (October 6, 2022)

This release of `tracing` incorporates changes from `tracing-core`
[v0.1.30][core-0.1.30] and `tracing-attributes` [v0.1.23][attrs-0.1.23],
including the new `Subscriber::on_register_dispatch` method for
performing late initialization after a `Subscriber` is registered as a
`Dispatch`, and bugfixes for the `#[instrument]` attribute.
Additionally, it fixes instances of the `bare_trait_objects` lint, which
is now a warning on `tracing`'s MSRV and will become an error in the
next edition.

### Fixed

- **attributes**: Incorrect handling of inner attributes in
  `#[instrument]`ed functions (#2307)
- **attributes**: Incorrect location of compiler diagnostic spans
  generated for type errors in `#[instrument]`ed `async fn`s (#2270)
- **attributes**: Updated `syn` dependency to fix compilation with `-Z
  minimal-versions` (#2246)
- `bare_trait_objects` warning in `valueset!` macro expansion (#2308)

### Added

- **core**: `Subscriber::on_register_dispatch` method (#2269)
- **core**: `WeakDispatch` type and `Dispatch::downgrade()` function
  (#2293)

### Changed

- `tracing-core`: updated to [0.1.30][core-0.1.30]
- `tracing-attributes`: updated to [0.1.23][attrs-0.1.23]

### Documented

- Added [`tracing-web`] and [`reqwest-tracing`] to related crates
  (#2283, #2331)

Thanks to new contributors @compiler-errors, @e-nomem, @WorldSEnder,
@Xiami2012, and @tl-rodrigo-gryzinski, as well as @jswrenn and @CAD97,
for contributing to this release!

[core-0.1.30]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.30
[attrs-0.1.23]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.23
[`tracing-web`]: https://crates.io/crates/tracing-web/
[`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing/
@SanchithHegde
Copy link

Would it be too much to ask for an #[allow(clippy::unreachable)] to be added on line 67? (I can open a PR if necessary, or if anyone can directly make that change on master branch, that should be fine too.)

let fake_return_edge = quote_spanned! {return_span=>
#[allow(unreachable_code, clippy::diverging_sub_expression, clippy::let_unit_value)]
if false {
let __tracing_attr_fake_return: #return_type =
unreachable!("this is just for type inference, and is unreachable code");
return __tracing_attr_fake_return;
}
};

We use #![warn(clippy::unreachable)] across our codebase and we now receive a load of clippy warnings about this unreachable! call after the tracing upgrade.

@compiler-errors
Copy link
Contributor Author

compiler-errors commented Oct 18, 2022

I think opening a PR for this would be fine. Alternatively, one could do the same thing as #[async_trait] and use an alternative desugaring to provide the same return type hint: https://github.com/dtolnay/async-trait/blob/master/src/expand.rs#L374

Though please be careful that it handles return-position impl Trait correctly, since async_trait doesn't need to handle that, but this definitely does.

Abhicodes-crypto added a commit to Abhicodes-crypto/tracing that referenced this pull request Oct 25, 2022
hawkw pushed a commit that referenced this pull request Nov 4, 2022
## Motivation

PR #2270 added an unreachable branch with an explicit return value to
`#[instrument]` in `async fn`s in order to fix type inference issues.
That PR added the appropriate `#[allow]` attribute for the Rust
compiler's unreachable code linting, but not Clippy's, so a Clippy
warning is still emitted. See:
#2270 (comment)

## Solution

Adding the clippy lint warning as discussed here:
#2270 (comment)
liuhaozhan added a commit to liuhaozhan/tracing that referenced this pull request Nov 17, 2022
## Motivation

PR #2270 added an unreachable branch with an explicit return value to
`#[instrument]` in `async fn`s in order to fix type inference issues.
That PR added the appropriate `#[allow]` attribute for the Rust
compiler's unreachable code linting, but not Clippy's, so a Clippy
warning is still emitted. See:
tokio-rs/tracing#2270 (comment)

## Solution

Adding the clippy lint warning as discussed here:
tokio-rs/tracing#2270 (comment)
str4d added a commit to str4d/tracing that referenced this pull request Jan 9, 2023
The fake return edge was added in tokio-rs#2270 to improve type
errors in instrumented async functions. However, it meant that the user
block was being modified outside of `gen_block`. This created a negative
interaction with tokio-rs#1614, which suppressed a clippy lint
internally while explicitly enabling it on the user block. The installed
fake return edge generated this same lint, but the user had no way to
suppress it: lint directives above the instrumentation were ignored
because of the internal suppression, and lints inside the user block
could not influence the fake return edge's scope.

We now avoid modifying the user block outside of `gen_block`, and
restrict the fake return edge to async functions. We also apply the same
clippy lint suppression technique to the installed fake return edge.

Closes tokio-rs#2410.
hawkw pushed a commit that referenced this pull request Apr 21, 2023
## Motivation

PR #2270 added an unreachable branch with an explicit return value to
`#[instrument]` in `async fn`s in order to fix type inference issues.
That PR added the appropriate `#[allow]` attribute for the Rust
compiler's unreachable code linting, but not Clippy's, so a Clippy
warning is still emitted. See:
#2270 (comment)

## Solution

Adding the clippy lint warning as discussed here:
#2270 (comment)
hawkw pushed a commit that referenced this pull request Apr 21, 2023
## Motivation

PR #2270 added an unreachable branch with an explicit return value to
`#[instrument]` in `async fn`s in order to fix type inference issues.
That PR added the appropriate `#[allow]` attribute for the Rust
compiler's unreachable code linting, but not Clippy's, so a Clippy
warning is still emitted. See:
#2270 (comment)

## Solution

Adding the clippy lint warning as discussed here:
#2270 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants