The pass works by walking functions in the modules looking for mutable alloc_box
that contains a weak variable and is knowably a capture. In such a case, the
pass checks all uses of the alloc_box interprocedurally including through
closures and if provably immutable marks the box and all closure parameters as
being inferred immutable.
This change also then subsequently changes SILIsolationInfo to make it so that
such boxes are considered Sendable in a conservative manner that pattern matches
the weak reference code emission pretty closely.
The reason why I am doing this is that issue #82427 correctly tightened region
isolation checking to catch unsafe concurrent access to mutable shared
state. However, this introduced a regression for a common Swift pattern:
capturing `self` weakly in escaping closures.
The problem occurs because:
1. Weak captures are stored in heap-allocated boxes.
2. By default, these boxes are **mutable** (`var`) even if never written to after initialization
3. Mutable boxes are non-Sendable (they could be unsafely mutated from multiple threads)
4. Region isolation now correctly errors when sending non-Sendable values across isolation boundaries
This breaks code like:
```swift
@MainActor class C {
func test() {
timer { [weak self] in // Captures self in a mutable box
Task { @MainActor in
self?.update() // ERROR: sending mutable box risks data races
}
}
}
}
```
Note how even though `self` is Sendable since it is MainActor-isolated, the *box
containing* the weak reference is not Sendable because it is mutable.
With the change in this commit, we now recognize that the box can safely be
treated as Sendable since we would never write to it.
rdar://166081666