You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/NNNN-lifetime-dependency.md
+33-33Lines changed: 33 additions & 33 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -63,16 +63,16 @@ These lifetime dependencies can be expressed in several different ways, with var
63
63
64
64
### Background: "Escapable" and “Nonescapable” Types
65
65
66
-
In order to avoid changing the meaning of existing code, we will introduce two complementary type constraints:
67
-
`Escapable` and `~Escapable`.
68
-
These constraints can appear in a type declaration as a protocol.
66
+
In order to avoid changing the meaning of existing code, we will introduce a
67
+
new protocol `Escapable` which can be suppressed with `~Escapable`.
69
68
70
69
Normal Swift types are `Escapable` by default.
71
70
This implies that they can be returned, stored in properties, or otherwise "escape" the local context.
72
-
Conversely, types explicitly declared `~Escapable` are not allowed to escape the local context except in very specific circumstances.
73
-
A separate proposal explains the general syntax and semantics of `Escapable` and `~Escapable` types.
71
+
Conversely, types can be explicitly declared to be "nonescapable" using `~Escapable`.
72
+
These types are not allowed to escape the local context except in very specific circumstances.
73
+
A separate proposal explains the general syntax and semantics of `Escapable` and `~Escapable`.
74
74
75
-
By themselves, `~Escapable` types have severe constraints on usage.
75
+
By themselves, nonescapable types have severe constraints on usage.
76
76
For example, consider a hypothetical `BufferReference` type that is similar to the standard library `UnsafeBufferPointer` or the `StorageView` type that is being proposed for inclusion in the standard library.
77
77
It simply holds a pointer and size and can be used to access data stored in a contiguous block of memory.
78
78
(We are not proposing this type; it is shown here merely for illustrative purposes.)
Because this type is marked `~Escapable`, it cannot be returned from a function or even initialized without some way to relax the escapability restrictions.
88
-
This proposal provides a set of constraints that can tie the lifetime of a `~Escapable` value to the lifetime of some other value.
88
+
This proposal provides a set of constraints that can tie the lifetime of a nonescapable value to the lifetime of some other value.
89
89
In the most common cases, these constraints can be inferred automatically.
90
90
91
91
### Explicit Lifetime Dependency Annotations
@@ -133,12 +133,12 @@ Similar to the previous example:
133
133
* No other read or write access to the array will be allowed for as long as the returned value exists.
134
134
135
135
In both this and the previous case, the lifetime of the return value is "scoped" to the lifetime of the original value.
136
-
Because lifetime dependencies can only be attached to `~Escapable` values, types that contain pointers will generally need to be `~Escapable` in order to provide safe semantics.
137
-
As a result, **scoped lifetime dependencies** are the only possibility whenever an `Escapable` value (such as an Array or similar container) is providing a `~Escapable` value (such as the `BufferReference` or `MutatingBufferReference` in these examples).
136
+
Because lifetime dependencies can only be attached to nonescapable values, types that contain pointers will generally need to be nonescapable in order to provide safe semantics.
137
+
As a result, **scoped lifetime dependencies** are the only possibility whenever an `Escapable` value (such as an Array or similar container) is providing a nonescapable value (such as the `BufferReference` or `MutatingBufferReference` in these examples).
138
138
139
139
#### Copy Lifetime Dependency
140
140
141
-
The case where a `~Escapable` value is used to produce a different `~Escapable` value is somewhat different.
141
+
The case where a nonescapable value is used to produce another nonescapable value is somewhat different.
142
142
Here's a typical example that constructs a new `BufferReference` from an existing one:
In this examples, the `~Escapable` result depends on a `~Escapable` value.
152
-
Recall that `~Escapable` values such as these represent values that are already lifetime-constrained to another value.
151
+
In this examples, the nonescapable result depends on a nonescapable value.
152
+
Recall that nonescapable values such as these represent values that are already lifetime-constrained to another value.
153
153
154
154
For a `consuming` method, the return value cannot have a scoped lifetime dependency on the original value, since the original value no longer exists when the method returns.
155
155
Instead, the return value must "copy" the lifetime dependency from the original:
**`parameter-convention`* is one of the ownership specifiers **`borrowing`**, **`consuming`**, or **`inout`**, (this may be implied by Swift’s default parameter ownership rules),
185
-
*`ResultType` must be `~Escapable`.
185
+
*`ResultType` must be nonescapable.
186
186
187
-
If the `ArgType` is `Escapable`, the return value will have a new scoped dependency on the argument.
188
-
(This is the only possibility, as an `Escapable` value cannot have an existing lifetime dependency,
189
-
so we cannot copy it.)
187
+
If the `ArgType` is escapable, the return value will have a new scoped dependency on the argument.
188
+
(This is the only possibility, as an escapable value cannot have an existing lifetime dependency,
189
+
so we cannot copy the lifetime dependency.)
190
190
A scoped dependency ensures the argument will not be destroyed while the result is alive.
191
191
Also, access to the argument will be restricted for the lifetime of the result following Swift's usual exclusivity rules:
192
192
193
193
* A `borrowing` parameter-convention extends borrowing access, prohibiting mutations of the argument.
194
194
* An `inout` parameter-convention extends mutating access, prohibiting any access to the argument.
195
195
* A `consuming` parameter-convention is illegal, since that ends the lifetime of the argument immediately.
196
196
197
-
If the `ArgType` is `~Escapable`, then it can have a pre-existing lifetime dependency.
197
+
If the `ArgType` is nonescapable, then it can have a pre-existing lifetime dependency.
198
198
In this case, the semantics of `@dependsOn()` are slightly different:
199
199
* A `consuming` parameter-convention will copy the lifetime dependency from the argument to the result
200
200
* A `borrowing` or `inout` parameter-convention can either copy the lifetime dependency or create a new scoped lifetime dependency.
The syntax above allows developers to explicitly annotate lifetime dependencies in their code.
228
228
But because the possibilities are limited, we can usually allow the compiler to infer a suitable dependency.
229
-
The detailed rules are below, but generally we require that the return type be `~Escapable` and that there be one “obvious” source for the dependency.
229
+
The detailed rules are below, but generally we require that the return type be nonescapable and that there be one “obvious” source for the dependency.
230
230
231
-
In particular, we can infer a lifetime dependency on `self` for any method that returns a `~Escapable` type.
232
-
As above, the details vary depending on whether `self` is `Escapable` or `~Escapable`:
231
+
In particular, we can infer a lifetime dependency on `self` for any method that returns a nonescapable value.
232
+
As above, the details vary depending on whether `self` is escapable or nonescapable:
233
233
234
234
```swift
235
235
structNonescapableType: ~Escapable { ... }
@@ -253,7 +253,7 @@ struct NEStruct: ~Escapable {
253
253
}
254
254
```
255
255
256
-
For free or static functions or initializers, we can infer a lifetime dependency when the return value is `~Escapable` and there is only one obvious argument that can serve as the source of the dependency.
256
+
For free or static functions or initializers, we can infer a lifetime dependency when the return value is nonescapable and there is only one obvious argument that can serve as the source of the dependency.
257
257
For example:
258
258
259
259
```swift
@@ -277,9 +277,9 @@ We expect these implicit inferences to cover most cases, with the explicit form
277
277
278
278
### Relation to ~Escapable
279
279
280
-
The lifetime dependencies described in this document can be applied only to `~Escapable` return values.
281
-
Further, any return value that is `~Escapable` must have a lifetime dependency.
282
-
In particular, this implies that the initializer for a non-escapable type must have at least one argument.
280
+
The lifetime dependencies described in this document can be applied only to nonescapable return values.
281
+
Further, any return value that is nonescapable must have a lifetime dependency.
282
+
In particular, this implies that the initializer for a nonescapable type must have at least one argument.
283
283
284
284
```swift
285
285
structS: ~Escapable {
@@ -374,20 +374,20 @@ The implications of mutation modifiers and argument type on the resulting lifeti
374
374
375
375
If there is no explicit lifetime dependency, we will automatically infer one according to the following rules:
376
376
377
-
**For methods where the return type is `~Escapable`**, we will infer a dependency against self, depending on the mutation type of the function.
377
+
**For methods where the return value is nonescapable**, we will infer a dependency against self, depending on the mutation type of the function.
378
378
Note that this is not affected by the presence, type, or modifier of any other arguments to the method.
379
379
380
380
**For a free or static functions or initializers with at least one argument,** we will infer a lifetime dependency when all of the following are true:
381
381
382
-
* the return type is `~Escapable`,
382
+
* the return value is nonescapable,
383
383
* there is exactly one argument that satisfies any of the following:
384
-
- is either `~Copyable` or `~Escapable`
384
+
- is either noncopyable or nonescapable, or
385
385
- has an explicit `borrowing`, `consuming`, or `inout` convention specified
386
386
387
387
In this case, the compiler will infer a dependency on the unique argument identified by this last set of conditions.
388
388
389
389
**In no other case** will a function, method, or initializer implicitly gain a lifetime dependency.
390
-
If a function, method, or initializer has a `~Escapable` return type, does not have an explicit lifetime dependency annotation, and does not fall into one of the cases above, then that will be a compile-time error.
390
+
If a function, method, or initializer has a nonescapable return value, does not have an explicit lifetime dependency annotation, and does not fall into one of the cases above, then that will be a compile-time error.
391
391
392
392
## Source compatibility
393
393
@@ -433,7 +433,7 @@ This was changed after we realized that there was in practice almost always a si
433
433
434
434
#### Lifetime Dependencies for Computed Properties
435
435
436
-
It might be useful to allow lifetime dependencies between `self` and the value returned by a computed property.
436
+
It would be useful to allow lifetime dependencies between `self` and the value returned by a computed property.
437
437
There is some ambiguity here, since resilience hides the distinction between a computed and stored property.
438
438
In particular, the resilience concern might prevent us from inferring lifetime dependencies for properties across module boundaries.
439
439
The notation for an explicit lifetime dependency on a property might look like the following:
@@ -449,12 +449,12 @@ extension Type1 {
449
449
```
450
450
451
451
Where `borrowing` or `consuming` would indicate that the returned value has a lifetime dependency on `self`.
452
-
We expect that the lifetime notation would be mandatory for any property that provided a `~Escaping` value.
452
+
We expect that the lifetime notation would be mandatory for any property that provided a `~Escapable` value.
453
453
454
454
#### Lifetime Dependencies for Escapable Types
455
455
456
-
This proposal has deliberately limited the application of lifetime dependencies to return types that are `~Escapable`.
457
-
This simplifies the model by identifying `~Escapable` types as exactly those types that can carry such dependencies.
456
+
This proposal has deliberately limited the application of lifetime dependencies to return types that are nonescapable.
457
+
This simplifies the model by identifying nonescapable types as exactly those types that can carry such dependencies.
458
458
It also helps simplify the enforcement of lifetime constraints by guaranteeing that constrained values cannot escape before being returned.
459
459
Most importantly, this restriction helps ensure that the new semantics (especially lifetime dependency inference) cannot accidentally break existing code.
460
460
We expect that in the future, additional investigation can reveal a way to relax this restriction.
0 commit comments