Skip to content

Commit ad56977

Browse files
authored
Merge pull request #69430 from slavapestov/silgen-typed-throws-wip
Preliminary SILGen support for address-only typed throws
2 parents 137ba61 + 581776b commit ad56977

20 files changed

+409
-122
lines changed

include/swift/SIL/AbstractionPattern.h

+23-3
Original file line numberDiff line numberDiff line change
@@ -1521,6 +1521,22 @@ class AbstractionPattern {
15211521
/// abstraction pattern for its result type.
15221522
AbstractionPattern getFunctionResultType() const;
15231523

1524+
/// Given that the value being abstracted is a function, return the
1525+
/// abstraction pattern for its thrown error type.
1526+
llvm::Optional<AbstractionPattern> getFunctionThrownErrorType() const;
1527+
1528+
/// Utility method to adjust a thrown error pattern and thrown error type
1529+
/// to account for some quirks in type lowering.
1530+
///
1531+
/// When lowered with an opaque pattern,
1532+
///
1533+
/// - () -> () becomes () -> (),
1534+
/// - () throws(any Error) -> () becomes () -> (@error any Error),
1535+
///
1536+
/// *not* () -> (@error_indirect Never) or () -> (@error_indirect any Error).
1537+
llvm::Optional<std::pair<AbstractionPattern, CanType>>
1538+
getFunctionThrownErrorType(CanAnyFunctionType substFnInterfaceType) const;
1539+
15241540
/// Given that the value being abstracted is a function type, return
15251541
/// the abstraction pattern for one of its parameter types.
15261542
AbstractionPattern getFunctionParamType(unsigned index) const;
@@ -1611,15 +1627,19 @@ class AbstractionPattern {
16111627
/// Given that this is a pack expansion, do the pack elements need to be
16121628
/// passed indirectly?
16131629
bool arePackElementsPassedIndirectly(TypeConverter &TC) const;
1614-
1630+
16151631
/// If this abstraction pattern appears in function return position, how is
16161632
/// the corresponding value returned?
16171633
CallingConventionKind getResultConvention(TypeConverter &TC) const;
1618-
1634+
16191635
/// If this abstraction pattern appears in function parameter position, how
16201636
/// is the corresponding value passed?
16211637
CallingConventionKind getParameterConvention(TypeConverter &TC) const;
1622-
1638+
1639+
/// If this abstraction pattern appears in function thrown error position, how
1640+
/// is the corresponding value passed?
1641+
CallingConventionKind getErrorConvention(TypeConverter &TC) const;
1642+
16231643
/// Generate the abstraction pattern for lowering the substituted SIL
16241644
/// function type for a function type matching this abstraction pattern.
16251645
///

include/swift/SIL/SILArgument.h

+2
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ class SILFunctionArgument : public SILArgument {
433433

434434
bool isIndirectResult() const;
435435

436+
bool isIndirectErrorResult() const;
437+
436438
SILArgumentConvention getArgumentConvention() const;
437439

438440
/// Given that this is an entry block argument, and given that it does

include/swift/SIL/SILFunctionConventions.h

+2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class SILModuleConventions {
7878
public:
7979
static bool isPassedIndirectlyInSIL(SILType type, SILModule &M);
8080

81+
static bool isThrownIndirectlyInSIL(SILType type, SILModule &M);
82+
8183
static bool isReturnedIndirectlyInSIL(SILType type, SILModule &M);
8284

8385
static SILModuleConventions getLoweredAddressConventions(SILModule &M) {

include/swift/SIL/SILType.h

+7
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,13 @@ class SILType {
340340
return isAddressOnly(type, tc, sig, TypeExpansionContext::minimal());
341341
}
342342

343+
/// Return true if this type must be thrown indirectly.
344+
static bool isFormallyThrownIndirectly(CanType type,
345+
Lowering::TypeConverter &tc,
346+
CanGenericSignature sig) {
347+
return isAddressOnly(type, tc, sig, TypeExpansionContext::minimal());
348+
}
349+
343350
/// True if the type, or the referenced type of an address type, is loadable.
344351
/// This is the opposite of isAddressOnly.
345352
bool isLoadable(const SILFunction &F) const {

lib/AST/ASTDumper.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -4227,16 +4227,16 @@ namespace {
42274227
printFlag(T->isAsync(), "async");
42284228
printFlag(T->isThrowing(), "throws");
42294229
}
4230-
if (Type thrownError = T->getThrownError()) {
4231-
printFieldQuoted(thrownError.getString(), "thrown_error");
4232-
}
42334230
if (Type globalActor = T->getGlobalActor()) {
42344231
printFieldQuoted(globalActor.getString(), "global_actor");
42354232
}
42364233

42374234
printClangTypeRec(T->getClangTypeInfo(), T->getASTContext());
42384235
printAnyFunctionParamsRec(T->getParams(), "input");
42394236
printRec(T->getResult(), "output");
4237+
if (Type thrownError = T->getThrownError()) {
4238+
printRec(thrownError, "thrown_error");
4239+
}
42404240
}
42414241

42424242
void visitFunctionType(FunctionType *T, StringRef label) {

lib/SIL/IR/AbstractionPattern.cpp

+135-8
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,78 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const {
12141214
llvm_unreachable("bad kind");
12151215
}
12161216

1217+
llvm::Optional<AbstractionPattern>
1218+
AbstractionPattern::getFunctionThrownErrorType() const {
1219+
switch (getKind()) {
1220+
case Kind::Invalid:
1221+
llvm_unreachable("querying invalid abstraction pattern!");
1222+
case Kind::ObjCCompletionHandlerArgumentsType:
1223+
case Kind::Tuple:
1224+
llvm_unreachable("abstraction pattern for tuple cannot be function");
1225+
case Kind::Opaque:
1226+
return *this;
1227+
case Kind::Type: {
1228+
if (isTypeParameterOrOpaqueArchetype())
1229+
return getOpaque();
1230+
1231+
if (auto errorType = cast<AnyFunctionType>(getType())->getEffectiveThrownErrorType()) {
1232+
return AbstractionPattern(getGenericSubstitutions(),
1233+
getGenericSignatureForFunctionComponent(),
1234+
(*errorType)->getCanonicalType());
1235+
}
1236+
1237+
return llvm::None;
1238+
}
1239+
case Kind::Discard:
1240+
llvm_unreachable("don't need to discard function abstractions yet");
1241+
case Kind::ClangType:
1242+
case Kind::CFunctionAsMethodType:
1243+
case Kind::PartialCurriedCFunctionAsMethodType:
1244+
case Kind::CXXMethodType:
1245+
case Kind::PartialCurriedCXXMethodType:
1246+
case Kind::CurriedObjCMethodType:
1247+
case Kind::CurriedCFunctionAsMethodType:
1248+
case Kind::CurriedCXXMethodType:
1249+
case Kind::PartialCurriedObjCMethodType:
1250+
case Kind::ObjCMethodType:
1251+
llvm_unreachable("implement me");
1252+
case Kind::OpaqueFunction:
1253+
case Kind::OpaqueDerivativeFunction:
1254+
return llvm::None;
1255+
}
1256+
llvm_unreachable("bad kind");
1257+
}
1258+
1259+
llvm::Optional<std::pair<AbstractionPattern, CanType>>
1260+
AbstractionPattern::getFunctionThrownErrorType(
1261+
CanAnyFunctionType substFnInterfaceType) const {
1262+
auto optOrigErrorType = getFunctionThrownErrorType();
1263+
if (!optOrigErrorType)
1264+
return llvm::None;
1265+
1266+
auto &ctx = substFnInterfaceType->getASTContext();
1267+
auto optErrorType = substFnInterfaceType->getEffectiveThrownErrorType();
1268+
1269+
if (isTypeParameterOrOpaqueArchetype()) {
1270+
if (!optErrorType)
1271+
return llvm::None;
1272+
1273+
if (!(*optErrorType)->isEqual(ctx.getErrorExistentialType())) {
1274+
llvm::errs() << "unsupported reabstraction\n";
1275+
abort();
1276+
}
1277+
1278+
return std::make_pair(AbstractionPattern(*optErrorType),
1279+
(*optErrorType)->getCanonicalType());
1280+
}
1281+
1282+
if (!optErrorType)
1283+
optErrorType = ctx.getErrorExistentialType();
1284+
1285+
return std::make_pair(*optOrigErrorType,
1286+
(*optErrorType)->getCanonicalType());
1287+
}
1288+
12171289
AbstractionPattern
12181290
AbstractionPattern::getObjCMethodAsyncCompletionHandlerType(
12191291
CanType swiftCompletionHandlerType) const {
@@ -1939,7 +2011,7 @@ AbstractionPattern::getParameterConvention(TypeConverter &TC) const {
19392011
case Kind::Opaque:
19402012
// Maximally abstracted values are always passed indirectly.
19412013
return Indirect;
1942-
2014+
19432015
case Kind::OpaqueFunction:
19442016
case Kind::OpaqueDerivativeFunction:
19452017
case Kind::PartialCurriedObjCMethodType:
@@ -1953,16 +2025,57 @@ AbstractionPattern::getParameterConvention(TypeConverter &TC) const {
19532025
case Kind::PartialCurriedCXXMethodType:
19542026
// Function types are always passed directly
19552027
return Direct;
1956-
2028+
19572029
case Kind::ClangType:
19582030
case Kind::Type:
19592031
case Kind::Discard:
19602032
// Pass according to the formal type.
19612033
return SILType::isFormallyPassedIndirectly(getType(),
1962-
TC,
1963-
getGenericSignatureOrNull())
2034+
TC,
2035+
getGenericSignatureOrNull())
19642036
? Indirect : Direct;
1965-
2037+
2038+
case Kind::Invalid:
2039+
case Kind::Tuple:
2040+
case Kind::ObjCCompletionHandlerArgumentsType:
2041+
llvm_unreachable("should not get here");
2042+
}
2043+
}
2044+
2045+
AbstractionPattern::CallingConventionKind
2046+
AbstractionPattern::getErrorConvention(TypeConverter &TC) const {
2047+
// Tuples should be destructured.
2048+
if (isTuple()) {
2049+
return Destructured;
2050+
}
2051+
switch (getKind()) {
2052+
case Kind::Opaque:
2053+
// Maximally abstracted values are always thrown indirectly.
2054+
return Indirect;
2055+
2056+
case Kind::OpaqueFunction:
2057+
case Kind::OpaqueDerivativeFunction:
2058+
case Kind::PartialCurriedObjCMethodType:
2059+
case Kind::CurriedObjCMethodType:
2060+
case Kind::PartialCurriedCFunctionAsMethodType:
2061+
case Kind::CurriedCFunctionAsMethodType:
2062+
case Kind::CFunctionAsMethodType:
2063+
case Kind::ObjCMethodType:
2064+
case Kind::CXXMethodType:
2065+
case Kind::CurriedCXXMethodType:
2066+
case Kind::PartialCurriedCXXMethodType:
2067+
// Function types are always thrown directly
2068+
return Direct;
2069+
2070+
case Kind::ClangType:
2071+
case Kind::Type:
2072+
case Kind::Discard:
2073+
// Pass according to the formal type.
2074+
return SILType::isFormallyThrownIndirectly(getType(),
2075+
TC,
2076+
getGenericSignatureOrNull())
2077+
? Indirect : Direct;
2078+
19662079
case Kind::Invalid:
19672080
case Kind::Tuple:
19682081
case Kind::ObjCCompletionHandlerArgumentsType:
@@ -2514,14 +2627,28 @@ class SubstFunctionTypePatternVisitor
25142627
if (yieldType) {
25152628
substYieldType = visit(yieldType, yieldPattern);
25162629
}
2517-
2630+
2631+
CanType newErrorType;
2632+
2633+
if (auto optPair = pattern.getFunctionThrownErrorType(func)) {
2634+
auto errorPattern = optPair->first;
2635+
auto errorType = optPair->second;
2636+
newErrorType = visit(errorType, errorPattern);
2637+
}
2638+
25182639
auto newResultTy = visit(func.getResult(),
25192640
pattern.getFunctionResultType());
25202641

25212642
llvm::Optional<FunctionType::ExtInfo> extInfo;
25222643
if (func->hasExtInfo())
25232644
extInfo = func->getExtInfo();
2524-
2645+
2646+
if (newErrorType) {
2647+
if (!extInfo)
2648+
extInfo = FunctionType::ExtInfo();
2649+
extInfo = extInfo->withThrows(true, newErrorType);
2650+
}
2651+
25252652
return CanFunctionType::get(FunctionType::CanParamArrayRef(newParams),
25262653
newResultTy, extInfo);
25272654
}
@@ -2562,7 +2689,7 @@ const {
25622689
auto substTy = visitor.handleUnabstractedFunctionType(substType, *this,
25632690
substYieldType,
25642691
origYieldType);
2565-
2692+
25662693
auto substSig = buildGenericSignature(TC.Context, GenericSignature(),
25672694
std::move(visitor.substGenericParams),
25682695
std::move(visitor.substRequirements))

lib/SIL/IR/SILArgument.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ bool SILFunctionArgument::isIndirectResult() const {
6464
return getIndex() < numIndirectResults;
6565
}
6666

67+
bool SILFunctionArgument::isIndirectErrorResult() const {
68+
auto numIndirectResults =
69+
getFunction()->getConventions().getNumIndirectSILResults();
70+
auto numIndirectErrorResults =
71+
getFunction()->getConventions().getNumIndirectSILErrorResults();
72+
return ((getIndex() >= numIndirectResults) &&
73+
(getIndex() < numIndirectResults + numIndirectErrorResults));
74+
}
75+
6776
SILArgumentConvention SILFunctionArgument::getArgumentConvention() const {
6877
return getFunction()->getConventions().getSILArgumentConvention(getIndex());
6978
}

lib/SIL/IR/SILFunctionType.cpp

+30-26
Original file line numberDiff line numberDiff line change
@@ -2190,32 +2190,6 @@ static CanSILFunctionType getSILFunctionType(
21902190
isAsync = true;
21912191
}
21922192

2193-
// Map 'throws' to the appropriate error convention.
2194-
// Give the type an error argument whether the substituted type semantically
2195-
// `throws` or if the abstraction pattern specifies a Swift function type
2196-
// that also throws. This prevents the need for a second possibly-thunking
2197-
// conversion when using a non-throwing function in more abstract throwing
2198-
// context.
2199-
bool isThrowing = substFnInterfaceType->getExtInfo().isThrowing();
2200-
if (auto origFnType = origType.getAs<AnyFunctionType>()) {
2201-
isThrowing |= origFnType->getExtInfo().isThrowing();
2202-
}
2203-
if (isThrowing && !foreignInfo.error &&
2204-
!foreignInfo.async) {
2205-
assert(!origType.isForeign()
2206-
&& "using native Swift error convention for foreign type!");
2207-
SILType exnType;
2208-
if (CanType thrownError = substFnInterfaceType.getThrownError()) {
2209-
exnType = TC.getLoweredType(thrownError, expansionContext);
2210-
} else {
2211-
// Untyped error throws the exception type.
2212-
exnType = SILType::getExceptionType(TC.Context);
2213-
}
2214-
assert(exnType.isObject());
2215-
errorResult = SILResultInfo(exnType.getASTType(),
2216-
ResultConvention::Owned);
2217-
}
2218-
22192193
// Get the yield type for an accessor coroutine.
22202194
SILCoroutineKind coroutineKind = SILCoroutineKind::None;
22212195
AbstractionPattern coroutineOrigYieldType = AbstractionPattern::getInvalid();
@@ -2308,6 +2282,36 @@ static CanSILFunctionType getSILFunctionType(
23082282
}
23092283
}
23102284

2285+
// Map 'throws' to the appropriate error convention.
2286+
// Give the type an error argument whether the substituted type semantically
2287+
// `throws` or if the abstraction pattern specifies a Swift function type
2288+
// that also throws. This prevents the need for a second possibly-thunking
2289+
// conversion when using a non-throwing function in more abstract throwing
2290+
// context.
2291+
bool isThrowing = substFnInterfaceType->getExtInfo().isThrowing();
2292+
if (auto origFnType = origType.getAs<AnyFunctionType>()) {
2293+
isThrowing |= origFnType->getExtInfo().isThrowing();
2294+
}
2295+
2296+
if (isThrowing && !foreignInfo.error &&
2297+
!foreignInfo.async) {
2298+
assert(!origType.isForeign()
2299+
&& "using native Swift error convention for foreign type!");
2300+
auto optPair = origType.getFunctionThrownErrorType(substFnInterfaceType);
2301+
assert(optPair &&
2302+
"Lowering a throwing function type against non-throwing pattern");
2303+
2304+
auto origErrorType = optPair->first;
2305+
auto errorType = optPair->second;
2306+
auto &errorTLConv = TC.getTypeLowering(origErrorType, errorType,
2307+
TypeExpansionContext::minimal());
2308+
2309+
errorResult = SILResultInfo(errorTLConv.getLoweredType().getASTType(),
2310+
errorTLConv.isAddressOnly()
2311+
? ResultConvention::Indirect
2312+
: ResultConvention::Owned);
2313+
}
2314+
23112315
// Lower the result type.
23122316
AbstractionPattern origResultType = origType.getFunctionResultType();
23132317
CanType substFormalResultType = substFnInterfaceType.getResult();

lib/SIL/IR/SILType.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,15 @@ bool SILModuleConventions::isPassedIndirectlyInSIL(SILType type, SILModule &M) {
713713
return false;
714714
}
715715

716+
bool SILModuleConventions::isThrownIndirectlyInSIL(SILType type, SILModule &M) {
717+
if (SILModuleConventions(M).loweredAddresses) {
718+
return M.Types.getTypeLowering(type, TypeExpansionContext::minimal())
719+
.isAddressOnly();
720+
}
721+
722+
return false;
723+
}
724+
716725
bool SILFunctionType::isNoReturnFunction(SILModule &M,
717726
TypeExpansionContext context) const {
718727
for (unsigned i = 0, e = getNumResults(); i < e; ++i) {

0 commit comments

Comments
 (0)