Skip to content

Commit c3a0979

Browse files
authored
Merge pull request swiftlang#69497 from DougGregor/runtime-normalize-thrown-error
2 parents a345e57 + 5a59dc1 commit c3a0979

File tree

4 files changed

+83
-3
lines changed

4 files changed

+83
-3
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,39 @@ swift::swift_getFunctionTypeMetadataGlobalActor(
15651565
return &FunctionTypes.getOrInsert(key).first->Data;
15661566
}
15671567

1568+
extern "C" const EnumDescriptor NOMINAL_TYPE_DESCR_SYM(s5NeverO);
1569+
extern "C" const ProtocolDescriptor PROTOCOL_DESCR_SYM(s5Error);
1570+
1571+
namespace {
1572+
/// Classification for a given thrown error type.
1573+
enum class ThrownErrorClassification {
1574+
/// An arbitrary thrown error.
1575+
Arbitrary,
1576+
/// 'Never', which means a function type is non-throwing.
1577+
Never,
1578+
/// 'any Error', which means the function type uses untyped throws.
1579+
AnyError,
1580+
};
1581+
1582+
/// Classify a thrown error type.
1583+
ThrownErrorClassification classifyThrownError(const Metadata *type) {
1584+
if (auto enumMetadata = dyn_cast<EnumMetadata>(type)) {
1585+
if (enumMetadata->getDescription() == &NOMINAL_TYPE_DESCR_SYM(s5NeverO))
1586+
return ThrownErrorClassification::Never;
1587+
} else if (auto existential = dyn_cast<ExistentialTypeMetadata>(type)) {
1588+
auto protocols = existential->getProtocols();
1589+
if (protocols.size() == 1 &&
1590+
!protocols[0].isObjC() &&
1591+
protocols[0].getSwiftProtocol() == &PROTOCOL_DESCR_SYM(s5Error) &&
1592+
!existential->isClassBounded() &&
1593+
!existential->isObjC())
1594+
return ThrownErrorClassification::AnyError;
1595+
}
1596+
1597+
return ThrownErrorClassification::Arbitrary;
1598+
}
1599+
}
1600+
15681601
const FunctionTypeMetadata *
15691602
swift::swift_getExtendedFunctionTypeMetadata(
15701603
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
@@ -1573,6 +1606,31 @@ swift::swift_getExtendedFunctionTypeMetadata(
15731606
ExtendedFunctionTypeFlags extFlags, const Metadata *thrownError) {
15741607
assert(flags.hasExtendedFlags() || extFlags.getIntValue() == 0);
15751608
assert(flags.hasExtendedFlags() || thrownError == nullptr);
1609+
1610+
if (thrownError) {
1611+
// Perform adjustments based on the given thrown error.
1612+
switch (classifyThrownError(thrownError)){
1613+
case ThrownErrorClassification::Arbitrary:
1614+
// Nothing to do.
1615+
break;
1616+
1617+
case ThrownErrorClassification::Never:
1618+
// The thrown error was 'Never', so make this a non-throwing function
1619+
flags = flags.withThrows(false);
1620+
1621+
// Fall through to clear out the error.
1622+
SWIFT_FALLTHROUGH;
1623+
1624+
case ThrownErrorClassification::AnyError:
1625+
// Clear out the thrown error and extended flags.
1626+
thrownError = nullptr;
1627+
extFlags = extFlags.withTypedThrows(false);
1628+
if (extFlags.getIntValue() == 0)
1629+
flags = flags.withExtendedFlags(false);
1630+
break;
1631+
}
1632+
}
1633+
15761634
FunctionCacheEntry::Key key = {
15771635
flags, diffKind, parameters,
15781636
reinterpret_cast<const ParameterFlags *>(parameterFlags), result,

test/IRGen/typed_throws.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,12 +406,12 @@ entry(%0: $*T):
406406
// CHECK: define{{.*}} swiftcc void @apply_closure_generic(ptr %0, ptr %1, ptr %T, ptr %V)
407407
// CHECK: [[T0:%.*]] = getelementptr inbounds ptr, ptr %T
408408
// CHECK: [[T1:%.*]] = load ptr, ptr [[T0]]
409-
// CHECK: [[T2:%.*]] = getelementptr inbounds %swift.vwtable, ptr [[T1]]
409+
// CHECK: [[T2:%.*]] = getelementptr inbounds %swift.vwtable{{.*}}
410410
// CHECK: [[T3:%.*]] = load i64, ptr [[T2]]
411411
// CHECK: [[T4:%.*]] = alloca i8, i64 [[T3]]
412412
// CHECK: [[V0:%.*]] = getelementptr inbounds ptr, ptr %V
413413
// CHECK: [[V1:%.*]] = load ptr, ptr [[V0]]
414-
// CHECK: [[V2:%.*]] = getelementptr inbounds %swift.vwtable, ptr [[V1]]
414+
// CHECK: [[V2:%.*]] = getelementptr inbounds %swift.vwtable{{.*}}
415415
// CHECK: [[V3:%.*]] = load i64, ptr [[V2]]
416416
// CHECK: [[V4:%.*]] = alloca i8, i64 [[V3]]
417417
// CHECK: call swiftcc void %0(ptr noalias sret(%swift.opaque) [[T4]], ptr swiftself %1, ptr noalias nocapture swifterror dereferenceable(8) %swifterror, ptr [[V4]])

test/Runtime/demangleToMetadata.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,12 +526,26 @@ enum MyBigError: Error {
526526
case epicFail
527527
}
528528

529+
@available(SwiftStdlib 5.11, *)
530+
func getFnTypeWithThrownError<E: Error>(_: E.Type) -> Any.Type {
531+
typealias Fn = (Int) throws(E) -> Void
532+
return Fn.self
533+
}
534+
529535
if #available(SwiftStdlib 5.11, *) {
530536
DemangleToMetadataTests.test("typed throws") {
531537
typealias Fn = (Int) throws(MyBigError) -> Void
532538
expectEqual("ySi4main10MyBigErrorOYKc", _mangledTypeName(Fn.self)!)
533-
print("Looking up the typed throws... \(_typeByName("ySi4main10MyBigErrorOYKc"))")
534539
expectEqual(Fn.self, _typeByName("ySi4main10MyBigErrorOYKc")!)
540+
541+
542+
expectEqual(getFnTypeWithThrownError(MyBigError.self), _typeByName("ySi4main10MyBigErrorOYKc")!)
543+
544+
// throws(any Error) -> throws
545+
expectEqual(getFnTypeWithThrownError((any Error).self), _typeByName("ySiKc")!)
546+
547+
// throws(Never) -> non-throwing
548+
expectEqual(getFnTypeWithThrownError(Never.self), _typeByName("ySic")!)
535549
}
536550
}
537551

unittests/runtime/Stdlib.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,3 +520,11 @@ const long long $ss7KeyPathCMo[1] = {0};
520520

521521
SWIFT_RUNTIME_STDLIB_INTERNAL
522522
const long long $ss12__SwiftValueCMn[1] = {0};
523+
524+
// Never and Error
525+
526+
SWIFT_RUNTIME_STDLIB_INTERNAL
527+
const long long $ss5NeverOMn[1] = {0};
528+
529+
SWIFT_RUNTIME_STDLIB_INTERNAL
530+
const long long $ss5ErrorMp[1] = {0};

0 commit comments

Comments
 (0)