The resignID call within the initializer moved into DI, because an assignment to
the actorSystem, and thus initialization of the id, is no longer guaranteed to happen.
Thus, while we previously could model the resignation as a clean-up emitted on all
unwind paths in an initializer, now it's conditional, based on whether the id was
initialized. This is exactly what DI is designed to do, so we inject the resignation
call just before we call the identity's deinit.
The `@exclusivity(unchecked)` attribute can be used on variables to selectively disable exclusivity checking.
For completeness, also the `@exclusivity(checked)` variant is supported: it turns on exclusivity checking for specific variables if exclusivity enforcement is disabled by the command line option.
This new attribute is a missing implementation part of SE-0176 (https://github.com/apple/swift-evolution/blob/main/proposals/0176-enforce-exclusive-access-to-memory.md).
rdar://31121356
Don't crash when we're SILGen'ing accesses to globals in top-level code.
The address is found in the top-level main function because we generate
the initialization code directly. In the case when we're generating the
body of the implicit main function, the presence of the address does not
indicate that the variable is local.
Some globals, like static stored properties, are lazily initialized.
For situations where we do a direct access to that property,
we will first call a function that tries to initialize the var if needed,
before returning the address of the global to perform the direct access.
In this specific case, we were not on the right actor when invoking
that function.
fixes rdar://83411416
When trying to access a let-bound property of an actor across
a moudule boundary, the operation should be treated as async.
But, upon reaching SILGen, the compiler would crash when trying
to emit the needed hop, because the base of the element reference
was missing. This commit fixes that and adds regression coverage.
resolves rdar://81812013
Just for convenicence.
* Replace `llvm::isa_and_nonnull` with imported `isa_and_nonnull`
* Repalce some `EXPR && isa<T>(EXPR)` with `isa_and_nonnull<T>(EXPR)`
Change the code generation patterns for `async let` bindings to use an ABI based on the following
functions:
- `swift_asyncLet_begin`, which starts an `async let` child task, but which additionally
now associates the `async let` with a caller-owned buffer to receive the result of the task.
This is intended to allow the task to emplace its result in caller-owned memory, allowing the
child task to be deallocated after completion without invalidating the result buffer.
- `swift_asyncLet_get[_throwing]`, which replaces `swift_asyncLet_wait[_throwing]`. Instead of
returning a copy of the value, this entry point concerns itself with populating the local buffer.
If the buffer hasn't been populated, then it awaits completion of the task and emplaces the
result in the buffer; otherwise, it simply returns. The caller can then read the result out of
its owned memory. These entry points are intended to be used before every read from the
`async let` binding, after which point the local buffer is guaranteed to contain an initialized
value.
- `swift_asyncLet_finish`, which replaces `swift_asyncLet_end`. Unlike `_end`, this variant
is async and will suspend the parent task after cancelling the child to ensure it finishes
before cleaning up. The local buffer will also be deinitialized if necessary. This is intended
to be used on exit from an `async let` scope, to handle cleaning up the local buffer if necessary
as well as cancelling, awaiting, and deallocating the child task.
- `swift_asyncLet_consume[_throwing]`, which combines `get` and `finish`. This will await completion
of the task, leaving the result value in the result buffer (or propagating the error, if it
throws), while destroying and deallocating the child task. This is intended as an optimization
for reading `async let` variables that are read exactly once by their parent task.
To avoid an epoch break with existing swiftinterfaces and ABI clients, the old builtins and entry
points are kept intact for now, but SILGen now only generates code using the new interface.
This new interface fixes several issues with the old async let codegen, including use-after-free
crashes if the `async let` was never awaited, and the inability to read from an `async let` variable
more than once.
rdar://77855176
The fix is to implement part of SILGen that I asserted could not
happen because I couldn't formulate a situation where an access
to instance-isolated state would happen at the point in the code.
But, if a property wrapper's wrapped-value is global-actor
isolated, and is wrapping an actor instance, then it does happen.
Implementation details:
If the address is isolated to an actor instance, then we need the
base in order to perform a hop prior to starting the access,
so I just pass the base value through SILGen to the point it is
needed, since the base is available from all of the callers.
When accessing a static property isolated to a
global-actor, such as MainActor, a `hop_to_executor`
was not being emitted. This was caught by an assertion
I had left to catch such cases, but of course in release
builds this will lead to incorrect SIL, etc.
This issue revealed some other problems with how
the implementation was done for other kinds of
accesses starting from a static property, e.g.,
emitting a redundant hop for the same access.
This was fixed by modelling the actor-isolation
placed into a component as only being accessible
by consuming it from the component. This prevents
the emission of the hops more than once.
Thus, the regression test was updated to catch
unexpected hop_to_executor instructions.
Resolves rdar://78292384
Convenience initializers only contain assignments to self, but not initializations.
This case was not handled when deciding between a regular assignment and assign_by_wrapper.
https://bugs.swift.org/browse/SR-14675
rdar://78892507
Tasks shouldn't normally hog the actor context indefinitely after making a call that's bound to
that actor, since that prevents the actor from potentially taking on other jobs it needs to
be able to address. Set up SILGen so that it saves the current executor (using a new runtime
entry point) and hops back to it after every actor call, not only ones where the caller context
is also actor-bound.
The added executor hopping here also exposed a bug in the runtime implementation while processing
DefaultActor jobs, where if an actor job returned to the processing loop having already yielded
the thread back to a generic executor, we would still attempt to make the actor give up the thread
again, corrupting its state.
rdar://71905765
The strategy for implementing them is integrated with the
PathComponent infrastructure in SILGen in order to correctly
support mixtures of chained accesses and forced optionals, etc.
The actor isolation information is only piped into LValues from
the expressions that might be marked implicitly-async.
* Refactoring: replace "Destination" and the ownership qualifier by a single "Mode". This represents much better the mode how the instruction is to be lowered. NFC
* Make assign_by_wrapper printable and parseable.
* Fix lowering of the assign modes for indirect results of the init-closure: The indirect result was initialized and not assigned to. The fix is to insert a destroy_addr before calling the init closure. This fixes a memory lifetime error and/or a memory leak. Found by inspection.
* Fix an iterator-invalidation crash in RawSILInstLowering
* Add tests for lowering assign_by_wrapper.
LifetimeChecker::shouldEmitError in order to avoid incorrectly
populating EmittedErrorLocs when no error is emitted.
This fixes a few corner cases where DI would error out or crash
while assigning to a wrapped property with a nonmutating setter.
Implement SIL generation for "async let" constructs, which involves:
1. Creating a child task future at the point of declaration of the "async let",
which runs the initializer in an async closure.
2. Entering a cleanup to destroy the child task.
3. Entering a cleanup to cancel the child task.
4. Waiting for the child task when any of the variables is reference.
5. Decomposing the result of the child task to write the results into the
appropriate variables.
Implements rdar://71123479.
Add AccesssedStorage::compute and computeInScope to mirror AccessPath.
Allow recovering the begin_access for Nested storage.
Adds AccessedStorage.visitRoots().
captured local variables for the assign_by_wrapper setter.
Since assign_by_wrapper will always be re-written to initialization
if the captured local variable is uninitialized, it's unnecessary
to mark the capture as an escape. This lets us support out-of-line
initialization for local property wrappers.
```
class Generic<T> {
@objc dynamic func method() {}
}
extension Generic {
@_dynamicReplacement(for:method())
func replacement() {}
}
```
The standard mechanism of using Objective-C categories for dynamically
replacing @objc methods in generic classes does not work.
Instead we mark the native entry point as replaceable.
Because this affects all @objc methods in generic classes (whether there
is a replacement or not) by making the native entry point
`[dynamically_replaceable]` (regardless of optimization mode) we guard this by
the -enable-implicit-dynamic flag because we are late in the release cycle.
* Replace isNativeDynamic and isObjcDynamic by calls to shouldUse*Dispatch and
shouldUse*Replacement
This disambiguates between which dispatch method we should use at call
sites and how these methods should implement dynamic function
replacement.
* Don't emit the method entry for @_dynamicReplacement(for:) of generic class
methods
There is not way to call this entry point since we can't generate an
objective-c category for generic classes.
rdar://63679357
This became necessary after recent function type changes that keep
substituted generic function types abstract even after substitution to
correctly handle automatic opaque result type substitution.
Instead of performing the opaque result type substitution as part of
substituting the generic args the underlying type will now be reified as
part of looking at the parameter/return types which happens as part of
the function convention apis.
rdar://62560867
This is achieved in 3 steps:
1. CSApply detects assignments to property wrappers inside constructors, and produces an `inout` expr instead of a `load`, which it normally would because nonmutating setters take the `self` by-value. This is necessary becasue the assign_by_wrapper instruction expects an address type for its $1 operand.
2. SILGenLValue now emits the assign_by_wrapper pattern for such setters, ignoring the fact that they capture `self` by value. It also introduces an additional load instruction for the setter patrial_apply because the setter signature still expects a value and we now have an address (because of (1)).
3. DefiniteInitialization specifically ignores load instructions used to produce a `self` value for a setter referenced on assign_by_wrapper because it will be deleted by lowering anyway.
Resolves rdar://problem/60600911 and rdar://problem/52280477
GetterSetterComponent::hasPropertyWrapper() now checks for more
stuff than just whether there's a property wrapper or not.
It's therefore renamed to canRewriteSetAsPropertyWrapperInit().
When assigning to a wrapped variable in 'init()', if the property wrapper's
'wrappedValue:' parameter is an escaping autoclosure, the initializer and
setter have incompatible types -- the setter takes a value, and initializer
takes a closure returning that value.
An assign_by_wrapper with incompatible types causes SIL verification to fail.
This commit makes the SIL not use assign_by_wrapper in such cases, and use the
setter directly, resulting in a definitive initialization (DI) error instead.
struct S {
@Lazy var n: Int // Lazy.init(wrappedValue: @autoclosure ... )
init() {
n = 1 // error: 'self' used before all stored properties are initialized
}
}