From 04a7cc7cdd5bcafc0910babe34b880027575d566 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 31 Mar 2016 15:52:29 -0400 Subject: [PATCH] Enablement of ObjectiveCBridgeable protocol for Linux Make the ObjectiveCBridgeable protocol available and minimal pieces of the runtime support for it available even without an Objective-C runtime. This is motivated by supporting bridging in swift-corelibs-foundation on Linux via the compiler/runtime support provided by ObjectiveCBridgeable. Also enable the six existing testcases for ObjectiveCBridgeable that don't import Foundation or truly rely on an Objective-C runtime being present. --- stdlib/public/core/BridgeObjectiveC.swift | 25 +++++++++++++++++++-- stdlib/public/runtime/Casting.cpp | 10 +++++++-- test/1_stdlib/Bridgeable.swift | 9 ++++++-- test/SILOptimizer/bridging_checked_cast.sil | 1 - test/expr/cast/array_bridge.swift | 2 -- test/expr/cast/array_downcast.swift | 2 -- test/expr/cast/bridged.swift | 2 -- test/expr/cast/set_bridge.swift | 2 -- unittests/runtime/CMakeLists.txt | 7 ++++++ 9 files changed, 45 insertions(+), 15 deletions(-) diff --git a/stdlib/public/core/BridgeObjectiveC.swift b/stdlib/public/core/BridgeObjectiveC.swift index a1ebdf17e8219..ae9c5b3b4d3a6 100644 --- a/stdlib/public/core/BridgeObjectiveC.swift +++ b/stdlib/public/core/BridgeObjectiveC.swift @@ -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 @@ -92,6 +91,7 @@ public protocol _ObjectiveCBridgeable { -> Self } +#if _runtime(_ObjC) //===--- Bridging for metatypes -------------------------------------------===// /// A stand-in for a value of metatype type. @@ -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. @@ -163,9 +164,12 @@ public struct _BridgeableMetatype: _ObjectiveCBridgeable { /// - otherwise, the result is empty. @warn_unused_result public func _bridgeToObjectiveC(_ x: T) -> AnyObject? { +#if _runtime(_ObjC) if _fastPath(_isClassOrObjCExistential(T.self)) { return unsafeBitCast(x, to: AnyObject.self) } +#endif + return _bridgeNonVerbatimToObjectiveC(x) } @@ -177,6 +181,7 @@ public func _bridgeToObjectiveCUnconditional(_ 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 @@ -193,6 +198,7 @@ func _bridgeToObjectiveCUnconditionalAutorelease(_ x: T) -> AnyObject _autorelease(bridged) return bridged } +#endif @warn_unused_result @_silgen_name("swift_bridgeNonVerbatimToObjectiveC") @@ -211,9 +217,11 @@ func _bridgeNonVerbatimToObjectiveC(_ x: T) -> AnyObject? /// - otherwise, trap. @warn_unused_result public func _forceBridgeFromObjectiveC(_ 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) @@ -250,9 +258,11 @@ public func _conditionallyBridgeFromObjectiveC( _ 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) @@ -293,6 +303,7 @@ func _bridgeNonVerbatimFromObjectiveCConditional( _ result: inout T? ) -> Bool + /// Determines if values of a given type can be converted to an Objective-C /// representation. /// @@ -301,9 +312,12 @@ func _bridgeNonVerbatimFromObjectiveCConditional( /// `T._isBridgedToObjectiveC()`. @warn_unused_result public func _isBridgedToObjectiveC(_: T.Type) -> Bool { +#if _runtime(_ObjC) if _fastPath(_isClassOrObjCExistential(T.self)) { return true } +#endif + return _isBridgedNonVerbatimToObjectiveC(T.self) } @@ -317,15 +331,21 @@ func _isBridgedNonVerbatimToObjectiveC(_: T.Type) -> Bool /// `Array` can be `unsafeBitCast` as an array of `AnyObject`. @warn_unused_result public func _isBridgedVerbatimToObjectiveC(_: 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.Type) -> Any.Type? { +#if _runtime(_ObjC) if _fastPath(_isClassOrObjCExistential(T.self)) { return T.self } +#endif return _getBridgedNonVerbatimObjectiveCType(T.self) } @@ -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 diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 7c7c9985e1a58..164c9a40e8365 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -2268,7 +2268,6 @@ static inline bool swift_isClassOrObjCExistentialTypeImpl(const Metadata *T) { return false; } -#if SWIFT_OBJC_INTEROP //===----------------------------------------------------------------------===// // Bridging to and from Objective-C //===----------------------------------------------------------------------===// @@ -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 @@ -2491,6 +2491,7 @@ static bool _dynamicCastClassToValueViaObjCBridgeable( return success; } +#endif //===--- Bridging helpers for the Swift stdlib ----------------------------===// // Functions that must discover and possibly use an arbitrary type's @@ -2498,8 +2499,10 @@ static bool _dynamicCastClassToValueViaObjCBridgeable( // documentation. //===----------------------------------------------------------------------===// +#if SWIFT_OBJC_INTEROP extern "C" const _ObjectiveCBridgeableWitnessTable _TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables; +#endif static const _ObjectiveCBridgeableWitnessTable * findBridgeWitness(const Metadata *T) { @@ -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(T); if (metaTy->InstanceType->isAnyClass()) return &_TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables; +#endif break; } case MetadataKind::ExistentialMetatype: { +#if SWIFT_OBJC_INTEROP auto existentialMetaTy = static_cast(T); if (existentialMetaTy->isObjC()) return &_TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables; +#endif break; } @@ -2682,7 +2689,6 @@ extern "C" bool swift_isBridgedNonVerbatimToObjectiveC( return bridgeWitness && bridgeWitness->isBridgedToObjectiveC(value, T, bridgeWitness); } -#endif // func isClassOrObjCExistential(x: T.Type) -> Bool SWIFT_RUNTIME_EXPORT diff --git a/test/1_stdlib/Bridgeable.swift b/test/1_stdlib/Bridgeable.swift index 78f18fef40713..c2dcb698756d2 100644 --- a/test/1_stdlib/Bridgeable.swift +++ b/test/1_stdlib/Bridgeable.swift @@ -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?) @@ -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 : _ObjectiveCBridgeable { diff --git a/test/SILOptimizer/bridging_checked_cast.sil b/test/SILOptimizer/bridging_checked_cast.sil index 0ce66b9df0604..7932812236d08 100644 --- a/test/SILOptimizer/bridging_checked_cast.sil +++ b/test/SILOptimizer/bridging_checked_cast.sil @@ -1,5 +1,4 @@ // RUN: %target-sil-opt -enable-sil-verify-all -inline %s | FileCheck %s -// REQUIRES: objc_interop import Swift diff --git a/test/expr/cast/array_bridge.swift b/test/expr/cast/array_bridge.swift index 5d07a32429d13..ce78928a38c99 100644 --- a/test/expr/cast/array_bridge.swift +++ b/test/expr/cast/array_bridge.swift @@ -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?) diff --git a/test/expr/cast/array_downcast.swift b/test/expr/cast/array_downcast.swift index c7dffca418f5a..823395b3f39da 100644 --- a/test/expr/cast/array_downcast.swift +++ b/test/expr/cast/array_downcast.swift @@ -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?) diff --git a/test/expr/cast/bridged.swift b/test/expr/cast/bridged.swift index 93ab037409fae..ec032c4e90d7a 100644 --- a/test/expr/cast/bridged.swift +++ b/test/expr/cast/bridged.swift @@ -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. diff --git a/test/expr/cast/set_bridge.swift b/test/expr/cast/set_bridge.swift index eeb9e824fe218..58822bf5298b7 100644 --- a/test/expr/cast/set_bridge.swift +++ b/test/expr/cast/set_bridge.swift @@ -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?) diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt index 8b8a23d7ecfcb..702ef1252e10c 100644 --- a/unittests/runtime/CMakeLists.txt +++ b/unittests/runtime/CMakeLists.txt @@ -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