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

Inconsistent lifetime inference when using impl Trait reference in function return position #116639

Closed
jflatow opened this issue Oct 11, 2023 · 2 comments
Labels
C-bug Category: This is a bug. F-return_position_impl_trait_in_trait `#![feature(return_position_impl_trait_in_trait)]`

Comments

@jflatow
Copy link

jflatow commented Oct 11, 2023

Given that this is using an unstable feature, I'm not sure if a bug report is appropriate, but I thought it might be useful information for those working on #99697.

I tried this code:

#![feature(return_position_impl_trait_in_trait)]

pub trait A<'a, Q: P<'a>>: Sized {
    fn m(&self) -> Option<&'a impl M<'a, Q, Self>>; // impl ref fails, generic succeeds
}

pub enum E<'a, Q: P<'a>, N: M<'a, Q, Self>> {
    O(&'a N, Q),
}

impl<'a, Q: P<'a>, N: M<'a, Q, Self>> A<'a, Q> for E<'a, Q, N> {
    fn m(&self) -> Option<&'a impl M<'a, Q, Self>> {
        match self {
            Self::O(n, _) => Some(*n),
        }
    }
}

pub trait M<'a, Q: P<'a>, B: A<'a, Q>>: Sized {}

pub trait S<'a>: Sized {
    type A;

    fn s<'b>(&'a self, u: &'b Self::A) where 'a: 'b;
}

pub trait P<'a>: Sized + 'a {
    type M: M<'a, Self, <Self as S<'a>>::A>;
}

impl<'a, T: P<'a>> S<'a> for T {
    type A = E<'a, Self, T::M>;

    fn s<'b>(&'a self, u: &'b Self::A) where 'a: 'b {
        u.m();
    }
}

I expected this to compile. If I add a generic N: M<...> above and return a reference to it instead in the trait, it does work.

Instead when using the &'a impl M<...>, the compiler insists that 'b needs to live longer than 'a, which I think is an overly restrictive inference that prevents efficient memory management as it cannot be bypassed.

Meta

rustc +nightly --version --verbose:

rustc 1.75.0-nightly (187b8131d 2023-10-03)
binary: rustc
commit-hash: 187b8131d4f760f856b214fce34534903276f2ef
commit-date: 2023-10-03
host: x86_64-apple-darwin
release: 1.75.0-nightly
LLVM version: 17.0.2
Backtrace

error: lifetime may not live long enough
  --> lifetime.rs:35:9
   |
31 | impl<'a, T: P<'a>> S<'a> for T {
   |      -- lifetime `'a` defined here
...
34 |     fn s<'b>(&'a self, u: &'b Self::A) where 'a: 'b {
   |          -- lifetime `'b` defined here
35 |         u.m();
   |         ^^^^^ argument requires that `'b` must outlive `'a`
   |
   = help: consider adding the following bound: `'b: 'a`

error: aborting due to previous error

@jflatow jflatow added the C-bug Category: This is a bug. label Oct 11, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Oct 11, 2023
@compiler-errors
Copy link
Member

compiler-errors commented Oct 12, 2023

This is consistent with the capture rules for RPITITs. The problem here is that the signature for:

fn m(&self) -> Option<&'a impl M<'a, Q, Self>> {

requires that 'a outlives all of the lifetimes captured by the impl M<...>, including the elided lifetime for &self.

This can be fixed by adding an explicit outlives bound on the impl M<...>, like impl M<...> + 'a:

fn m(&self) -> Option<&'a (impl M<'a, Q, Self> + 'a)> {

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e1fceffe62d5a0fb4666389a84edda94

@compiler-errors compiler-errors added F-return_position_impl_trait_in_trait `#![feature(return_position_impl_trait_in_trait)]` and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Oct 12, 2023
@jflatow
Copy link
Author

jflatow commented Oct 12, 2023

Thanks that is tricky and great to know!

@jflatow jflatow closed this as completed Oct 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. F-return_position_impl_trait_in_trait `#![feature(return_position_impl_trait_in_trait)]`
Projects
None yet
Development

No branches or pull requests

3 participants