SILGen: Bitcast indirect returns that differ only in concurrency annotations.

A call to a `@preconcurrency` function goes through a function conversion
that removes `Sendable` from existentials among other things. Implement
support for this by bitcasting indirect return slots whose type differs
from the formal indirect return type in concurrency markings only.

Fixes rdar://154240007
This commit is contained in:
Joe Groff
2025-07-08 17:02:15 -07:00
parent 6e8287c29e
commit 8ac81dc755
3 changed files with 30 additions and 7 deletions

View File

@@ -754,6 +754,13 @@ public:
SILType subst(SILModule &M, SubstitutionMap subs,
TypeExpansionContext context) const;
/// Strip concurrency annotations from the representation type.
SILType stripConcurrency(bool recursive, bool dropGlobalActor) {
auto strippedASTTy = getASTType()->stripConcurrency(recursive, dropGlobalActor);
return SILType::getPrimitiveType(strippedASTTy->getCanonicalType(),
getCategory());
}
/// Return true if this type references a "ref" type that has a single pointer
/// representation. Class existentials do not always qualify.
bool isHeapObjectReferenceType() const;

View File

@@ -1966,15 +1966,21 @@ static void emitRawApply(SILGenFunction &SGF,
SmallVector<SILValue, 4> argValues;
// Add the buffers for the indirect results if needed.
#ifndef NDEBUG
assert(indirectResultAddrs.size() == substFnConv.getNumIndirectSILResults());
unsigned resultIdx = 0;
for (auto indResultTy :
substFnConv.getIndirectSILResultTypes(SGF.getTypeExpansionContext())) {
assert(indResultTy == indirectResultAddrs[resultIdx++]->getType());
for (auto indResultTy : substFnConv.getIndirectSILResultTypes(SGF.getTypeExpansionContext())) {
auto indResultAddr = indirectResultAddrs[resultIdx++];
if (indResultAddr->getType() != indResultTy) {
// Bitcast away differences in Sendable, global actor, etc.
if (indResultAddr->getType().stripConcurrency(/*recursive*/ true, /*dropGlobalActor*/ true)
== indResultTy.stripConcurrency(/*recursive*/ true, /*dropGlobalActor*/ true)) {
indResultAddr = SGF.B.createUncheckedAddrCast(loc, indResultAddr, indResultTy);
}
}
assert(indResultTy == indResultAddr->getType());
argValues.push_back(indResultAddr);
}
#endif
argValues.append(indirectResultAddrs.begin(), indirectResultAddrs.end());
assert(!!indirectErrorAddr == substFnConv.hasIndirectSILErrorResults());
if (indirectErrorAddr)

View File

@@ -0,0 +1,10 @@
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
@preconcurrency
func test() -> (any Sendable)? { nil }
// CHECK-LABEL: sil {{.*}} @$s{{.*}}callWithPreconcurrency
func callWithPreconcurrency() {
// CHECK: unchecked_addr_cast {{.*}} to $*Optional<any Sendable>
let x = test()
}