Different behaviour of lifetime dependency for `let` and `var`

The following codes compile successfully:

struct B: ~Escapable {
    @_lifetime(immortal)
    init() {}
    func doSomething() {}
}

struct A: ~Copyable {
    var b: B { 
        @_lifetime(borrow self)
        get {
            return .init() 
        }
    }
    consuming func consume() {}
}

func test() {
    var a = A()
    do {
        let b = a.b
        b.doSomething()
    }
    a.consume()
}

However, if we change the var a = A() to let a = A():

struct B: ~Escapable {
    @_lifetime(immortal)
    init() {}
    func doSomething() {}
}

struct A: ~Copyable {
    var b: B { 
        @_lifetime(borrow self)
        get {
            return .init() 
        }
    }
    consuming func consume() {}
}

func test() {
    let a = A()    // <-- change from var to let
    do {
        let b = a.b
        b.doSomething()
    }
    a.consume()
    // error: Noncopyable 'a' cannot be consumed when captured by an escaping closure or borrowed by a non-Escapable type
}

We got an error on a.consume() saying we cannot consume a because it is still being borrowed by a non-Escapable type. But here the lifetime of b has already been ended after the do block and should not affect a anymore. Besides, it only occurs when a is a let constant. This issue persists in 6.2, 6.3 and 6.4 beta. Is there any workaround for that? Using var instead of let pass the compilation, but will also give a warning saying a was never mutated.

3 Likes