Skip to content

Commit 0042201

Browse files
authored
Merge pull request #69700 from DougGregor/typed-throws-reabstraction-thunks
[Typed throws] Implement reabstraction thunks that change the error
2 parents 16cbb76 + d031296 commit 0042201

File tree

14 files changed

+378
-74
lines changed

14 files changed

+378
-74
lines changed

include/swift/SIL/SILFunctionConventions.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,7 @@ class SILFunctionConventions {
216216
return getSILType(funcTy->getErrorResult(), context);
217217
}
218218

219-
bool isTypedError() const {
220-
return !funcTy->getErrorResult()
221-
.getInterfaceType()->isExistentialWithError();
222-
}
219+
bool isTypedError() const;
223220

224221
/// Returns an array of result info.
225222
/// Provides convenient access to the underlying SILFunctionType.

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,8 +1279,15 @@ AbstractionPattern::getFunctionThrownErrorType(
12791279
(*optErrorType)->getCanonicalType());
12801280
}
12811281

1282-
if (!optErrorType)
1283-
optErrorType = ctx.getErrorExistentialType();
1282+
if (!optErrorType) {
1283+
Type origErrorSubstType =
1284+
optOrigErrorType->getType()
1285+
.subst(optOrigErrorType->getGenericSubstitutions());
1286+
if (origErrorSubstType->isNever())
1287+
optErrorType = ctx.getNeverType();
1288+
else
1289+
optErrorType = ctx.getErrorExistentialType();
1290+
}
12841291

12851292
return std::make_pair(*optOrigErrorType,
12861293
(*optErrorType)->getCanonicalType());

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4943,3 +4943,10 @@ CanSILFunctionType SILFunction::getLoweredFunctionTypeInContext(
49434943
auto funTy = M.Types.getLoweredType(origFunTy , context);
49444944
return cast<SILFunctionType>(funTy.getASTType());
49454945
}
4946+
4947+
bool SILFunctionConventions::isTypedError() const {
4948+
return !funcTy->getErrorResult()
4949+
.getInterfaceType()->isEqual(
4950+
funcTy->getASTContext().getErrorExistentialType()) ||
4951+
hasIndirectSILErrorResults();
4952+
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6087,7 +6087,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
60876087
}
60886088

60896089
if (fnConv.hasIndirectSILErrorResults()) {
6090-
assert(fnConv.isTypedError());
60916090
auto errorResult = fnConv.getSILErrorType(F.getTypeExpansionContext());
60926091
check("indirect error result", errorResult);
60936092
}

