Skip to content

GAT: Fails to compile with additional bounds #139207

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # 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
# for free to join this conversation on GitHub. Already have an account? # 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