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

Cannot coerce dyn Trait<'short> + 'long to dyn Trait<'long> + 'long #139457

Open
Jules-Bertholet opened this issue Apr 6, 2025 · 3 comments
Open
Labels
A-lifetimes Area: Lifetimes / regions A-trait-objects Area: trait objects, vtable layout C-discussion Category: Discussion or questions that doesn't represent real issues. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@Jules-Bertholet
Copy link
Contributor

I tried this code:

trait Trait<'a> {}

fn convert<'short, 'long: 'short>(
    obj: Box<dyn Trait<'short> + 'long>,
) -> Box<dyn Trait<'long> + 'long> {
    obj
}

I expected to see this happen: It compiles. The concrete type of the dyn Trait<'short> + 'long cannot mention 'short (as it lives for all of 'long), so it must implement Trait<'long> also.

Instead, this happened:

error: lifetime may not live long enough
 --> src/lib.rs:6:5
  |
3 | fn convert<'short, 'long: 'short>(
  |            ------  ----- lifetime `'long` defined here
  |            |
  |            lifetime `'short` defined here
...
6 |     obj
  |     ^^^ function was supposed to return data with lifetime `'long` but it is returning data with lifetime `'short`
  |
  = help: consider adding the following bound: `'short: 'long`

Meta

rustc --version:

1.86.0

@rustbot label A-lifetimes A-trait-objects T-types

@Jules-Bertholet Jules-Bertholet added the C-bug Category: This is a bug. label Apr 6, 2025
@rustbot rustbot added needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. A-lifetimes Area: Lifetimes / regions A-trait-objects Area: trait objects, vtable layout T-types Relevant to the types team, which will review and decide on the PR/issue. labels Apr 6, 2025
@compiler-errors
Copy link
Member

compiler-errors commented Apr 6, 2025

Is this suggesting that I should be able to turn a dyn Trait<'a, 'b> + 'static into a dyn Trait<'a, 'static> + 'static? If so, that's unsound:

trait Trait<'a, 'b> {
    fn turn(&self, x: &'a str) -> &'b str;
}

impl<'a> Trait<'a, 'a> for () {
    fn turn(&self, x: &'a str) -> &'a str {
        x
    }
}

/// Emulate the requested upcasting behavior.
///
/// For obvious reasons this is impl'd via unsafe.
fn upcast<'a, 'b>(x: Box<dyn Trait<'a, 'b> + 'static>) -> Box<dyn Trait<'a, 'static> + 'static> {
    unsafe { std::mem::transmute(x) }
}

fn longer<'a>(x: &'a str) -> &'static str {
    let o: Box<dyn Trait<'a, 'a>> = Box::new(());
    upcast(o).turn(x)
}

If this is a behavior that would only work for one lifetime for some reason, then it doesn't really feel principled.

@compiler-errors compiler-errors removed the C-bug Category: This is a bug. label Apr 6, 2025
@Jules-Bertholet
Copy link
Contributor Author

Jules-Bertholet commented Apr 6, 2025

That’s a good example, thanks! But you could turn dyn Trait<'a, 'b> + 'static into dyn Trait<'static, 'static> + 'static. So I suppose the generalization would be:

trait Trait<'a, 'b, 'c> {}

fn convert<'short, 'short2, 'long: 'short + 'short2, 'longer: 'long>(
    obj: Box<dyn Trait<'short, 'short2, 'longer> + 'long>,
) -> Box<dyn Trait<'long, 'long, 'longer> + 'long> {
    obj
}

All lifetime parameters not already known to outlive 'long have to be converted 'short'long at once.

@compiler-errors
Copy link
Member

That doesn't seem like something we can implement given that the trait system doesn't know anything about lifetime relationships (especially so in NLL), and I'm not convinced the new strategy is sound either.

@jieyouxu jieyouxu added C-discussion Category: Discussion or questions that doesn't represent real issues. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 7, 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-objects Area: trait objects, vtable layout C-discussion Category: Discussion or questions that doesn't represent real issues. 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

4 participants