This PR is another attempt at landing #76903. The changes compared to
the original PR:
* Instead of increasing the size of SILDeclRef, store the necessary type
information in a side channel using withClosureTypeInfo.
* Rely on SGFContext to get the right ClangType
* Extend BridgingConversion with an AbstractionPattern to store the
original clang type.
* The PR above introduced a crash during indexing system modules that
references foreign types coming from modules imported as
implementation only. These entities are implementation details so they
do not need to be included during serialization. This PR adds a test
and adds logic to exclude such clang types in the serialization
process.
rdar://131321096&141786724
Revisit the optimization that provides a fast path for instances of
`NSError` when erasing the `Error` type in `emitExistentialErasure`. It
generated references to `NSError` when the `Foundation` module was
loaded, no matter how it was imported. This lead to deserialization
failures at reading the swiftmodule when that reference was added to
inlinable code while `Foundation` was not a public dependency.
Fix this crash by limiting the optimization to all non-inlinable code
and only inlinable code from a module with a public dependency on
`Foundation`. This is the similar check we apply to user written
inlinable code, however here we use the module-wide dependency instead
of per file imports.
rdar://142438679
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)
Like `?` or property access, `x!` can be borrowing, consuming, or mutated
through depending on the use site and the ownership of the base value.
Alter SILGen to emit `x!` as a borrowing operation when the result is only
used as a borrow. Fix the move-only checker not to treat the unreachable
branch as a dead path for values and try to destroy the value unnecessarily
and possibly out-of-order with cleanups on the value. Fixes rdar://127459955.
When erasing a pseudogeneric value in SILGen, we actually treat
the value as if it had the type `any AnyObject`, while in Sema,
it's an archetype. This requires SILGen to look up conformances
again instead of using the ones in the ErasureExpr.
I'm not sure there's any way to test this right now. We don't naturally
emit multiple function conversions on a single operand, and the only way
to get a similar effect is to coerce, which interrupts the application of
`@_inheritActorContext`. So I think this is dead code until we add closure
isolation controls, and even then it might be dead unless we allow coercion
of isolated closures, which maybe we won't. But it's the right thing to do
in the abstract, and I was thinking of it now.
This allows us to propagate abstraction patterns from optional parameters
all the way to closure emission, which optimizes some code patterns but
(more importantly) propagates our knowledge that we're converting to an
`@isolated(any)` function type down to closure emission, allowing us to
set the isolation correctly.
There are still some conversion cases missing --- if we can't combine
conversions for whatever reason, we should at least shift our knowledge
that we need to produce an `@isolated(any)` type down, the same way that
we shift it when emitting a closure that we can't directly emit in the
target abstraction pattern. But this completes the obvious cases of
peepholing for closure emission.
a closure expression, then don't actually do it. The long term plan is
to actually do this, which should just be a matter of taking some of the
code out of reabstraction thunk emission and using it in prolog/epilog/return
emission. In the short term, the goal is just to get the conversion
information down to the closure emitter so that we can see that we're
erasing into an `@isolated(any)` type and then actually erase the
closure's isolation properly instead of relying on type-based erasure,
which can't handle parameter/capture isolation correctly.
This generates significantly better code directly out of SILGen, at
the cost of having to reimplement a little bit of the argument-emission
logic to handle default arguments. But it also neatly sidesteps the
problems we have with splitting tuple RValues when the tuple contains
a pack expansion, which will require some significant surgery to RValue
to fix. That, in turn, fixes rdar://121489308.
Reformatting everything now that we have `llvm` namespaces. I've
separated this from the main commit to help manage merge-conflicts and
for making it a bit easier to read the mega-patch.
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".
I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
Whenever we want to forward to a +1 value but don't need to destroy
the original memory, use isPlusOneOrTrivial.
This follows the existing naming scheme.
Fixes rdar://108001491 (SIL verification failed: Found mutating or
consuming use of an in_guaranteed parameter?!:
!ImmutableAddressUseVerifier().isMutatingOrConsuming(fArg))
This required quite a bit of infrastructure for emitting this kind of
tuple expression, although I'm not going to claim they really work yet;
in particular, I know the RValue constructor is going to try to explode
them, which it really shouldn't.
It also doesn't include the caller side of returns, for which I'll need
to teach ResultPlan to do the new abstraction-pattern walk. But that's
next.
The callers to ConversionInitialization::tryPeephole assume that, if the conversion peephole
succeeded, that the peepholed result was fully emitted into the initialization. However, if
the ConversionInitialization sat on top of an in-memory initialization, then tryPeephole would
only set the value of the ConversionInitialization, without forwarding the value into the underlying
initialization, causing code generation to proceed leaving the underlying memory uninitialized.
This problem becomes exposed now when literal closures are emitted with a return value that is
indirectly returned and also reabstracted, and the return expression undergoes a ping-pong reabstraction
pair: we see through the conversions and peephole away the reabstractions, but fail to emplace the
result in the indirect return slot.
Fixes rdar://92654098
Literal closures are only ever directly referenced in the context of the expression they're written in,
so it's wasteful to emit them at their fully-substituted calling convention and then reabstract them if
they're passed directly to a generic function. Avoid this by saving the abstraction pattern of the context
before emitting the closure, and then lowering its main entry point's calling convention at that
level of abstraction. Generalize some of the prolog/epilog code to handle converting arguments and returns
to the correct representation for a different abstraction level.
Use APIs for creating terminator results that handle forwarding
ownership consistently.
Add ManagedValue::forForwardedRValue(SILValue) to handle cleanups
consistently based on ownership forwarding.
Add SILGenBuilder::createForwardedTermResult(SILType type) for
creating termator results with the correct ownership and cleanups.
Add SILGenBuilder::createTermResult(SILType type, ValueOwnershipKind
ownership) that handles cleanup based on terminator result ownership.
Add SILGenBuilder::createOptionalSomeResult(SwitchEnumInst) so a lot
of code doesn't need to deal with unwrapping Optional types,
terminator results, and ownership rules.
Replace the existing "phi" APIs with a single
SILGenBuilder::createPhi(SILType, ValueOwnershipKind) that handles
cleanup based on phi ownership.
Phis and terminator results are fundamentally different and need to be handled differently everywhere. Remove the confusion where terminator results were generated with a "phi argument" API.
Literal closures are only ever directly referenced in the context of the expression they're written in,
so it's wasteful to emit them at their fully-substituted calling convention and then reabstract them if
they're passed directly to a generic function. Avoid this by saving the abstraction pattern of the context
before emitting the closure, and then lowering its main entry point's calling convention at that
level of abstraction. Generalize some of the prolog/epilog code to handle converting arguments and returns
to the correct representation for a different abstraction level.
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)`
Literal closures are only ever directly referenced in the context of the expression they're written in,
so it's wasteful to emit them at their fully-substituted calling convention and then reabstract them if
they're passed directly to a generic function. Avoid this by saving the abstraction pattern of the context
before emitting the closure, and then lowering its main entry point's calling convention at that
level of abstraction. Generalize some of the prolog/epilog code to handle converting arguments and returns
to the correct representation for a different abstraction level.
This makes it easier to understand conceptually why a ValueOwnershipKind with
Any ownership is invalid and also allowed me to explicitly document the lattice
that relates ownership constraints/value ownership kinds.
This means that it can only have a guaranteed object as an operandand that we
validate that all uses of the result address of open_existential_box occur only
within the lifetime of said object's borrow scope.
This fixes an immediate bug with subst-to-orig conversion of
parameter functions that I'm surprised isn't otherwise tested.
More importantly, it preserves valuable information that should
let us handle a much wider variety of variant representations
that aren't necessarily expressed in the AbstractionPattern.