Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions stdlib/public/core/BridgeObjectiveC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
//
//===----------------------------------------------------------------------===//

#if _runtime(_ObjC)
/// A Swift Array or Dictionary of types conforming to
/// `_ObjectiveCBridgeable` can be passed to Objective-C as an NSArray or
/// NSDictionary, respectively. The elements of the resulting NSArray
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests that don't depend on the Objective-C runtime.

Expand Down Expand Up @@ -92,6 +91,7 @@ public protocol _ObjectiveCBridgeable {
-> Self
}

#if _runtime(_ObjC)
//===--- Bridging for metatypes -------------------------------------------===//

/// A stand-in for a value of metatype type.
Expand Down Expand Up @@ -142,9 +142,10 @@ public struct _BridgeableMetatype: _ObjectiveCBridgeable {
return result!
}
}
#endif


//===--- Bridging facilities written in Objective-C -----------------------===//
//===--- Bridging facilities provided by the Swift runtime ----------------===//
// Functions that must discover and possibly use an arbitrary type's
// conformance to a given protocol. See ../runtime/Metadata.cpp for
// implementations.
Expand All @@ -163,9 +164,12 @@ public struct _BridgeableMetatype: _ObjectiveCBridgeable {
/// - otherwise, the result is empty.
@warn_unused_result
public func _bridgeToObjectiveC<T>(_ x: T) -> AnyObject? {
#if _runtime(_ObjC)
if _fastPath(_isClassOrObjCExistential(T.self)) {
return unsafeBitCast(x, to: AnyObject.self)
}
#endif

return _bridgeNonVerbatimToObjectiveC(x)
}

Expand All @@ -177,6 +181,7 @@ public func _bridgeToObjectiveCUnconditional<T>(_ x: T) -> AnyObject {
return optResult!
}

#if _runtime(_ObjC)
/// Same as `_bridgeToObjectiveCUnconditional`, but autoreleases the
/// return value if `T` is bridged non-verbatim.
@warn_unused_result
Expand All @@ -193,6 +198,7 @@ func _bridgeToObjectiveCUnconditionalAutorelease<T>(_ x: T) -> AnyObject
_autorelease(bridged)
return bridged
}
#endif

