Skip to content

GAT: Fails to compile with additional bounds #139207

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

Open
Ddystopia opened this issue Apr 1, 2025 · 9 comments
Open

GAT: Fails to compile with additional bounds #139207

Ddystopia opened this issue Apr 1, 2025 · 9 comments
Labels
A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system A-type-system Area: Type system C-bug Category: This is a bug. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@Ddystopia
Copy link
Contributor

Ddystopia commented Apr 1, 2025

I tried this code:

trait Gat {
    type Assoc<'a>;
}

struct Foo<S>(S);

impl<S> Foo<S> {
    fn bar<'a, C, T>(&self)
    where
        C: Gat<Assoc<'a> = T>,
        C: Gat<Assoc<'static> = S>, // By commenting out this bound code will compile
    {
        self.foo::<C, T>(); // or comment out this line, it will compile too
    }

    fn foo<'a, C, T>(&self)
    where
        C: Gat<Assoc<'a> = T>,
        // To be closer to original code `C: Gat<Assoc<'static> = S>` may be included, but error is the same anyway
    {
    }
}

I expected to see this happen: Code should compile

Instead, this happened: Code did not compile. Probably because 'a is different in both cases, I but cannot specify lifetime arguments explicitly if late bound lifetime parameters are present #42868 .

 1  error[E0284]: type annotations needed: cannot satisfy `<C as Gat>::Assoc<'_> == T`
   --> src/main.rs:13:14
    |
 13 |         self.foo::<C, T>();
    |              ^^^ cannot satisfy `<C as Gat>::Assoc<'_> == T`
    |
 note: required by a bound in `Foo::<S>::foo`
   --> src/main.rs:18:16
    |
 16 |     fn foo<'a, C, T>(&self)
    |        --- required by a bound in this associated function
 17 |     where
 18 |         C: Gat<Assoc<'a> = T>,
    |                ^^^^^^^^^^^^^ required by this bound in `Foo::<S>::foo`

Meta

rustc --version --verbose:

rustc 1.87.0-nightly (b48576b4d 2025-03-22)
binary: rustc
commit-hash: b48576b4db5a595f453891f0b7243ef75d8c0afa
commit-date: 2025-03-22
host: x86_64-unknown-linux-gnu
release: 1.87.0-nightly
LLVM version: 20.1.1
@Ddystopia Ddystopia added the C-bug Category: This is a bug. label Apr 1, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 1, 2025
@fmease fmease added C-discussion Category: Discussion or questions that doesn't represent real issues. A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system and removed C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 1, 2025
@fmease

This comment has been minimized.

@fmease
Copy link
Member

fmease commented Apr 1, 2025

The error message could be better tho.

@fmease fmease added the A-type-system Area: Type system label Apr 1, 2025
@Ddystopia
Copy link
Contributor Author

Are you sure? If remove the call to foo, code compiles too. It is already usable and works. The only limitation is that I cannot call those functions inside other functions like that, forcing me to have code duplication or unsafe common function without type system's protection.

@fmease
Copy link
Member

fmease commented Apr 1, 2025

Oof, I should've looked more closely, my bad. Right, it's not impossible to call Foo::bar.

@fmease
Copy link
Member

fmease commented Apr 1, 2025

I mean I guess what I wrote previously about lifetimes is still the root cause ultimately.

Given only C: Gat<Assoc<'a> = T> in bar's environment, you can trivially prove C: Gat<Assoc<'a> = T> as required by foo.

However, once you have given C: Gat<Assoc<'a> = T> and C: Gat<Assoc<'static> = S> and want to prove C: Gat<Assoc<'a> = T> or more precisely <C as Gat>::Assoc<'a> == T you fail because <C as Gat>::Assoc<'a> no longer normalizes to T via the environment (since it could also normalize to S since we're still dealing modulo (same-rank) lifetimes). It's considered ambiguous (T and S are rigid here and thus not equal).

@fmease
Copy link
Member

fmease commented Apr 1, 2025

I might be mistaken I don't think this is fixable in Rust's current type system.

Edit: But let's see what others have to say. I remember there already being ago-old GH issues about this.

@fmease
Copy link
Member

fmease commented Apr 1, 2025

#21974 comes to mind

@Ddystopia
Copy link
Contributor Author

I think, no matter what, this should probably not be triaged as a discussion, because something is wrong there.

@Ddystopia
Copy link
Contributor Author

By the way, my use case is to have an allocator for a single type inside the static memory (like StaticCell), but without the limitation for 'static. So the allocator has MaybeUniniy<Foo<'static>> inside but returns Box<Foo<'a>, _>, backed by bytes from that MaybeUninit. There is no specialization on lifetimes etc, it is just a way to enforce that static and non-static versions are the same (there are real asserts too, but type system errors are better for the user). And the trait is from hkt crate.

@fmease fmease added C-bug Category: This is a bug. T-types Relevant to the types team, which will review and decide on the PR/issue. and removed C-discussion Category: Discussion or questions that doesn't represent real issues. labels Apr 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system A-type-system Area: Type system C-bug Category: This is a bug. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants