GAT implementation requires bounds inconsistently
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
See #150418 for a version of this issue using RPITIT instead of GATs.
pub trait Exists<T: ?Sized> {}
impl<T: ?Sized, U: ?Sized> Exists<T> for U {}
pub trait NotAnRpitit<Arg> {
type Assoc;
type Gat<'a>: Exists<&'a Self::Assoc>
where
Self::Assoc: 'a;
fn method<'a>(&'a self) -> Self::Gat<'a>;
// (Disables issue 87479 *requirement* to have `Self: 'a` on Gat.)
fn _shush(_: Self::Gat<'_>) {}
}
impl<Arg> NotAnRpitit<Arg> for Option<Arg> {
type Assoc = Option<Arg>;
type Gat<'a> = [&'a Self::Assoc; 0]
where
Self::Assoc: 'a;
fn method<'a>(&'a self) -> Self::Gat<'a>
{
[]
}
}
I expected to see this happen: compiles, or is at least consistent with the first diff below.
Instead, this happened:
error[E0276]: impl has stricter requirements than trait
--> src/lib.rs:24:22
|
6 | type Gat<'a>: Exists<&'a Self::Assoc>
| ------------------------------------- definition of `Gat` from trait
...
24 | Self::Assoc: 'a,
| ^^ impl has extra requirement `Arg: 'a`
error[E0309]: the parameter type `Arg` may not live long enough
--> src/lib.rs:22:5
|
22 | type Gat<'a> = [&'a Self::Assoc; 0]
| ^^^^^^^^^--^
| | |
| | the parameter type `Arg` must be valid for the lifetime `'a` as defined here...
| ...so that the reference type `&'a Option<Arg>` does not outlive the data it points at
|
help: consider adding an explicit lifetime bound
|
24 | Self::Assoc: 'a, Arg: 'a
| +++++++
The error seems bad and inconsistent for a couple reasons.
- The bounds on the implementation match the trait definition. Ideally it should not be possible for that to fail.
- The following changes do compile.
impl<Arg> NotAnRpitit<Arg> for Option<Arg> {
- type Assoc = Option<Arg>;
+ type Assoc = Arg;
type Gat<'a> = [&'a Self::Assoc; 0]
where
Self::Assoc: 'a;
fn method<'a>(&'a self) -> Self::Gat<'a>
{
[]
}
}
pub trait NotAnRpitit<Arg> {
type Assoc;
type Gat<'a>: Exists<&'a Self::Assoc>
where
+ Self: 'a,
Self::Assoc: 'a;
fn method<'a>(&'a self) -> Self::Gat<'a>;
// (Disables issue 87479 *requirement* to have `Self: 'a` on Gat.)
fn _shush(_: Self::Gat<'_>) {}
}
impl<Arg> NotAnRpitit<Arg> for Option<Arg> {
type Gat<'a> = [&'a Self::Assoc; 0]
where
+ Self: 'a,
Self::Assoc: 'a;
The next solver has the same behavior.
I've wrestled with GATs enough that the second diff working doesn't surprise me (and the current #87479 requirements mean it's less likely for this issue to be encountered in practice). But I have no clue why type = Arg compiles while type = Option<Arg> does not.
Meta
Playground:
- Stable channel: 1.92.0
- Beta channel: 1.93.0-beta.4 (2025-12-18 e17ea4bf4e2f2094ad56)
- Nightly channel: 1.94.0-nightly (2025-12-25 fabece9e9491d0a3c365)
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
Reproduce the example in src/lib.rs using the linked Rust Playground, then compare the reported behavior with the two compiling variants and the next-solver result. Read the related discussions in #150418 and #87479. Done means the inconsistent bound behavior is explained and the compiler diagnostics or implementation are corrected accordingly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100