Skip to content

Regression in required trait bounds in Rust 1.78.0  #124984

Closed
@alexcrichton

Description

@alexcrichton
Member

Code

This code

pub trait Host {}

impl<T: ?Sized + Host> Host for &mut T {}

pub trait GetHost<T>: Send + Sync + Copy + 'static {
    fn get_host<'a>(&self, data: &'a mut T) -> impl Host;
}

impl<T, U, F> GetHost<T> for F
where
    U: Host,
    F: Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static,
{
    fn get_host<'a>(&self, data: &'a mut T) -> impl Host {
        self(data)
    }
}

fn main() {}

Compiles successfully with Rust 1.77.0 but fails to compile with Rust 1.78.0:

error[E0309]: the parameter type `U` may not live long enough
  --> foo.rs:15:9
   |
14 |     fn get_host<'a>(&self, data: &'a mut T) -> impl Host {
   |                 -- the parameter type `U` must be valid for the lifetime `'a` as defined here...
15 |         self(data)
   |         ^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound
   |
14 |     fn get_host<'a>(&self, data: &'a mut T) -> impl Host where U: 'a {
   |                                                          +++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0309`.

Version it worked on

It most recently worked on: 1.77.0

Version with regression

rustc --version --verbose:

rustc 1.78.0 (9b00956e5 2024-04-29)
binary: rustc
commit-hash: 9b00956e56009bab2aa15d7bff10916599e3d6d6
commit-date: 2024-04-29
host: x86_64-unknown-linux-gnu
release: 1.78.0
LLVM version: 18.1.2

Information from cargo bisect-rustc

Regression in rust-lang-ci@68a543d (#118882)

searched nightlies: from nightly-2024-02-01 to nightly-2024-03-16
regressed nightly: nightly-2024-02-15
searched commit range: a84bb95...ee9c7c9
regressed commit: 7508c3e

bisected with cargo-bisect-rustc v0.6.8

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc --start 1.77.0 --end 1.78.0 --script rustc --preserve -- foo.rs --crate-type lib

Activity

added
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on May 10, 2024
lcnr

lcnr commented on May 10, 2024

@lcnr
Contributor

your code snippet does not seem to compile in 1.77 or 1.76? 🤔 https://rust.godbolt.org/z/vzhn87bfz

alexcrichton

alexcrichton commented on May 10, 2024

@alexcrichton
MemberAuthor

That may be a godbolt issue perhaps? https://rust.godbolt.org/z/e6nxK5oaq shows it passing with 77/76 and locally 1.77.0 compiles the example for me.

compiler-errors

compiler-errors commented on May 10, 2024

@compiler-errors
Member

@alexcrichton: The code you shared in the issue has an extra + 'a, causing it to fail both before and after 1.78.

alexcrichton

alexcrichton commented on May 10, 2024

@alexcrichton
MemberAuthor

Er apologies, that's my mistake. I was trying various versions locally and got the wires crossed. I've updated the above which also explains why the two godbolt links are differing in results.

I was surprised that this actually worked on 1.77.0, so is this actually a soundness issue fixed by #118882?

lcnr

lcnr commented on May 10, 2024

@lcnr
Contributor

The hidden type of impl Host ends up as &'a U and we currently don't have an implied U: 'a bound here. This breaks the invariants of our type system, using a pattern which can result in actual unsoundnesses. I don't think your snippet is unsound as is, but also don't know how we would fix #114936 without breaking your example

alexcrichton

alexcrichton commented on May 10, 2024

@alexcrichton
MemberAuthor

Ah ok, if this is expected no worries, I just wanted to confirm!

Would you happen to know off the top of your head if there's a way we could somehow get this working? The ideal thing we want is:

fn foo<T>(f: impl Fn(&mut T) -> impl Host) { ... }

and we're trying to hack around it of sorts with a custom GetHost trait, but I'm having a tough time figuring out how to model this use case.

alexcrichton

alexcrichton commented on May 10, 2024

@alexcrichton
MemberAuthor

Ah well in any case this appears to be expected so there's no issue here I believe. We'll work on getting something alternative working instead.

lcnr

lcnr commented on May 10, 2024

@lcnr
Contributor

Would you happen to know off the top of your head if there's a way we could somehow get this working? The ideal thing we want is:

It's really hard as you need a for<'a> U: 'a bound which currently forces U to be 'static while ideally it would only allow instantiating 'a with lifetimes which outlive 'a. We will support this in a few years as these kinds of bounds are necessary to fix e.g. #25860

but up until then I also don't have a nice fix for this :/

alexcrichton

alexcrichton commented on May 10, 2024

@alexcrichton
MemberAuthor

Ah no worries! I was able to adapt this and get something working, albeit not as egonomically as desired.

In any case thanks for the quick responses here, it's definitely appreciated!

removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on May 10, 2024
removed
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
on May 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.regression-untriagedUntriaged performance or correctness regression.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @alexcrichton@compiler-errors@apiraino@lcnr@jieyouxu

        Issue actions

          Regression in required trait bounds in Rust 1.78.0 · Issue #124984 · rust-lang/rust