lib/SILGen/SILGenApply.cpp

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5716,7 +5716,6 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
57165716
CanSILFunctionType silFnType = substFnType.castTo<SILFunctionType>();
57175717
SILFunctionConventions fnConv(silFnType, SGM.M);
57185718
SILType resultType = fnConv.getSILResultType(getTypeExpansionContext());
5719-
57205719
if (!silFnType->hasErrorResult()) {
57215720
return B.createApply(loc, fn, subs, args);
57225721
}
@@ -5729,19 +5728,64 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
57295728
{
57305729
B.emitBlock(errorBB);
57315730

5732-
SILValue error;
5733-
bool indirectError = fnConv.hasIndirectSILErrorResults();
5734-
5735-
if (!indirectError) {
5736-
error = errorBB->createPhiArgument(
5731+
// Grab the inner error.
5732+
SILValue innerError;
5733+
bool hasInnerIndirectError = fnConv.hasIndirectSILErrorResults();
5734+
if (!hasInnerIndirectError) {
5735+
innerError = errorBB->createPhiArgument(
57375736
fnConv.getSILErrorType(getTypeExpansionContext()),
57385737
OwnershipKind::Owned);
5738+
} else {
5739+
// FIXME: This probably belongs on SILFunctionConventions.
5740+
innerError = args[fnConv.getNumIndirectSILResults()];
5741+
}
5742+
5743+
// Convert to the outer error, if we need to.
5744+
SILValue outerError;
5745+
SILType innerErrorType = innerError->getType().getObjectType();
5746+
SILType outerErrorType = F.mapTypeIntoContext(
5747+
F.getConventions().getSILErrorType(getTypeExpansionContext()));
5748+
if (IndirectErrorResult && IndirectErrorResult == innerError) {
5749+
// Fast path: we aliased the indirect error result slot because both are
5750+
// indirect and the types matched, so we are done.
5751+
} else if (!IndirectErrorResult && !hasInnerIndirectError &&
5752+
innerErrorType == outerErrorType) {
5753+
// Fast path: both have a direct error result and the types line up, so
5754+
// rethrow the inner error.
5755+
outerError = innerError;
5756+
} else {
5757+
// The error requires some kind of translation.
5758+
5759+
// Load the inner error, if it was returned indirectly.
5760+
if (innerError->getType().isAddress()) {
5761+
innerError = emitLoad(loc, innerError, getTypeLowering(innerErrorType),
5762+
SGFContext(), IsTake).forward(*this);
5763+
}
5764+
5765+
// If we need to convert the error type, do so now.
5766+
if (innerErrorType != outerErrorType) {
5767+
auto conversion = Conversion::getOrigToSubst(
5768+
AbstractionPattern(innerErrorType.getASTType()),
5769+
outerErrorType.getASTType(),
5770+
outerErrorType);
5771+
outerError = emitConvertedRValue(loc, conversion, SGFContext(),
5772+
[innerError](SILGenFunction &SGF, SILLocation loc, SGFContext C) {
5773+
return ManagedValue::forForwardedRValue(SGF, innerError);
5774+
}).forward(*this);
5775+
}
5776+
5777+
// If the outer error is returned indirectly, copy from the converted
5778+
// inner error to the outer error slot.
5779+
if (IndirectErrorResult) {
5780+
emitSemanticStore(loc, outerError, IndirectErrorResult,
5781+
getTypeLowering(outerErrorType), IsInitialization);
5782+
}
57395783
}
57405784

57415785
Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind);
57425786

5743-
if (!indirectError)
5744-
B.createThrow(loc, error);
5787+
if (!IndirectErrorResult)
5788+
B.createThrow(loc, outerError);
57455789
else
57465790
B.createThrowAddr(loc);
57475791
}

lib/SILGen/SILGenFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2273,7 +2273,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
22732273
/// Used for emitting SILArguments of bare functions, such as thunks.
22742274
void collectThunkParams(
22752275
SILLocation loc, SmallVectorImpl<ManagedValue> &params,
2276-
SmallVectorImpl<ManagedValue> *indirectResultParams = nullptr);
2276+
SmallVectorImpl<ManagedValue> *indirectResultParams = nullptr,
2277+
SmallVectorImpl<ManagedValue> *indirectErrorParams = nullptr);
22772278

