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

GAT: lifetime mismatch when requiring lifetime bounds despite type not using the lifetimes at all #87748

Closed
athre0z opened this issue Aug 4, 2021 · 7 comments · Fixed by #88312 or #99217
Labels
A-GATs Area: Generic associated types (GATs) C-bug Category: This is a bug. F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs GATs-triaged Issues using the `generic_associated_types` feature that have been triaged S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test.

Comments

@athre0z
Copy link
Contributor

athre0z commented Aug 4, 2021

Compiling this code:

#![feature(generic_associated_types)]

trait MyTrait {
    type Assoc<'a, 'b> where 'b: 'a;
    fn do_sth(arg: Self::Assoc<'_, '_>);
}

struct Foo;

impl MyTrait for Foo {
    type Assoc<'a, 'b> where 'b: 'a = u32;
    
    fn do_sth(_: u32) {}
    // fn do_sth(_: Self::Assoc<'static, 'static>) {}
    // fn do_sth(_: Self::Assoc<'_, '_>) {}
}

I'd expect all of these three versions to compile. The associated type has two lifetimes as well as a lifetime bound 'b: 'a, but u32 doesn't use the lifetime. However, I'm getting a compiler error:

error[E0478]: lifetime bound not satisfied
  --> src/lib.rs:13:5
   |
13 |     fn do_sth(_: u32) {}
   |     ^^^^^^^^^^^^^^^^^
   |
note: lifetime parameter instantiated with the anonymous lifetime #2 defined on the method body at 13:5
  --> src/lib.rs:13:5
   |
13 |     fn do_sth(_: u32) {}
   |     ^^^^^^^^^^^^^^^^^
note: but lifetime parameter must outlive the anonymous lifetime #1 defined on the method body at 13:5
  --> src/lib.rs:13:5
   |
13 |     fn do_sth(_: u32) {}
   |     ^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0478`.
error: could not compile `playground` due to previous error

Without the where 'b: 'a, all three compile fine.

Playground Link

@athre0z athre0z added the C-bug Category: This is a bug. label Aug 4, 2021
@jonas-schievink jonas-schievink added the F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs label Aug 4, 2021
@jackh726
Copy link
Member

So, I think this is mostly just "intended"; the 'b: 'a bound is required to hold regardless of it's used.

That said, I would expect Self::Assoc<'static, 'static> to work. Looking into it.

@jackh726
Copy link
Member

Err, no Self::Assoc<'static, 'static> shouldn't work...because that is "stricter" than the trait.

@athre0z
Copy link
Contributor Author

athre0z commented Aug 24, 2021

Hmm, by "stricter" do you mean "more specific"? As in: because Self::Assoc<'static, 'static> is more specific than Self::Assoc<'_, '_>, it shouldn't work? I'd argue that this is "stricter" regardless of the presence of the where 'b: 'a and without the where constraint, it compiles fine.

Edit: Thinking about it for a bit more, I think I get what you mean. The function should need to be generic over the lifetime as well. I guess the true bug would then be that it does compile without the where?

Edit 2: Thinking about it for even longer, it does seem fine for it to compile, since the Self::Assoc<'static, 'static>, while stricter than the original trait bound, is not stricter than the concrete type. In non-GAT traits, I can also use the "stricter"/more specific u32 directly and have it work fine:

trait MyTrait {
    type Assoc;
    fn do_sth(arg: Self::Assoc);
}

struct Foo;

impl MyTrait for Foo {
    type Assoc = u32;
    
    fn do_sth(_: u32) {}
}

I guess there isn't any precedent yet for "slightly more specific", since without GAT, you either pass the assoc type or the concrete one, nothing in between.

@jackh726
Copy link
Member

Okay, so I've convinced myself that example 3 should work based on implied bounds. This is just a bug.

Example 1 is a little weird. When we check the trait fn, we can use implied bounds to prove that 'b: 'a. We can't actually normalize Assoc because Self isn't know. But, when we try to check that the impl fn matches the trait, we then use Foo as Self, and we can normalize Self::Assoc<'_, '_>, but we haven't generated the implied bounds needed to satisfy 'b: 'a because the current function doesn't use the projection as an input type. We should probably be using the implied bounds of the trait fn when normalizing the trait fn input types. This is also, now that I think about, likely a bug too.

Example 2 (Self::Assoc<'static, 'static>) is indeed not supposed to be able to compile. Imagine we had type Baz = impl MyTrait with the defining use being Foo. We could then pass any lifetimes 'a and 'b, as long as 'b: 'a to do_sth. Well, the impl on Foo expects that those are both 'static, Normally, this is a problem because we could extend the the lifetime of the input types, but can't actually because the type is u32. Hmm. It's a bit dubious though; I would expect that we shouldn't want to look at the actual type of the associated type when doing WF checks on the fn sig. While we theoretically could, I don't think we want to change this.

@jackh726
Copy link
Member

Okay I have a fix and the Self:Assoc<'static, 'static> example fell out naturally. Will make a PR shortly.

@athre0z
Copy link
Contributor Author

athre0z commented Aug 26, 2021

That's great to hear! Thanks for your effort with this! :-)

Manishearth added a commit to Manishearth/rust that referenced this issue Aug 27, 2021
Treat types in unnormalized function signatures as well-formed

Fixes rust-lang#87748

r? `@nikomatsakis`
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Aug 27, 2021
Treat types in unnormalized function signatures as well-formed

Fixes rust-lang#87748

r? ``@nikomatsakis``
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Aug 27, 2021
Treat types in unnormalized function signatures as well-formed

Fixes rust-lang#87748

r? ```@nikomatsakis```
@bors bors closed this as completed in 59ce765 Aug 29, 2021
@jackh726 jackh726 reopened this Nov 30, 2021
@jackh726
Copy link
Member

jackh726 commented Feb 7, 2022

GATs issue triage: not blocking. The implied bounds story here is not great. But the simple attempt to fix thing opened up soundness holes. It's also not backwards-incompatible to fix.

@jackh726 jackh726 added the GATs-triaged Issues using the `generic_associated_types` feature that have been triaged label Feb 7, 2022
@jackh726 jackh726 added the S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test. label Mar 12, 2022
@bors bors closed this as completed in 63e4312 Aug 9, 2022
@fmease fmease added the A-GATs Area: Generic associated types (GATs) label Nov 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-GATs Area: Generic associated types (GATs) C-bug Category: This is a bug. F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs GATs-triaged Issues using the `generic_associated_types` feature that have been triaged S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test.
Projects
None yet
4 participants