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
- `unsafeLifetime` is currently implemented as `_overrideLifetime`
- Clarify distinction between using an inout parameter as a source or target,
and point out what occurs (nothing) if a parameter is both the source and
target of a dependency
- Give an explicit example of conjoined dependence with multiple lifetimes
on the same target
Copy file name to clipboardExpand all lines: proposals/NNNN-lifetime-dependency.md
+59-18
Original file line number
Diff line number
Diff line change
@@ -15,9 +15,9 @@ This is deeply related to `~Escapable` types, as introduced in [SE-0446](0446-no
15
15
**Edited** (March 20, 2025):
16
16
17
17
- Replaced `dependsOn` return type modifier with a declaration-level `@lifetime` attribute.
18
-
Removed dependency inference rules.
18
+
Removed dependency inference rules.
19
19
- Integrated links to proposals SE-0446 (`Escapable`), SE-0447 (`Span`), SE-0456 (`Span`-producing properties), and SE-0467 (`MutableSpan`) that have undergone review.
20
-
- Added SE-0458 `@unsafe` annotations to the `unsafeLifetime` standard library functions, and added `@unsafe` as a requirement for APIs using `BitwiseCopyable` lifetime dependencies under strict memory safety.
20
+
- Added SE-0458 `@unsafe` annotations to the `_overrideLifetime` standard library functions, and added `@unsafe` as a requirement for APIs using `BitwiseCopyable` lifetime dependencies under strict memory safety.
21
21
22
22
**Edited** (April 12, 2024): Changed `@dependsOn` to `dependsOn` to match the current implementation.
23
23
@@ -547,27 +547,37 @@ unsafe storage.withUnsafeBufferPointer { buffer in
547
547
548
548
### Standard library extensions
549
549
550
-
#### `unsafeLifetime` helper functions
550
+
#### `_overrideLifetime` helper functions
551
551
552
-
The following two helper functions will be added for implementing low-level data types:
552
+
The following helper functions will be added for implementing low-level data types:
553
553
554
554
```swift
555
555
/// Replace the current lifetime dependency of `dependent` with a new copied lifetime dependency on `source`.
556
556
///
557
557
/// Precondition: `dependent` has an independent copy of the dependent state captured by `source`.
Since `self.base` is an `Escapable` value, it does not propagate the lifetime dependence of its container. Without the call to `unsafeLifetime`, `local` would be limited to the local scope of the value retrieved from `self.base`, and could not be returned from the method. In this example, `unsafeLifetime` communicates that all of the dependent state from `self` has been *copied* into `local`, and, therefore, `local` can persist after `self` is destroyed.
596
+
Since `self.base` is an `Escapable` value, it does not propagate the lifetime dependence of its container. Without the call to `_overrideLifetime`, `local` would be limited to the local scope of the value retrieved from `self.base`, and could not be returned from the method. In this example, `_overrideLifetime` communicates that all of the dependent state from `self` has been *copied* into `local`, and, therefore, `local` can persist after `self` is destroyed.
587
597
588
-
`unsafeLifetime` can also be used to construct an immortal value where the compiler cannot prove immortality by passing a `Void` value as the source of the dependence:
598
+
`_overrideLifetime` can also be used to construct an immortal value where the compiler cannot prove immortality by passing a `Void` value as the source of the dependence:
This means that an `inout` parameter of potentially non-`Escapable` type can interact with lifetimes in three ways:
820
+
821
+
- as the source of a scoped dependency, as in `@lifetime([<target>:] inout x)`
822
+
- as the source of a copied dependency, as in `@lifetime([<target>:] copy x)`
823
+
- as the target of a dependency, as in `@lifetime(x: <dependency>)`
824
+
825
+
so it is worth restating the behavior here to emphasize the distinctions.
826
+
A scoped dependency `@lifetime(inout x)` indicates that the target's lifetime is constrained by exclusive access to `x`.
827
+
A copied dependency `@lifetime(copy x)` indicates that the target copies its lifetime constraint from value of `x` when the callee *begins* execution.
828
+
As the target of a dependency, `@lifetime(x: <dependency>)` indicates the lifetime constraint added to the value of `x` after the callee *ends* execution.
829
+
830
+
By composition, an `inout` parameter can appear as both the source and target of a dependency, although there is no net effect to doing so. `@lifetime(x: inout x)` states that the value of `x` on return from the callee is dependent on exclusive access to the variable `x`, but any value that can be stored in a mutable variable must already live at least as long as any exclusive access to `x` that could occur. `@lifetime(x: copy x)` states that the value of `x` on return from the callee copies its dependency from the value of `x` when the function began execution, in effect stating that the lifetime dependency does not change.
`inout` argument dependence behaves like a conditional reassignment. After the call, the variable passed to the `inout` argument has both its original dependence along with a new dependence on the argument that is the source of the argument dependence.
@@ -821,6 +844,24 @@ do {
821
844
parse(span) // 🛑 Error: 'span' escapes the scope of 'a2'
822
845
```
823
846
847
+
#### Explicit conjoined dependence
848
+
849
+
A declaration can also express a conjoined dependence explicitly by applying multiple lifetime dependencies to the same target:
// A Pair cannot outlive the lifetime of either of its fields.
857
+
@lifetime(copy first, copy second)
858
+
init(first: T, second: U) {
859
+
self.first= first
860
+
self.second= second
861
+
}
862
+
}
863
+
```
864
+
824
865
#### `Escapable` properties in a non-`Escapable` type
825
866
826
867
A non-`Escapable` type inevitably contains `Escapable` properties.
@@ -899,14 +940,14 @@ This poses a few problems:
899
940
900
941
2.`lifetime(unchecked)` is a blunt tool for opting out of safety. Experience shows that such tools are overused as workarounds for compiler errors without fixing the problem. A safety workaround should more precisely identify the source of unsafety.
901
942
902
-
`unsafeLifetime` is the proposed tool for disabling dependence checks. Passing `Void` as the dependence source is a reasonable way to convert a nonescaping value to an immortal value:
943
+
`_overrideLifetime` is the proposed tool for disabling dependence checks. Passing `Void` as the dependence source is a reasonable way to convert a nonescaping value to an immortal value:
0 commit comments