mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Most of this is in updating the standard library, SDK overlays, and
piles of test cases to use the new names. No surprises here, although
this shows us some potential heuristic tweaks.
There is one substantive compiler change that needs to be factored out
involving synthesizing calls to copyWithZone()/copy(zone:). Aside from
that, there are four failing tests:
Swift :: ClangModules/objc_parse.swift
Swift :: Interpreter/SDK/Foundation_test.swift
Swift :: Interpreter/SDK/archiving_generic_swift_class.swift
Swift :: Interpreter/SDK/objc_currying.swift
due to two independent remaining compiler bugs:
* We're not getting partial ordering between NSCoder's
encode(AnyObject, forKey: String) and NSKeyedArchiver's version of
that method, and
* Dynamic lookup (into AnyObject) doesn't know how to find the new
names. We need the Swift name lookup tables enabled to address this.
1765 lines
52 KiB
Plaintext
1765 lines
52 KiB
Plaintext
// RUN: rm -rf %t
|
|
// RUN: mkdir -p %t
|
|
//
|
|
// RUN: %S/../../utils/gyb %s -o %t/main.swift
|
|
// RUN: %target-clang -fobjc-arc %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
|
|
// REQUIRES: executable_test
|
|
|
|
// XFAIL: linux
|
|
|
|
import Darwin
|
|
import StdlibUnittest
|
|
import StdlibUnittestFoundationExtras
|
|
import Foundation
|
|
|
|
%{
|
|
all_array_types = [ 'ContiguousArray', 'ArraySlice', 'Array' ]
|
|
}%
|
|
|
|
extension Array {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
|
|
extension ArraySlice {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
|
|
extension ContiguousArray {
|
|
var identity: UnsafePointer<Void> {
|
|
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)
|
|
}
|
|
|
|
protocol TestProtocol1 {}
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
// Check that the generic parameter is called 'Element'.
|
|
extension ${array_type} where Element : TestProtocol1 {
|
|
var _elementIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
/// Returns an ${array_type} that does not share its buffer with other arrays.
|
|
func getFresh${array_type}<S : Sequence>(sequence: S)
|
|
-> ${array_type}<S.Iterator.Element> {
|
|
var result: ${array_type}<S.Iterator.Element> = []
|
|
result.reserveCapacity(sequence.underestimateCount())
|
|
for element in sequence {
|
|
result.append(element)
|
|
}
|
|
return result
|
|
}
|
|
|
|
% end
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
struct SequenceWithCustomUnderestimateCount : Sequence {
|
|
init(_ data: [Int]) {
|
|
self._data = MinimalSequence(elements: data.map(OpaqueValue.init))
|
|
}
|
|
|
|
func iterator() -> MinimalSequence<OpaqueValue<Int>>.Iterator {
|
|
return _data.iterator()
|
|
}
|
|
|
|
func underestimateCount() -> Int {
|
|
++SequenceWithCustomUnderestimateCount.timesUnderestimateCountWasCalled
|
|
return _data.underestimateCount()
|
|
}
|
|
|
|
static var timesUnderestimateCountWasCalled: Int = 0
|
|
|
|
let _data: MinimalSequence<OpaqueValue<Int>>
|
|
}
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}/init(Sequence)") {
|
|
let base = SequenceWithCustomUnderestimateCount(
|
|
[ 0, 30, 10, 90 ])
|
|
|
|
SequenceWithCustomUnderestimateCount.timesUnderestimateCountWasCalled = 0
|
|
|
|
let result = ${array_type}(base)
|
|
|
|
expectEqual([ 0, 30, 10, 90 ], result.map { $0.value })
|
|
|
|
expectEqual(1, SequenceWithCustomUnderestimateCount.timesUnderestimateCountWasCalled)
|
|
|
|
expectEqualSequence(
|
|
[], Array(base).map { $0.value }, "sequence should be consumed")
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
/*
|
|
FIXME: add this test when Array<T> 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}/appendNonUnique") {
|
|
var x: ${array_type}<Int> = []
|
|
x.reserveCapacity(10002)
|
|
let capacity = x.capacity
|
|
for _ in 1...10000 {
|
|
let y = x
|
|
x.append(1)
|
|
expectTrue(x.capacity == capacity)
|
|
let z = x
|
|
x.removeAt(0)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/emptyAllocation") {
|
|
let arr0 = ${array_type}<Int>()
|
|
let arr1 = ${array_type}<TestValueTy>(repeating: TestValueTy(0), count: 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}<TestValueTy> = []
|
|
let emptyLiteralsShareBuffer = arr0._buffer.identity == arr2._buffer.identity
|
|
expectTrue(emptyLiteralsShareBuffer)
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/filter") {
|
|
if true {
|
|
let arr: ${array_type}<Int> = []
|
|
var result = arr.filter() {
|
|
(x: Int) -> Bool in
|
|
expectUnreachable()
|
|
return true
|
|
}
|
|
expectType(Array<Int>.self, &result)
|
|
expectEqual([], result)
|
|
expectEqual(0, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.filter() { (x: Int) -> Bool in true }
|
|
expectEqual([ 0, 30, 10, 90 ], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.filter() { (x: Int) -> Bool in false }
|
|
expectEqual([], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.filter() { $0 % 3 == 0 }
|
|
expectEqual([ 0, 30, 90 ], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/map") {
|
|
if true {
|
|
let arr: ${array_type}<Int> = []
|
|
var result = arr.map() {
|
|
(x: Int) -> Int16 in
|
|
expectUnreachable()
|
|
return 42
|
|
}
|
|
expectType(Array<Int16>.self, &result)
|
|
expectEqual([], result)
|
|
expectEqual(0, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.map() { $0 + 1 }
|
|
expectEqual([ 1, 31, 11, 91 ], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/flatMap") {
|
|
let enumerate : Int -> ${array_type}<Int> =
|
|
{ return ${array_type}(1..<($0 + 1)) }
|
|
expectEqualSequence([], ${array_type}().flatMap(enumerate))
|
|
expectEqualSequence([ 1 ], ${array_type}([ 1 ]).flatMap(enumerate))
|
|
expectEqualSequence(
|
|
[ 1, 1, 2 ],
|
|
${array_type}([ 1, 2 ]).flatMap(enumerate))
|
|
expectEqualSequence(
|
|
[ 1, 1, 1, 2 ],
|
|
${array_type}([ 1, 2 ]).flatMap(enumerate).flatMap(enumerate))
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/Mirror") {
|
|
do {
|
|
let input: ${array_type}<Int> = []
|
|
var output = ""
|
|
dump(input, &output)
|
|
|
|
let expected =
|
|
"- 0 elements\n"
|
|
|
|
expectEqual(expected, output)
|
|
}
|
|
do {
|
|
let input: ${array_type}<Int> = [ 10, 20, 30, 40 ]
|
|
var output = ""
|
|
dump(input, &output)
|
|
|
|
let expected =
|
|
"▿ 4 elements\n" +
|
|
" - [0]: 10\n" +
|
|
" - [1]: 20\n" +
|
|
" - [2]: 30\n" +
|
|
" - [3]: 40\n"
|
|
|
|
expectEqual(expected, output)
|
|
}
|
|
% if array_type == 'ArraySlice':
|
|
do {
|
|
let base = [ 10, 20, 30, 40 ]
|
|
let input: ArraySlice<Int> = base[1..<3]
|
|
var output = ""
|
|
dump(input, &output)
|
|
|
|
let expected =
|
|
"▿ 2 elements\n" +
|
|
" - [0]: 20\n" +
|
|
" - [1]: 30\n"
|
|
|
|
expectEqual(expected, output)
|
|
}
|
|
% end
|
|
}
|
|
|
|
% end
|
|
|
|
% for Kind in ['Array', 'ContiguousArray']:
|
|
ArrayTestSuite.test("${Kind}/popLast") {
|
|
// Empty
|
|
if true {
|
|
var a = ${Kind}<Int>()
|
|
let popped = a.popLast()
|
|
expectEmpty(popped)
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
|
|
if true {
|
|
var popped = [Int]()
|
|
var a: ${Kind}<Int> = [1010, 2020, 3030]
|
|
while let element = a.popLast() {
|
|
popped.append(element)
|
|
}
|
|
expectEqualSequence([1010, 2020, 3030], popped.reverse())
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
}
|
|
% end
|
|
|
|
// Check how removeFirst() affects indices.
|
|
% for Kind in ['Array', 'ContiguousArray']:
|
|
ArrayTestSuite.test("${Kind}/removeFirst") {
|
|
if true {
|
|
var a: ${Kind}<OpaqueValue<Int>> = ${Kind}([ 1 ].map(OpaqueValue.init))
|
|
a.removeFirst()
|
|
expectEqual(0, a.startIndex)
|
|
}
|
|
if true {
|
|
var a: ${Kind}<OpaqueValue<Int>> = ${Kind}([ 1, 2 ].map(OpaqueValue.init))
|
|
a.removeFirst()
|
|
expectEqual(0, a.startIndex)
|
|
}
|
|
}
|
|
% end
|
|
|
|
ArrayTestSuite.test("ArraySlice/removeFirst") {
|
|
if true {
|
|
let a: [OpaqueValue<Int>] = [ 99, 1010, 99 ].map(OpaqueValue.init)
|
|
var s = a[1..<2]
|
|
expectEqual(1, s.startIndex)
|
|
s.removeFirst()
|
|
expectEqual(2, s.startIndex)
|
|
}
|
|
if true {
|
|
let a: [OpaqueValue<Int>] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init)
|
|
var s = a[1..<2]
|
|
expectEqual(1, s.startIndex)
|
|
s.removeFirst()
|
|
expectEqual(2, s.startIndex)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// _withUnsafeMutableBufferPointerIfSupported()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct WithUnsafeMutableBufferPointerIfSupportedTest {
|
|
let sequence: [Int]
|
|
let loc: SourceLoc
|
|
|
|
init(
|
|
_ sequence: [Int],
|
|
file: String = __FILE__, line: UInt = __LINE__
|
|
) {
|
|
self.sequence = sequence
|
|
self.loc = SourceLoc(file, line, comment: "test data")
|
|
}
|
|
}
|
|
|
|
let withUnsafeMutableBufferPointerIfSupportedTests = [
|
|
WithUnsafeMutableBufferPointerIfSupportedTest([]),
|
|
WithUnsafeMutableBufferPointerIfSupportedTest([ 10 ]),
|
|
WithUnsafeMutableBufferPointerIfSupportedTest([ 10, 20, 30, 40, 50 ]),
|
|
]
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}/_withUnsafeMutableBufferPointerIfSupported") {
|
|
for test in withUnsafeMutableBufferPointerIfSupportedTests {
|
|
var a = getFresh${array_type}(test.sequence.map(OpaqueValue.init))
|
|
if true {
|
|
// Read.
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<[OpaqueValue<Int>]> in
|
|
let bufferPointer =
|
|
UnsafeMutableBufferPointer(start: baseAddress, count: count)
|
|
return OpaqueValue(Array(bufferPointer))
|
|
}
|
|
expectType(Optional<OpaqueValue<Array<OpaqueValue<Int>>>>.self, &result)
|
|
expectEqualSequence(test.sequence, result!.value.map { $0.value })
|
|
expectEqualSequence(test.sequence, a.map { $0.value })
|
|
}
|
|
if true {
|
|
// Read and write.
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<Array<OpaqueValue<Int>>> in
|
|
let bufferPointer =
|
|
UnsafeMutableBufferPointer(start: baseAddress, count: count)
|
|
let result = OpaqueValue(Array(bufferPointer))
|
|
for i in bufferPointer.indices {
|
|
bufferPointer[i] = OpaqueValue(bufferPointer[i].value * 10)
|
|
}
|
|
return result
|
|
}
|
|
expectType(Optional<OpaqueValue<Array<OpaqueValue<Int>>>>.self, &result)
|
|
expectEqualSequence(test.sequence, result!.value.map { $0.value })
|
|
expectEqualSequence(
|
|
test.sequence.map { $0 * 10 },
|
|
a.map { $0.value })
|
|
}
|
|
}
|
|
// FIXME: tests for arrays bridged from Objective-C.
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/_withUnsafeMutableBufferPointerIfSupported/ReplacingTheBufferTraps/1") {
|
|
var a = getFresh${array_type}([ OpaqueValue(10) ])
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<Int> in
|
|
// buffer = UnsafeMutableBufferPointer(start: buffer.baseAddress, count: 0)
|
|
// FIXME: does not trap since the buffer is not passed inout.
|
|
// expectCrashLater()
|
|
return OpaqueValue(42)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/_withUnsafeMutableBufferPointerIfSupported/ReplacingTheBufferTraps/2") {
|
|
var a = getFresh${array_type}([ OpaqueValue(10) ])
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<Int> in
|
|
// buffer = UnsafeMutableBufferPointer(start: nil, count: 1)
|
|
// FIXME: does not trap since the buffer is not passed inout.
|
|
// expectCrashLater()
|
|
return OpaqueValue(42)
|
|
}
|
|
}
|
|
|
|
//===---
|
|
// Check that iterators traverse a snapshot of the collection.
|
|
//===---
|
|
|
|
ArrayTestSuite.test(
|
|
"${array_type}/mutationDoesNotAffectIterator/subscript/store") {
|
|
var arr: ${array_type}<Int> = [ 1010, 1020, 1030 ]
|
|
var iter = arr.iterator()
|
|
arr[0] = 1011
|
|
expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(iter)))
|
|
}
|
|
|
|
ArrayTestSuite.test(
|
|
"${array_type}/mutationDoesNotAffectIterator/subscript/append") {
|
|
var arr: ${array_type}<Int> = [ 1010, 1020, 1030 ]
|
|
var iter = arr.iterator()
|
|
arr.append(1040)
|
|
expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(iter)))
|
|
}
|
|
|
|
ArrayTestSuite.test(
|
|
"${array_type}/mutationDoesNotAffectIterator/subscript/replaceSubrange") {
|
|
var arr: ${array_type}<Int> = [ 1010, 1020, 1030 ]
|
|
var iter = arr.iterator()
|
|
arr.replaceSubrange(1..<3, with: [ 1040, 1050, 1060 ])
|
|
expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(iter)))
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// COW tests
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
func withInoutInt(inout x: Int, body: (inout x: Int) -> Void) {
|
|
body(x: &x)
|
|
}
|
|
|
|
func withInoutT<T>(inout x: T, body: (inout x: T) -> Void) {
|
|
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.
|
|
// <rdar://problem/18439579> 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<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), ${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<Int>), 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: ArraySlice<${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
|
|
|
|
// FIXME: all the tests below are applicable to ArraySlice, too.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// NSArray -> Array bridging tests
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
func isNativeArray<Element>(a: Array<Element>) -> Bool {
|
|
return a._hoistableIsNativeTypeChecked()
|
|
}
|
|
|
|
func isCocoaArray<Element>(a: Array<Element>) -> Bool {
|
|
return !isNativeArray(a)
|
|
}
|
|
|
|
func getAsImmutableNSArray(a: Array<Int>) -> NSArray {
|
|
var elements = a.map { TestObjCValueTy($0) as AnyObject? }
|
|
return NSArray(objects: &elements, count: elements.count)
|
|
}
|
|
|
|
func getAsNSArray(a: Array<Int>) -> NSArray {
|
|
// Return an `NSMutableArray` to make sure that it has a unique
|
|
// pointer identity.
|
|
return getAsNSMutableArray(a)
|
|
}
|
|
|
|
func getAsNSMutableArray(a: Array<Int>) -> NSMutableArray {
|
|
let result = NSMutableArray()
|
|
for element in a {
|
|
result.add(TestObjCValueTy(element))
|
|
}
|
|
return result
|
|
}
|
|
|
|
@objc
|
|
class CustomImmutableNSArray : NSArray {
|
|
init(_privateInit: ()) {
|
|
super.init()
|
|
}
|
|
|
|
override init() {
|
|
expectUnreachable()
|
|
super.init()
|
|
}
|
|
|
|
override init(objects: UnsafePointer<AnyObject?>, count: Int) {
|
|
super.init(objects: objects, count: count)
|
|
}
|
|
|
|
required init(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) not implemented by CustomImmutableNSArray")
|
|
}
|
|
|
|
@objc
|
|
override func copy(zone zone: NSZone) -> AnyObject {
|
|
++CustomImmutableNSArray.timesCopyWithZoneWasCalled
|
|
return self
|
|
}
|
|
|
|
@objc
|
|
override func objectAt(index: Int) -> AnyObject {
|
|
++CustomImmutableNSArray.timesObjectAtIndexWasCalled
|
|
return _data[index]
|
|
}
|
|
|
|
@objc
|
|
override var count: Int {
|
|
++CustomImmutableNSArray.timesCountWasCalled
|
|
return _data.count
|
|
}
|
|
|
|
@objc
|
|
override func countByEnumeratingWith(
|
|
state: UnsafeMutablePointer<NSFastEnumerationState>,
|
|
objects: AutoreleasingUnsafeMutablePointer<AnyObject?>,
|
|
count: Int
|
|
) -> Int {
|
|
var theState = state.memory
|
|
if theState.state == 0 {
|
|
theState.state = 1
|
|
theState.itemsPtr =
|
|
AutoreleasingUnsafeMutablePointer(_data._baseAddressIfContiguous)
|
|
theState.mutationsPtr = _fastEnumerationStorageMutationsPtr
|
|
state.memory = theState
|
|
return _data.count
|
|
}
|
|
return 0
|
|
}
|
|
|
|
let _data = [ 10, 20, 30 ].map { TestObjCValueTy($0) }
|
|
|
|
static var timesCopyWithZoneWasCalled = 0
|
|
static var timesObjectAtIndexWasCalled = 0
|
|
static var timesCountWasCalled = 0
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Verbatim.BridgeUsingAs") {
|
|
if true {
|
|
let source = [ 10, 20, 30 ]
|
|
let nsa = getAsNSArray(source)
|
|
var result = nsa as Array
|
|
expectTrue(isCocoaArray(result))
|
|
expectType(Array<AnyObject>.self, &result)
|
|
checkSequence(source.map { TestObjCValueTy($0) as AnyObject }, result) {
|
|
($0 as! TestObjCValueTy).value == ($1 as! TestObjCValueTy).value
|
|
}
|
|
}
|
|
if true {
|
|
let source = [ 10, 20, 30 ]
|
|
let nsa = getAsNSArray(source)
|
|
var result = nsa as! Array<TestObjCValueTy>
|
|
expectTrue(isCocoaArray(result))
|
|
expectType(Array<TestObjCValueTy>.self, &result)
|
|
checkSequence(source.map { TestObjCValueTy($0) }, result) {
|
|
$0.value == $1.value
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.BridgeUsingAs") {
|
|
let source = [ 10, 20, 30 ]
|
|
let nsa = getAsNSArray(source)
|
|
var result = nsa as! Array<TestBridgedValueTy>
|
|
expectTrue(isNativeArray(result))
|
|
expectType(Array<TestBridgedValueTy>.self, &result)
|
|
checkSequence(source.map { TestBridgedValueTy($0) }, result) {
|
|
$0.value == $1.value
|
|
}
|
|
}
|
|
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Verbatim.ArrayIsCopied") {
|
|
let source = [ 10, 20, 30 ]
|
|
let nsa = getAsNSMutableArray(source)
|
|
let result = nsa as Array<AnyObject>
|
|
expectTrue(isCocoaArray(result))
|
|
|
|
// Delete the value from NSMutableArray.
|
|
expectEqual(20, (nsa[1] as! TestObjCValueTy).value)
|
|
nsa.removeObjectAt(1)
|
|
expectEqual(30, (nsa[1] as! TestObjCValueTy).value)
|
|
|
|
// Check that the Array is not affected.
|
|
expectEqual(20, result[1].value)
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.ArrayIsCopied") {
|
|
let source = [ 10, 20, 30 ]
|
|
let nsa = getAsNSMutableArray(source)
|
|
var result = nsa as! Array<TestBridgedValueTy>
|
|
expectTrue(isNativeArray(result))
|
|
|
|
// Delete the value from NSMutableArray.
|
|
expectEqual(20, (nsa[1] as! TestObjCValueTy).value)
|
|
nsa.removeObjectAt(1)
|
|
expectEqual(30, (nsa[1] as! TestObjCValueTy).value)
|
|
|
|
// Check that the Array is not affected.
|
|
expectEqual(20, result[1].value)
|
|
}
|
|
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Verbatim.NSArrayIsRetained") {
|
|
let nsa = NSArray(array: getAsNSArray([ 10, 20, 30 ]))
|
|
var a: Array<AnyObject> = _convertNSArrayToArray(nsa)
|
|
var bridgedBack: NSArray = _convertArrayToNSArray(a)
|
|
|
|
expectEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.NSArrayIsCopied") {
|
|
let nsa = NSArray(array: getAsNSArray([ 10, 20, 30 ]))
|
|
var a: Array<TestBridgedValueTy> = _convertNSArrayToArray(nsa)
|
|
var bridgedBack: NSArray = _convertArrayToNSArray(a)
|
|
|
|
expectNotEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Verbatim.ImmutableArrayIsRetained") {
|
|
let nsa: NSArray = CustomImmutableNSArray(_privateInit: ())
|
|
|
|
CustomImmutableNSArray.timesCopyWithZoneWasCalled = 0
|
|
CustomImmutableNSArray.timesObjectAtIndexWasCalled = 0
|
|
CustomImmutableNSArray.timesCountWasCalled = 0
|
|
let a: Array<AnyObject> = _convertNSArrayToArray(nsa)
|
|
expectEqual(1, CustomImmutableNSArray.timesCopyWithZoneWasCalled)
|
|
expectEqual(0, CustomImmutableNSArray.timesObjectAtIndexWasCalled)
|
|
expectEqual(0, CustomImmutableNSArray.timesCountWasCalled)
|
|
|
|
let bridgedBack: NSArray = _convertArrayToNSArray(a)
|
|
|
|
expectEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.ImmutableArrayIsCopied") {
|
|
let nsa: NSArray = CustomImmutableNSArray(_privateInit: ())
|
|
|
|
CustomImmutableNSArray.timesCopyWithZoneWasCalled = 0
|
|
CustomImmutableNSArray.timesObjectAtIndexWasCalled = 0
|
|
CustomImmutableNSArray.timesCountWasCalled = 0
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
var a: Array<TestBridgedValueTy> = []
|
|
|
|
// FIXME: bridging shouldn't dump array contents into the autorelease pool.
|
|
autoreleasepoolIfUnoptimizedReturnAutoreleased {
|
|
a = _convertNSArrayToArray(nsa)
|
|
expectEqual(1, CustomImmutableNSArray.timesCopyWithZoneWasCalled)
|
|
expectEqual(3, CustomImmutableNSArray.timesObjectAtIndexWasCalled)
|
|
expectNotEqual(0, CustomImmutableNSArray.timesCountWasCalled)
|
|
expectEqual(3, TestBridgedValueTy.bridgeOperations)
|
|
}
|
|
|
|
let bridgedBack: NSArray = _convertArrayToNSArray(a)
|
|
|
|
expectNotEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
|
|
// FIXME: test API calls on the BridgedFromObjC arrays.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array -> NSArray bridging tests
|
|
//
|
|
// Element is bridged verbatim.
|
|
//
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ArrayTestSuite.test("BridgedToObjC.Verbatim.BridgeUsingAs") {
|
|
let source = [ 10, 20, 30 ].map { TestObjCValueTy($0) }
|
|
let result = source as NSArray
|
|
expectTrue(isNativeNSArray(result))
|
|
expectEqual(3, result.count)
|
|
autoreleasepoolIfUnoptimizedReturnAutoreleased {
|
|
expectEqual(10, (result[0] as! TestObjCValueTy).value)
|
|
expectEqual(20, (result[1] as! TestObjCValueTy).value)
|
|
expectEqual(30, (result[2] as! TestObjCValueTy).value)
|
|
}
|
|
}
|
|
|
|
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.objectAt(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.objectAt(index)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Verbatim/objectAtIndex") {
|
|
let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3)
|
|
|
|
var v: AnyObject = a.objectAt(0)
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a.objectAt(1)
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a.objectAt(2)
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAt(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAt(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAt(2), UInt.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<Int>] {
|
|
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<AnyObject>.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<Int>] {
|
|
ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects/trap/\(indexRange)")
|
|
.crashOutputMatches("Array index out of range")
|
|
.code {
|
|
let a = getBridgedNSArrayOfRefTypeVerbatimBridged(
|
|
numElements: 3, capacity: 16)
|
|
let buffer = UnsafeMutablePointer<AnyObject>.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<AnyObject>.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, UInt.self)
|
|
|
|
v = buffer[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = buffer[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAt(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAt(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAt(2), UInt.self))
|
|
}
|
|
|
|
buffer.dealloc(3)
|
|
_fixLifetime(a)
|
|
|
|
expectAutoreleasedKeysAndValues(unopt: (0, 3))
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Verbatim/copyWithZone") {
|
|
let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3)
|
|
let copy: AnyObject = a.copy(zone: nil)
|
|
expectEqual(unsafeBitCast(a, UInt.self), unsafeBitCast(copy, UInt.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, UInt.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.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.objectAt(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAt(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAt(2), UInt.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, UInt.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, UInt.self))
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array -> NSArray bridging tests
|
|
//
|
|
// Element is bridged non-verbatim.
|
|
//
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ArrayTestSuite.test("BridgedToObjC.Nonverbatim.BridgeUsingAs") {
|
|
let source = [ 10, 20, 30 ].map { TestBridgedValueTy($0) }
|
|
var result = source as NSArray
|
|
expectTrue(isNativeNSArray(result))
|
|
expectEqual(3, result.count)
|
|
autoreleasepoolIfUnoptimizedReturnAutoreleased {
|
|
expectEqual(10, (result[0] as! TestBridgedValueTy).value)
|
|
expectEqual(20, (result[1] as! TestBridgedValueTy).value)
|
|
expectEqual(30, (result[2] as! TestBridgedValueTy).value)
|
|
}
|
|
}
|
|
|
|
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.objectAt(index)
|
|
}
|
|
}
|
|
|
|
for index in [ -100, -1, 3, 4, 100 ] {
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex/trap/\(index)") {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)
|
|
expectCrashLater()
|
|
a.objectAt(index)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex") {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)
|
|
|
|
var v: AnyObject = a.objectAt(0)
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a.objectAt(1)
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a.objectAt(2)
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAt(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAt(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAt(2), UInt.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<Int>] {
|
|
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<AnyObject>.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<Int>] {
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/getObjects/trap/\(indexRange)")
|
|
.crashOutputMatches("Array index out of range")
|
|
.code {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(
|
|
numElements: 3, capacity: 16)
|
|
let buffer = UnsafeMutablePointer<AnyObject>.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<AnyObject>.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, UInt.self)
|
|
|
|
v = buffer[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = buffer[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAt(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAt(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAt(2), UInt.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.copy(zone: nil)
|
|
expectEqual(unsafeBitCast(a, UInt.self), unsafeBitCast(copy, UInt.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, UInt.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.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.objectAt(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAt(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAt(2), UInt.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, UInt.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.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.objectAt(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAt(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAt(2), UInt.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, UInt.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, UInt.self))
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// NSArray -> Array -> NSArray bridging tests.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ArrayTestSuite.test("BridgedToObjC.Verbatim.RoundtripThroughSwiftArray") {
|
|
% for (MiddleType, AsCast) in [
|
|
% ('Array<AnyObject>', 'as'),
|
|
% ('Array<TestObjCValueTy>', 'as!'),
|
|
% ]:
|
|
if true {
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a: ${MiddleType} = _convertNSArrayToArray(nsa)
|
|
let bridgedBack = _convertArrayToNSArray(a)
|
|
|
|
expectEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
if true {
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a = nsa ${AsCast} ${MiddleType}
|
|
let bridgedBack: NSArray = a as NSArray
|
|
|
|
expectEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
% end
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC.Nonverbatim.RoundtripThroughSwiftArray") {
|
|
if true {
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a: Array<TestBridgedValueTy> = _convertNSArrayToArray(nsa)
|
|
let bridgedBack = _convertArrayToNSArray(a)
|
|
expectEqual(3, TestBridgedValueTy.bridgeOperations)
|
|
}
|
|
if true {
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a = nsa as! Array<TestBridgedValueTy>
|
|
let bridgedBack: NSArray = a as NSArray
|
|
expectEqual(3, TestBridgedValueTy.bridgeOperations)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array and EvilCollection that changes its size while we are not looking
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
let evilBoundsError = "EvilCollection: index out of range"
|
|
|
|
final class EvilCollection : Collection {
|
|
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 iterator() -> CollectionDefaultIterator<EvilCollection> {
|
|
return CollectionDefaultIterator(self)
|
|
}
|
|
}
|
|
|
|
for (step, evilBoundsCheck) in [ (1, true), (-1, false), (-1, true) ] {
|
|
|
|
let message = step < 0 && evilBoundsCheck
|
|
? evilBoundsError
|
|
: "invalid Collection: count differed in successive traversals"
|
|
|
|
let constructionMessage =
|
|
/*_isStdlibInternalChecksEnabled() && !evilBoundsCheck && step <= 0
|
|
? "_UnsafePartiallyInitializedContiguousArrayBuffer has no more capacity"
|
|
:*/ message
|
|
|
|
// The invalid Collection error is a _debugPreconditon that will only fire
|
|
// in a Debug assert configuration.
|
|
let expectedToFail = (step < 0 && evilBoundsCheck) ||
|
|
_isDebugAssertConfiguration()
|
|
|
|
let natureOfEvil = step > 0 ? "Growth" : "Shrinkage"
|
|
let boundsChecked = evilBoundsCheck ? "BoundsChecked" : "NoBoundsCheck"
|
|
let testPrefix = "MemorySafety/\(boundsChecked)/Evil\(natureOfEvil)"
|
|
|
|
let t = ArrayTestSuite.test("\(testPrefix)/Infrastructure")
|
|
(evilBoundsCheck && _isDebugAssertConfiguration()
|
|
? t.crashOutputMatches(evilBoundsError) : t)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
let count0 = evil.count
|
|
let count1 = evil.count
|
|
expectNotEqual(count0, count1)
|
|
if step > 0 {
|
|
expectLE(count0, count1)
|
|
}
|
|
else {
|
|
expectGE(count0, count1)
|
|
}
|
|
if evilBoundsCheck {
|
|
expectCrashLater()
|
|
}
|
|
let x = evil[-1]
|
|
_blackHole(x)
|
|
}
|
|
|
|
let t2 = ArrayTestSuite.test("\(testPrefix)/Construction")
|
|
(_isDebugAssertConfiguration() && expectedToFail
|
|
? t2.crashOutputMatches(constructionMessage) : t2)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
|
|
let a = Array(evil)
|
|
_blackHole(a)
|
|
}
|
|
|
|
for (op, rangeMax) in ["Grow":0, "Shrink":200] {
|
|
let t3 = ArrayTestSuite.test("\(testPrefix)/replaceSubrange/\(op)Unique")
|
|
(_isDebugAssertConfiguration() ? t3.crashOutputMatches(message) : t3)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array((0..<200).lazy.map { TestValueTy($0) })
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
a.replaceSubrange(0..<rangeMax, with: evil)
|
|
}
|
|
|
|
let t4 = ArrayTestSuite.test("\(testPrefix)/replaceSubrange/\(op)NonUnique")
|
|
(_isDebugAssertConfiguration() ? t4.crashOutputMatches(message) : t4)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array((0..<200).lazy.map { TestValueTy($0) })
|
|
var b = a
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
a.replaceSubrange(0..<rangeMax, with: evil)
|
|
_fixLifetime(b)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/SequenceMap")
|
|
.skip(.Custom(
|
|
{ _isFastAssertConfiguration() },
|
|
reason: "this trap is not guaranteed to happen in -Ounchecked"))
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if step < 0 {
|
|
expectCrashLater()
|
|
}
|
|
let a = AnySequence(evil).map { $0 }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/CollectionMap")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
|
|
let a = evil.map { $0 }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/FilterAll")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
let a = evil.filter { _ in true }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/FilterNone")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
let a = evil.filter { _ in false }
|
|
_blackHole(a)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Special cases and one-off tests.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}<Void>/map") {
|
|
// This code used to crash because it generated an array of Void with
|
|
// stride == 0.
|
|
if true {
|
|
let input: ${array_type}<Void> = [ (), (), () ]
|
|
let result = input.map { (_) -> Void in return () }
|
|
expectEqual(3, result.count)
|
|
}
|
|
|
|
if true {
|
|
let input: ${array_type}<OpaqueValue<Int>> = [
|
|
OpaqueValue(10), OpaqueValue(20), OpaqueValue(30)
|
|
]
|
|
let result = input.map { (_) -> Void in return () }
|
|
expectEqual(3, result.count)
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
ArrayTestSuite.setUp {
|
|
resetLeaksOfDictionaryKeysValues()
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
}
|
|
|
|
ArrayTestSuite.tearDown {
|
|
if _isDebugAssertConfiguration() {
|
|
// The return autorelease optimization does not happen reliable.
|
|
expectNoLeaksOfDictionaryKeysValues()
|
|
}
|
|
}
|
|
|
|
runAllTests()
|
|
|