Skip to content

Commit a9ca58d

Browse files
committed
New alternative considered: dependsOn(unchecked)
to disable lifetime dependence checking
1 parent eb1d88e commit a9ca58d

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

proposals/NNNN-lifetime-dependency.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,15 @@ extension Span {
544544

545545
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.
546546

547+
`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:
548+
549+
```swift
550+
init() dependsOn(immortal) {
551+
self.value = getGlobalConstant() // OK: unchecked dependence.
552+
self = unsafeLifetime(dependent: self, dependsOn: ())
553+
}
554+
```
555+
547556
## Detailed design
548557

549558
### Relation to ~Escapable
@@ -859,6 +868,42 @@ func f(arg1: borrow Array<Int>) -> borrow(arg1) Span<Int>
859868
```
860869
This was changed after we realized that there was in practice almost always a single viable semantic for any given situation, so the additional refinement seemed unnecessary.
861870

871+
### dependsOn(unchecked) to disable lifetime dependence checking
872+
873+
A `dependsOn(unchecked)` annotation could allow programmers to disable lifetime dependence checking for a function result or argument. For example, the programmer may want to compose a nonescapable result from an immortal value that isn't visible to the compiler:
874+
875+
```swift
876+
init() dependsOn(immortal) {
877+
self.value = getGlobalConstant() // 🛑 ERROR: immortal dependence on a temporary value
878+
}
879+
```
880+
881+
To avoid the error, the programmer could disable dependence checking on the function result altogether:
882+
883+
```swift
884+
init() dependsOn(unchecked) {
885+
self.value = getGlobalConstant() // OK: unchecked dependence.
886+
}
887+
```
888+
889+
This poses a few problems:
890+
891+
1. Declaring a result "unchecked" only affects checking within the function body; it doesn't affect checking in clients of the API, so really shouldn't be part of the API. In the example above, `dependsOn(immortal)` has the correct semantics at the API level.
892+
893+
2. `dependsOn(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.
894+
895+
3. The more kewords we add to `dependsOn`, the more chance they will collide with a parameter name.
896+
897+
`unsafeLifetime` is the propsed tool for disabling dependence checks. Passing `Void` as the dependence source is a reasonable way to convert a nonescaping value to an immortal value:
898+
899+
900+
```swift
901+
init() dependsOn(immortal) {
902+
self.value = getGlobalConstant() // OK: unchecked dependence.
903+
self = unsafeLifetime(dependent: self, dependsOn: ())
904+
}
905+
```
906+
862907
## Future Directions
863908

864909
### Lifetime Dependencies for Tuples

0 commit comments

Comments
 (0)