"Impl not general enough" error for using an associated type with drop glue over an await point
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
trait Trait<'cx>: Sized {
type State: Default;
}
struct Problem<'cx, T: Trait<'cx>> {
state: T::State,
cx: &'cx (),
}
impl<'cx, T: Trait<'cx>> Problem<'cx, T> {
fn new() -> Self {
Self {
state: Default::default(),
cx: &(),
}
}
}
struct Impler<'cx>(&'cx ());
impl<'cx> Trait<'cx> for Impler<'cx> {
type State = String;
}
fn problem<'cx>() -> impl Future<Output = ()> + Send {
async move {
let _problem: Problem<'cx, Impler<'cx>> = Problem::new();
async {}.await;
}
}
I expected to see this happen: successful compilation
Instead, this happened: compilation error
error: implementation of `Trait` is not general enough
--> src/lib.rs:26:5
|
26 | / async move {
27 | | let _problem: Problem<'cx, Impler<'cx>> = Problem::new();
28 | | async {}.await;
29 | | }
| |_____^ implementation of `Trait` is not general enough
|
= note: `Trait<'1>` would have to be implemented for the type `Impler<'0>`, for any two lifetimes `'0` and `'1`...
= note: ...but `Trait<'2>` is actually implemented for the type `Impler<'2>`, for some specific lifetime `'2`
error: could not compile `tmp` (lib) due to 1 previous error
With -Znext-solver the error is:
error[E0277]: `{coroutine witness@src/lib.rs:26:5: 26:15}` cannot be sent between threads safely
--> src/lib.rs:25:1
|
25 | fn problem<'cx>() -> impl Future<Output = ()> + Send {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `{coroutine witness@src/lib.rs:26:5: 26:15}` cannot be sent between threads safely
26 | async move {
| ---------- within this `{async block@src/lib.rs:26:5: 26:15}`
|
= help: within `{async block@src/lib.rs:26:5: 26:15}`, the trait `Send` is not implemented for `{coroutine witness@src/lib.rs:26:5: 26:15}`
note: required because it's used within this `async` block
--> src/lib.rs:26:5
|
26 | async move {
| ^^^^^^^^^^
error[E0277]: `{coroutine witness@src/lib.rs:26:5: 26:15}` cannot be sent between threads safely
--> src/lib.rs:26:5
|
26 | async move {
| ^---------
| |
| _____within this `{async block@src/lib.rs:26:5: 26:15}`
| |
27 | | let _problem: Problem<'cx, Impler<'cx>> = Problem::new();
28 | | async {}.await;
29 | | }
| |_____^ `{coroutine witness@src/lib.rs:26:5: 26:15}` cannot be sent between threads safely
|
= help: within `{async block@src/lib.rs:26:5: 26:15}`, the trait `Send` is not implemented for `{coroutine witness@src/lib.rs:26:5: 26:15}`
note: required because it's used within this `async` block
--> src/lib.rs:26:5
|
26 | async move {
| ^^^^^^^^^^
error[E0277]: `{coroutine witness@src/lib.rs:26:5: 26:15}` cannot be sent between threads safely
--> src/lib.rs:25:54
|
25 | fn problem<'cx>() -> impl Future<Output = ()> + Send {
| ______________________________________________________^
26 | | async move {
| | ---------- within this `{async block@src/lib.rs:26:5: 26:15}`
27 | | let _problem: Problem<'cx, Impler<'cx>> = Problem::new();
28 | | async {}.await;
29 | | }
30 | | }
| |_^ `{coroutine witness@src/lib.rs:26:5: 26:15}` cannot be sent between threads safely
|
= help: within `{async block@src/lib.rs:26:5: 26:15}`, the trait `Send` is not implemented for `{coroutine witness@src/lib.rs:26:5: 26:15}`
note: required because it's used within this `async` block
--> src/lib.rs:26:5
|
26 | async move {
| ^^^^^^^^^^
For more information about this error, try `rustc --explain E0277`.
error: could not compile `tmp` (lib) due to 3 previous errors
There are five simple modifications to the code that make it compile (also on `-Znext-solver):
- remove the
Sendbound on the output future offn problem() - replace the
StateofImplerwith a type that doesn't need drop glue - move the await point above the creation of
Problem - remove the lifetime of
Trait - remove the lifetime of
Impler
Another modification that makes it compile is to split Trait into a supertrait without a lifetime:
trait Super {
type State: Default;
}
trait Trait<'cx>: Super + Sized {}
This fix is what I ended up using in my codebase. It also made me think that this might be a compiler bug.
Meta
rustc --version --verbose:
rustc 1.95.0-nightly (842bd5be2 2026-01-29)
binary: rustc
commit-hash: 842bd5be253e17831e318fdbd9d01d716557cc75
commit-date: 2026-01-29
host: x86_64-unknown-linux-gnu
release: 1.95.0-nightly
LLVM version: 22.1.0
(feel free to improve the title)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the supplied src/lib.rs reproducer and run it on the reported nightly, both with and without -Znext-solver. Compare the diagnostics across the listed code modifications, then trace the compiler behavior responsible for the await-point, associated-type, and lifetime interaction. Done means the original example compiles as expected without requiring one of the workarounds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100