// RUN: %target-run-simple-swift // REQUIRES: executable_test import StdlibUnittest import Swift // Also import modules which are used by StdlibUnittest internally. This // workaround is needed to link all required libraries in case we compile // StdlibUnittest with -sil-serialize-all. import SwiftPrivate #if _runtime(_ObjC) import ObjectiveC #endif class DeinitTester { private let onDeinit: () -> () init(onDeinit: () -> ()) { self.onDeinit = onDeinit } deinit { onDeinit() } } let OptionalTests = TestSuite("Optional") protocol TestProtocol1 {} // Check the generic parameter name. extension Optional where Wrapped : TestProtocol1 { var _wrappedIsTestProtocol1: Bool { fatalError("not implemented") } } extension ImplicitlyUnwrappedOptional where Wrapped : TestProtocol1 { var _wrappedIsTestProtocol1: Bool { fatalError("not implemented") } } OptionalTests.test("nil comparison") { var x: Int? = nil expectFalse(x != nil) switch x { case .some(let y): expectUnreachable() case .none: break } x = .some(1) expectTrue(x != nil) if true { var y1: Int? = .none expectTrue(y1 == nil) var y2: Int? = .none expectTrue(y2 == nil) } let x1: Int? = nil let x2: Int? = .none expectTrue(x1 == nil) expectTrue(x2 == nil) switch x { case .some(let y): expectEqual("1", "\(y)") case .none: assert(false) } expectEqual("forced extraction: 1.", "forced extraction: \(x!).") expectEqual("forced extraction use: 2.", "forced extraction use: \(x!.successor()).") } func testRelation(p: (Int?, Int?) -> Bool) -> [Bool] { typealias optPair = (Int?, Int?) let relationships: [optPair] = [ (1, 1), (1, 2), (2, 1), (1, .none), (.none, 1), (.none, .none) ] return relationships.map { p($0, $1) } } OptionalTests.test("Equatable") { expectEqual([true, false, false, false, false, true], testRelation(==)) expectEqual([false, true, true, true, true, false], testRelation(!=)) expectEqual([false, true, false, false, true, false], testRelation(<)) } struct X {} class C {} class E : Equatable {} func == (_: E, _: E) -> Bool { return true } OptionalTests.test("initializers") { let _: X? = nil let _: X? = X() let _: C? = nil let _: C? = C() } OptionalTests.test("nil comparison") { let v0: Int? = nil let v1: Int? = 1 expectFalse(v1 == nil) expectTrue(v1 != nil) expectTrue(v0 == nil) expectFalse(v0 != nil) expectFalse(nil == v1) expectTrue(nil != v1) expectTrue(nil == v0) expectFalse(nil != v0) let e0: E? = nil let e1: E? = E() expectFalse(e1 == nil) expectTrue(e1 != nil) expectTrue(e0 == nil) expectFalse(e0 != nil) expectFalse(nil == e1) expectTrue(nil != e1) expectTrue(nil == e0) expectFalse(nil != e0) /* // FIXME: Optional() == nil where T: !Equatable let _: X? = nil let _: X? = X() expectFalse(x1 == nil) expectTrue(x1 != nil) expectTrue(x0 == nil) expectFalse(x0 != nil) expectFalse(nil == x1) expectTrue(nil != x1) expectTrue(nil == x0) expectFalse(nil != x0) */ } OptionalTests.test("??") { var counter = 0 func nextCounter() -> Int { counter += 1; return counter-1 } func nextCounter2() -> Int? { return nextCounter() } let a: Int? = 123 let b: Int? = nil let c: Int? = nil let d: Int? = 456 let e: Int? = nil let f: Int? = nil expectEqual(123, a ?? nextCounter()) expectEqual(0, b ?? nextCounter()) expectEqual(1, c ?? nextCounter()) expectEqual(456, d ?? nextCounter()) expectEqual(456, e ?? d ?? nextCounter()) expectEqual(2, f ?? nextCounter()) expectEqual(Optional(456), c ?? d) expectEqual(nil, c ?? e) expectEqual(Optional(123), a ?? nextCounter2()) expectEqual(Optional(3), b ?? nextCounter2()) expectEqual(Optional(4), c ?? nextCounter2()) expectEqual(Optional(456), d ?? nextCounter2()) expectEqual(Optional(456), e ?? d ?? nextCounter2()) expectEqual(Optional(5), f ?? nextCounter2()) } OptionalTests.test("flatMap") { let half: Int32 -> Int16? = { if $0 % 2 == 0 { return Int16($0 / 2) } else { return .none } } expectOptionalEqual(2 as Int16, half(4)) expectEmpty(half(3)) expectEmpty((.none as Int32?).flatMap(half)) expectOptionalEqual(2 as Int16, (4 as Int32?).flatMap(half)) expectEmpty((3 as Int32?).flatMap(half)) } @inline(never) func anyToAny(a: T, _ : U.Type) -> U { return a as! U } @inline(never) func anyToAnyOrNil(a: T, _ : U.Type) -> U? { return a as? U } func canGenericCast(a: T, _ ty : U.Type) -> Bool { return anyToAnyOrNil(a, ty) != nil } OptionalTests.test("Casting Optional") { let x = C() let sx: C? = x let nx: C? = nil expectTrue(anyToAny(x, Optional.self)! === x) expectTrue(anyToAny(sx, C.self) === x) expectTrue(anyToAny(sx, Optional.self)! === x) expectTrue(anyToAny(nx, Optional.self) == nil) expectTrue(anyToAnyOrNil(nx, C.self) == nil) let i = Int.max let si: Int? = Int.max let ni: Int? = nil expectEqual(anyToAny(i, Optional.self)!, Int.max) expectEqual(anyToAny(si, Int.self), Int.max) expectEqual(anyToAny(si, Optional.self)!, Int.max) expectTrue(anyToAny(ni, Optional.self) == nil) expectTrue(anyToAnyOrNil(ni, Int.self) == nil) let ssx: C?? = sx expectTrue(anyToAny(ssx, Optional.self)! === x) expectTrue(anyToAny(x, Optional>.self)!! === x) expectTrue(anyToAnyOrNil(ni, Int.self) == nil) // Test for SR-459: Weakened optionals don't zero. var deinitRan = false do { var t = DeinitTester { deinitRan = true } _ = anyToAny(Optional(t), CustomDebugStringConvertible.self) } expectTrue(deinitRan) } OptionalTests.test("Casting Optional Traps") { let nx: C? = nil expectCrashLater() anyToAny(nx, Int.self) } class TestNoString {} class TestString : CustomStringConvertible, CustomDebugStringConvertible { var description: String { return "AString" } var debugDescription: String { return "XString" } } class TestStream : Streamable { func write(to target: inout Target) { target.write("AStream") } } func debugPrintStr(a: T) -> String { var s = "" debugPrint(a, terminator: "", to: &s) return s } // Optional should not conform to output stream protocols itself, but is // convertible to them if its wrapped type is. // Furthermore, printing an Optional should always print the debug // description regardless of whether the wrapper type conforms to an // output stream protocol. OptionalTests.test("Optional OutputStream") { let optNoString: TestNoString? = TestNoString() expectFalse(optNoString is CustomStringConvertible) expectFalse(canGenericCast(optNoString, CustomStringConvertible.self)) expectFalse(optNoString is Streamable) expectFalse(canGenericCast(optNoString, Streamable.self)) expectTrue(optNoString is CustomDebugStringConvertible) expectTrue(canGenericCast(optNoString, CustomDebugStringConvertible.self)) expectEqual(String(optNoString), "Optional(main.TestNoString)") expectEqual(debugPrintStr(optNoString), "Optional(main.TestNoString)") let iouNoString: TestNoString! = TestNoString() // IUO directly conforms to CustomStringConvertible. // Disabled pending SR-164 // expectTrue(iouNoString is CustomStringConvertible) expectTrue(canGenericCast(iouNoString, CustomStringConvertible.self)) expectFalse(iouNoString is Streamable) expectFalse(canGenericCast(iouNoString, Streamable.self)) // CustomDebugStringConvertible conformance is a temporary hack. // Disabled pending SR-164 // expectTrue(iouNoString is CustomDebugStringConvertible) expectTrue(canGenericCast(iouNoString, CustomDebugStringConvertible.self)) expectEqual(String(iouNoString), "main.TestNoString") expectEqual(debugPrintStr(iouNoString), "main.TestNoString") let optString: TestString? = TestString() expectTrue(optString is CustomStringConvertible) expectTrue(canGenericCast(optString, CustomStringConvertible.self)) expectTrue(optString is CustomDebugStringConvertible) expectTrue(canGenericCast(optString, CustomDebugStringConvertible.self)) expectEqual(String(TestString()), "AString") expectEqual(String(optString), "Optional(XString)") expectEqual(debugPrintStr(optString), "Optional(XString)") let iouString: TestString! = TestString() expectTrue(iouString is CustomStringConvertible) expectTrue(canGenericCast(iouString, CustomStringConvertible.self)) // CustomDebugStringConvertible conformance is a temporary hack. expectTrue(iouString is CustomDebugStringConvertible) expectTrue(canGenericCast(iouString, CustomDebugStringConvertible.self)) expectEqual(String(iouString), "AString") // FIXME: Ideally the debug output would be "XString", but a reasonable // implementation of that behavior requires conditional conformance. // (directly invoking debugPrint(Any) already works correctly). expectEqual(debugPrintStr(iouString), "AString") let optStream: TestStream? = TestStream() expectTrue(optStream is Streamable) expectTrue(canGenericCast(optStream, Streamable.self)) expectTrue(optStream is CustomDebugStringConvertible) expectTrue(canGenericCast(optStream, CustomDebugStringConvertible.self)) expectEqual(String(TestStream()), "AStream") expectEqual(String(optStream), "Optional(AStream)") expectEqual(debugPrintStr(optStream), "Optional(AStream)") } OptionalTests.test("unsafelyUnwrapped") { let empty: Int? = nil let nonEmpty: Int? = 3 expectEqual(3, nonEmpty.unsafelyUnwrapped) expectCrashLater() empty.unsafelyUnwrapped } runAllTests()