The `projection` flag indicates that `index_addr` projects an element address from an array base address, as opposed to being used for general pointer arithmetic.
When this flag is set, the result address can only reach the single element at the given index — it is not possible to chain multiple `index_addr` instructions to reach other array elements from the result.
Without this flag, the result may be used as the base of another `index_addr`, allowing arithmetic across element boundaries (e.g. an `index_addr` with index 1 followed by an `index_addr` with index 2 reaches the element at offset 3).
An `index_addr [projection]` is mandatory to go from an array base address to an element - even if it's the first element, i.e. the index is zero.
This means that the optimizer must not remove `index_addr [projection]` with a zero index.
Key paths rooted at a protocol metatype could slip through the normal metatype checks and reach SILGen when they referenced a static property like \.foo. That left the compiler in the wrong state and could crash instead of producing a targeted error.
Teach constraint fixing to reject static member references through protocol metatype roots, add a dedicated diagnostic for that case, and consistently treat metatype bases as AnyMetatypeType during type checking and SILGen.
Apply the expected isolation before attempting to reabstraction.
This is the same as `@isolated(any)` and the common logic has
been factored in a closure.
Such closures have a specialized direct conversion to actual `nonisolated(nonsending)`
type. They gain an implicit isolation parameter that isn't marked as "isolated"
and gets ignored in the prolog.
We cannot use spare bits or other overlapping storage layout tricks with fundamentally
address-only enums, and we can take advantage of this to do borrowing switches or other
in-place projections without copying the value. However, for resilient enums, the
implementation may use spare bit packing, but the type must be handled address-only
outside of its defining module, and we didn't have a way to express that with
borrowing switch. Optimization passes have also been running into problems with the
complexity that we were using `unchecked_take_enum_data_addr` sometimes as a pure
operation. This patch splits the instruction into three:
- `unchecked_inplace_enum_data_addr` represents a nondestructive in-place enum
projection. It is only allowed for enums whose projection operation is
nondestructive.
- `unchecked_take_enum_data_addr` represents a destructive enum projection,
invalidating the enum and leaving the payload to be further consumed.
This matches the current instruction's semantics.
- `unchecked_borrow_enum_data_addr` represents a borrowing enum projection.
The instruction takes a second operand for "scratch" space, which the
enum representation may be copied into in order to avoid invalidating the
enum value, so the result is dependent on the lifetime of both the
original enum and the scratch buffer. This allows for borrowing switches
over resilient enums.
`unchecked_borrow_enum_data_addr` is implemented by taking advantage of the
"address-only enums can't do spare bit optimization" property at runtime.
We inspect the operand type's bitwise-borrowability from its metadata. If
the type is bitwise-borrowable, then we are allowed to bitwise-copy the
enum to the scratch space and apply the projection to the scratch space,
preserving the original value. If the type is not bitwise-borrowable, then
we cannot use spare bit optimization in its layout, so we apply the
projection in-place.
Fixes rdar://174952822.
Prevents situations when actor isolation ends up not being set
un-intentionally i.e. when cloning, specializating, or creating
thunks.
The thunks get `unspecified` isolation at the moment.
This commit fixes two issues:
1. When emitting an IgnoredRead LValue, we were emitting an access to the
LValue, closing its formal evaluation scope, and then placing the
ignored_use. This is incorrect since LValue assumes that it can produce borrowed
values for an IgnoredRead. If we attempt to use an ignored_use on those, we will
get a use after free since the borrowed value's lifetime has eneded. I changed
LValue's emission so that we insert the ignored_use inside of LValue within the
formal evaluation scope.
2. After some thought, I realized that the /real/ reason that this is even
possible is that we return RValues for IgnoredRead ignoring that it is possibly
unsafe to use it. Rather than do that, I changed LValue so that if an
IgnoredRead is used, an empty RValue is returned enforcing at compile time that
we can never make this same mistake. If a user actually wants to use the
resulting RValue, they should use a different SGFAccessKind that guarantees a
valid value. To do this though, I found that there was an additional case
involving force value exprs where were doing the same incorrect thing with
IgnoredRead but just had gotten lucky for a long time. To fix that, I added a
new way to just add the force value expr as an LValue component so that the
force value expr happens inside the LValue machinery instead of outside it.
rdar://173152507
Previously we would crash on this pattern:
```swift
let x: Never
switch x {}
```
This appears to be due to the fact that the switch over the uninhabited
value did not result in any instructions DI considers a use being
produced. This change adds special handling of this case so that we
now emit a load of the value so DI correctly diagnoses the use before
init.
ForEach support for Borrowing sequence
For testing purposes, this commit includes _BorrowingSequence and _BorrowingIterator protocols, with conformance for Span and InlineArray.
Replace the three-stage conversion approach that uses intermediate variables
with a simpler switch-based flow that directly converts based on source type
representation and reuses initial values to unobfuscate what data is being used
where. This eliminates control-dependent logic and makes the conversion path
immediately clear from the case structure and the variable usage.
These conversions are artificial conversions inserted by Sema since isolation is
not represented on interface types. We previously looked though:
1. A single conversion that added nonisolated(nonsending).
2. A two level conversion where the first conversion added Sendable and the
second added nonisolated(nonsending).
In this case, Sema is generating a single conversion that combines the Sendable
and isolation conversion.
To be consistent, I also updated the code that involved conversion from
execution caller to global actor as well in case we hit the same case there.
https://github.com/swiftlang/swift/issues/83812
rdar://158685169
We were creating the JumpDests too early, so lowering a 'break' or 'continue'
statement would perform cleanups that were recorded while evaluating the
pack expansion expression, which would cause SIL verifier errors and
runtime crashes.
- Fixes https://github.com/swiftlang/swift/issues/78598
- Fixes rdar://131847933