Compile-time lifetime dependency annotations#3145
Compile-time lifetime dependency annotations#3145atrick wants to merge 2 commits intoswiftlang:mainfrom
Conversation
- Incorporate content from previous pitches - Reorganize proposal structure and flow - Add sections covering implicit defaults, closures, and lifetime requirements
de61433 to
1ad4fd1
Compare
| In addition to function declarations, function types must support lifetime annotations so functions that return non-`Escapable` types can be passed as closures. | ||
|
|
||
| ``` | ||
| func foo(closure: @lifetime(borrow arg) (_ arg: Container) -> Span<T>) { ... } |
There was a problem hiding this comment.
This should be @_lifetime instead of @lifetime. Other examples need to be updated as well.
There was a problem hiding this comment.
This is a proposal for the non-underscored syntax, so all the @_lifetime have been changed to @lifetime.
Of course, that's confusing to adopters using this as documentation. So maybe this should be explained in the introduction?
There was a problem hiding this comment.
If adopters are using examples listed here to experiment, they may see confusing errors.
There was a problem hiding this comment.
The proposal now mentions that the current implementation uses underscore. I believe adopters will get this warning
warning: Unsupported use of @lifetime, use @_lifetime to specify lifetime dependencies
Xazax-hun
left a comment
There was a problem hiding this comment.
I haven't looked at the detailed design yet, but have some questions inline.
|
|
||
| The `borrow` or `&` dependency specifiers indicate a scoped dependency on the argument. A scoped dependency must correspond to the argument's ownership: | ||
|
|
||
| * A `borrow` dependency specifier requires `borrowing` ownership. It extends borrowing access, prohibiting mutations of the argument, but allowing other simultaneous borrowing accesses. |
There was a problem hiding this comment.
If borrow and & can only be used with one parameter convention, does that mean we have some redundancy in the syntax and we could get rid of some tokens?
There was a problem hiding this comment.
Yes, the redundancy is intentional (in fact we added it later). We don't want the syntax to indicate that a mutable value is being "borrowed", as in @_lifetime(borrow x), because that normally implies a read-only shared borrow. The lifetime dependency only cares that there is either an immutable or mutable access scope, but programmers always think in terms of the parameter's ownership borrowing or inout.
| An `inout` parameter that is conditionally reassigned has two dependency sources: | ||
|
|
||
| ```swift | ||
| @lifetime(span: copy span, copy another) |
There was a problem hiding this comment.
How is the syntax disambiguated when we also have a return type?
I.e., how the annotation would look like for:
func mayReassign(span: inout Span<Int>, to another: Span<Int>) -> Span<Int> {
span = (...) ? span : another
return another
}There was a problem hiding this comment.
Or are we missing a span: after the comma?
There was a problem hiding this comment.
Each target uses a separate @_lifetime attribute because they're really unrelated, so the target is only written once:
@lifetime(target: source1, source2)
I can see how that's confusing. hopefully the grammar makes it clear. This example is:
@lifetime(span: /*span ,*/ another)
@lifetime(span, another) // if the result can be copied from either parameter
func mayReassign(span: inout Span<Int>, to another: Span<Int>) -> Span<Int> {
|
|
||
| ```swift | ||
| struct Wrapper<Element: ~Escapable>: ~Escapable { | ||
| var element: Element { |
There was a problem hiding this comment.
Why do we require these lifetime annotations? Shouldn't these follow from substituting the generic argument for Element in generic code?
There was a problem hiding this comment.
Yes, the lifetime attributes in that example are all the defaults. That's mentioned just below the example. I added a comment to the example too.
| _ = span | ||
| ``` | ||
|
|
||
| In the future, with additional syntax support, it may be possible for a function type to express dependenies simultaneously on both the closure value and its parameters. See "Closure capture dependency syntax". |
There was a problem hiding this comment.
What happens when a closure captures a Span or a MutableSpan? Does that have any implications on the escapability, copyability or any other properties of the closure?
There was a problem hiding this comment.
The future direction "Fine-grained closure capture dependencies" has an example of a closure capturing a Span. It doesn't change much other than loosen the lifetime restriction on the captured value... the closure's result could outlive the captured span, as long as it doesn't outlive that span's dependency (the container that gave you the span)
|
I hope all this is not from my device and if it is , or even if it’s another developer, you are tracking and updating privately without the person consent, is this how all of you do ? So most of this software was stolen and claimed. Anyway if this is from my database , stop it or I shut it down myself , |
Propose a
@lifetimeattribute to explicitly annotate declarations that produce non-Escapablevalues.This proposal is also intended to serve as documentation of the state of the compiler implementation of the experimental
Lifetimesfeature for early adopters.Previous proposal: #2750