mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The SDK directory is now confusing as the Windows target also has a SDK overlay. In order to make this more uniform, move the SDK directory to Darwin which covers the fact that this covers the XNU family of OSes. The Windows directory contains the SDK overlay for the Windows target.
575 lines
21 KiB
Plaintext
575 lines
21 KiB
Plaintext
//===--- ErrorObject.mm - Cocoa-interoperable recoverable error object ----===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This implements the object representation of the standard Error
|
|
// type, which represents recoverable errors in the language. This
|
|
// implementation is designed to interoperate efficiently with Cocoa libraries
|
|
// by:
|
|
// - allowing for NSError and CFError objects to "toll-free bridge" to
|
|
// Error existentials, which allows for cheap Cocoa to Swift interop
|
|
// - allowing a native Swift error to lazily "become" an NSError when
|
|
// passed into Cocoa, allowing for cheap Swift to Cocoa interop
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Runtime/Config.h"
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
#include "swift/Runtime/Casting.h"
|
|
#include "swift/Runtime/Debug.h"
|
|
#include "swift/Runtime/ObjCBridge.h"
|
|
#include "swift/Basic/Lazy.h"
|
|
#include "swift/Demangling/ManglingMacros.h"
|
|
#include "ErrorObject.h"
|
|
#include "Private.h"
|
|
#include <dlfcn.h>
|
|
#include <objc/NSObject.h>
|
|
#include <objc/runtime.h>
|
|
#include <objc/message.h>
|
|
#include <objc/objc.h>
|
|
#include <Foundation/Foundation.h>
|
|
#include "../Darwin/Foundation/NSError.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::hashable_support;
|
|
|
|
/// A subclass of NSError used to represent bridged native Swift errors.
|
|
/// This type cannot be subclassed, and should not ever be instantiated
|
|
/// except by the Swift runtime.
|
|
///
|
|
/// NOTE: older runtimes called this _SwiftNativeNSError. The two must
|
|
/// coexist, so it was renamed. The old name must not be used in the new
|
|
/// runtime.
|
|
@interface __SwiftNativeNSError : NSError
|
|
@end
|
|
|
|
@implementation __SwiftNativeNSError
|
|
|
|
+ (instancetype)allocWithZone:(NSZone *)zone {
|
|
(void)zone;
|
|
swift::crash("__SwiftNativeNSError cannot be instantiated");
|
|
}
|
|
|
|
- (void)dealloc {
|
|
// We must destroy the contained Swift value.
|
|
auto error = (SwiftError*)self;
|
|
error->getType()->vw_destroy(error->getValue());
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
// Override the domain/code/userInfo accessors to follow our idea of NSError's
|
|
// layout. This gives us a buffer in case NSError decides to change its stored
|
|
// property order.
|
|
|
|
- (NSString*)domain {
|
|
auto error = (const SwiftError*)self;
|
|
// The domain string should not be nil; if it is, then this error box hasn't
|
|
// been initialized yet as an NSError.
|
|
auto domain = error->domain.load(SWIFT_MEMORY_ORDER_CONSUME);
|
|
assert(domain
|
|
&& "Error box used as NSError before initialization");
|
|
// Don't need to .retain.autorelease since it's immutable.
|
|
return cf_const_cast<NSString*>(domain);
|
|
}
|
|
|
|
- (NSInteger)code {
|
|
auto error = (const SwiftError*)self;
|
|
return error->code.load(SWIFT_MEMORY_ORDER_CONSUME);
|
|
}
|
|
|
|
- (NSDictionary*)userInfo {
|
|
auto error = (const SwiftError*)self;
|
|
auto userInfo = error->userInfo.load(SWIFT_MEMORY_ORDER_CONSUME);
|
|
assert(userInfo
|
|
&& "Error box used as NSError before initialization");
|
|
// Don't need to .retain.autorelease since it's immutable.
|
|
return cf_const_cast<NSDictionary*>(userInfo);
|
|
}
|
|
|
|
- (id)copyWithZone:(NSZone *)zone {
|
|
(void)zone;
|
|
// __SwiftNativeNSError is immutable, so we can return the same instance back.
|
|
return [self retain];
|
|
}
|
|
|
|
- (Class)classForCoder {
|
|
// This is a runtime-private subclass. When archiving or unarchiving, do so
|
|
// as an NSError.
|
|
return getNSErrorClass();
|
|
}
|
|
|
|
// Note: We support comparing cases of `@objc` enums defined in Swift to
|
|
// pure `NSError`s. They should compare equal as long as the domain and
|
|
// code match. Equal values should have equal hash values. Thus, we can't
|
|
// use the Swift hash value computation that comes from the `Hashable`
|
|
// conformance if one exists, and we must use the `NSError` hashing
|
|
// algorithm.
|
|
//
|
|
// So we are not overriding the `hash` method, even though we are
|
|
// overriding `isEqual:`.
|
|
|
|
- (BOOL)isEqual:(id)other {
|
|
auto self_ = (const SwiftError *)self;
|
|
auto other_ = (const SwiftError *)other;
|
|
assert(!self_->isPureNSError());
|
|
|
|
if (self == other) {
|
|
return YES;
|
|
}
|
|
|
|
if (!other) {
|
|
return NO;
|
|
}
|
|
|
|
if (other_->isPureNSError()) {
|
|
return [super isEqual:other];
|
|
}
|
|
|
|
auto hashableBaseType = self_->getHashableBaseType();
|
|
if (!hashableBaseType || other_->getHashableBaseType() != hashableBaseType) {
|
|
return [super isEqual:other];
|
|
}
|
|
|
|
auto hashableConformance = self_->getHashableConformance();
|
|
if (!hashableConformance) {
|
|
return [super isEqual:other];
|
|
}
|
|
|
|
return _swift_stdlib_Hashable_isEqual_indirect(
|
|
self_->getValue(), other_->getValue(), hashableBaseType,
|
|
hashableConformance);
|
|
}
|
|
|
|
@end
|
|
|
|
Class swift::getNSErrorClass() {
|
|
return SWIFT_LAZY_CONSTANT([NSError class]);
|
|
}
|
|
|
|
const Metadata *swift::getNSErrorMetadata() {
|
|
return SWIFT_LAZY_CONSTANT(
|
|
swift_getObjCClassMetadata((const ClassMetadata *)getNSErrorClass()));
|
|
}
|
|
|
|
static Class getSwiftNativeNSErrorClass() {
|
|
return SWIFT_LAZY_CONSTANT([__SwiftNativeNSError class]);
|
|
}
|
|
|
|
/// Allocate a catchable error object.
|
|
BoxPair
|
|
swift::swift_allocError(const Metadata *type,
|
|
const WitnessTable *errorConformance,
|
|
OpaqueValue *initialValue,
|
|
bool isTake) {
|
|
auto TheSwiftNativeNSError = getSwiftNativeNSErrorClass();
|
|
assert(class_getInstanceSize(TheSwiftNativeNSError) == sizeof(SwiftErrorHeader)
|
|
&& "NSError layout changed!");
|
|
|
|
// Determine the extra allocated space necessary to carry the value.
|
|
// TODO: If the error type is a simple enum with no associated values, we
|
|
// could emplace it in the "code" slot of the NSError and save ourselves
|
|
// some work.
|
|
|
|
unsigned size = type->getValueWitnesses()->getSize();
|
|
unsigned alignMask = type->getValueWitnesses()->getAlignmentMask();
|
|
|
|
size_t alignmentPadding = -sizeof(SwiftError) & alignMask;
|
|
size_t totalExtraSize = sizeof(SwiftError) - sizeof(SwiftErrorHeader)
|
|
+ alignmentPadding + size;
|
|
size_t valueOffset = alignmentPadding + sizeof(SwiftError);
|
|
|
|
// Allocate the instance as if it were a CFError. We won't really initialize
|
|
// the CFError parts until forced to though.
|
|
auto instance
|
|
= (SwiftError *)class_createInstance(TheSwiftNativeNSError, totalExtraSize);
|
|
|
|
// Leave the NSError bits zero-initialized. We'll lazily instantiate them when
|
|
// needed.
|
|
|
|
// Initialize the Swift type metadata.
|
|
instance->type = type;
|
|
instance->errorConformance = errorConformance;
|
|
instance->hashableBaseType = nullptr;
|
|
instance->hashableConformance = nullptr;
|
|
|
|
auto valueBytePtr = reinterpret_cast<char*>(instance) + valueOffset;
|
|
auto valuePtr = reinterpret_cast<OpaqueValue*>(valueBytePtr);
|
|
|
|
// If an initial value was given, copy or take it in.
|
|
if (initialValue) {
|
|
if (isTake)
|
|
type->vw_initializeWithTake(valuePtr, initialValue);
|
|
else
|
|
type->vw_initializeWithCopy(valuePtr, initialValue);
|
|
}
|
|
|
|
// Return the SwiftError reference and a pointer to the uninitialized value
|
|
// inside.
|
|
return BoxPair{reinterpret_cast<HeapObject*>(instance), valuePtr};
|
|
}
|
|
|
|
/// Deallocate an error object whose contained object has already been
|
|
/// destroyed.
|
|
void
|
|
swift::swift_deallocError(SwiftError *error, const Metadata *type) {
|
|
object_dispose((id)error);
|
|
}
|
|
|
|
/// Get the error bridging info from the Foundation overlay. If it can't
|
|
/// be loaded, return all NULLs.
|
|
static ErrorBridgingInfo getErrorBridgingInfo() {
|
|
auto *info = SWIFT_LAZY_CONSTANT(
|
|
reinterpret_cast<ErrorBridgingInfo *>(
|
|
dlsym(RTLD_DEFAULT, ERROR_BRIDGING_SYMBOL_NAME_STRING)));
|
|
if (!info) {
|
|
ErrorBridgingInfo nulls = {};
|
|
return nulls;
|
|
}
|
|
return *info;
|
|
}
|
|
|
|
static const WitnessTable *getNSErrorConformanceToError() {
|
|
// CFError and NSError are toll-free-bridged, so we can use either type's
|
|
// witness table interchangeably. CFError's is potentially slightly more
|
|
// efficient since it doesn't need to dispatch for an unsubclassed NSCFError.
|
|
// The error bridging info lives in the Foundation overlay, but it should be
|
|
// safe to assume that that's been linked in if a user is using NSError in
|
|
// their Swift source.
|
|
|
|
auto conformance = getErrorBridgingInfo().CFErrorErrorConformance;
|
|
assert(conformance &&
|
|
"Foundation overlay not loaded, or 'CFError : Error' conformance "
|
|
"not available");
|
|
return swift_getWitnessTable(conformance,
|
|
conformance->getCanonicalTypeMetadata(),
|
|
nullptr);
|
|
}
|
|
|
|
static const HashableWitnessTable *getNSErrorConformanceToHashable() {
|
|
auto conformance = getErrorBridgingInfo().NSObjectHashableConformance;
|
|
assert(conformance &&
|
|
"ObjectiveC overlay not loaded, or 'NSObject : Hashable' conformance "
|
|
"not available");
|
|
return (const HashableWitnessTable *)swift_getWitnessTable(
|
|
conformance,
|
|
conformance->getCanonicalTypeMetadata(),
|
|
nullptr);
|
|
}
|
|
|
|
bool SwiftError::isPureNSError() const {
|
|
// We can do an exact type check; __SwiftNativeNSError shouldn't be subclassed
|
|
// or proxied.
|
|
return _swift_getClass(this) != (ClassMetadata *)getSwiftNativeNSErrorClass();
|
|
}
|
|
|
|
const Metadata *SwiftError::getType() const {
|
|
if (isPureNSError()) {
|
|
auto asError = reinterpret_cast<NSError *>(const_cast<SwiftError *>(this));
|
|
return swift_getObjCClassMetadata((ClassMetadata*)[asError class]);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
const WitnessTable *SwiftError::getErrorConformance() const {
|
|
if (isPureNSError()) {
|
|
return getNSErrorConformanceToError();
|
|
}
|
|
return errorConformance;
|
|
}
|
|
|
|
const Metadata *SwiftError::getHashableBaseType() const {
|
|
if (isPureNSError()) {
|
|
return getNSErrorMetadata();
|
|
}
|
|
if (auto type = hashableBaseType.load(std::memory_order_acquire)) {
|
|
if (reinterpret_cast<uintptr_t>(type) == 1) {
|
|
return nullptr;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
const Metadata *expectedType = nullptr;
|
|
const Metadata *hashableBaseType = findHashableBaseType(type);
|
|
this->hashableBaseType.compare_exchange_strong(
|
|
expectedType, hashableBaseType ? hashableBaseType
|
|
: reinterpret_cast<const Metadata *>(1),
|
|
std::memory_order_acq_rel);
|
|
return type;
|
|
}
|
|
|
|
const HashableWitnessTable *SwiftError::getHashableConformance() const {
|
|
if (isPureNSError()) {
|
|
return getNSErrorConformanceToHashable();
|
|
}
|
|
if (auto wt = hashableConformance.load(std::memory_order_acquire)) {
|
|
if (reinterpret_cast<uintptr_t>(wt) == 1) {
|
|
return nullptr;
|
|
}
|
|
return wt;
|
|
}
|
|
|
|
const HashableWitnessTable *expectedWT = nullptr;
|
|
const HashableWitnessTable *wt =
|
|
reinterpret_cast<const HashableWitnessTable *>(
|
|
swift_conformsToProtocol(type, &HashableProtocolDescriptor));
|
|
hashableConformance.compare_exchange_strong(
|
|
expectedWT, wt ? wt : reinterpret_cast<const HashableWitnessTable *>(1),
|
|
std::memory_order_acq_rel);
|
|
return wt;
|
|
}
|
|
|
|
/// Extract a pointer to the value, the type metadata, and the Error
|
|
/// protocol witness from an error object.
|
|
///
|
|
/// The "scratch" pointer should point to an uninitialized word-sized
|
|
/// temporary buffer. The implementation may write a reference to itself to
|
|
/// that buffer if the error object is a toll-free-bridged NSError instead of
|
|
/// a native Swift error, in which case the object itself is the "boxed" value.
|
|
///
|
|
/// This function is called by compiler-generated code.
|
|
void
|
|
swift::swift_getErrorValue(const SwiftError *errorObject,
|
|
void **scratch,
|
|
ErrorValueResult *out) {
|
|
// TODO: Would be great if Clang had a return-three convention so we didn't
|
|
// need the out parameter here.
|
|
|
|
out->type = errorObject->getType();
|
|
|
|
// Check for a bridged Cocoa NSError.
|
|
if (errorObject->isPureNSError()) {
|
|
// Return a pointer to the scratch buffer.
|
|
*scratch = (void*)errorObject;
|
|
out->value = (const OpaqueValue *)scratch;
|
|
out->errorConformance = getNSErrorConformanceToError();
|
|
} else {
|
|
out->value = errorObject->getValue();
|
|
out->errorConformance = errorObject->errorConformance;
|
|
}
|
|
}
|
|
|
|
// internal func _getErrorDomainNSString<T : Error>
|
|
// (_ x: UnsafePointer<T>) -> AnyObject
|
|
#define getErrorDomainNSString \
|
|
MANGLE_SYM(s23_getErrorDomainNSStringyyXlSPyxGs0B0RzlF)
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
|
|
NSString *getErrorDomainNSString(const OpaqueValue *error,
|
|
const Metadata *T,
|
|
const WitnessTable *Error);
|
|
|
|
// internal func _getErrorCode<T : Error>(_ x: UnsafePointer<T>) -> Int
|
|
#define getErrorCode \
|
|
MANGLE_SYM(s13_getErrorCodeySiSPyxGs0B0RzlF)
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
|
|
NSInteger getErrorCode(const OpaqueValue *error,
|
|
const Metadata *T,
|
|
const WitnessTable *Error);
|
|
|
|
// internal func _getErrorUserInfoNSDictionary<T : Error>(_ x: UnsafePointer<T>) -> AnyObject
|
|
#define getErrorUserInfoNSDictionary \
|
|
MANGLE_SYM(s29_getErrorUserInfoNSDictionaryyyXlSgSPyxGs0B0RzlF)
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
|
|
NSDictionary *getErrorUserInfoNSDictionary(
|
|
const OpaqueValue *error,
|
|
const Metadata *T,
|
|
const WitnessTable *Error);
|
|
|
|
// @_silgen_name("_swift_stdlib_getErrorDefaultUserInfo")
|
|
// internal func _getErrorDefaultUserInfo<T : Error>(_ x: T) -> AnyObject
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
|
|
NSDictionary *_swift_stdlib_getErrorDefaultUserInfo(OpaqueValue *error,
|
|
const Metadata *T,
|
|
const WitnessTable *Error) {
|
|
// public func Foundation._getErrorDefaultUserInfo<T: Error>(_ error: T)
|
|
// -> AnyObject?
|
|
auto foundationGetDefaultUserInfo = getErrorBridgingInfo().GetErrorDefaultUserInfo;
|
|
if (!foundationGetDefaultUserInfo) {
|
|
return nullptr;
|
|
}
|
|
|
|
// +0 Convention: In the case where we have the +1 convention, this will
|
|
// destroy the error for us, otherwise, it will take the value guaranteed. The
|
|
// conclusion is that we can leave this alone.
|
|
return foundationGetDefaultUserInfo(error, T, Error);
|
|
}
|
|
|
|
/// Take an Error box and turn it into a valid NSError instance. Error is passed
|
|
/// at +1.
|
|
id
|
|
swift::_swift_stdlib_bridgeErrorToNSError(SwiftError *errorObject) {
|
|
auto ns = reinterpret_cast<NSError *>(errorObject);
|
|
|
|
// If we already have a domain set, then we've already initialized.
|
|
// If this is a real NSError, then Cocoa and Core Foundation's initializers
|
|
// guarantee that the domain is never nil, so if this test fails, we can
|
|
// assume we're working with a bridged error. (Note that Cocoa and CF
|
|
// **will** allow the userInfo storage to be initialized to nil.)
|
|
//
|
|
// If this is a bridged error, then the domain, code, and user info are
|
|
// lazily computed, and the domain will be nil if they haven't been computed
|
|
// yet. The initialization is ordered in such a way that all other lazy
|
|
// initialization of the object happens-before the domain initialization so
|
|
// that the domain can be used alone as a flag for the initialization of the
|
|
// object.
|
|
if (errorObject->domain.load(std::memory_order_acquire)) {
|
|
return ns;
|
|
}
|
|
|
|
// Otherwise, calculate the domain, code, and user info, and
|
|
// initialize the NSError.
|
|
auto value = SwiftError::getIndirectValue(&errorObject);
|
|
auto type = errorObject->getType();
|
|
auto witness = errorObject->getErrorConformance();
|
|
|
|
NSString *domain = getErrorDomainNSString(value, type, witness);
|
|
NSInteger code = getErrorCode(value, type, witness);
|
|
NSDictionary *userInfo = getErrorUserInfoNSDictionary(value, type, witness);
|
|
|
|
// Never produce an empty userInfo dictionary.
|
|
if (!userInfo)
|
|
userInfo = SWIFT_LAZY_CONSTANT(@{});
|
|
|
|
// The error code shouldn't change, so we can store it blindly, even if
|
|
// somebody beat us to it. The store can be relaxed, since we'll do a
|
|
// store(release) of the domain last thing to publish the initialized
|
|
// NSError.
|
|
errorObject->code.store(code, std::memory_order_relaxed);
|
|
|
|
// However, we need to cmpxchg the userInfo; if somebody beat us to it,
|
|
// we need to release.
|
|
CFDictionaryRef expectedUserInfo = nullptr;
|
|
if (!errorObject->userInfo.compare_exchange_strong(expectedUserInfo,
|
|
(CFDictionaryRef)userInfo,
|
|
std::memory_order_acq_rel))
|
|
objc_release(userInfo);
|
|
|
|
// We also need to cmpxchg in the domain; if somebody beat us to it,
|
|
// we need to release.
|
|
//
|
|
// Storing the domain must be the **LAST THING** we do, since it's
|
|
// also the flag that the NSError has been initialized.
|
|
CFStringRef expectedDomain = nullptr;
|
|
if (!errorObject->domain.compare_exchange_strong(expectedDomain,
|
|
(CFStringRef)domain,
|
|
std::memory_order_acq_rel))
|
|
objc_release(domain);
|
|
|
|
return ns;
|
|
}
|
|
|
|
extern "C" const ProtocolDescriptor PROTOCOL_DESCR_SYM(s5Error);
|
|
|
|
bool
|
|
swift::tryDynamicCastNSErrorObjectToValue(HeapObject *object,
|
|
OpaqueValue *dest,
|
|
const Metadata *destType,
|
|
DynamicCastFlags flags) {
|
|
Class NSErrorClass = getNSErrorClass();
|
|
|
|
// The object must be an NSError subclass.
|
|
if (![reinterpret_cast<id>(object) isKindOfClass: NSErrorClass])
|
|
return false;
|
|
|
|
NSError *srcInstance = reinterpret_cast<NSError *>(object);
|
|
|
|
// A __SwiftNativeNSError box can always be unwrapped to cast the value back
|
|
// out as an Error existential.
|
|
if (!reinterpret_cast<SwiftError*>(srcInstance)->isPureNSError()) {
|
|
ProtocolDescriptorRef theErrorProtocol(&PROTOCOL_DESCR_SYM(s5Error),
|
|
ProtocolDispatchStrategy::Swift);
|
|
auto theErrorTy =
|
|
swift_getExistentialTypeMetadata(ProtocolClassConstraint::Any,
|
|
nullptr, 1, &theErrorProtocol);
|
|
return swift_dynamicCast(dest, reinterpret_cast<OpaqueValue *>(&object),
|
|
theErrorTy, destType, flags);
|
|
}
|
|
|
|
// public func Foundation._bridgeNSErrorToError<
|
|
// T : _ObjectiveCBridgeableError
|
|
// >(error: NSError, out: UnsafeMutablePointer<T>) -> Bool {
|
|
auto bridgeNSErrorToError = getErrorBridgingInfo().BridgeErrorToNSError;
|
|
// protocol _ObjectiveCBridgeableError
|
|
auto TheObjectiveCBridgeableError = getErrorBridgingInfo().ObjectiveCBridgeableError;
|
|
|
|
// If the Foundation overlay isn't loaded, then arbitrary NSErrors can't be
|
|
// bridged.
|
|
if (!bridgeNSErrorToError || !TheObjectiveCBridgeableError)
|
|
return false;
|
|
|
|
// Is the target type a bridgeable error?
|
|
auto witness = swift_conformsToProtocol(destType,
|
|
TheObjectiveCBridgeableError);
|
|
|
|
if (witness) {
|
|
// If so, attempt the bridge.
|
|
if (bridgeNSErrorToError(srcInstance, dest, destType, witness)) {
|
|
if (flags & DynamicCastFlags::TakeOnSuccess)
|
|
objc_release(srcInstance);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// If the destination is just an Error then we can bridge directly.
|
|
auto *destTypeExistential = dyn_cast<ExistentialTypeMetadata>(destType);
|
|
if (destTypeExistential &&
|
|
destTypeExistential->getRepresentation() == ExistentialTypeRepresentation::Error) {
|
|
auto destBoxAddr = reinterpret_cast<NSError**>(dest);
|
|
*destBoxAddr = objc_retain(srcInstance);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
swift::tryDynamicCastNSErrorToValue(OpaqueValue *dest,
|
|
OpaqueValue *src,
|
|
const Metadata *srcType,
|
|
const Metadata *destType,
|
|
DynamicCastFlags flags) {
|
|
// NSError instances must be class instances, anything else automatically fails.
|
|
switch (srcType->getKind()) {
|
|
case MetadataKind::Class:
|
|
case MetadataKind::ObjCClassWrapper:
|
|
case MetadataKind::ForeignClass:
|
|
return tryDynamicCastNSErrorObjectToValue(*reinterpret_cast<HeapObject **>(src),
|
|
dest, destType, flags);
|
|
|
|
// Not a class.
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SwiftError *
|
|
swift::swift_errorRetain(SwiftError *error) {
|
|
// For now, SwiftError is always objc-refcounted.
|
|
return (SwiftError*)objc_retain((id)error);
|
|
}
|
|
|
|
void
|
|
swift::swift_errorRelease(SwiftError *error) {
|
|
// For now, SwiftError is always objc-refcounted.
|
|
return objc_release((id)error);
|
|
}
|
|
|
|
/// Breakpoint hook for debuggers.
|
|
SWIFT_CC(swift) void
|
|
swift::swift_willThrow(SWIFT_CONTEXT void *unused,
|
|
SWIFT_ERROR_RESULT SwiftError **error) {
|
|
// empty
|
|
}
|
|
|
|
#endif
|
|
|