Skip to content

Commit 694d95a

Browse files
committed
SE-0459: Add handling of unsafe for for..in iteration
1 parent 7eab91d commit 694d95a

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

proposals/0458-strict-memory-safety.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,42 @@ func passUnsafe() {
411411
}
412412
```
413413

414+
### `for..in` loops
415+
416+
Swift's `for..in` loops are effectively implemented as syntactic sugar over the `Sequence` and `IteratorProtocol` protocols, where the `for..in` creates a new iterator (with `Sequence.makeIterator()`) and then calls its `next()` operation for each loop iteration. If the conformances to `Sequence` are `IteratorProtocol` is `@unsafe`, the loop will introduce a warning:
417+
418+
```swift
419+
let someUnsafeBuffer: UnsafeBufferPointer<Element> = unsafe ...
420+
for x in someBuffer { // warning: use of unsafe conformance of 'UnsafeBufferPointer' to 'Sequence'
421+
// and someBuffer has unsafe type 'UnsafeBufferPointer'
422+
// ...
423+
}
424+
```
425+
426+
Following the precedent set by [SE-0298](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0298-asyncsequence.md), which introduced effects in loops, the `unsafe` keyword that acknowledges unsafe behavior in the iteration will follow the `for`:
427+
428+
```swift
429+
let someUnsafeBuffer: UnsafeBufferPointer<Element> = unsafe ...
430+
for unsafe x in someBuffer { // still warns that someBuffer has unsafe type 'UnsafeBufferPointer'
431+
// ...
432+
}
433+
```
434+
435+
This may not be the only unsafe behavior in the `for..in` loop. For example, the expression that produces the sequence itself (via the reference to `someBuffer`) is also unsafe, so it needs to be acknowledged:
436+
437+
```swift
438+
let someUnsafeBuffer: UnsafeBufferPointer<Element> = unsafe ...
439+
for unsafe x in unsafe someBuffer {
440+
// ...
441+
}
442+
```
443+
444+
This repeated `unsafe` also occurs with the other effects: if an `async throws` function `getAsyncSequence()` produces an `AsyncSequence` whose iteration can throw, one will end up with two `try` and `await` keywords:
445+
446+
```swift
447+
for try await x in try await getAsyncSequence() { ... }
448+
```
449+
414450
### Strict safety mode and escalatable warnings
415451

416452
The strict memory safety mode can be enabled with the new compiler flag `-strict-memory-safety`.
@@ -733,6 +769,7 @@ We could introduce an optional `message` argument to the `@unsafe` attribute, wh
733769

734770
* **Revision 3 (following second review eextension)**
735771
* Do not require declarations with unsafe types in their signature to be marked `@unsafe`; it is implied. They may be marked `@safe` to indicate that they are actually safe.
772+
* Add `unsafe` for iteration via the `for..in` syntax.
736773

737774
* **Revision 2 (following first review extension)**
738775
* Specified that variables of unsafe type passed in to uses of `@safe` declarations (e.g., calls, property accesses) are not diagnosed as themselves being unsafe. This makes means that expressions like `unsafeBufferePointer.count` will be considered safe.

0 commit comments

Comments
 (0)