22782279
/// Build the type of a function transformation thunk.
22792280
CanSILFunctionType buildThunkType(CanSILFunctionType &sourceType,

lib/SILGen/SILGenPoly.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,8 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple,
850850

851851
void SILGenFunction::collectThunkParams(
852852
SILLocation loc, SmallVectorImpl<ManagedValue> &params,
853-
SmallVectorImpl<ManagedValue> *indirectResults) {
853+
SmallVectorImpl<ManagedValue> *indirectResults,
854+
SmallVectorImpl<ManagedValue> *indirectErrors) {
854855
// Add the indirect results.
855856
for (auto resultTy : F.getConventions().getIndirectSILResultTypes(
856857
getTypeExpansionContext())) {
@@ -864,6 +865,19 @@ void SILGenFunction::collectThunkParams(
864865
indirectResults->push_back(ManagedValue::forLValue(arg));
865866
}
866867

868+
if (F.getConventions().hasIndirectSILErrorResults()) {
869+
assert(F.getConventions().getNumIndirectSILErrorResults() == 1);
870+
auto paramTy = F.mapTypeIntoContext(
871+
F.getConventions().getSILErrorType(getTypeExpansionContext()));
872+
auto inContextParamTy = F.getLoweredType(paramTy.getASTType())
873+
.getCategoryType(paramTy.getCategory());
874+
SILArgument *arg = F.begin()->createFunctionArgument(inContextParamTy);
875+
if (indirectErrors)
876+
indirectErrors->push_back(ManagedValue::forLValue(arg));
877+
878+
IndirectErrorResult = arg;
879+
}
880+
867881
// Add the parameters.
868882
auto paramTypes = F.getLoweredFunctionType()->getParameters();
869883
for (auto param : paramTypes) {
@@ -4831,6 +4845,31 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
48314845
outputSubstType.getResult(),
48324846
fnType, thunkType);
48334847

4848+
// If the function we're calling has as indirect error result, create an
4849+
// argument for it.
4850+
SILValue innerIndirectErrorAddr;
4851+
if (auto innerError = fnType->getOptionalErrorResult()) {
4852+
if (innerError->getConvention() == ResultConvention::Indirect) {
4853+
auto loweredErrorResultType = SGF.getSILType(*innerError, fnType);
4854+
if (SGF.IndirectErrorResult &&
4855+
SGF.IndirectErrorResult->getType().getObjectType()
4856+
== loweredErrorResultType) {
4857+
// The type of the indirect error is the same for both the inner
4858+
// function and the thunk, so we can re-use the indirect error slot.
4859+
innerIndirectErrorAddr = SGF.IndirectErrorResult;
4860+
} else {
4861+
// The type of the indirect error in the inner function differs from
4862+
// that of the thunk, or the thunk has a direct error, so allocate a
4863+
// stack location for the inner indirect error.
4864+
innerIndirectErrorAddr =
4865+
SGF.B.createAllocStack(loc, loweredErrorResultType);
4866+
SGF.enterDeallocStackCleanup(innerIndirectErrorAddr);
4867+
}
4868+
4869+
argValues.push_back(innerIndirectErrorAddr);
4870+
}
4871+
}
4872+
48344873
// Add the rest of the arguments.
48354874
forwardFunctionArguments(SGF, loc, fnType, args, argValues);
48364875

lib/SILGen/SILGenProlog.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,17 +1813,22 @@ uint16_t SILGenFunction::emitBasicProlog(
18131813
emitIndirectResultParameters(*this, resultType, origResultType, DC);
18141814

18151815
llvm::Optional<AbstractionPattern> origErrorType;
1816-
if (errorType) {
1817-
if (origClosureType &&
1818-
!origClosureType->isTypeParameterOrOpaqueArchetype()) {
1819-
origErrorType =
1820-
origClosureType->getFunctionThrownErrorType();
1821-
} else {
1822-
origErrorType =
1823-
AbstractionPattern(genericSig.getCanonicalSignature(),
1824-
(*errorType)->getCanonicalType());
1816+
if (origClosureType && !origClosureType->isTypeParameterOrOpaqueArchetype()) {
1817+
CanType substClosureType = origClosureType->getType()
1818+
.subst(origClosureType->getGenericSubstitutions())->getCanonicalType();
1819+
CanAnyFunctionType substClosureFnType =
1820+
cast<AnyFunctionType>(substClosureType);
1821+
if (auto optPair = origClosureType->getFunctionThrownErrorType(substClosureFnType)) {
1822+
origErrorType = optPair->first;
1823+
errorType = optPair->second;
18251824
}
1825+
} else if (errorType) {
1826+
origErrorType = AbstractionPattern(genericSig.getCanonicalSignature(),
1827+
(*errorType)->getCanonicalType());
1828+
}
18261829

1830+
if (origErrorType && errorType &&
1831+
F.getConventions().hasIndirectSILErrorResults()) {
18271832
emitIndirectErrorParameter(*this, *errorType, *origErrorType, DC);
18281833
}
18291834

lib/SILGen/SILGenStmt.cpp

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,58 +1547,65 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
15471547
}
15481548
}
15491549

1550+
bool shouldDiscard = ThrowDest.getThrownError().Discard;
1551+
SILType exnType = exn->getType().getObjectType();
15501552
SILBasicBlock &throwBB = *ThrowDest.getBlock();
1551-
if (!throwBB.getArguments().empty()) {
1552-
assert(exn);
1553-
assert(!indirectErrorAddr);
1554-
1555-
auto errorArg = throwBB.getArguments()[0];
1556-
1557-
// If we don't have an existential box, create one to jump to the throw
1558-
// destination.
1559-
SILType errorArgType = errorArg->getType();
1560-
if (exn->getType() != errorArgType) {
1561-
SILType existentialBoxType = SILType::getExceptionType(getASTContext());
1562-
assert(errorArgType == existentialBoxType);
1563-
1564-
// FIXME: Callers should provide this conformance from places recorded in
1565-
// the AST.
1566-
ProtocolConformanceRef conformances[1] = {
1567-
getModule().getSwiftModule()->conformsToProtocol(
1568-
exn->getType().getASTType(), getASTContext().getErrorDecl())
1569-
};
1570-
exnMV = emitExistentialErasure(
1571-
loc,
1572-
exn->getType().getASTType(),
1573-
getTypeLowering(exn->getType()),
1574-
getTypeLowering(existentialBoxType),
1575-
getASTContext().AllocateCopy(conformances),
1576-
SGFContext(),
1577-
[&](SGFContext C) -> ManagedValue {
1578-
return ManagedValue::forForwardedRValue(*this, exn);
1579-
});
1580-
1581-
exn = exnMV.forward(*this);
1582-
}
1583-
1584-
// A direct error value is passed to the epilog block as a BB argument.
1585-
args.push_back(exn);
1586-
} else if (ThrowDest.getThrownError().Discard) {
1587-
assert(!indirectErrorAddr);
1588-
if (exn)
1589-
B.createDestroyAddr(loc, exn);
1590-
} else {
1591-
assert(indirectErrorAddr);
1553+
SILType destErrorType = indirectErrorAddr
1554+
? indirectErrorAddr->getType().getObjectType()
1555+
: !throwBB.getArguments().empty()
1556+
? throwBB.getArguments()[0]->getType().getObjectType()
1557+
: exnType;
1558+
1559+
// If the thrown error type differs from what the throw destination expects,
1560+
// perform the conversion.
1561+
// FIXME: Can the AST tell us what to do here?
1562+
if (exnType != destErrorType && !shouldDiscard) {
1563+
assert(destErrorType == SILType::getExceptionType(getASTContext()));
1564+
1565+
ProtocolConformanceRef conformances[1] = {
1566+
getModule().getSwiftModule()->conformsToProtocol(
1567+
exn->getType().getASTType(), getASTContext().getErrorDecl())
1568+
};
1569+
1570+
exn = emitExistentialErasure(
1571+
loc,
1572+
exnType.getASTType(),
1573+
getTypeLowering(exnType),
1574+
getTypeLowering(destErrorType),
1575+
getASTContext().AllocateCopy(conformances),
1576+
SGFContext(),
1577+
[&](SGFContext C) -> ManagedValue {
1578+
if (exn->getType().isAddress()) {
1579+
return emitLoad(loc, exn, getTypeLowering(exnType), SGFContext(),
1580+
IsTake);
1581+
}
15921582

1593-
// FIXME: opaque values
1583+
return ManagedValue::forForwardedRValue(*this, exn);
1584+
}).forward(*this);
1585+
}
1586+
assert(exn->getType().getObjectType() == destErrorType);
15941587

1595-
// If an error value was provided by the caller, copy it into the
1596-
// indirect error result. Otherwise we assume the indirect error
1597-
// result has been initialized.
1598-
if (exn) {
1588+
if (indirectErrorAddr) {
1589+
if (exn->getType().isAddress()) {
15991590
B.createCopyAddr(loc, exn, indirectErrorAddr,
16001591
IsTake, IsInitialization);
1592+
} else {
1593+
// An indirect error is written into the destination error address.
1594+
emitSemanticStore(loc, exn, indirectErrorAddr,
1595+
getTypeLowering(destErrorType), IsInitialization);
16011596
}
1597+
} else if (!throwBB.getArguments().empty()) {
1598+
// Load if we need to.
1599+
if (exn->getType().isAddress()) {
1600+
exn = emitLoad(loc, exn, getTypeLowering(exnType), SGFContext(), IsTake)
1601+
.forward(*this);
1602+
}
1603+
1604+
// A direct error value is passed to the epilog block as a BB argument.
1605+
args.push_back(exn);
1606+
} else if (shouldDiscard) {
1607+
if (exn && exn->getType().isAddress())
1608+
B.createDestroyAddr(loc, exn);
16021609
}
16031610

16041611
// Branch to the cleanup destination.

lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ static bool canSpecializeFunction(SILFunction *F,
114114
if (F->getConventions().hasIndirectSILResults())
115115
return false;
116116

117+
// For now ignore functions with indirect error results.
118+
if (F->getConventions().hasIndirectSILErrorResults())
119+
return false;
120+
117121
// For now ignore coroutines.
118122
if (F->getLoweredFunctionType()->isCoroutine())
119123
return false;

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,10 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
517517
if (shouldNotSpecialize(Callee, Apply ? Apply.getFunction() : nullptr))
518518
return false;
519519

520+
// FIXME: Specialization with typed throws.
521+
if (Callee->getConventions().hasIndirectSILErrorResults())
522+
return false;
523+
520524
SpecializedGenericEnv = nullptr;
521525
SpecializedGenericSig = nullptr;
522526
auto CalleeGenericSig = Callee->getLoweredFunctionType()

0 commit comments

Comments
 (0)