Skip to content

Commit 2e82c6b

Browse files
committed
Use "nonescapable" for the concept, rather than ~Escapable
1 parent eed1b05 commit 2e82c6b

File tree

1 file changed

+33
-33
lines changed

1 file changed

+33
-33
lines changed

proposals/NNNN-lifetime-dependency.md

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@ These lifetime dependencies can be expressed in several different ways, with var
6363

6464
### Background: "Escapable" and “Nonescapable” Types
6565

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`.
6968

7069
Normal Swift types are `Escapable` by default.
7170
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`.
7474

75-
By themselves, `~Escapable` types have severe constraints on usage.
75+
By themselves, nonescapable types have severe constraints on usage.
7676
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.
7777
It simply holds a pointer and size and can be used to access data stored in a contiguous block of memory.
7878
(We are not proposing this type; it is shown here merely for illustrative purposes.)
@@ -85,7 +85,7 @@ struct BufferReference<T>: ~Escapable {
8585
```
8686

8787
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.
8989
In the most common cases, these constraints can be inferred automatically.
9090

9191
### Explicit Lifetime Dependency Annotations
@@ -133,12 +133,12 @@ Similar to the previous example:
133133
* No other read or write access to the array will be allowed for as long as the returned value exists.
134134

135135
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).
138138

139139
#### Copy Lifetime Dependency
140140

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.
142142
Here's a typical example that constructs a new `BufferReference` from an existing one:
143143
```swift
144144
struct BufferReference<T>: ~Escapable {
@@ -148,8 +148,8 @@ struct BufferReference<T>: ~Escapable {
148148
}
149149
```
150150

151-
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.
153153

154154
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.
155155
Instead, the return value must "copy" the lifetime dependency from the original:
@@ -182,19 +182,19 @@ func f(arg: <parameter-convention> ArgType) -> @dependsOn(arg) ResultType
182182
Where
183183

184184
* *`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.
186186

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.)
190190
A scoped dependency ensures the argument will not be destroyed while the result is alive.
191191
Also, access to the argument will be restricted for the lifetime of the result following Swift's usual exclusivity rules:
192192

193193
* A `borrowing` parameter-convention extends borrowing access, prohibiting mutations of the argument.
194194
* An `inout` parameter-convention extends mutating access, prohibiting any access to the argument.
195195
* A `consuming` parameter-convention is illegal, since that ends the lifetime of the argument immediately.
196196

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.
198198
In this case, the semantics of `@dependsOn()` are slightly different:
199199
* A `consuming` parameter-convention will copy the lifetime dependency from the argument to the result
200200
* A `borrowing` or `inout` parameter-convention can either copy the lifetime dependency or create a new scoped lifetime dependency.
@@ -212,7 +212,7 @@ Given a method of this form:
212212
<mutation-modifier> func method(... args ...) -> @dependsOn(self) ResultType
213213
```
214214

215-
The behavior depends as above on the mutation-modifier and whether the defining type is `Escapable` or `~Escapable`.
215+
The behavior depends as above on the mutation-modifier and whether the defining type is escapable or nonescapable.
216216

217217
**Initializers:** An initializer can define lifetime dependencies on one or more arguments.
218218
In this case, we use the same rules same as for “Functions” above
@@ -226,10 +226,10 @@ init(arg: <parameter-convention> ArgType) -> @dependsOn(arg) Self
226226

227227
The syntax above allows developers to explicitly annotate lifetime dependencies in their code.
228228
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.
230230

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:
233233

234234
```swift
235235
struct NonescapableType: ~Escapable { ... }
@@ -253,7 +253,7 @@ struct NEStruct: ~Escapable {
253253
}
254254
```
255255

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.
257257
For example:
258258

259259
```swift
@@ -277,9 +277,9 @@ We expect these implicit inferences to cover most cases, with the explicit form
277277

278278
### Relation to ~Escapable
279279

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.
283283

284284
```swift
285285
struct S: ~Escapable {
@@ -374,20 +374,20 @@ The implications of mutation modifiers and argument type on the resulting lifeti
374374

375375
If there is no explicit lifetime dependency, we will automatically infer one according to the following rules:
376376

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.
378378
Note that this is not affected by the presence, type, or modifier of any other arguments to the method.
379379

380380
**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:
381381

382-
* the return type is `~Escapable`,
382+
* the return value is nonescapable,
383383
* there is exactly one argument that satisfies any of the following:
384-
- is either `~Copyable` or `~Escapable`
384+
- is either noncopyable or nonescapable, or
385385
- has an explicit `borrowing`, `consuming`, or `inout` convention specified
386386

387387
In this case, the compiler will infer a dependency on the unique argument identified by this last set of conditions.
388388

389389
**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.
391391

392392
## Source compatibility
393393

@@ -433,7 +433,7 @@ This was changed after we realized that there was in practice almost always a si
433433

434434
#### Lifetime Dependencies for Computed Properties
435435

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.
437437
There is some ambiguity here, since resilience hides the distinction between a computed and stored property.
438438
In particular, the resilience concern might prevent us from inferring lifetime dependencies for properties across module boundaries.
439439
The notation for an explicit lifetime dependency on a property might look like the following:
@@ -449,12 +449,12 @@ extension Type1 {
449449
```
450450

451451
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.
453453

454454
#### Lifetime Dependencies for Escapable Types
455455

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.
458458
It also helps simplify the enforcement of lifetime constraints by guaranteeing that constrained values cannot escape before being returned.
459459
Most importantly, this restriction helps ensure that the new semantics (especially lifetime dependency inference) cannot accidentally break existing code.
460460
We expect that in the future, additional investigation can reveal a way to relax this restriction.

0 commit comments

Comments
 (0)