// RUN: rm -rf %t // RUN: mkdir -p %t // // FIXME: -fobjc-abi-version=2 is a band-aid fix for for rdar://16946936 // // RUN: %S/../../utils/gyb %s -o %t/main.swift // RUN: xcrun -sdk %target-sdk-name clang++ -fobjc-arc -fobjc-abi-version=2 -arch %target-cpu %S/Inputs/SlurpFastEnumeration/SlurpFastEnumeration.m -c -o %t/SlurpFastEnumeration.o // RUN: %S/../../utils/line-directive %t/main.swift -- %target-build-swift %S/Inputs/DictionaryKeyValueTypes.swift %t/main.swift -I %S/Inputs/SlurpFastEnumeration/ -Xlinker %t/SlurpFastEnumeration.o -o %t/Array -Xfrontend -disable-access-control // RUN: %S/../../utils/line-directive %t/main.swift -- %target-run %t/Array // XFAIL: linux import Darwin import StdlibUnittest import Foundation %{ all_array_types = [ 'ContiguousArray', 'Slice', 'Array', '_UnitTestArray' ] }% extension Array { var identity: UnsafePointer { return self._buffer.identity } } extension Slice { var identity: UnsafePointer { return self._buffer.identity } } extension ContiguousArray { var identity: UnsafePointer { return self._buffer.identity } } extension _UnitTestArray { var identity: UnsafePointer { return self._buffer.identity } } var ArrayTestSuite = TestSuite("Array") ArrayTestSuite.test("sizeof") { var a = [ 10, 20, 30 ] #if arch(i386) || arch(arm) expectEqual(4, sizeofValue(a)) #else expectEqual(8, sizeofValue(a)) #endif } ArrayTestSuite.test("valueDestruction") { var a = [TestValueTy]() for i in 100...110 { a.append(TestValueTy(i)) } } //===----------------------------------------------------------------------===// // Native array tests // FIXME: incomplete. //===----------------------------------------------------------------------===// ArrayTestSuite.test("Native/count/empty") { let a = [TestValueTy]() expectEqual(0, a.count) } ArrayTestSuite.test("Native/count") { let a = [ TestValueTy(10), TestValueTy(20), TestValueTy(30) ] expectEqual(3, a.count) } ArrayTestSuite.test("Native/isEmpty/empty") { let a = [TestValueTy]() expectTrue(a.isEmpty) } ArrayTestSuite.test("Native/isEmpty") { let a = [ TestValueTy(10), TestValueTy(20), TestValueTy(30) ] expectFalse(a.isEmpty) } enum EnumWithoutPayloads : Equatable { case A, B, C, D } func == (lhs: EnumWithoutPayloads, rhs: EnumWithoutPayloads) -> Bool { switch (lhs, rhs) { case (.A, .A), (.B, .B), (.C, .C), (.D, .D): return true default: return false } } % for array_type in all_array_types: ArrayTestSuite.test("${array_type}/Sliceable/Enums") { typealias E = EnumWithoutPayloads if true { let expected = [ E.A, E.B, E.C, E.D ] let sliceable = ${array_type}(expected) checkSliceableWithBidirectionalIndex( expected, sliceable, SourceLocStack().withCurrentLoc()) } /* FIXME: add this test when Array can be conditionally Equatable. if true { let expected = [ [ E.A, E.B ], [ E.B, E.C ], [ E.D ], [ E.A, E.B, E.D ] ] let sliceable = ${array_type}(expected) checkSliceableWithBidirectionalIndex( expected, sliceable, SourceLocStack().withCurrentLoc()) } */ } ArrayTestSuite.test("${array_type}/emptyAllocation") { let arr0 = ${array_type}() let arr1 = ${array_type}(count: 0, repeatedValue: TestValueTy(0)) // Empty arrays all use the same buffer expectEqual(arr0._buffer.identity, arr1._buffer.identity) let hasNilBuffer = arr1.identity == nil expectFalse(hasNilBuffer) let arr2: ${array_type} = [] let emptyLiteralsShareBuffer = arr0._buffer.identity == arr2._buffer.identity expectTrue(emptyLiteralsShareBuffer) } % end //===----------------------------------------------------------------------===// // COW tests // FIXME: incomplete. //===----------------------------------------------------------------------===// func withInoutInt(inout x: Int, body: (inout x: Int) -> ()) { body(x: &x) } func withInoutT(inout x: T, body: (inout x: T) -> ()) { body(x: &x) } % for element_type in [ 'TestValueTy', 'TestBridgedValueTy' ]: % for array_type in all_array_types: ArrayTestSuite.test("${array_type}<${element_type}>/subscript(_: Int)/COW") { var a: ${array_type}<${array_type}<${element_type}>> = [ [ ${element_type}(10), ${element_type}(20), ${element_type}(30), ${element_type}(40), ${element_type}(50), ${element_type}(60), ${element_type}(70) ] ] let identityOuter = a.identity var identityInner = a[0].identity func checkIdentity(stackTrace: SourceLocStack) { % if element_type == 'TestValueTy': // Does not reallocate storage because we changed a property based on a // reference; array storage was not changed. Writeback of the inner array // does not happen. expectEqual(identityOuter, a.identity, stackTrace: stackTrace) expectEqual(identityInner, a[0].identity, stackTrace: stackTrace) % else: expectEqual(identityOuter, a.identity, stackTrace: stackTrace) // Should not reallocate storage. expectEqual(identityInner, a[0].identity, stackTrace: stackTrace) % end } // Mutating through a subscript expression. a[0][0] = ${element_type}(1010) checkIdentity(SourceLocStack().withCurrentLoc()) a[0][1].value = 1020 checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a) { (inout x: ${array_type}<${array_type}<${element_type}>>) in x[0][2].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0]) { (inout x: ${array_type}<${element_type}>) in x[3].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) // This will reallocate storage unless Array uses addressors for subscript. //withInoutT(&a[0][4]) { // (inout x: ${element_type}) in // x.value += 1000 //} // FIXME: both of these lines crash the compiler. // Passing an expression based on addressors as // 'inout' crashes SILGen //withInoutT(&a[0][5].value, { $0 += 1000 }) //withInoutInt(&a[0][6].value, { $0 += 1000 }) // Don't change the last element. expectEqual(1010, a[0][0].value) expectEqual(1020, a[0][1].value) expectEqual(1030, a[0][2].value) expectEqual(1040, a[0][3].value) expectEqual(50, a[0][4].value) expectEqual(60, a[0][5].value) expectEqual(70, a[0][6].value) } ArrayTestSuite.test("${array_type}<${element_type}>/subscript(_: Range)/COW") { var a: ${array_type}<${array_type}<${element_type}>> = [ [ ${element_type}(10), ${element_type}(20), ${element_type}(30), ${element_type}(40), ${element_type}(50), ${element_type}(60), ${element_type}(70), ${element_type}(80), ${element_type}(90), ] ] let identityOuter = a.identity var identityInner = a[0].identity func checkIdentity(stackTrace: SourceLocStack) { % if element_type == 'TestValueTy': // Does not reallocate storage because we changed a property based on a // reference; array storage was not changed. expectEqual(identityOuter, a.identity, stackTrace: stackTrace) expectEqual(identityInner, a[0].identity, stackTrace: stackTrace) % else: expectEqual(identityOuter, a.identity, stackTrace: stackTrace) // Writeback happens in subscript(Range), but array notices that the new // value did not change. // Another writeback happens in Array.subscript(Int), but this is not what we // want. expectNotEqual(identityInner, a[0].identity, stackTrace: stackTrace) identityInner = a[0].identity % end } // Mutating through a subscript expression. a[0..<1][0][0] = ${element_type}(1010) // Reallocates storage because of the writeback in Array.subscript(Int). expectEqual(identityOuter, a.identity) expectNotEqual(identityInner, a[0].identity) identityInner = a[0].identity a[0..<1][0][1].value = 1020 checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a) { (inout x: ${array_type}<${array_type}<${element_type}>>) in x[0..<1][0][2].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0..<1]) { (inout x: Slice<${array_type}<${element_type}>>) in x[0][3].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0..<1][0]) { (inout x: ${array_type}<${element_type}>) in x[4].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0..<1][0][5]) { (inout x: ${element_type}) in x.value += 1000 } // Reallocates storage because of the writeback in Array.subscript(Int) // (writeback is being requested for the array element even though it is not // needed). expectEqual(identityOuter, a.identity) expectNotEqual(identityInner, a[0].identity) identityInner = a[0].identity withInoutT(&a[0..<1][0][6].value) { (inout x: Int) in x += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutInt(&a[0..<1][0][7].value) { (inout x: Int) in x += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) // Don't change the last element. expectEqual(1010, a[0][0].value) expectEqual(1020, a[0][1].value) expectEqual(1030, a[0][2].value) expectEqual(1040, a[0][3].value) expectEqual(1050, a[0][4].value) expectEqual(1060, a[0][5].value) expectEqual(1070, a[0][6].value) expectEqual(1080, a[0][7].value) expectEqual(90, a[0][8].value) } % end % end //===----------------------------------------------------------------------===// // NSArray -> Array bridging tests // FIXME: incomplete. //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Array -> NSArray bridging tests // // Key and Value are bridged verbatim. // // FIXME: incomplete. //===----------------------------------------------------------------------===// ArrayTestSuite.test("BridgedToObjC/Verbatim/count/empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) expectEqual(0, a.count) } ArrayTestSuite.test("BridgedToObjC/Verbatim/count") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged() expectEqual(3, a.count) } for index in [ -100, -1, 0, 1, 100 ] { ArrayTestSuite.test( "BridgedToObjC/Verbatim/objectAtIndex/empty/trap/\(index)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) expectCrashLater() a.objectAtIndex(index) } } for index in [ -100, -1, 3, 4, 100 ] { ArrayTestSuite.test("BridgedToObjC/Verbatim/objectAtIndex/trap/\(index)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) expectCrashLater() a.objectAtIndex(index) } } ArrayTestSuite.test("BridgedToObjC/Verbatim/objectAtIndex") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) var v: AnyObject = a.objectAtIndex(0) expectEqual(10, (v as TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, UWord.self) v = a.objectAtIndex(1) expectEqual(20, (v as TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, UWord.self) v = a.objectAtIndex(2) expectEqual(30, (v as TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, UWord.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self)) expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self)) expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self)) } expectAutoreleasedKeysAndValues(unopt: (0, 3)) } for indexRange in [ -2..<(-2), 1..<1, 0..<4, -2..<(-1), -1..<2, 0..<1, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects/empty/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged( numElements: 0, capacity: 16) let buffer = UnsafeMutablePointer.alloc(16) a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<0)) expectCrashLater() a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } for indexRange in [ 0..<4, -2..<(-1), -1..<2, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged( numElements: 3, capacity: 16) let buffer = UnsafeMutablePointer.alloc(16) a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) expectCrashLater() a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) let buffer = UnsafeMutablePointer.alloc(16) a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) var v: AnyObject = buffer[0] expectEqual(10, (v as TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, UWord.self) v = buffer[1] expectEqual(20, (v as TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, UWord.self) v = buffer[2] expectEqual(30, (v as TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, UWord.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self)) expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self)) expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self)) } buffer.dealloc(3) _fixLifetime(a) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Verbatim/copyWithZone") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) let copy: AnyObject = a.copyWithZone(nil) expectEqual(unsafeBitCast(a, UWord.self), unsafeBitCast(copy, UWord.self)) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromSwift/3") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromSwift/7") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 7) checkArrayFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70 ], a, { a }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromObjC/Empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) checkArrayFastEnumerationFromObjC( [], a, { a }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a.objectEnumerator() }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromSwift") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromSwift/Partial") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 9) checkArrayEnumeratorPartialFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ], a, maxFastEnumerationItems: 5, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/BridgeBack/Reallocate") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) var v: AnyObject = a[0] expectEqual(10, (v as TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, UWord.self) v = a[1] expectEqual(20, (v as TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, UWord.self) v = a[2] expectEqual(30, (v as TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, UWord.self) // Bridge back to native array. var native: [TestObjCValueTy] = _convertNSArrayToArray(a) native[0] = TestObjCValueTy(110) native[1] = TestObjCValueTy(120) native[2] = TestObjCValueTy(130) native.append(TestObjCValueTy(140)) // Ensure that the compiler does not elide mutation of the native array. _blackHole(native) // Check that mutating the native array did not affect the bridged array. expectEqual(3, a.count) expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self)) expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self)) expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self)) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Verbatim/BridgeBack/Adopt") { // Bridge back to native array. var native: [TestObjCValueTy] = _convertNSArrayToArray( getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3)) let identity1 = unsafeBitCast(native, UWord.self) // Mutate elements, but don't change length. native[0] = TestObjCValueTy(110) native[1] = TestObjCValueTy(120) native[2] = TestObjCValueTy(130) // Expect no reallocations. expectEqual(identity1, unsafeBitCast(native, UWord.self)) } //===----------------------------------------------------------------------===// // Array -> NSArray bridging tests // // Key and Value are bridged non-verbatim. // // FIXME: incomplete. //===----------------------------------------------------------------------===// ArrayTestSuite.test("BridgedToObjC/Custom/count/empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) expectEqual(0, a.count) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/count") { let a = getBridgedNSArrayOfValueTypeCustomBridged() expectEqual(3, a.count) expectEqual(0, TestBridgedValueTy.bridgeOperations) } for index in [ -100, -1, 0, 1, 100 ] { ArrayTestSuite.test( "BridgedToObjC/Custom/objectAtIndex/empty/trap/\(index)") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) expectCrashLater() a.objectAtIndex(index) } } for index in [ -100, -1, 3, 4, 100 ] { ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex/trap/\(index)") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) expectCrashLater() a.objectAtIndex(index) } } ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) var v: AnyObject = a.objectAtIndex(0) expectEqual(10, (v as TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, UWord.self) v = a.objectAtIndex(1) expectEqual(20, (v as TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, UWord.self) v = a.objectAtIndex(2) expectEqual(30, (v as TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, UWord.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self)) expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self)) expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self)) } expectEqual(3, TestBridgedValueTy.bridgeOperations) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } for indexRange in [ -2..<(-2), 1..<1, 0..<4, -2..<(-1), -1..<2, 0..<1, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Custom/getObjects/empty/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfValueTypeCustomBridged( numElements: 0, capacity: 16) let buffer = UnsafeMutablePointer.alloc(16) a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<0)) expectCrashLater() a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } for indexRange in [ 0..<4, -2..<(-1), -1..<2, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Custom/getObjects/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfValueTypeCustomBridged( numElements: 3, capacity: 16) let buffer = UnsafeMutablePointer.alloc(16) a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) expectCrashLater() a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } ArrayTestSuite.test("BridgedToObjC/Custom/getObjects") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) let buffer = UnsafeMutablePointer.alloc(16) a.getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) var v: AnyObject = buffer[0] expectEqual(10, (v as TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, UWord.self) v = buffer[1] expectEqual(20, (v as TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, UWord.self) v = buffer[2] expectEqual(30, (v as TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, UWord.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self)) expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self)) expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self)) } buffer.dealloc(3) _fixLifetime(a) expectEqual(3, TestBridgedValueTy.bridgeOperations) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Custom/copyWithZone") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) let copy: AnyObject = a.copyWithZone(nil) expectEqual(unsafeBitCast(a, UWord.self), unsafeBitCast(copy, UWord.self)) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a }, { ($0 as TestObjCValueTy).value }) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromSwift/3") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a }, { ($0 as TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromSwift/7") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 7) checkArrayFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70 ], a, { a }, { ($0 as TestObjCValueTy).value }) expectEqual(7, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromObjC/Empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) checkArrayFastEnumerationFromObjC( [], a, { a }, { ($0 as TestObjCValueTy).value }) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a }, { ($0 as TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a.objectEnumerator() }, { ($0 as TestObjCValueTy).value }) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromSwift") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromSwift/Partial") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 9) checkArrayEnumeratorPartialFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ], a, maxFastEnumerationItems: 5, { ($0 as TestObjCValueTy).value }) expectEqual(9, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/BridgeBack/Cast") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) var v: AnyObject = a[0] expectEqual(10, (v as TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, UWord.self) v = a[1] expectEqual(20, (v as TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, UWord.self) v = a[2] expectEqual(30, (v as TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, UWord.self) // Bridge back to native array with a cast. var native: [TestObjCValueTy] = _convertNSArrayToArray(a) native[0] = TestObjCValueTy(110) native[1] = TestObjCValueTy(120) native[2] = TestObjCValueTy(130) native.append(TestObjCValueTy(140)) // Ensure that the compiler does not elide mutation of the native array. _blackHole(native) // Check that mutating the native array did not affect the bridged array. expectEqual(3, a.count) expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self)) expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self)) expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self)) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Custom/BridgeBack/Reallocate") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) var v: AnyObject = a[0] expectEqual(10, (v as TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, UWord.self) v = a[1] expectEqual(20, (v as TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, UWord.self) v = a[2] expectEqual(30, (v as TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, UWord.self) // Bridge back to native array. var native: [TestBridgedValueTy] = _convertNSArrayToArray(a) native[0] = TestBridgedValueTy(110) native[1] = TestBridgedValueTy(120) native[2] = TestBridgedValueTy(130) native.append(TestBridgedValueTy(140)) // Ensure that the compiler does not elide mutation of the native array. _blackHole(native) // Check that mutating the native array did not affect the bridged array. expectEqual(3, a.count) expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self)) expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self)) expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self)) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Custom/BridgeBack/Adopt") { // Bridge back to native array. var native: [TestBridgedValueTy] = _convertNSArrayToArray( getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)) let identity1 = unsafeBitCast(native, UWord.self) // Mutate elements, but don't change length. native[0] = TestBridgedValueTy(110) native[1] = TestBridgedValueTy(120) native[2] = TestBridgedValueTy(130) // Expect no reallocations. expectEqual(identity1, unsafeBitCast(native, UWord.self)) } //===----------------------------------------------------------------------===// // Array and EvilCollection that changes its size while we are not looking //===----------------------------------------------------------------------===// let evilBoundsError = "EvilCollection: index out of range" final class EvilCollection : CollectionType { init(_ growth: Int, boundsChecked: Bool) { self.growth = growth self.boundsChecked = boundsChecked } var growth: Int var count: Int = 20 var boundsChecked: Bool var startIndex : Int { count += growth return 0 } var endIndex : Int { return count } subscript(i: Int) -> TestValueTy { if boundsChecked { precondition(i >= 0 && i < count, evilBoundsError) } return TestValueTy(i) } func generate() -> IndexingGenerator { return IndexingGenerator(self) } } for (step, evilBoundsCheck) in [ (1, true), (-1, false), (-1, true) ] { let message = step < 0 && evilBoundsCheck ? evilBoundsError : "invalid CollectionType: count differed in successive traversals" let natureOfEvil = step > 0 ? "Growth" : "Shrinkage" let boundsChecked = evilBoundsCheck ? "BoundsChecked" : "NoBoundsCheck" let testPrefix = "MemorySafety/\(boundsChecked)/Evil\(natureOfEvil)" let t = ArrayTestSuite.test("\(testPrefix)/Infrastructure") (evilBoundsCheck ? t.crashOutputMatches(evilBoundsError) : t).code { let evil = EvilCollection(step, boundsChecked: evilBoundsCheck) let count0 = count(evil) let count1 = count(evil) expectNotEqual(count0, count1) if step > 0 { expectLE(count0, count1) } else { expectGE(count0, count1) } if evilBoundsCheck { expectCrashLater() } let x = evil[-1] } ArrayTestSuite.test("\(testPrefix)/Construction") .crashOutputMatches(message) .code { let evil = EvilCollection(step, boundsChecked: evilBoundsCheck) expectCrashLater() let a = Array(evil) } for (op, rangeMax) in ["Grow":0, "Shrink":200] { ArrayTestSuite.test("\(testPrefix)/replaceRange/\(op)Unique") .crashOutputMatches(message) .code { let evil = EvilCollection(step, boundsChecked: evilBoundsCheck) var a = Array(lazy(0..<200).map { TestValueTy($0) }) expectCrashLater() a.replaceRange(0..