mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Handle any Error and Never thrown error types during runtime uniquing.
When forming runtime metadata for a function type that has either `any Error` or `Never` as the specified thrown error type, drop the thrown error type and normalize down to (untyped) `throws` or non-throwing, as appropriate.
This commit is contained in:
@@ -1565,6 +1565,39 @@ swift::swift_getFunctionTypeMetadataGlobalActor(
|
|||||||
return &FunctionTypes.getOrInsert(key).first->Data;
|
return &FunctionTypes.getOrInsert(key).first->Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" const EnumDescriptor NOMINAL_TYPE_DESCR_SYM(s5NeverO);
|
||||||
|
extern "C" const ProtocolDescriptor PROTOCOL_DESCR_SYM(s5Error);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/// Classification for a given thrown error type.
|
||||||
|
enum class ThrownErrorClassification {
|
||||||
|
/// An arbitrary thrown error.
|
||||||
|
Arbitrary,
|
||||||
|
/// 'Never', which means a function type is non-throwing.
|
||||||
|
Never,
|
||||||
|
/// 'any Error', which means the function type uses untyped throws.
|
||||||
|
AnyError,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Classify a thrown error type.
|
||||||
|
ThrownErrorClassification classifyThrownError(const Metadata *type) {
|
||||||
|
if (auto enumMetadata = dyn_cast<EnumMetadata>(type)) {
|
||||||
|
if (enumMetadata->getDescription() == &NOMINAL_TYPE_DESCR_SYM(s5NeverO))
|
||||||
|
return ThrownErrorClassification::Never;
|
||||||
|
} else if (auto existential = dyn_cast<ExistentialTypeMetadata>(type)) {
|
||||||
|
auto protocols = existential->getProtocols();
|
||||||
|
if (protocols.size() == 1 &&
|
||||||
|
!protocols[0].isObjC() &&
|
||||||
|
protocols[0].getSwiftProtocol() == &PROTOCOL_DESCR_SYM(s5Error) &&
|
||||||
|
!existential->isClassBounded() &&
|
||||||
|
!existential->isObjC())
|
||||||
|
return ThrownErrorClassification::AnyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThrownErrorClassification::Arbitrary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const FunctionTypeMetadata *
|
const FunctionTypeMetadata *
|
||||||
swift::swift_getExtendedFunctionTypeMetadata(
|
swift::swift_getExtendedFunctionTypeMetadata(
|
||||||
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
||||||
@@ -1573,6 +1606,31 @@ swift::swift_getExtendedFunctionTypeMetadata(
|
|||||||
ExtendedFunctionTypeFlags extFlags, const Metadata *thrownError) {
|
ExtendedFunctionTypeFlags extFlags, const Metadata *thrownError) {
|
||||||
assert(flags.hasExtendedFlags() || extFlags.getIntValue() == 0);
|
assert(flags.hasExtendedFlags() || extFlags.getIntValue() == 0);
|
||||||
assert(flags.hasExtendedFlags() || thrownError == nullptr);
|
assert(flags.hasExtendedFlags() || thrownError == nullptr);
|
||||||
|
|
||||||
|
if (thrownError) {
|
||||||
|
// Perform adjustments based on the given thrown error.
|
||||||
|
switch (classifyThrownError(thrownError)){
|
||||||
|
case ThrownErrorClassification::Arbitrary:
|
||||||
|
// Nothing to do.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ThrownErrorClassification::Never:
|
||||||
|
// The thrown error was 'Never', so make this a non-throwing function
|
||||||
|
flags = flags.withThrows(false);
|
||||||
|
|
||||||
|
// Fall through to clear out the error.
|
||||||
|
SWIFT_FALLTHROUGH;
|
||||||
|
|
||||||
|
case ThrownErrorClassification::AnyError:
|
||||||
|
// Clear out the thrown error and extended flags.
|
||||||
|
thrownError = nullptr;
|
||||||
|
extFlags = extFlags.withTypedThrows(false);
|
||||||
|
if (extFlags.getIntValue() == 0)
|
||||||
|
flags = flags.withExtendedFlags(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FunctionCacheEntry::Key key = {
|
FunctionCacheEntry::Key key = {
|
||||||
flags, diffKind, parameters,
|
flags, diffKind, parameters,
|
||||||
reinterpret_cast<const ParameterFlags *>(parameterFlags), result,
|
reinterpret_cast<const ParameterFlags *>(parameterFlags), result,
|
||||||
|
|||||||
@@ -526,12 +526,26 @@ enum MyBigError: Error {
|
|||||||
case epicFail
|
case epicFail
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(SwiftStdlib 5.11, *)
|
||||||
|
func getFnTypeWithThrownError<E: Error>(_: E.Type) -> Any.Type {
|
||||||
|
typealias Fn = (Int) throws(E) -> Void
|
||||||
|
return Fn.self
|
||||||
|
}
|
||||||
|
|
||||||
if #available(SwiftStdlib 5.11, *) {
|
if #available(SwiftStdlib 5.11, *) {
|
||||||
DemangleToMetadataTests.test("typed throws") {
|
DemangleToMetadataTests.test("typed throws") {
|
||||||
typealias Fn = (Int) throws(MyBigError) -> Void
|
typealias Fn = (Int) throws(MyBigError) -> Void
|
||||||
expectEqual("ySi4main10MyBigErrorOYKc", _mangledTypeName(Fn.self)!)
|
expectEqual("ySi4main10MyBigErrorOYKc", _mangledTypeName(Fn.self)!)
|
||||||
print("Looking up the typed throws... \(_typeByName("ySi4main10MyBigErrorOYKc"))")
|
|
||||||
expectEqual(Fn.self, _typeByName("ySi4main10MyBigErrorOYKc")!)
|
expectEqual(Fn.self, _typeByName("ySi4main10MyBigErrorOYKc")!)
|
||||||
|
|
||||||
|
|
||||||
|
expectEqual(getFnTypeWithThrownError(MyBigError.self), _typeByName("ySi4main10MyBigErrorOYKc")!)
|
||||||
|
|
||||||
|
// throws(any Error) -> throws
|
||||||
|
expectEqual(getFnTypeWithThrownError((any Error).self), _typeByName("ySiKc")!)
|
||||||
|
|
||||||
|
// throws(Never) -> non-throwing
|
||||||
|
expectEqual(getFnTypeWithThrownError(Never.self), _typeByName("ySic")!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user