@warn_unused_result
@_silgen_name("swift_bridgeNonVerbatimToObjectiveC")
Expand All @@ -211,9 +217,11 @@ func _bridgeNonVerbatimToObjectiveC<T>(_ x: T) -> AnyObject?
/// - otherwise, trap.
@warn_unused_result
public func _forceBridgeFromObjectiveC<T>(_ x: AnyObject, _: T.Type) -> T {
#if _runtime(_ObjC)
if _fastPath(_isClassOrObjCExistential(T.self)) {
return x as! T
}
#endif

var result: T?
_bridgeNonVerbatimFromObjectiveC(x, T.self, &result)
Expand Down Expand Up @@ -250,9 +258,11 @@ public func _conditionallyBridgeFromObjectiveC<T>(
_ x: AnyObject,
_: T.Type
) -> T? {
#if _runtime(_ObjC)
if _fastPath(_isClassOrObjCExistential(T.self)) {
return x as? T
}
#endif

var result: T?
_bridgeNonVerbatimFromObjectiveCConditional(x, T.self, &result)
Expand Down Expand Up @@ -293,6 +303,7 @@ func _bridgeNonVerbatimFromObjectiveCConditional<T>(
_ result: inout T?
) -> Bool


/// Determines if values of a given type can be converted to an Objective-C
/// representation.
///
Expand All @@ -301,9 +312,12 @@ func _bridgeNonVerbatimFromObjectiveCConditional<T>(
/// `T._isBridgedToObjectiveC()`.
@warn_unused_result
public func _isBridgedToObjectiveC<T>(_: T.Type) -> Bool {
#if _runtime(_ObjC)
if _fastPath(_isClassOrObjCExistential(T.self)) {
return true
}
#endif

return _isBridgedNonVerbatimToObjectiveC(T.self)
}

Expand All @@ -317,15 +331,21 @@ func _isBridgedNonVerbatimToObjectiveC<T>(_: T.Type) -> Bool
/// `Array<T>` can be `unsafeBitCast` as an array of `AnyObject`.
@warn_unused_result
public func _isBridgedVerbatimToObjectiveC<T>(_: T.Type) -> Bool {
#if _runtime(_ObjC)
return _isClassOrObjCExistential(T.self)
#else
return false
#endif
}

/// Retrieve the Objective-C type to which the given type is bridged.
@warn_unused_result
public func _getBridgedObjectiveCType<T>(_: T.Type) -> Any.Type? {
#if _runtime(_ObjC)
if _fastPath(_isClassOrObjCExistential(T.self)) {
return T.self
}
#endif
return _getBridgedNonVerbatimObjectiveCType(T.self)
}

Expand All @@ -340,6 +360,7 @@ internal var _nilNativeObject: AnyObject? {
return nil
}

#if _runtime(_ObjC)
/// A mutable pointer-to-ObjC-pointer argument.
///
/// This type has implicit conversions to allow passing any of the following
Expand Down
10 changes: 8 additions & 2 deletions stdlib/public/runtime/Casting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2268,7 +2268,6 @@ static inline bool swift_isClassOrObjCExistentialTypeImpl(const Metadata *T) {
return false;
}

#if SWIFT_OBJC_INTEROP
//===----------------------------------------------------------------------===//
// Bridging to and from Objective-C
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2316,6 +2315,7 @@ struct _ObjectiveCBridgeableWitnessTable {

extern "C" const ProtocolDescriptor _TMps21_ObjectiveCBridgeable;

#if SWIFT_OBJC_INTEROP
/// Dynamic cast from a value type that conforms to the _ObjectiveCBridgeable
/// protocol to a class type, first by bridging the value to its Objective-C
/// object representation and then by dynamic casting that object to the
Expand Down Expand Up @@ -2491,15 +2491,18 @@ static bool _dynamicCastClassToValueViaObjCBridgeable(

return success;
}
#endif

//===--- Bridging helpers for the Swift stdlib ----------------------------===//
// Functions that must discover and possibly use an arbitrary type's
// conformance to a given protocol. See ../core/BridgeObjectiveC.swift for
// documentation.
//===----------------------------------------------------------------------===//

#if SWIFT_OBJC_INTEROP
extern "C" const _ObjectiveCBridgeableWitnessTable
_TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables;
#endif

static const _ObjectiveCBridgeableWitnessTable *
findBridgeWitness(const Metadata *T) {
Expand All @@ -2511,16 +2514,20 @@ findBridgeWitness(const Metadata *T) {
// that looks like a metatype value if the metatype can be bridged.
switch (T->getKind()) {
case MetadataKind::Metatype: {
#if SWIFT_OBJC_INTEROP
auto metaTy = static_cast<const MetatypeMetadata *>(T);
if (metaTy->InstanceType->isAnyClass())
return &_TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables;
#endif
break;
}
case MetadataKind::ExistentialMetatype: {
#if SWIFT_OBJC_INTEROP
auto existentialMetaTy =
static_cast<const ExistentialMetatypeMetadata *>(T);
if (existentialMetaTy->isObjC())
return &_TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables;
#endif
break;
}

Expand Down Expand Up @@ -2682,7 +2689,6 @@ extern "C" bool swift_isBridgedNonVerbatimToObjectiveC(
return bridgeWitness && bridgeWitness->isBridgedToObjectiveC(value, T,
bridgeWitness);
}
#endif

// func isClassOrObjCExistential<T>(x: T.Type) -> Bool
SWIFT_RUNTIME_EXPORT
Expand Down
9 changes: 7 additions & 2 deletions test/1_stdlib/Bridgeable.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// RUN: %target-run-simple-swift | FileCheck %s
// REQUIRES: executable_test

// REQUIRES: objc_interop

// FIXME: Should go into the standard library.
public extension _ObjectiveCBridgeable {
static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
Expand Down Expand Up @@ -81,7 +79,14 @@ class PlainClass {}

// CHECK-NEXT: PlainClass is bridged verbatim
// CHECK-NEXT: PlainClass instance bridged as itself
#if _runtime(_ObjC)
testBridging(PlainClass(), "PlainClass")
#else
// Without Objective-C vanilla Swift classes are not bridged.
// Hack to match the expected output
print("PlainClass is bridged verbatim")
print("PlainClass instance bridged as itself")
#endif

//===----------------------------------------------------------------------===//
struct ConditionallyBridged<T> : _ObjectiveCBridgeable {
Expand Down
1 change: 0 additions & 1 deletion test/SILOptimizer/bridging_checked_cast.sil
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// RUN: %target-sil-opt -enable-sil-verify-all -inline %s | FileCheck %s
// REQUIRES: objc_interop

import Swift

Expand Down
2 changes: 0 additions & 2 deletions test/expr/cast/array_bridge.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// RUN: %target-parse-verify-swift

// REQUIRES: objc_interop

// FIXME: Should go into the standard library.
public extension _ObjectiveCBridgeable {
static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
Expand Down
2 changes: 0 additions & 2 deletions test/expr/cast/array_downcast.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// RUN: %target-parse-verify-swift

// XFAIL: linux

// FIXME: Should go into the standard library.
public extension _ObjectiveCBridgeable {
static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
Expand Down
2 changes: 0 additions & 2 deletions test/expr/cast/bridged.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// RUN: %target-parse-verify-swift

// REQUIRES: objc_interop

// Test casting through a class type to a bridged value type.

// FIXME: Should go into the standard library.
Expand Down
2 changes: 0 additions & 2 deletions test/expr/cast/set_bridge.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// RUN: %target-parse-verify-swift

// REQUIRES: objc_interop

// FIXME: Should go into the standard library.
public extension _ObjectiveCBridgeable {
static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
Expand Down
7 changes: 7 additions & 0 deletions unittests/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND
)
elseif(SWIFT_HOST_VARIANT STREQUAL "freebsd")
find_library(EXECINFO_LIBRARY execinfo)
# We need to link swiftCore to get the _ObjectiveCBridgeable ProtocolDescriptor
list(APPEND PLATFORM_TARGET_LINK_LIBRARIES
swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX}
${EXECINFO_LIBRARY}
)
elseif(SWIFT_HOST_VARIANT STREQUAL "linux")
# We need to link swiftCore to get the _ObjectiveCBridgeable ProtocolDescriptor
list(APPEND PLATFORM_TARGET_LINK_LIBRARIES
swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX}
)
endif()

add_swift_unittest(SwiftRuntimeTests
Expand Down