# Lifetime dependency annotations and function subtyping

**URL:** <https://forums.swift.org/t/lifetime-dependency-annotations-and-function-subtyping/89243>\
**Category:** Using Swift\
**Tags:** ownership, lifetime\
**Created:** [August 28, 2026, 12:11am UTC](https://forums.swift.org/t/lifetime-dependency-annotations-and-function-subtyping/89243 "2026-08-28T00:11:22Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![zackbach](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/zackbach/32/43682_2.png) [@zackbach](https://forums.swift.org/u/zackbach)\
**Post date:** [August 28, 2026, 12:11am UTC](https://forums.swift.org/t/lifetime-dependency-annotations-and-function-subtyping/89243/1 "2026-08-28T00:11:23Z")

</div>

When a function returns a non-escapable type that copies the lifetime dependencies of an input, the `copy` lifetime annotation is used:

```swift
struct NE: ~Escapable { }

@_lifetime(copy ne)
func copies(_ ne: borrowing NE) -> NE { return copy ne }

```

Such a function that returns a copy will still type-check, even if the lifetime annotation is replaced with `borrow ne` or `&ne` (if the parameter is changed to be taken as `inout`):

```swift
@_lifetime(borrow ne)
func stillCopies(_ ne: borrowing NE) -> NE { 
    return copy ne
    // OR, equivalently:
    // return copies(ne)
}

@_lifetime(&ne)
func stillCopies2(_ ne: inout NE) -> NE { 
    return copy ne
}

```

This makes sense—creating a scoped dependency on a borrow of `ne` necessarily implies that anything `ne` in turn depends on (i.e. the dependencies get copied above) is still alive as well.

This behavior led me to believe that there should be a subtyping relation between such function types, where the type of `copies` would be a subtype of the type of `stillCopies`, since any function with a copied dependence could be used as one with a scoped dependence. However, this is not the case:

```swift
// does NOT typecheck
// error: cannot convert value of type '@_lifetime(copy 0) (borrowing NE) -> NE' to specified type '@_lifetime(borrow ne) (_ ne: NE) -> NE'
let clos : @_lifetime(borrow ne) (_ ne: NE) -> NE = copies;

```

A similar error arises when attempting to conform to a protocol written with a `@_lifetime(borrow ne)` annotation using a conformance annotated as `@_lifetime(copy ne)`. Note that these _are_ positions where sub-lifetime annotations are permitted (for instance, a protocol annotated as `@_lifetime(copy a, copy b)` may have a conformance annotated with just `@_lifetime(copy a)`

Am I incorrect in thinking that this subtyping relationship should hold? Or would this be sound, and my above observations are merely limitations of the current implementation?

---

<div class="post-metadata">

**Author:** ![aviva](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aviva/32/44327_2.png) [@aviva](https://forums.swift.org/u/aviva)\
**Post date:** [August 28, 2026, 9:40pm UTC](https://forums.swift.org/t/lifetime-dependency-annotations-and-function-subtyping/89243/2 "2026-08-28T21:40:27Z")

</div>

Great question, I had the same confusion! I said (as part of some other discussion, about what witnesses were valid for a protocol with dependency annotations)

> `immortal <: borrow self <: copy self`, but not the other way around, `copy self` is "weaker" guarantee than `borrow self` , generic code may want to consume P and still use the Ref, but `copy self` won't allow that. (this is isn't accepted by compiler today but i do think it could be made to work?)

@aidan-hall said (hope it's ok to copy his message 😁 )

> We did consider allowing conversion between copy and borrow when adding lifetime checking for protocol conformances, and just didn't at the time because it wasn't necessary to support any conformances in existing code.  
> (link to internal "allow conversion (contravariance) from lifetime(copy) to lifetime(borrow) for function types (protocol/closure)")
> 
> The conversion rules as implemented by the compiler today are documented here (sorry if the wording is confusing):  
> [swift/docs/ReferenceGuides/LifetimeAnnotation.md at main · swiftlang/swift · GitHub](https://github.com/swiftlang/swift/blob/main/docs/ReferenceGuides/LifetimeAnnotation.md#lifetime-subtyping)

So, afaik, yes this subtyping relationship is safe and could safely imply a subtyping relationship between function types, but no the compiler does not support it.

---

<div class="post-metadata">

**Author:** ![aviva](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aviva/32/44327_2.png) [@aviva](https://forums.swift.org/u/aviva)\
**Post date:** [September 2, 2026, 6:00pm UTC](https://forums.swift.org/t/lifetime-dependency-annotations-and-function-subtyping/89243/3 "2026-09-02T18:00:19Z")

</div>

> [@aviva](#):
>
> immortal \<: borrow self \<: copy self

Oops this is backwards, should read `immortal <: copy self <: borrow self` I think... my whole answer seems transposed wrt function type conversion.
