mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This replaces swiftMSVCRT with swiftCRT. The big difference here is that the `visualc` module is no longer imported nor exported. The `visualc` module remains in use for a singular test wrt availability, but this should effectively remove the need for the `visualc` module. The difference between the MSVCRT and ucrt module was not well understood by most. MSVCRT provided ucrt AND visualc, combining pieces of the old MSVCRT and the newer ucrt. The ucrt module is what you really wanted most of the time, however, would need to use MSVCRT for the convenience aliases for type-generic math and the deprecated math constants. Unfortunately, we cannot shadow the `ucrt` module and create a Swift SDK overlay for ucrt as that seems to result in circular dependencies when processing the `_Concurrency` module. Although this makes using the C library easier for most people, it has a more important subtle change: it cleaves the dependency on visualc. This means that this enables use of Swift without Visual Studio for the singular purpose of providing 3 header files. Additionally, it removes the need for the installation of 2 of the 4 support files. This greatly simplifies the deployment process on Windows.
786 lines
25 KiB
Swift
786 lines
25 KiB
Swift
// RUN: %empty-directory(%t)
|
|
//
|
|
// RUN: %gyb %s -o %t/Runtime.swift
|
|
// RUN: %target-build-swift -parse-stdlib -module-name a %t/Runtime.swift -o %t.out
|
|
// RUN: %target-codesign %t.out
|
|
// RUN: %target-run %t.out
|
|
// REQUIRES: executable_test
|
|
|
|
import Swift
|
|
import StdlibUnittest
|
|
import SwiftShims
|
|
|
|
#if canImport(Darwin)
|
|
import Darwin
|
|
#elseif canImport(Glibc)
|
|
import Glibc
|
|
#elseif os(Windows)
|
|
import CRT
|
|
import WinSDK
|
|
#else
|
|
#error("Unsupported platform")
|
|
#endif
|
|
|
|
@_silgen_name("swift_demangle")
|
|
public
|
|
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 10.15, iOS 13.0, tvOS 13.0, watchOS 6.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)
|
|
|
|
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: class {
|
|
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)
|
|
}
|
|
|
|
Runtime.test("SwiftError layout constants for LLDB") {
|
|
let offsetof_SwiftError_typeMetadata = pointerToSwiftCoreSymbol(name: "_swift_lldb_offsetof_SwiftError_typeMetadata")!
|
|
let sizeof_SwiftError = pointerToSwiftCoreSymbol(name: "_swift_lldb_sizeof_SwiftError")!
|
|
|
|
#if canImport(Darwin)
|
|
#if arch(i386) || arch(arm)
|
|
expectEqual(20, offsetof_SwiftError_typeMetadata.load(as: UInt.self))
|
|
expectEqual(36, sizeof_SwiftError.load(as: UInt.self))
|
|
#else
|
|
expectEqual(40, offsetof_SwiftError_typeMetadata.load(as: UInt.self))
|
|
expectEqual(72, sizeof_SwiftError.load(as: UInt.self))
|
|
#endif
|
|
#elseif os(Linux) || os(Android) || os(Windows) || os(OpenBSD)
|
|
expectEqual(16, offsetof_SwiftError_typeMetadata.load(as: UInt.self))
|
|
expectEqual(32, sizeof_SwiftError.load(as: UInt.self))
|
|
#else
|
|
_UnimplementedError()
|
|
#endif
|
|
}
|
|
|
|
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") {
|
|
// [SR-8158]: Printing type(of: Codable & Protocol type ) EXC_BAD_ACCESS
|
|
// 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 arch(i386) || arch(arm)
|
|
expectEqual(4, MemoryLayout<Optional<AnyObject>>.size)
|
|
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
|
|
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 arch(i386) || arch(arm)
|
|
// Not applicable to 32-bit architectures.
|
|
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
|
|
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))
|
|
}
|
|
|
|
// _stdlib_isOSVersionAtLeast is broken for
|
|
// watchOS. rdar://problem/20234735
|
|
#if canImport(Darwin)
|
|
// 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.
|
|
expectFalse(isAtLeastOS(1066, 0, 0))
|
|
expectTrue(isAtLeastOS(0, 1066, 0))
|
|
expectTrue(isAtLeastOS(0, 0, 1066))
|
|
|
|
// 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))
|
|
}
|
|
#endif
|
|
}
|
|
|
|
runAllTests()
|
|
|