Skip to content

Commit 7a54e78

Browse files
committed
SIL: Lower the thrown error type of a function type using the correct abstraction pattern
1 parent c4e0c96 commit 7a54e78

File tree

6 files changed

+143
-34
lines changed

6 files changed

+143
-34
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,6 +1521,10 @@ 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+
AbstractionPattern getFunctionThrownErrorType() const;
1527+
15241528
/// Given that the value being abstracted is a function type, return
15251529
/// the abstraction pattern for one of its parameter types.
15261530
AbstractionPattern getFunctionParamType(unsigned index) const;
@@ -1611,15 +1615,19 @@ class AbstractionPattern {
16111615
/// Given that this is a pack expansion, do the pack elements need to be
16121616
/// passed indirectly?
16131617
bool arePackElementsPassedIndirectly(TypeConverter &TC) const;
1614-
1618+
16151619
/// If this abstraction pattern appears in function return position, how is
16161620
/// the corresponding value returned?
16171621
CallingConventionKind getResultConvention(TypeConverter &TC) const;
1618-
1622+
16191623
/// If this abstraction pattern appears in function parameter position, how
16201624
/// is the corresponding value passed?
16211625
CallingConventionKind getParameterConvention(TypeConverter &TC) const;
1622-
1626+
1627+
/// If this abstraction pattern appears in function thrown error position, how
1628+
/// is the corresponding value passed?
1629+
CallingConventionKind getErrorConvention(TypeConverter &TC) const;
1630+
16231631
/// Generate the abstraction pattern for lowering the substituted SIL
16241632
/// function type for a function type matching this abstraction pattern.
16251633
///

include/swift/SIL/SILFunctionConventions.h

Lines changed: 2 additions & 0 deletions
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

Lines changed: 7 additions & 0 deletions
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/SIL/IR/AbstractionPattern.cpp

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,48 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const {
12141214
llvm_unreachable("bad kind");
12151215
}
12161216

1217+
static CanType getThrownErrorType(CanType type) {
1218+
auto funcTy = cast<AnyFunctionType>(type);
1219+
assert(funcTy->isThrowing());
1220+
return (*funcTy->getEffectiveThrownErrorType())->getCanonicalType();
1221+
}
1222+
1223+
AbstractionPattern AbstractionPattern::getFunctionThrownErrorType() const {
1224+
switch (getKind()) {
1225+
case Kind::Invalid:
1226+
llvm_unreachable("querying invalid abstraction pattern!");
1227+
case Kind::ObjCCompletionHandlerArgumentsType:
1228+
case Kind::Tuple:
1229+
llvm_unreachable("abstraction pattern for tuple cannot be function");
1230+
case Kind::Opaque:
1231+
return *this;
1232+
case Kind::Type: {
1233+
if (isTypeParameterOrOpaqueArchetype())
1234+
return AbstractionPattern::getOpaque();
1235+
1236+
return AbstractionPattern(getGenericSubstitutions(),
1237+
getGenericSignatureForFunctionComponent(),
1238+
getThrownErrorType(getType()));
1239+
}
1240+
case Kind::Discard:
1241+
llvm_unreachable("don't need to discard function abstractions yet");
1242+
case Kind::ClangType:
1243+
case Kind::CFunctionAsMethodType:
1244+
case Kind::PartialCurriedCFunctionAsMethodType:
1245+
case Kind::CXXMethodType:
1246+
case Kind::PartialCurriedCXXMethodType:
1247+
case Kind::CurriedObjCMethodType:
1248+
case Kind::CurriedCFunctionAsMethodType:
1249+
case Kind::CurriedCXXMethodType:
1250+
case Kind::PartialCurriedObjCMethodType:
1251+
case Kind::ObjCMethodType:
1252+
case Kind::OpaqueFunction:
1253+
case Kind::OpaqueDerivativeFunction:
1254+
llvm_unreachable("implement me");
1255+
}
1256+
llvm_unreachable("bad kind");
1257+
}
1258+
12171259
AbstractionPattern
12181260
AbstractionPattern::getObjCMethodAsyncCompletionHandlerType(
12191261
CanType swiftCompletionHandlerType) const {
@@ -1939,7 +1981,7 @@ AbstractionPattern::getParameterConvention(TypeConverter &TC) const {
19391981
case Kind::Opaque:
19401982
// Maximally abstracted values are always passed indirectly.
19411983
return Indirect;
1942-
1984+
19431985
case Kind::OpaqueFunction:
19441986
case Kind::OpaqueDerivativeFunction:
19451987
case Kind::PartialCurriedObjCMethodType:
@@ -1953,16 +1995,57 @@ AbstractionPattern::getParameterConvention(TypeConverter &TC) const {
19531995
case Kind::PartialCurriedCXXMethodType:
19541996
// Function types are always passed directly
19551997
return Direct;
1956-
1998+
19571999
case Kind::ClangType:
19582000
case Kind::Type:
19592001
case Kind::Discard:
19602002
// Pass according to the formal type.
19612003
return SILType::isFormallyPassedIndirectly(getType(),
1962-
TC,
1963-
getGenericSignatureOrNull())
2004+
TC,
2005+
getGenericSignatureOrNull())
19642006
? Indirect : Direct;
1965-
2007+
2008+
case Kind::Invalid:
2009+
case Kind::Tuple:
2010+
case Kind::ObjCCompletionHandlerArgumentsType:
2011+
llvm_unreachable("should not get here");
2012+
}
2013+
}
2014+
2015+
AbstractionPattern::CallingConventionKind
2016+
AbstractionPattern::getErrorConvention(TypeConverter &TC) const {
2017+
// Tuples should be destructured.
2018+
if (isTuple()) {
2019+
return Destructured;
2020+
}
2021+
switch (getKind()) {
2022+
case Kind::Opaque:
2023+
// Maximally abstracted values are always thrown indirectly.
2024+
return Indirect;
2025+
2026+
case Kind::OpaqueFunction:
2027+
case Kind::OpaqueDerivativeFunction:
2028+
case Kind::PartialCurriedObjCMethodType:
2029+
case Kind::CurriedObjCMethodType:
2030+
case Kind::PartialCurriedCFunctionAsMethodType:
2031+
case Kind::CurriedCFunctionAsMethodType:
2032+
case Kind::CFunctionAsMethodType:
2033+
case Kind::ObjCMethodType:
2034+
case Kind::CXXMethodType:
2035+
case Kind::CurriedCXXMethodType:
2036+
case Kind::PartialCurriedCXXMethodType:
2037+
// Function types are always thrown directly
2038+
return Direct;
2039+
2040+
case Kind::ClangType:
2041+
case Kind::Type:
2042+
case Kind::Discard:
2043+
// Pass according to the formal type.
2044+
return SILType::isFormallyThrownIndirectly(getType(),
2045+
TC,
2046+
getGenericSignatureOrNull())
2047+
? Indirect : Direct;
2048+
19662049
case Kind::Invalid:
19672050
case Kind::Tuple:
19682051
case Kind::ObjCCompletionHandlerArgumentsType:

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 26 additions & 26 deletions
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,32 @@ 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+
if (isThrowing && !foreignInfo.error &&
2296+
!foreignInfo.async) {
2297+
assert(!origType.isForeign()
2298+
&& "using native Swift error convention for foreign type!");
2299+
auto origErrorType = origType.getFunctionThrownErrorType();
2300+
auto errorType = *substFnInterfaceType->getEffectiveThrownErrorType();
2301+
auto &errorTLConv = TC.getTypeLowering(origErrorType,
2302+
errorType->getCanonicalType(),
2303+
TypeExpansionContext::minimal());
2304+
2305+
errorResult = SILResultInfo(errorTLConv.getLoweredType().getASTType(),
2306+
errorTLConv.isAddressOnly()
2307+
? ResultConvention::Indirect
2308+
: ResultConvention::Owned);
2309+
}
2310+
23112311
// Lower the result type.
23122312
AbstractionPattern origResultType = origType.getFunctionResultType();
23132313
CanType substFormalResultType = substFnInterfaceType.getResult();

lib/SIL/IR/SILType.cpp

Lines changed: 9 additions & 0 deletions
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)