I've been trying to get my head around @_lifetime and ~Escapable. I'm making progress, but I encountered something that has me stumped.
Here's the code in question:
struct Restricted: ~Escapable {
// error: Cannot borrow the lifetime of 'string', which has consuming ownership on an initializer
init(_ string: String) {
}
}
If I'm understanding right, even though this is an initializer, the single parameter default rule applies. So the above code is equivalent to:
struct Restricted: ~Escapable {
// error: Invalid use of borrow dependence with consuming ownership
@_lifetime(borrow string)
init(_ string: String) {
}
}
Also invalid.
Spelling this out fully, just for the sake of my own understanding, also does not work. But how it fails somehow both seems very logical and surprising at the same time.
Am I making any mistakes here? And, is it is even possible to construct an initializer for a ~Escapable that takes an Escapable parameter? What might my options be?
(if there is any documentation around this, please do point me to it!)
In the current design, ~E types must depend on some value or access. In this case, the thing to depend on is the string you init it with. However, initializers default to consuming their parameters, so this string doesn't have a lifetime you can depend on. If you imagine lifetimes as tracking dependencies between values, there is no reasonable dependency to track here, since Restrictedowns the string due to the consuming convention. Afaik what this diagnostic is attempting to communicate is that the compiler attempted to depend on this parameter, but it doesn't have a lifetime.
When initializing a ~Escapable struct (struct SpanView: ~Escapable), the Swift 6.2+ lifetime checker requires an explicit @_lifetime(...) annotation on init whenever the returned ~Escapable value has no inferred lifetime source from another ~Escapable parameter.
If all parameters to init are Escapable (or if a parameter is only read during construction without being borrowed for the lifetime of self), the compiler assumes self might depend on the local borrow scope of that parameter unless you either:
Add an explicit @_lifetime(borrow source) (or @_lifetime(immortal) if self holds no borrowed references), or
Mark the transient Escapable configuration parameter so the lifetime checker knows self's lifetime is tied strictly to the borrowed storage container rather than the auxiliary argument.