[Pitch] Non-Escapable Types and Lifetime Dependency

Hi Curtis. Good point. That section of the pitch is not clear. When we update and repitch this, we should add a couple of points.

First, any declaration with an explicit lifetime dependency should generally override all the inferrence rules that would normally apply to that declaration. This should handle your case:

@lifetime(item)
func foo<T: ~Escapable, U: ~Escapable, R: ~Escapable>(
    item: some BorrowedMember<T, R>,
    x: T,
    y: U
) -> R { … }

We currently use @lifetime annotations instead of dependsOn within the language implementation. That makes it easier to see where the experimental feature is used. Note that same-type inferrence is not implemented yet.

The above @lifetime annotation would only be allowed if the compiler can recognize that BorrowedMember<T, R> is conditionally ~Escapable when T is ~Escapable.


Second, same-type inferrence is limitted by the same-type requirements of the declaration's generic context. So, by itself, this function has no inferred dependencies and would in fact be an illegal declaration:

func foo<T: ~Escapable, U: ~Escapable, R: ~Escapable>(x: T, y: U) -> R { ... }

Simply calling the function with substitutions of the same type would not cause any dependency to be inferred:

func bar<T: ~Escapable>(x: T, y: T) -> T {
  foo(x, y) // ERROR: no lifetime dependency
}

Instead, inferrence only happens when the declaration's generic context has same-type requirements:

struct Foo<T: ~Escapable, U: ~Escapable, R: ~Escapable> {}

extension Foo where T == R {
  /* Infers @lifetime(x) */
  func foo<T: ~Escapable, U: ~Escapable, R: ~Escapable>(x: T, y: U) -> R { ... }
}
1 Like