We were not able to use an existential as the base
of an access that strictly borrows the existential,
because SILGen's RValue emission would establish
a fresh evaluation scope just for the existential's
opening, and then copy the opened value out.
This is problematic for noncopyable existentials.
So this patch moves & adds FormalEvaluationScope's
around so they're broad enough to enable a
borrow of an existential. The idea behind this
refactoring is to establish top-level
FormalEvaluationScopes when initially creating
RValue's for Expr's in SILGen. Any more-tightly
scoped operations will already establish their own
nested scope, so this is mostly adding safe-guards.
I've limited the existentials fix to noncopyables
for now.
part of rdar://159079818
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
There's an unfortunate layering difference in the cleanup order between address-only
and loadable error values during `catch` pattern matching: for address-only values,
the value is copied into a temporary stack slot, and the stack slot is cleaned up
on exit from the pattern match, meaning the value must be moved into the error return
slot on the "no catch" case before cleanups run. But if it's a loadable value, then
we borrow it for the duration of the switch, and the borrow is released during cleanup
on exit from the pattern match, so the value must be forwarded after running cleanups.
The way the code is structured, it handles these cases properly when the convention of
the function being emitted is in sync with the fundamental properties of the error type
(when the error type is loadable and the error return is by value, or when the error
type is address-only and the error return is indirect, in other words). But when
a closure literal with a loadable error type is emitted in an argument context that
expects a function with an indirect error return, we would try to forward the loadable
error value into the error return slot while a borrow is still active on it, leading
to verifier errors. Defer forwarding the value into memory until after cleanups are
popped, fixing rdar://126576356.
A tidier solution might be to always emit the function body to use a bbarg on the
throw block to pass the error value from the body emission to the epilog when the
type is loadable, deferring the move into memory to the epilog block. This would
make the right behavior fall out of the existing implementation, but would require
a bit more invasive changes (pretty much everywhere that checks IndirectErrorReturn
would need to check a different-tracked AddressOnlyErrorType bit instead or in
addition). This change is more localized.
The runtime function `swift_willThrowTyped` takes its argument
`@in_guaranteed`. In opaque values SIL, that's passed directly. Don't
store non-address errors before passing them to the function.
We do this by pushing the conversion down to the emission of the
closure expression, then teaching closure emission to apply the isolation
to the closure. Ideally, we combine the isolation along with the rest of
the conversion peephole, but if necessary, we make sure we emit the
isolation.
`swift_willThrow` is called with an error right before it is thrown.
This existing entrypoint requires an already-boxed error existential;
with typed errors, we don't have the error existential on hand, so we
would need to allocate the box to throw a typed error. That's not okay.
Introduce a new `swift_willThrowTypedImpl` entry point into the runtime
that will first check for the presence of an error handler and, if one
is present, box the error to provide to the error handler. This
maintains the no-allocations path for typed errors while still
allowing existing error handlers to work.
This new entrypoint isn't available on older Swift runtimes, so create
a back-deployable shim called by the compiler. On new-enough platforms,
this will call through to `swift_willThrowTypedImpl`. On older
platforms, we drop the error and don't call the registered will-throw
handler at all. This is a compromise that avoids boxing when throwing
typed errors, at the cost of a slightly different experience for this
new feature on older runtimes.
Fixes rdar://119828459.
This models the conversion from an uninhabited
value to any type, and allows us to get rid of
a couple of places where we'd attempt to drop
the return statement instead.
Correctly determining the DeclContext needed for an
ExplicitCaughtTypeRequest is tricky for a number of callers, and
mistakes here can easily lead to redundant computation of the caught
type, redundant diagnostics, etc.
Instead, put a `DeclContext` into `DoCatchStmt`, because that's the
only catch node that needs a `DeclContext` but does not have one.
During the review of SE-0413, typed throws, the notion of a `do throws`
syntax for `do..catch` blocks came up. Implement that syntax and
semantics, as a way to explicitly specify the type of error that is
thrown from the `do` body in `do..catch` statement.
This peephole optimization in SILGen requires us to use the thrown
error for the context of a closure type rather than the thrown error
for the closure AST node itself.
Introduce SILGen support for reabstractions thunks that change the
error, between indirect and direct errors as well as conversions
amongst error types (e.g., from concrete to `any Error`).
The type that is caught by the `catch` clauses in a `do..catch` block is
determined by the union of the thrown error types in the `do`
statement. Compute this type and use it for the catch clauses. This
does several things at once:
* Makes the type of the implicit `error` be a more-specific concrete
type when all throwing sites throw that same type
* When there's a concrete type for the error, one can use patterns
like `.cancelled`
* Check that this error type can be rethrown in the current context
* Verify that SIL generation involving do..catch with typed errors
doesn't require any existentials.
Lower the thrown error type into the SIL function type. This requires
very little code because the thrown error type was already modeled as
a SILResultInfo, which carries type information. Note that this
lowering does not yet account for error types that need to passed
indirectly, but we will need to do so for (e.g.) using resilient error
types.
Teach a few places in SIL generation not to assume that thrown types
are always the existential error type, which primarily comes down to
ensuring that rethrow epilogues have the thrown type of the
corresponding function or closure.
Teach throw emission to implicitly box concrete thrown errors in the
error existential when needed to satisfy the throw destination. This
is a temporary solution that helps translate typed throws into untyped
throws, but it should be replaced by a better modeling within the AST
of the points at which thrown errors are converted.
If we have an uninhabited branch, emit it as an
ignored expr followed by an unreachable.
Previously we would omit the unreachable and rely
on the SILOptimizer to infer it, but we ought to
just emit it here. Also check `isUninhabited()`
instead of `isStructurallyUninhabited` since this
better matches what we allow in Sema. For tuples
of uninhabited values, we can do a regular
initialization without issue.
These allow multi-statement `if`/`switch` expression
branches that can produce a value at the end by
saying `then <expr>`. This is gated behind
`-enable-experimental-feature ThenStatements`
pending evolution discussion.
This is a futile attempt to discourage future use of getType() by
giving it a "scary" name.
We want people to use getInterfaceType() like with the other decl kinds.
`Initialization` is stateful and not meant to be emitted into multiple times across different contexts.
If emitting into an initialization causes it to be split or aborted, that will carry over into
further uses of the initialization. This was happening during `if` and `switch` expression
emission, leading to miscompiles or compiler crashes. Fix this by saving only the buffer when
we prepare emission for a statement expression, and creating the initialization in the scope
where the expression for a branch actually gets emitted. Fixes rdar://112213253.
variadic-tuple results. There are three parts to this.
First, fix the emission of indirect result parameters to do a
proper abstraction-pattern-aware traversal of tuple patterns.
There was a FIXME here and everything.
Second, fix the computation of substituted abstraction
patterns to properly handle vanishing tuples. The previous code
was recursively destructuring tuples, but only when it saw a
tuple as the substituted type, which of course breaks on vanishing
tuples.
Finally, fix the emission of returns into vanishing tuple
patterns by allowing the code to not produce a TupleInitialization
when the tuple pattern vanishes. We should always get a singleton
element initializer in this case.
Fixes rdar://109843932, plus a closely-related test case for
vanishing tuples that I added myself.
drop_deinit ultimately only affects the semantics of its
destroy_value. Avoid generating releases for destroys in which the
deinit has been dropped. Instead, individually release the members.