As with the lexical flag, when creating an alloc_stack corresponding to
an alloc_box, transfer the var_decl flag from any begin_borrow users of
the box.
We've been building up this exponential explosion of task-creation
builtins because it's not currently possible to overload builtins.
As long as all of the operands are scalar, though, it's pretty easy
to peephole optional injections in IRGen, which means we can at
least just use a single builtin in SIL and then break it apart in
IRGen to decide which options to set.
I also eliminated the metadata argument, which can easily be recreated
from the substitutions. I also added proper verification for the builtin,
which required (1) getting `@Sendable` right more consistently and (2)
updating a bunch of tests checking for things that are not actually
valid, like passing a function that returns an Int directly.
We didn't catch the case where a function returns a tuple where at least one of the tuple elements is returned as `owned`.
In such a case the apply must not be cse'd.
Fixes a miscompile which results in an over-release.
rdar://121597250
I am doing this since region based isolation hit the same issue that the move
checker did. So it makes sense to refactor the functionality into its own pass
and move it into a helper pass that runs before both.
It is very conservative and only stubifies functions that the specialization
passes explicitly mark as this being ok to be done to.
For years, optimizer engineers have been hitting a common bug caused by passes
assuming all SILValues have a parent function only to be surprised by SILUndef.
Generally we see SILUndef not that often so we see this come up later in
testing. This patch eliminates that problem by making SILUndef uniqued at the
function level instead of the module level. This ensures that it makes sense for
SILUndef to have a parent function, eliminating this possibility since we can
define an API to get its parent function.
rdar://123484595
Relax some existing pattern matches and add some unhandled instructions to the
walkers so that borrowing switches over address-only enums are properly analyzed
for incorrect consumption. Add a `[strict]` flag to `mark_unresolved_move_only_value`
to indicate a borrow access that should remain a borrow access even if the subject
is later stack-promoted from a box.
Mem2Reg may materialize the unique instance of empty types when
promoting an address of that empty type. Previously, it was required
that the top-most type in the aggregate be empty. This failed to handle
the case where a projection of empty type from a non-empty aggregate was
promoted.
For example:
```
%addr = alloc_stack $((), C)
%empty_addr = tuple_element_addr $addr : $*((), C), 0
%addr = load %empty_addr : $*()
```
where `C` is some non-empty type.
Here, that case is handled by using `undef` for each non-empty field in
the projected-from aggregate.
In the example,
```
%empty = tuple ()
%tuple = tuple (%empty : $(), undef : $C)
%empty_again = tuple_extract %tuple : $((), C), 0
```
rdar://122417297
In preparation for inserting mark_dependence instructions for lifetime
dependencies early, immediately after SILGen. That will simplify the
implementation of borrowed arguments.
Marking them unresolved is needed to make OSSA verification
conservative until lifetime dependence diagnostics runs.
Previously, `visitProductLeafAccessPathNodes` required its caller to
provide both an `AccessPath` `path` and an `SILValue` `address` which
satisfied `path == AccessPath::compute(address)` to force the caller to
handle the case of an invalid `AccessPath`. Now, instead, it computes
the value itself and returns false if it's invalid.
It could be tweaked to also return false if the provided lambda returned
false but that would make the only currently extant callers less
pleasant and also would not be sufficient in the case of caller who
wanted to distinguish between an invalid `AccessPath` and a particular
leaf visit returning false.
It's better to ask SILType if it is MoveOnly than go to the AST type and
ask if it is noncopyable, because some types in SIL do not have a
well-defined notion of conformance in the AST.
When an actual instance of a distributed actor is on the local node, it is
has the capabilities of `Actor`. This isn't expressible directly in the type
system, because not all `DistributedActor`s are `Actor`s, nor is the
opposite true.
Instead, provide an API `DistributedActor.asLocalActor` that can only
be executed when the distributed actor is known to be local (because
this API is not itself `distributed`), and produces an existential
`any Actor` referencing that actor. The resulting existential value
carries with it a special witness table that adapts any type
conforming to the DistributedActor protocol into a type that conforms
to the Actor protocol. It is "as if" one had written something like this:
extension DistributedActor: Actor { }
which, of course, is not permitted in the language. Nonetheless, we
lovingly craft such a witness table:
* The "type" being extended is represented as an extension context,
rather than as a type context. This hasn't been done before, all Swift
runtimes support it uniformly.
* A special witness is provided in the Distributed library to implement
the `Actor.unownedExecutor` operation. This witness back-deploys to the
Swift version were distributed actors were introduced (5.7). On Swift
5.9 runtimes (and newer), it will use
`DistributedActor.unownedExecutor` to support custom executors.
* The conformance of `Self: DistributedActor` is represented as a
conditional requirement, which gets satisfied by the witness table
that makes the type a `DistributedActor`. This makes the special
witness work.
* The witness table is *not* visible via any of the normal runtime
lookup tables, because doing so would allow any
`DistributedActor`-conforming type to conform to `Actor`, which would
break the safety model.
* The witness table is emitted on demand in any client that needs it.
In back-deployment configurations, there may be several witness tables
for the same concrete distributed actor conforming to `Actor`.
However, this duplication can only be observed under fairly extreme
circumstances (where one is opening the returned existential and
instantiating generic types with the distributed actor type as an
`Actor`, then performing dynamic type equivalence checks), and will
not be present with a new Swift runtime.
All of these tricks together mean that we need no runtime changes, and
`asLocalActor` back-deploys as far as distributed actors, allowing it's
use in `#isolation` and the async for...in loop.
Concurrency runtime expects discarding task operation entrypoint
function not to have result type, but the current SILGen
implementation generates reabstraction thunk to convert `() -> Void`
to `() -> T` for the operation function.
Since the `T` is always `Void` for DiscardingTG, the mismatch of result
type expectation does not cause any problem on most platforms, but the
signature mismatch causes a problem on WebAssembly.
This patch introduces new builtin operations for creating discarding
task, which always takes `() -> Void` as the operation function type.
The dependent 'value' may be marked 'nonescaping', which guarantees that the
lifetime dependence is statically enforceable. In this case, the compiler
must be able to follow all values forwarded from the dependent 'value', and
recognize all final (non-forwarded, non-escaping) use points. This implies
that `findPointerEscape` is false. A diagnostic pass checks that the
incoming SIL to verify that these use points are all initially within the
'base' lifetime. Regular 'mark_dependence' semantics ensure that
optimizations cannot violate the lifetime dependence after diagnostics.