rust-lang / rust-lang/rust

Borrow checker fails to pick up existing region bounds in the environment when aliases are given to assoicated types in trait bounds.

Open
#121,601 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-borrow-checker C-bug T-types
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

It occurs to me that adding named type terms to associated type of trait bounds can lead to borrow check failure, while the same code without "naming" the associated type passes the borrow check.

I tried this code:

pub trait Trait1 {
    type Output1;
    fn call<'z>(&'z self) -> &'z Self::Output1;
}

pub trait Trait2<T> {
    type Output2;
    fn call2<'x>(_: &'x T) -> &'x Self::Output2;
}

impl<A, B, T: Trait1<Output1 = A>> Trait2<T> for B // Mind this `A` here
where
    B: Trait2<T::Output1>,
{
    type Output2 = <B as Trait2<T::Output1>>::Output2;
    fn call2<'y>(source: &'y T) -> &'y Self::Output2 {
        let t = source.call();
        B::call2(t)
    }
}

I expected to see this happen:
It should compile just like the following rewrite, without naming the Output1 to A.

pub trait Trait1 {
    type Output1;
    fn call<'z>(&'z self) -> &'z Self::Output1;
}

pub trait Trait2<T> {
    type Output2;
    fn call2<'x>(_: &'x T) -> &'x Self::Output2;
}

impl<B, T: Trait1> Trait2<T> for B
where
    B: Trait2<T::Output1>,
{
    type Output2 = <B as Trait2<T::Output1>>::Output2;
    fn call2<'y>(source: &'y T) -> &'y Self::Output2 {
        let t = source.call();
        B::call2(t)
    }
}

Instead, this happened:

error[E0309]: the parameter type `A` may not live long enough
  --> lifetime.rs:17:17
   |
16 |     fn call2<'y>(source: &'y T) -> &'y Self::Output2 {
   |              -- the parameter type `A` must be valid for the lifetime `'y` as defined here...
17 |         let t = source.call();
   |                 ^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound
   |
16 |     fn call2<'y>(source: &'y T) -> &'y Self::Output2 where A: 'y {
   |                                                      +++++++++++

error[E0309]: the parameter type `A` may not live long enough
  --> lifetime.rs:18:9
   |
16 |     fn call2<'y>(source: &'y T) -> &'y Self::Output2 {
   |              -- the parameter type `A` must be valid for the lifetime `'y` as defined here...
17 |         let t = source.call();
18 |         B::call2(t)
   |         ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound
   |
16 |     fn call2<'y>(source: &'y T) -> &'y Self::Output2 where A: 'y {
   |                                                      +++++++++++

error: aborting due to 2 previous errors

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

Mind that due to the trait definition, it is not possible to apply the suggestion that is emitted by rustc.

Meta

This is found on the latest master, as of writing, and stable.

rustc --version --verbose:

rustc 1.78.0-nightly (256b6fb19 2024-02-06)
binary: rustc
commit-hash: 256b6fb19a2c018eaad4806d2369d1f6a71fc6ec
commit-date: 2024-02-06
host: x86_64-unknown-linux-gnu
release: 1.78.0-nightly
LLVM version: 17.0.6
Backtrace

Not an ICE, so not applicable.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by compiling the first Rust reproducer with the reported stable or nightly compiler and compare it with the rewrite that omits the associated-type alias. Trace the borrow-checker handling of the named Output1 = A trait bound; done means the original example compiles without adding the impossible A: 'y bound.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.