Files
swift-mirror/test/stdlib/ArrayBridge.swift
Doug Gregor 22dc55058e Make bridgeFromObjectiveC return non-optional.
Now that we use bridgeFromObjectiveCConditional to perform conditional
bridging, make bridgeFromObjectiveC handle forced bridging. For the
latter, deferred checking is acceptable.

Almost all of <rdar://problem/17319154>.


Swift SVN r19046
2014-06-20 13:15:41 +00:00

492 lines
16 KiB
Swift

//===--- ArrayBridge.swift - Tests of Array casting and bridging ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: rm -rf %t
// RUN: mkdir -p %t
//
// FIXME: -fobjc-abi-version=2 is a band-aid fix for for rdar://16946936
//
// RUN: xcrun -sdk %target-sdk-name clang++ -fobjc-abi-version=2 -arch %target-cpu %S/Inputs/ArrayBridge/ArrayBridge.m -c -o %t/ArrayBridgeObjC.o -g
// RUN: %target-build-swift %s -I %S/Inputs/ArrayBridge/ -Xlinker %t/ArrayBridgeObjC.o -o %t/ArrayBridge
// RUN: %target-run %t/ArrayBridge > %t.txt
// RUN: FileCheck %s < %t.txt
// CHECK: testing...
println("testing...")
import Foundation
import ArrayBridgeObjC
var trackedCount = 0
var nextTrackedSerialNumber = 0
@objc protocol Fooable {
func foo()
}
@objc protocol Barable {
func bar()
}
@objc protocol Bazable {
func baz()
}
class Tracked : NSObject, ForwardIndex, Printable, Fooable {
func foo() { }
init(_ value: Int) {
++trackedCount
serialNumber = ++nextTrackedSerialNumber
self.value = value
}
deinit {
assert(serialNumber > 0, "double destruction!")
--trackedCount
serialNumber = -serialNumber
}
override var description: String {
assert(serialNumber > 0, "dead Tracked!")
return "Base#\(serialNumber)(\(value))"
}
func succ() -> Tracked {
return Tracked(self.value.succ())
}
var value: Int
var serialNumber: Int
}
func == (x: Tracked, y: Tracked) -> Bool {
return x.value == y.value
}
typealias Base = Tracked
class Derived : Base, Printable, Barable {
func bar() { }
override var description: String {
assert(serialNumber > 0, "dead Tracked!")
return "Derived#\(serialNumber)(\(value))"
}
}
class BridgedObjC : Base, Printable, Barable {
func bar() { }
override var description: String {
assert(serialNumber > 0, "dead Tracked!")
return "BridgedObjC#\(serialNumber)(\(value))"
}
}
struct BridgedSwift : Printable, _ConditionallyBridgedToObjectiveC {
static func getObjectiveCType() -> Any.Type {
return BridgedObjC.self
}
func bridgeToObjectiveC() -> BridgedObjC {
return BridgedObjC(trak.value)
}
static func isBridgedToObjectiveC() -> Bool {
return true
}
static func bridgeFromObjectiveC(x: BridgedObjC) -> BridgedSwift {
assert(x.value >= 0, "not bridged")
return BridgedSwift(x.value)
}
static func bridgeFromObjectiveCConditional(x: BridgedObjC) -> BridgedSwift? {
return x.value >= 0 ? BridgedSwift(x.value) : nil
}
var description: String {
assert(trak.serialNumber > 0, "dead Tracked!")
return "BridgedSwift#\(trak.serialNumber)(\(trak.value))"
}
init(_ value: Int) {
self.trak = Tracked(value)
}
func succ() -> BridgedSwift {
return BridgedSwift(trak.value.succ())
}
var trak: Tracked
}
// A class used to test various Objective-C thunks.
class Thunks : NSObject {
func createBridgedObjC(value: Int) -> AnyObject {
return BridgedObjC(value)
}
@objc func acceptBridgedObjCArray(x: BridgedObjC[]) {
println("acceptBridgedObjCArray(\(x))")
}
@objc func produceBridgedObjCArray(numItems: Int) -> BridgedObjC[] {
var array: BridgedObjC[] = []
for i in 0..<numItems {
array.append(BridgedObjC(i))
}
println("produceBridgedObjCArray(\(array))")
return array
}
@objc func acceptBridgedSwiftArray(x: BridgedSwift[]) {
println("acceptBridgedSwiftArray(\(x))")
}
@objc func produceBridgedSwiftArray(numItems: Int) -> BridgedSwift[] {
var array: BridgedSwift[] = []
for i in 0..<numItems {
array.append(BridgedSwift(i))
}
println("produceBridgedSwiftArray(\(array))")
return array
}
}
//===--- Bridged Verbatim -------------------------------------------------===//
// Base is "bridged verbatim"
//===----------------------------------------------------------------------===//
func testBridgedVerbatim() {
let bases: Base[] = [Base(100), Base(200), Base(300)]
//===--- Implicit conversion to/from NSArray ------------------------------===//
// CHECK-NEXT: Base#1(100)
let basesConvertedToNSArray: NSArray = bases
println(basesConvertedToNSArray.objectAtIndex(0) as Base)
// Create an ordinary NSArray, not a native one
let nsArrayOfBase: NSArray = NSArray(object: Base(42))
// NSArray converts implicitly to AnyObject[]...
let nsArrayOfBaseConvertedToAnyObjectArray: AnyObject[] = nsArrayOfBase
// Capture the representation of the first element
// CHECK-NEXT: [[base42:Base.*42]]
println(nsArrayOfBase.objectAtIndex(0) as Base)
// ...with the same elements
// CHECK-NEXT: [[base42]]
println(nsArrayOfBaseConvertedToAnyObjectArray[0] as Base)
//===--- Up- and Down-casts -----------------------------------------------===//
var derived: Derived[] = [Derived(11), Derived(22)]
// CHECK-NEXT: [[derived0:\[Derived#[0-9]+\(11\), Derived#[0-9]+\(22\)\]{1}]]
println(derived)
// upcast is implicit
let derivedAsBases: Base[] = derived
// CHECK-NEXT: [[derived0]]
println(derivedAsBases)
// Arrays are logically distinct after upcast
derived[0] = Derived(33)
// CHECK-NEXT: {{\[Derived#[0-9]+\(33\), Derived#[0-9]+\(22\)]}}
println(derived)
// CHECK-NEXT: [[derived0]]
println(derivedAsBases)
// CHECK-NEXT: [[derived0]]
if let roundTripDerived = derivedAsBases as? Derived[] {
println(roundTripDerived)
}
else {
println("roundTripDerived upcast failed")
}
// CHECK-NEXT: [[derived2:\[Derived#[0-9]+\(44\), Derived#[0-9]+\(55\)\]{1}]]
let derivedInBaseBuffer: Base[] = [Derived(44), Derived(55)]
println(derivedInBaseBuffer)
// CHECK-NEXT: Explicit downcast-ability is based on element type, not buffer type
if let downcastBaseBuffer = derivedInBaseBuffer as? Derived[] {
println("Explicit downcast-ability is based on element type, not buffer type")
}
else {
println("Unexpected downcast failure")
}
// We can up-cast to array of AnyObject
// CHECK-NEXT: [[derived2]]
let derivedAsAnyObjectArray: AnyObject[] = derivedInBaseBuffer
println(derivedAsAnyObjectArray)
// CHECK-NEXT: downcastBackToBase = [[derived2]]
if let downcastBackToBase = derivedAsAnyObjectArray as? Base[] {
println("downcastBackToBase = \(downcastBackToBase)")
}
else {
println("downcastBackToBase failed")
}
// CHECK-NEXT: downcastBackToDerived = [[derived2]]
if let downcastBackToDerived = derivedAsAnyObjectArray as? Derived[] {
println("downcastBackToDerived = \(downcastBackToDerived)")
}
else {
println("downcastBackToDerived failed")
}
// CHECK-NEXT: downcastToProtocols = [[derived2]]
if let downcastToProtocols = derivedAsAnyObjectArray as? Fooable[] {
println("downcastToProtocols = \(downcastToProtocols)")
} else {
println("downcastToProtocols failed")
}
// CHECK-NEXT: downcastToProtocols = [[derived2]]
if let downcastToProtocols = derivedAsAnyObjectArray as? Barable[] {
println("downcastToProtocols = \(downcastToProtocols)")
} else {
println("downcastToProtocols failed")
}
// CHECK-NEXT: downcastToProtocols = [[derived2]]
if let downcastToProtocols = derivedAsAnyObjectArray as? protocol<Barable, Fooable>[] {
println("downcastToProtocols = \(downcastToProtocols)")
} else {
println("downcastToProtocols failed")
}
// CHECK-NEXT: downcastToProtocols failed
if let downcastToProtocols = derivedAsAnyObjectArray as? protocol<Barable, Bazable>[] {
println("downcastToProtocols = \(downcastToProtocols)")
} else {
println("downcastToProtocols failed")
}
// CHECK-NEXT: produceBridgedObjCArray([BridgedObjC[[A:#[0-9]+]](0), BridgedObjC[[B:#[0-9]+]](1), BridgedObjC[[C:#[0-9]+]](2), BridgedObjC[[D:#[0-9]+]](3), BridgedObjC[[E:#[0-9]+]](4)])
testBridgedObjC(Thunks())
// CHECK-NEXT: 5 elements in the array
// CHECK-NEXT: BridgedObjC[[A]](0)
// CHECK-NEXT: BridgedObjC[[B]](1)
// CHECK-NEXT: BridgedObjC[[C]](2)
// CHECK-NEXT: BridgedObjC[[D]](3)
// CHECK-NEXT: BridgedObjC[[E]](4)
// CHECK-NEXT: acceptBridgedObjCArray([BridgedObjC[[A:#[0-9]+]](10), BridgedObjC[[B:#[0-9]+]](11), BridgedObjC[[C:#[0-9]+]](12), BridgedObjC[[D:#[0-9]+]](13), BridgedObjC[[E:#[0-9]+]](14)])
}
testBridgedVerbatim()
//===--- Explicitly Bridged -----------------------------------------------===//
// BridgedSwift conforms to _BridgedToObjectiveC
//===----------------------------------------------------------------------===//
func testExplicitlyBridged() {
// CHECK-LABEL: testExplicitlyBridged()
println("testExplicitlyBridged()")
let bridgedSwifts = [BridgedSwift(42), BridgedSwift(17)]
let bridgedSwiftsAsNSArray: NSArray = bridgedSwifts
// CHECK-NEXT: [BridgedObjC#{{[0-9]+}}(42), BridgedObjC#{{[0-9]+}}(17)]
println("bridgedSwiftsAsNSArray = \(bridgedSwiftsAsNSArray as AnyObject[]))")
// Make sure we can bridge back.
let roundTripBridgedSwifts
= BridgedSwift[].bridgeFromObjectiveC(bridgedSwiftsAsNSArray)
// CHECK-NEXT-NOT: [BridgedSwift#[[id00]](42), BridgedSwift#[[id01]](17)]
// CHECK-NEXT: [BridgedSwift#[[id10:[0-9]+]](42), BridgedSwift#[[id11:[0-9]+]](17)]
println("roundTripBridgedSwifts = \(roundTripBridgedSwifts))")
// Make a real Cocoa NSArray of these...
let cocoaBridgedSwifts = NSArray(array: bridgedSwiftsAsNSArray)
// ...and bridge *that* back
let bridgedBackSwifts
= BridgedSwift[].bridgeFromObjectiveC(cocoaBridgedSwifts)
// CHECK-NEXT-NOT: [BridgedSwift#[[id00]](42), BridgedSwift#[[id01]](17)]
// CHECK-NEXT-NOT: [BridgedSwift#[[id10]](42), BridgedSwift#[[id11]](17)]
// CHECK-NEXT: [BridgedSwift#{{[0-9]+}}(42), BridgedSwift#{{[0-9]+}}(17)]
println("bridgedBackSwifts = \(bridgedBackSwifts)")
// all: verbatim, not, and doesn't bridge
// implicit conversions to/from NSArray
// Base[] -> Derived[] and Derived[] -> Base[] where Base can be AnyObject
// defining @objc method taking T[] and returning T[]
// Up-casts.
let bridgedSwiftsAsBridgedObjCs: BridgedObjC[] = bridgedSwifts
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(bridgedSwiftsAsBridgedObjCs[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(bridgedSwiftsAsBridgedObjCs[1])
let bridgedSwiftsAsBases: Base[] = bridgedSwifts
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(bridgedSwiftsAsBases[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(bridgedSwiftsAsBases[1])
let bridgedSwiftsAsAnyObjects: AnyObject[] = bridgedSwifts
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(bridgedSwiftsAsAnyObjects[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(bridgedSwiftsAsAnyObjects[1])
// Downcasts of non-verbatim bridged value types to objects.
if true {
let downcasted = bridgedSwifts as BridgedObjC[]
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(downcasted[1])
}
if true {
let downcasted = bridgedSwifts as Base[]
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(downcasted[1])
}
if true {
let downcasted = bridgedSwifts as AnyObject[]
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(downcasted[1])
}
// Downcasts of up-casted arrays.
if let downcasted = bridgedSwiftsAsAnyObjects as? BridgedObjC[] {
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(downcasted[1])
} else {
println("Could not downcast AnyObject[] to BridgedObjC[]?")
}
if let downcasted = bridgedSwiftsAsAnyObjects as? Base[] {
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(downcasted[1])
} else {
println("Could not downcast AnyObject[] to Base[]?")
}
// Downcast of Cocoa array to an array of classes.
let wrappedCocoaBridgedSwifts: AnyObject[] = cocoaBridgedSwifts
if let downcasted = wrappedCocoaBridgedSwifts as? BridgedObjC[] {
// CHECK-NEXT: BridgedObjC#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedObjC#[[ID1:[0-9]+]](17)
println(downcasted[1])
} else {
println("Could not downcast AnyObject[] to BridgedObjC[]?")
}
// Downcast of Cocoa array to an array of values.
if let downcasted = wrappedCocoaBridgedSwifts as? BridgedSwift[] {
// CHECK-NEXT: BridgedSwift#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedSwift#[[ID1:[0-9]+]](17)
println(downcasted[1])
} else {
println("Could not downcast AnyObject[] to BridgedSwift[]?")
}
// Downcast of Cocoa array to an array of strings (which should fail)
// CHECK-NEXT: Could not downcast AnyObject[] to String[]
if let downcasted = wrappedCocoaBridgedSwifts as? String[] {
println("Shouldn't be able to downcast to an array of strings")
} else {
println("Could not downcast AnyObject[] to String[]")
}
// Downcast from an implicitly unwrapped optional array of AnyObjects.
var wrappedCocoaBridgedSwiftsIUO: AnyObject[]! = wrappedCocoaBridgedSwifts
if let downcasted = wrappedCocoaBridgedSwiftsIUO as? BridgedSwift[] {
// CHECK-NEXT: BridgedSwift#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedSwift#[[ID1:[0-9]+]](17)
println(downcasted[1])
} else {
println("Could not downcast AnyObject[]! to BridgedSwift[]")
}
// Downcast from a nil implicitly unwrapped optional array of AnyObjects.
wrappedCocoaBridgedSwiftsIUO = nil
if let downcasted = wrappedCocoaBridgedSwiftsIUO as? BridgedSwift[] {
println("Cannot downcast from a nil array!")
} else {
// CHECK-NEXT: Correctly rejected downcast of nil array
println("Correctly rejected downcast of nil array")
}
// Downcast from an optional array of AnyObjects.
var wrappedCocoaBridgedSwiftsOpt: AnyObject[]? = wrappedCocoaBridgedSwifts
if let downcasted = wrappedCocoaBridgedSwiftsOpt as? BridgedSwift[] {
// CHECK-NEXT: BridgedSwift#[[ID0:[0-9]+]](42)
println(downcasted[0])
// CHECK-NEXT: BridgedSwift#[[ID1:[0-9]+]](17)
println(downcasted[1])
} else {
println("Could not downcast AnyObject[]! to BridgedSwift[]")
}
// Downcast from a nil optional array of AnyObjects.
wrappedCocoaBridgedSwiftsOpt = nil
if let downcasted = wrappedCocoaBridgedSwiftsOpt as? BridgedSwift[] {
println("Cannot downcast from a nil array!")
} else {
// CHECK-NEXT: Correctly rejected downcast of nil array
println("Correctly rejected downcast of nil array")
}
// CHECK-NEXT: produceBridgedSwiftArray([BridgedSwift[[A:#[0-9]+]](0), BridgedSwift[[B:#[0-9]+]](1), BridgedSwift[[C:#[0-9]+]](2), BridgedSwift[[D:#[0-9]+]](3), BridgedSwift[[E:#[0-9]+]](4)])
testBridgedSwift(Thunks())
// CHECK-NEXT: 5 elements in the array
// CHECK-NEXT: BridgedObjC[[A:#[0-9]+]](0)
// CHECK-NEXT: BridgedObjC[[B:#[0-9]+]](1)
// CHECK-NEXT: BridgedObjC[[C:#[0-9]+]](2)
// CHECK-NEXT: BridgedObjC[[D:#[0-9]+]](3)
// CHECK-NEXT: BridgedObjC[[E:#[0-9]+]](4)
// CHECK-NEXT: acceptBridgedSwiftArray([BridgedSwift[[A:#[0-9]+]](10), BridgedSwift[[B:#[0-9]+]](11), BridgedSwift[[C:#[0-9]+]](12), BridgedSwift[[D:#[0-9]+]](13), BridgedSwift[[E:#[0-9]+]](14)])
}
testExplicitlyBridged()
//===--- Non-bridging -----------------------------------------------------===//
// X is not bridged to Objective-C
//===----------------------------------------------------------------------===//
struct X {}
/*
let x: NSArray = arrayAsID(bases)!
println(x.objectAtIndex(0) as Base)
*/
// CHECK-NEXT: done.
println("done.")