mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Find all the usages of `--enable-experimental-feature` or `--enable-upcoming-feature` in the tests and replace some of the `REQUIRES: asserts` to use `REQUIRES: swift-feature-Foo` instead, which should correctly apply to depending on the asserts/noasserts mode of the toolchain for each feature. Remove some comments that talked about enabling asserts since they don't apply anymore (but I might had miss some). All this was done with an automated script, so some formatting weirdness might happen, but I hope I fixed most of those. There might be some tests that were `REQUIRES: asserts` that might run in `noasserts` toolchains now. This will normally be because their feature went from experimental to upcoming/base and the tests were not updated.
792 lines
25 KiB
Swift
792 lines
25 KiB
Swift
// RUN: %empty-directory(%t)
|
|
//
|
|
// RUN: %gyb %s -o %t/Runtime.swift
|
|
// RUN: %target-build-swift -parse-stdlib -module-name a -enable-experimental-feature Extern %t/Runtime.swift -o %t.out
|
|
// RUN: %target-codesign %t.out
|
|
// RUN: %target-run %t.out
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: reflection
|
|
// REQUIRES: swift_feature_Extern
|
|
|
|
import Swift
|
|
import StdlibUnittest
|
|
import SwiftShims
|
|
|
|
#if canImport(Darwin)
|
|
import Darwin
|
|
#elseif canImport(Glibc)
|
|
import Glibc
|
|
#elseif os(WASI)
|
|
import WASILibc
|
|
#elseif canImport(Android)
|
|
import Android
|
|
#elseif os(Windows)
|
|
import CRT
|
|
import WinSDK
|
|
#else
|
|
#error("Unsupported platform")
|
|
#endif
|
|
|
|
@_extern(c, "swift_demangle")
|
|
func _stdlib_demangleImpl(
|
|
mangledName: UnsafePointer<CChar>?,
|
|
mangledNameLength: UInt,
|
|
outputBuffer: UnsafeMutablePointer<CChar>?,
|
|
outputBufferSize: UnsafeMutablePointer<UInt>?,
|
|
flags: UInt32
|
|
) -> UnsafeMutablePointer<CChar>?
|
|
|
|
func _stdlib_demangleName(_ mangledName: String) -> String {
|
|
return mangledName.utf8CString.withUnsafeBufferPointer {
|
|
(mangledNameUTF8CStr) in
|
|
|
|
let demangledNamePtr = _stdlib_demangleImpl(
|
|
mangledName: mangledNameUTF8CStr.baseAddress,
|
|
mangledNameLength: UInt(mangledNameUTF8CStr.count - 1),
|
|
outputBuffer: nil,
|
|
outputBufferSize: nil,
|
|
flags: 0)
|
|
|
|
if let demangledNamePtr = demangledNamePtr {
|
|
let demangledName = String(cString: demangledNamePtr)
|
|
_swift_stdlib_free(demangledNamePtr)
|
|
return demangledName
|
|
}
|
|
return mangledName
|
|
}
|
|
}
|
|
|
|
var swiftObjectCanaryCount = 0
|
|
class SwiftObjectCanary {
|
|
init() {
|
|
swiftObjectCanaryCount += 1
|
|
}
|
|
deinit {
|
|
swiftObjectCanaryCount -= 1
|
|
}
|
|
}
|
|
|
|
struct SwiftObjectCanaryStruct {
|
|
var ref = SwiftObjectCanary()
|
|
}
|
|
|
|
var Runtime = TestSuite("Runtime")
|
|
|
|
Runtime.test("_canBeClass") {
|
|
expectEqual(1, _canBeClass(SwiftObjectCanary.self))
|
|
expectEqual(0, _canBeClass(SwiftObjectCanaryStruct.self))
|
|
|
|
typealias SwiftClosure = () -> ()
|
|
expectEqual(0, _canBeClass(SwiftClosure.self))
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// The protocol should be defined in the standard library, otherwise the cast
|
|
// does not work.
|
|
typealias P1 = CustomReflectable
|
|
typealias P2 = CustomStringConvertible
|
|
protocol Q1 {}
|
|
|
|
extension P1 {
|
|
var success: Bool {
|
|
print(String(describing: customMirror))
|
|
return String(describing: customMirror) == "Mirror for ()"
|
|
}
|
|
}
|
|
|
|
// A small struct that can be stored inline in an opaque buffer.
|
|
struct StructConformsToP1 : CustomReflectable, Q1 {
|
|
var customMirror: Mirror {
|
|
return Mirror(reflecting: ())
|
|
}
|
|
}
|
|
|
|
// A small struct that can be stored inline in an opaque buffer.
|
|
struct Struct2ConformsToP1<T : CustomReflectable> : CustomReflectable, Q1 {
|
|
init(_ value: T) {
|
|
self.value = value
|
|
}
|
|
var customMirror: Mirror {
|
|
return value.customMirror
|
|
}
|
|
var value: T
|
|
}
|
|
|
|
// A large struct that cannot be stored inline in an opaque buffer.
|
|
struct Struct3ConformsToP2 : CustomStringConvertible, Q1 {
|
|
var a: UInt64 = 10
|
|
var b: UInt64 = 20
|
|
var c: UInt64 = 30
|
|
var d: UInt64 = 40
|
|
|
|
var description: String {
|
|
// Don't rely on string interpolation, it uses the casts that we are trying
|
|
// to test.
|
|
var result = ""
|
|
result += _uint64ToString(a) + " "
|
|
result += _uint64ToString(b) + " "
|
|
result += _uint64ToString(c) + " "
|
|
result += _uint64ToString(d)
|
|
return result
|
|
}
|
|
}
|
|
|
|
// A large struct that cannot be stored inline in an opaque buffer.
|
|
struct Struct4ConformsToP2<T : CustomStringConvertible> : CustomStringConvertible, Q1 {
|
|
var value: T
|
|
var e: UInt64 = 50
|
|
var f: UInt64 = 60
|
|
var g: UInt64 = 70
|
|
var h: UInt64 = 80
|
|
|
|
init(_ value: T) {
|
|
self.value = value
|
|
}
|
|
|
|
var description: String {
|
|
// Don't rely on string interpolation, it uses the casts that we are trying
|
|
// to test.
|
|
var result = value.description + " "
|
|
result += _uint64ToString(e) + " "
|
|
result += _uint64ToString(f) + " "
|
|
result += _uint64ToString(g) + " "
|
|
result += _uint64ToString(h)
|
|
return result
|
|
}
|
|
}
|
|
|
|
struct StructDoesNotConformToP1 : Q1 {}
|
|
|
|
class ClassConformsToP1 : CustomReflectable, Q1 {
|
|
var customMirror: Mirror {
|
|
return Mirror(reflecting: ())
|
|
}
|
|
}
|
|
|
|
class Class2ConformsToP1<T : CustomReflectable> : CustomReflectable, Q1 {
|
|
init(_ value: T) {
|
|
self.value = [value]
|
|
}
|
|
var customMirror: Mirror {
|
|
return value[0].customMirror
|
|
}
|
|
// FIXME: should be "var value: T", but we don't support it now.
|
|
var value: Array<T>
|
|
}
|
|
|
|
class ClassDoesNotConformToP1 : Q1 {}
|
|
|
|
Runtime.test("dynamicCasting with as") {
|
|
let someP1Value = StructConformsToP1()
|
|
let someP1Value2 = Struct2ConformsToP1(StructConformsToP1())
|
|
let someNotP1Value = StructDoesNotConformToP1()
|
|
let someP2Value = Struct3ConformsToP2()
|
|
let someP2Value2 = Struct4ConformsToP2(Struct3ConformsToP2())
|
|
let someP1Ref = ClassConformsToP1()
|
|
let someP1Ref2 = Class2ConformsToP1(ClassConformsToP1())
|
|
let someNotP1Ref = ClassDoesNotConformToP1()
|
|
|
|
expectTrue(someP1Value is P1)
|
|
expectTrue(someP1Value2 is P1)
|
|
expectFalse(someNotP1Value is P1)
|
|
expectTrue(someP2Value is P2)
|
|
expectTrue(someP2Value2 is P2)
|
|
expectTrue(someP1Ref is P1)
|
|
expectTrue(someP1Ref2 is P1)
|
|
expectFalse(someNotP1Ref is P1)
|
|
|
|
expectTrue(someP1Value as P1 is P1)
|
|
expectTrue(someP1Value2 as P1 is P1)
|
|
expectTrue(someP2Value as P2 is P2)
|
|
expectTrue(someP2Value2 as P2 is P2)
|
|
expectTrue(someP1Ref as P1 is P1)
|
|
|
|
expectTrue(someP1Value as Q1 is P1)
|
|
expectTrue(someP1Value2 as Q1 is P1)
|
|
expectFalse(someNotP1Value as Q1 is P1)
|
|
expectTrue(someP2Value as Q1 is P2)
|
|
expectTrue(someP2Value2 as Q1 is P2)
|
|
expectTrue(someP1Ref as Q1 is P1)
|
|
expectTrue(someP1Ref2 as Q1 is P1)
|
|
expectFalse(someNotP1Ref as Q1 is P1)
|
|
|
|
expectTrue(someP1Value as Any is P1)
|
|
expectTrue(someP1Value2 as Any is P1)
|
|
expectFalse(someNotP1Value as Any is P1)
|
|
expectTrue(someP2Value as Any is P2)
|
|
expectTrue(someP2Value2 as Any is P2)
|
|
expectTrue(someP1Ref as Any is P1)
|
|
expectTrue(someP1Ref2 as Any is P1)
|
|
expectFalse(someNotP1Ref as Any is P1)
|
|
|
|
expectTrue(someP1Ref as AnyObject is P1)
|
|
expectTrue(someP1Ref2 as AnyObject is P1)
|
|
expectFalse(someNotP1Ref as AnyObject is P1)
|
|
|
|
expectTrue((someP1Value as P1).success)
|
|
expectTrue((someP1Value2 as P1).success)
|
|
expectEqual("10 20 30 40", (someP2Value as P2).description)
|
|
expectEqual("10 20 30 40 50 60 70 80", (someP2Value2 as P2).description)
|
|
|
|
expectTrue((someP1Ref as P1).success)
|
|
expectTrue((someP1Ref2 as P1).success)
|
|
|
|
expectTrue(((someP1Value as Q1) as! P1).success)
|
|
expectTrue(((someP1Value2 as Q1) as! P1).success)
|
|
expectEqual("10 20 30 40", ((someP2Value as Q1) as! P2).description)
|
|
expectEqual("10 20 30 40 50 60 70 80",
|
|
((someP2Value2 as Q1) as! P2).description)
|
|
expectTrue(((someP1Ref as Q1) as! P1).success)
|
|
expectTrue(((someP1Ref2 as Q1) as! P1).success)
|
|
|
|
expectTrue(((someP1Value as Any) as! P1).success)
|
|
expectTrue(((someP1Value2 as Any) as! P1).success)
|
|
expectEqual("10 20 30 40", ((someP2Value as Any) as! P2).description)
|
|
expectEqual("10 20 30 40 50 60 70 80",
|
|
((someP2Value2 as Any) as! P2).description)
|
|
expectTrue(((someP1Ref as Any) as! P1).success)
|
|
expectTrue(((someP1Ref2 as Any) as! P1).success)
|
|
|
|
expectTrue(((someP1Ref as AnyObject) as! P1).success)
|
|
|
|
expectNil((someNotP1Value as? P1))
|
|
expectNil((someNotP1Ref as? P1))
|
|
|
|
expectTrue(((someP1Value as Q1) as? P1)!.success)
|
|
expectTrue(((someP1Value2 as Q1) as? P1)!.success)
|
|
expectNil(((someNotP1Value as Q1) as? P1))
|
|
expectEqual("10 20 30 40", ((someP2Value as Q1) as? P2)!.description)
|
|
expectEqual("10 20 30 40 50 60 70 80",
|
|
((someP2Value2 as Q1) as? P2)!.description)
|
|
expectTrue(((someP1Ref as Q1) as? P1)!.success)
|
|
expectTrue(((someP1Ref2 as Q1) as? P1)!.success)
|
|
expectNil(((someNotP1Ref as Q1) as? P1))
|
|
|
|
expectTrue(((someP1Value as Any) as? P1)!.success)
|
|
expectTrue(((someP1Value2 as Any) as? P1)!.success)
|
|
expectNil(((someNotP1Value as Any) as? P1))
|
|
expectEqual("10 20 30 40", ((someP2Value as Any) as? P2)!.description)
|
|
expectEqual("10 20 30 40 50 60 70 80",
|
|
((someP2Value2 as Any) as? P2)!.description)
|
|
expectTrue(((someP1Ref as Any) as? P1)!.success)
|
|
expectTrue(((someP1Ref2 as Any) as? P1)!.success)
|
|
expectNil(((someNotP1Ref as Any) as? P1))
|
|
|
|
expectTrue(((someP1Ref as AnyObject) as? P1)!.success)
|
|
expectTrue(((someP1Ref2 as AnyObject) as? P1)!.success)
|
|
expectNil(((someNotP1Ref as AnyObject) as? P1))
|
|
|
|
let doesThrow: (Int) throws -> Int = { $0 }
|
|
let doesNotThrow: (String) -> String = { $0 }
|
|
|
|
_ = doesThrow
|
|
|
|
expectTrue(doesThrow as Any is (Int) throws -> Int)
|
|
expectFalse(doesThrow as Any is (String) throws -> Int)
|
|
expectFalse(doesThrow as Any is (String) throws -> String)
|
|
expectFalse(doesThrow as Any is (Int) throws -> String)
|
|
expectFalse(doesThrow as Any is (Int) -> Int)
|
|
expectFalse(doesThrow as Any is (String) throws -> String)
|
|
expectFalse(doesThrow as Any is (String) -> String)
|
|
expectTrue(doesNotThrow as Any is (String) throws -> String)
|
|
expectTrue(doesNotThrow as Any is (String) -> String)
|
|
expectFalse(doesNotThrow as Any is (Int) -> String)
|
|
expectFalse(doesNotThrow as Any is (Int) -> Int)
|
|
expectFalse(doesNotThrow as Any is (String) -> Int)
|
|
expectFalse(doesNotThrow as Any is (Int) throws -> Int)
|
|
expectFalse(doesNotThrow as Any is (Int) -> Int)
|
|
}
|
|
|
|
extension Int {
|
|
class ExtensionClassConformsToP2 : P2 {
|
|
var description: String { return "abc" }
|
|
}
|
|
|
|
fileprivate class PrivateExtensionClassConformsToP2 : P2 {
|
|
var description: String { return "def" }
|
|
}
|
|
}
|
|
|
|
Runtime.test("dynamic cast to existential with cross-module extensions") {
|
|
let internalObj = Int.ExtensionClassConformsToP2()
|
|
let privateObj = Int.PrivateExtensionClassConformsToP2()
|
|
|
|
expectTrue(internalObj is P2)
|
|
expectTrue(privateObj is P2)
|
|
}
|
|
|
|
class SomeClass {}
|
|
struct SomeStruct {}
|
|
enum SomeEnum {
|
|
case A
|
|
init() { self = .A }
|
|
}
|
|
|
|
Runtime.test("typeName") {
|
|
expectEqual("a.SomeClass", _typeName(SomeClass.self))
|
|
expectEqual("a.SomeStruct", _typeName(SomeStruct.self))
|
|
expectEqual("a.SomeEnum", _typeName(SomeEnum.self))
|
|
expectEqual("Any.Protocol", _typeName(Any.Protocol.self))
|
|
expectEqual("Swift.AnyObject.Protocol", _typeName(AnyObject.Protocol.self))
|
|
expectEqual("Swift.AnyObject.Type.Protocol", _typeName(AnyClass.Protocol.self))
|
|
expectEqual("Swift.Optional<Swift.AnyObject>.Type", _typeName((AnyObject?).Type.self))
|
|
|
|
var a: Any = SomeClass()
|
|
expectEqual("a.SomeClass", _typeName(type(of: a)))
|
|
|
|
a = SomeStruct()
|
|
expectEqual("a.SomeStruct", _typeName(type(of: a)))
|
|
|
|
a = SomeEnum()
|
|
expectEqual("a.SomeEnum", _typeName(type(of: a)))
|
|
|
|
a = AnyObject.self
|
|
expectEqual("Swift.AnyObject.Protocol", _typeName(type(of: a)))
|
|
|
|
a = AnyClass.self
|
|
expectEqual("Swift.AnyObject.Type.Protocol", _typeName(type(of: a)))
|
|
|
|
a = (AnyObject?).self
|
|
expectEqual("Swift.Optional<Swift.AnyObject>.Type",
|
|
_typeName(type(of: a)))
|
|
|
|
a = Any.self
|
|
expectEqual("Any.Protocol", _typeName(type(of: a)))
|
|
}
|
|
|
|
class SomeSubclass : SomeClass {}
|
|
|
|
protocol SomeProtocol {}
|
|
class SomeConformingClass : SomeProtocol {}
|
|
class SomeConformingSubclass : SomeConformingClass {}
|
|
class UnicodeCläss {}
|
|
|
|
Runtime.test("typeByName") {
|
|
expectTrue(_typeByName("a.SomeClass") == SomeClass.self)
|
|
expectTrue(_typeByName("a.SomeSubclass") == SomeSubclass.self)
|
|
// name lookup will be via protocol conformance table
|
|
expectTrue(_typeByName("a.SomeConformingClass") == SomeConformingClass.self)
|
|
expectTrue(_typeByName("a.UnicodeCläss") == UnicodeCläss.self)
|
|
}
|
|
|
|
Runtime.test("demangleName") {
|
|
expectEqual("", _stdlib_demangleName(""))
|
|
expectEqual("abc", _stdlib_demangleName("abc"))
|
|
expectEqual("\0", _stdlib_demangleName("\0"))
|
|
expectEqual("Swift.Double", _stdlib_demangleName("$sSdD"))
|
|
expectEqual("x.a : x.Foo<x.Foo<x.Foo<Swift.Int, Swift.Int>, x.Foo<Swift.Int, Swift.Int>>, x.Foo<x.Foo<Swift.Int, Swift.Int>, x.Foo<Swift.Int, Swift.Int>>>",
|
|
_stdlib_demangleName("$s1x1aAA3FooCyADyADySiSiGADySiSiGGADyADySiSiGADySiSiGGGvp"))
|
|
expectEqual("Foobar", _stdlib_demangleName("$s13__lldb_expr_46FoobarCD"))
|
|
}
|
|
|
|
if #available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, visionOS 1.0, *) {
|
|
Runtime.test("demangleTruncate") {
|
|
// Swift.Int requires 10 bytes to be fully demangled.
|
|
let buffer = UnsafeMutableBufferPointer<Int8>.allocate(capacity: 10)
|
|
|
|
defer { buffer.deallocate() }
|
|
|
|
// Set last byte to a custom number, that way when we call swift_demangle
|
|
// the last byte should be unchanged rather than it being set to 0.
|
|
buffer[buffer.count - 1] = 16
|
|
|
|
// Only give 9 bytes though to exercise that swift_demangle doesn't write past
|
|
// the buffer.
|
|
var bufferSize = UInt(buffer.count - 1)
|
|
|
|
let mangled = "$sSi"
|
|
|
|
mangled.utf8CString.withUnsafeBufferPointer {
|
|
_ = _stdlib_demangleImpl(
|
|
mangledName: $0.baseAddress,
|
|
mangledNameLength: UInt($0.count - 1),
|
|
outputBuffer: buffer.baseAddress,
|
|
outputBufferSize: &bufferSize,
|
|
flags: 0
|
|
)
|
|
}
|
|
|
|
expectEqual(String(cString: buffer.baseAddress!), "Swift.In")
|
|
expectEqual(bufferSize, 10)
|
|
expectEqual(buffer[buffer.count - 1], 16)
|
|
}
|
|
}
|
|
|
|
% for optionality in ['', '?']:
|
|
Runtime.test("_stdlib_atomicCompareExchangeStrongPtr") {
|
|
typealias IntPtr = UnsafeMutablePointer<Int>
|
|
let origP1: IntPtr${optionality} = IntPtr(bitPattern: 0x10101010)!
|
|
let origP2: IntPtr${optionality} = IntPtr(bitPattern: 0x20202020)!
|
|
let origP3: IntPtr${optionality} = IntPtr(bitPattern: 0x30303030)!
|
|
|
|
do {
|
|
var object = origP1
|
|
var expected = origP1
|
|
let r = _stdlib_atomicCompareExchangeStrongPtr(
|
|
object: &object, expected: &expected, desired: origP2)
|
|
expectTrue(r)
|
|
expectEqual(origP2, object)
|
|
expectEqual(origP1, expected)
|
|
}
|
|
do {
|
|
var object = origP1
|
|
var expected = origP2
|
|
let r = _stdlib_atomicCompareExchangeStrongPtr(
|
|
object: &object, expected: &expected, desired: origP3)
|
|
expectFalse(r)
|
|
expectEqual(origP1, object)
|
|
expectEqual(origP1, expected)
|
|
}
|
|
|
|
struct FooStruct {
|
|
var i: Int
|
|
var object: IntPtr${optionality}
|
|
var expected: IntPtr${optionality}
|
|
|
|
init(object: IntPtr${optionality}, expected: IntPtr${optionality}) {
|
|
self.i = 0
|
|
self.object = object
|
|
self.expected = expected
|
|
}
|
|
}
|
|
do {
|
|
var foo = FooStruct(object: origP1, expected: origP1)
|
|
let r = _stdlib_atomicCompareExchangeStrongPtr(
|
|
object: &foo.object, expected: &foo.expected, desired: origP2)
|
|
expectTrue(r)
|
|
expectEqual(origP2, foo.object)
|
|
expectEqual(origP1, foo.expected)
|
|
}
|
|
do {
|
|
var foo = FooStruct(object: origP1, expected: origP2)
|
|
let r = _stdlib_atomicCompareExchangeStrongPtr(
|
|
object: &foo.object, expected: &foo.expected, desired: origP3)
|
|
expectFalse(r)
|
|
expectEqual(origP1, foo.object)
|
|
expectEqual(origP1, foo.expected)
|
|
}
|
|
}
|
|
% end
|
|
|
|
Runtime.test("casting AnyObject to class metatypes") {
|
|
do {
|
|
let ao: AnyObject = SomeClass()
|
|
expectTrue(ao as? Any.Type == nil)
|
|
expectTrue(ao as? AnyClass == nil)
|
|
}
|
|
|
|
do {
|
|
var a: Any = SomeClass()
|
|
expectTrue(a as? Any.Type == nil)
|
|
expectTrue(a as? AnyClass == nil)
|
|
|
|
a = SomeClass.self
|
|
expectTrue(a as? Any.Type == SomeClass.self)
|
|
expectTrue(a as? AnyClass == SomeClass.self)
|
|
expectTrue(a as? SomeClass.Type == SomeClass.self)
|
|
}
|
|
}
|
|
|
|
func wantonlyWrapInAny<T>(_ x: T) -> Any {
|
|
return x
|
|
}
|
|
|
|
// Because `type(of: x)` and `T.self` have the same type `T.Type` in
|
|
// a <T>(x: T) context, both operations must produce the concrete protocol
|
|
// type value when `T` is bound to an existential type `P`.
|
|
func castWithAbstractionBarrier<T>(_ x: T) -> (
|
|
staticWithConcreteType: T.Type,
|
|
dynamicWithConcreteType: T.Type,
|
|
staticWithErasedType: Any.Type,
|
|
dynamicWithErasedType: Any.Type,
|
|
dynamicExistentialWithErasedType: Any.Type,
|
|
dynamicDoubleWrappedExistentialWithErasedType: Any.Type
|
|
) {
|
|
return (
|
|
staticWithConcreteType: T.self,
|
|
dynamicWithConcreteType: type(of: x),
|
|
staticWithErasedType: T.self,
|
|
dynamicWithErasedType: type(of: x),
|
|
dynamicExistentialWithErasedType: type(of: x as Any),
|
|
dynamicDoubleWrappedExistentialWithErasedType:
|
|
type(of: wantonlyWrapInAny(wantonlyWrapInAny(x)))
|
|
)
|
|
}
|
|
|
|
Runtime.test("abstraction barrier on casting generic param bound to existential") {
|
|
let c: SomeConformingClass = SomeConformingSubclass()
|
|
let x: SomeProtocol = c
|
|
let (staticWithConcreteType,
|
|
dynamicWithConcreteType,
|
|
staticWithErasedType,
|
|
dynamicWithErasedType,
|
|
dynamicExistentialWithErasedType,
|
|
dynamicDoubleWrappedExistentialWithErasedType)
|
|
= castWithAbstractionBarrier(x as SomeProtocol)
|
|
|
|
expectTrue(staticWithConcreteType == SomeProtocol.self)
|
|
expectTrue(dynamicWithConcreteType == SomeProtocol.self)
|
|
expectTrue(staticWithErasedType == SomeProtocol.self)
|
|
expectTrue(dynamicWithErasedType == SomeProtocol.self)
|
|
|
|
// type(of: x as Any) can be a proper existential type cast
|
|
expectTrue(dynamicExistentialWithErasedType == SomeConformingSubclass.self)
|
|
expectTrue(dynamicDoubleWrappedExistentialWithErasedType
|
|
== SomeConformingSubclass.self)
|
|
}
|
|
|
|
class Malkovich: Malkovichable {
|
|
var malkovich: String { return "malkovich" }
|
|
}
|
|
protocol Malkovichable: AnyObject {
|
|
var malkovich: String { get }
|
|
}
|
|
|
|
struct GenericStructWithReferenceStorage<T> {
|
|
var a: T
|
|
unowned(safe) var unownedConcrete: Malkovich
|
|
unowned(unsafe) var unmanagedConcrete: Malkovich
|
|
weak var weakConcrete: Malkovich?
|
|
|
|
unowned(safe) var unownedProto: Malkovichable
|
|
unowned(unsafe) var unmanagedProto: Malkovichable
|
|
weak var weakProto: Malkovichable?
|
|
}
|
|
|
|
func exerciseReferenceStorageInGenericContext<T>(
|
|
_ x: GenericStructWithReferenceStorage<T>,
|
|
forceCopy y: GenericStructWithReferenceStorage<T>
|
|
) {
|
|
expectEqual(x.unownedConcrete.malkovich, "malkovich")
|
|
expectEqual(x.unmanagedConcrete.malkovich, "malkovich")
|
|
expectEqual(x.weakConcrete!.malkovich, "malkovich")
|
|
expectEqual(x.unownedProto.malkovich, "malkovich")
|
|
expectEqual(x.unmanagedProto.malkovich, "malkovich")
|
|
expectEqual(x.weakProto!.malkovich, "malkovich")
|
|
|
|
expectEqual(y.unownedConcrete.malkovich, "malkovich")
|
|
expectEqual(y.unmanagedConcrete.malkovich, "malkovich")
|
|
expectEqual(y.weakConcrete!.malkovich, "malkovich")
|
|
expectEqual(y.unownedProto.malkovich, "malkovich")
|
|
expectEqual(y.unmanagedProto.malkovich, "malkovich")
|
|
expectEqual(y.weakProto!.malkovich, "malkovich")
|
|
}
|
|
|
|
Runtime.test("Struct layout with reference storage types") {
|
|
let malkovich = Malkovich()
|
|
|
|
let x = GenericStructWithReferenceStorage(a: malkovich,
|
|
unownedConcrete: malkovich,
|
|
unmanagedConcrete: malkovich,
|
|
weakConcrete: malkovich,
|
|
unownedProto: malkovich,
|
|
unmanagedProto: malkovich,
|
|
weakProto: malkovich)
|
|
exerciseReferenceStorageInGenericContext(x, forceCopy: x)
|
|
|
|
expectEqual(x.unownedConcrete.malkovich, "malkovich")
|
|
expectEqual(x.unmanagedConcrete.malkovich, "malkovich")
|
|
expectEqual(x.weakConcrete!.malkovich, "malkovich")
|
|
expectEqual(x.unownedProto.malkovich, "malkovich")
|
|
expectEqual(x.unmanagedProto.malkovich, "malkovich")
|
|
expectEqual(x.weakProto!.malkovich, "malkovich")
|
|
|
|
// Make sure malkovich lives long enough.
|
|
print(malkovich)
|
|
}
|
|
|
|
var Reflection = TestSuite("Reflection")
|
|
|
|
func wrap1 (_ x: Any) -> Any { return x }
|
|
func wrap2<T>(_ x: T) -> Any { return wrap1(x) }
|
|
func wrap3 (_ x: Any) -> Any { return wrap2(x) }
|
|
func wrap4<T>(_ x: T) -> Any { return wrap3(x) }
|
|
func wrap5 (_ x: Any) -> Any { return wrap4(x) }
|
|
|
|
class JustNeedAMetatype {}
|
|
|
|
Reflection.test("nested existential containers") {
|
|
let wrapped = wrap5(JustNeedAMetatype.self)
|
|
expectEqual("\(wrapped)", "JustNeedAMetatype")
|
|
}
|
|
|
|
Reflection.test("dumpToAStream") {
|
|
var output = ""
|
|
dump([ 42, 4242 ], to: &output)
|
|
expectEqual("▿ 2 elements\n - 42\n - 4242\n", output)
|
|
}
|
|
|
|
|
|
class Brilliant {
|
|
let first: Int
|
|
let second: String
|
|
|
|
init(_ fst: Int, _ snd: String) {
|
|
self.first = fst
|
|
self.second = snd
|
|
}
|
|
}
|
|
|
|
Reflection.test("ObjectIdentifier/Hashable,Comparable") {
|
|
// Check that object identifiers are unique to class instances.
|
|
let a = Brilliant(1, "")
|
|
let b = Brilliant(2, "")
|
|
let c = Brilliant(3, "")
|
|
|
|
checkHashable(
|
|
[a, b, c].map(ObjectIdentifier.init),
|
|
equalityOracle: { $0 == $1 })
|
|
|
|
// Comparable
|
|
func isComparable<X : Comparable>(_ x: X) {}
|
|
isComparable(ObjectIdentifier(a))
|
|
// Check the ObjectIdentifier created is stable
|
|
expectTrue(
|
|
(ObjectIdentifier(a) < ObjectIdentifier(b))
|
|
!= (ObjectIdentifier(a) > ObjectIdentifier(b)))
|
|
expectFalse(
|
|
ObjectIdentifier(a) >= ObjectIdentifier(b)
|
|
&& ObjectIdentifier(a) <= ObjectIdentifier(b))
|
|
|
|
// Check that ordering is transitive.
|
|
expectEqual(
|
|
[ ObjectIdentifier(a), ObjectIdentifier(b), ObjectIdentifier(c) ].sorted(),
|
|
[ ObjectIdentifier(c), ObjectIdentifier(b), ObjectIdentifier(a) ].sorted())
|
|
}
|
|
|
|
Reflection.test("ObjectIdentifier/CustomDebugStringConvertible") {
|
|
let obj1 = Brilliant(1, "")
|
|
let obj2 = Brilliant(2, "")
|
|
|
|
let oi1 = ObjectIdentifier(obj1)
|
|
let oi2 = ObjectIdentifier(obj2)
|
|
|
|
expectEqual(String(reflecting: oi1), String(reflecting: oi1))
|
|
expectNotEqual(String(reflecting: oi1), String(reflecting: oi2))
|
|
|
|
let p1 = UnsafeRawPointer(bitPattern: UInt(bitPattern: oi1))!
|
|
expectPrinted("ObjectIdentifier(\(p1))", oi1)
|
|
let p2 = UnsafeRawPointer(bitPattern: Int(bitPattern: oi1))!
|
|
expectPrinted("ObjectIdentifier(\(p2))", oi1)
|
|
|
|
}
|
|
|
|
class C: Q1 & Codable { }
|
|
|
|
Reflection.test("multiprotocolTypes") {
|
|
// https://github.com/apple/swift/issues/50690
|
|
// EXC_BAD_ACCESS when calling 'type(of:)' on protocol composition with
|
|
// 'Codable'
|
|
//
|
|
// This use of String(reflecting:) exercises a previously incorrect cast in
|
|
// NonFixedExistentialMetatypeBox::Container::getNumWitnessTables.
|
|
let obj: Q1 & Codable = C()
|
|
let t = type(of: obj)
|
|
let x = String(reflecting: t)
|
|
expectEqual("a.C", x)
|
|
}
|
|
|
|
|
|
var BitTwiddlingTestSuite = TestSuite("BitTwiddling")
|
|
|
|
BitTwiddlingTestSuite.test("_pointerSize") {
|
|
#if _pointerBitWidth(_32)
|
|
expectEqual(4, MemoryLayout<Optional<AnyObject>>.size)
|
|
#elseif _pointerBitWidth(_64)
|
|
expectEqual(8, MemoryLayout<Optional<AnyObject>>.size)
|
|
#else
|
|
fatalError("implement")
|
|
#endif
|
|
}
|
|
|
|
BitTwiddlingTestSuite.test("_isPowerOf2/Int") {
|
|
func asInt(_ a: Int) -> Int { return a }
|
|
|
|
expectFalse(_isPowerOf2(asInt(-1025)))
|
|
expectFalse(_isPowerOf2(asInt(-1024)))
|
|
expectFalse(_isPowerOf2(asInt(-1023)))
|
|
expectFalse(_isPowerOf2(asInt(-4)))
|
|
expectFalse(_isPowerOf2(asInt(-3)))
|
|
expectFalse(_isPowerOf2(asInt(-2)))
|
|
expectFalse(_isPowerOf2(asInt(-1)))
|
|
expectFalse(_isPowerOf2(asInt(0)))
|
|
expectTrue(_isPowerOf2(asInt(1)))
|
|
expectTrue(_isPowerOf2(asInt(2)))
|
|
expectFalse(_isPowerOf2(asInt(3)))
|
|
expectTrue(_isPowerOf2(asInt(1024)))
|
|
#if _pointerBitWidth(_32)
|
|
// Not applicable to 32-bit architectures.
|
|
#elseif _pointerBitWidth(_64)
|
|
expectTrue(_isPowerOf2(asInt(0x8000_0000)))
|
|
#else
|
|
fatalError("implement")
|
|
#endif
|
|
expectFalse(_isPowerOf2(Int.min))
|
|
expectFalse(_isPowerOf2(Int.max))
|
|
}
|
|
|
|
BitTwiddlingTestSuite.test("_isPowerOf2/UInt") {
|
|
func asUInt(_ a: UInt) -> UInt { return a }
|
|
|
|
expectFalse(_isPowerOf2(asUInt(0)))
|
|
expectTrue(_isPowerOf2(asUInt(1)))
|
|
expectTrue(_isPowerOf2(asUInt(2)))
|
|
expectFalse(_isPowerOf2(asUInt(3)))
|
|
expectTrue(_isPowerOf2(asUInt(1024)))
|
|
expectTrue(_isPowerOf2(asUInt(0x8000_0000)))
|
|
expectFalse(_isPowerOf2(UInt.max))
|
|
}
|
|
|
|
var AvailabilityVersionsTestSuite = TestSuite("AvailabilityVersions")
|
|
|
|
AvailabilityVersionsTestSuite.test("_stdlib_isOSVersionAtLeast") {
|
|
func isAtLeastOS(_ major: Int, _ minor: Int, _ patch: Int) -> Bool {
|
|
return Bool(_builtinBooleanLiteral: _stdlib_isOSVersionAtLeast(
|
|
major._builtinWordValue,
|
|
minor._builtinWordValue,
|
|
patch._builtinWordValue))
|
|
}
|
|
|
|
// For calling the alternate entrypoint for macCatalyst versioning.
|
|
#if os(iOS) && targetEnvironment(macCatalyst)
|
|
func isVariantAtLeastOS(_ major: Int, _ minor: Int, _ patch: Int) -> Bool {
|
|
return Bool(_builtinBooleanLiteral: _stdlib_isVariantOSVersionAtLeast(
|
|
major._builtinWordValue,
|
|
minor._builtinWordValue,
|
|
patch._builtinWordValue))
|
|
}
|
|
#endif
|
|
|
|
// _stdlib_isOSVersionAtLeast is broken for
|
|
// watchOS. rdar://problem/20234735
|
|
#if canImport(Darwin) && _runtime(_ObjC)
|
|
// This test assumes that no version component on an OS we test upon
|
|
// will ever be greater than 1066 and that every major version will always
|
|
// be greater than 1.
|
|
|
|
#if !targetEnvironment(macCatalyst)
|
|
expectFalse(isAtLeastOS(1066, 0, 0))
|
|
expectTrue(isAtLeastOS(0, 1066, 0))
|
|
expectTrue(isAtLeastOS(0, 0, 1066))
|
|
#endif
|
|
|
|
// When using a runtime that's not part of the OS, 9999 is a special version
|
|
// that's always available. The _swift_classIsSwiftMask symbol is absent in OS
|
|
// libraries, so detect based on that.
|
|
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
|
|
let _swift_classIsSwiftMaskPtr = dlsym(RTLD_DEFAULT, "_swift_classIsSwiftMask")
|
|
if _swift_classIsSwiftMaskPtr != nil {
|
|
expectTrue(isAtLeastOS(9999, 0, 0))
|
|
#if os(iOS) && targetEnvironment(macCatalyst)
|
|
// On macCatalyst we need to check the variant (iOS) version rather than
|
|
// the macOS version.
|
|
expectTrue(isVariantAtLeastOS(9999, 0, 0))
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
runAllTests()
|
|
|