Skip to content

Borrow checker determines borrows by examining lifetime parameters on unexpanded associated types instead of inspecting their lifetime bounds #50029

Closed
@dylanede

Description

@dylanede

Consider the following (playpen):

trait Foo<'a> {
    type Out: 'a;
}

fn foo<'a, T>(_: &'a mut T) -> <T as Foo<'a>>::Out where T : Foo<'a> {
    unimplemented!()
}

fn baz<T>(mut x: T) where for<'a> T : Foo<'a>, for<'a> <T as Foo<'a>>::Out : 'static {
    let y = foo(&mut x);
    let z = foo(&mut x);
}

fn main() {
    struct Bar;
    impl<'a> Foo<'a> for Bar {
        type Out = i32;
    }
    let mut b = Bar;
    let y = foo(&mut b);
    let z = foo(&mut b);
}

main compiles fine, as expected, since the associated type expands to i32, which does not use the lifetime 'a that the mutable reference input argument is bound by.

baz however fails to compile (error message below), despite the additional constraint on Out to be 'static, implying that the return value of foo does not borrow the argument.

error[E0499]: cannot borrow `x` as mutable more than once at a time
  --> src/main.rs:11:22
   |
10 |     let y = foo(&mut x);
   |                      - first mutable borrow occurs here
11 |     let z = foo(&mut x);
   |                      ^ second mutable borrow occurs here
12 | }
   | - first borrow ends here

This problem appears to be unique to unexpanded associated types, as they are the only case where the lifetime parameters do not directly determine the lifetime bounds on the type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerC-enhancementCategory: An issue proposing an enhancement or a PR with one.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions