| // RUN: %target-swift-frontend -O -Xllvm -sil-disable-pass="Function Signature Optimization" -emit-sil %s | %FileCheck %s |
| // We want to check two things here: |
| // - Correctness |
| // - That certain "is" checks are eliminated based on static analysis at compile-time |
| // |
| // In ideal world, all those testNN functions should be simplified down to a single basic block |
| // which returns either true or false, i.e. all type checks should folded statically. |
| |
| // REQUIRES: objc_interop |
| |
| import Foundation |
| |
| class ObjCX : NSObject {} |
| |
| struct CX: _ObjectiveCBridgeable { |
| func _bridgeToObjectiveC() -> ObjCX { |
| return ObjCX() |
| } |
| |
| static func _forceBridgeFromObjectiveC(_ source: ObjCX, result: inout CX?) {} |
| |
| static func _conditionallyBridgeFromObjectiveC(_ source: ObjCX, result: inout CX?) -> Bool { |
| return false |
| } |
| |
| static func _unconditionallyBridgeFromObjectiveC(_ source: ObjCX?) |
| -> CX { |
| var result: CX? |
| _forceBridgeFromObjectiveC(source!, result: &result) |
| return result! |
| } |
| } |
| |
| // Check casts to types which are _ObjectiveCBridgeable |
| func cast0(_ o: AnyObject) -> Bool { |
| return o is CX |
| } |
| |
| // CHECK-LABEL: sil hidden [noinline] @_T017cast_folding_objc5test0SbyF |
| // CHECK: bb0 |
| // Check that cast is not eliminated even though cast0 is a conversion |
| // from a class to struct, because it casts to a struct implementing |
| // the _BridgedToObjectiveC protocol |
| // CHECK: checked_cast |
| // CHECK: return |
| @inline(never) |
| func test0() -> Bool { |
| return cast0(NSNumber(value:1)) |
| } |
| |
| // Check that this cast does not get eliminated, because |
| // the compiler does not statically know if this object |
| // is NSNumber can be converted into Int. |
| |
| // CHECK-LABEL: sil [noinline] @_T017cast_folding_objc35testMayBeBridgedCastFromObjCtoSwiftSiyXlF |
| // CHECK: unconditional_checked_cast_addr |
| // CHECK: return |
| @inline(never) |
| public func testMayBeBridgedCastFromObjCtoSwift(_ o: AnyObject) -> Int { |
| return o as! Int |
| } |
| |
| // Check that this cast does not get eliminated, because |
| // the compiler does not statically know if this object |
| // is NSString can be converted into String. |
| |
| // CHECK-LABEL: sil [noinline] @_T017cast_folding_objc41testConditionalBridgedCastFromObjCtoSwiftSSSgyXlF |
| // CHECK: unconditional_checked_cast_addr |
| // CHECK: return |
| @inline(never) |
| public func testConditionalBridgedCastFromObjCtoSwift(_ o: AnyObject) -> String? { |
| return o as? String |
| } |
| |
| public func castObjCToSwift<T>(_ t: T) -> Int { |
| return t as! Int |
| } |
| |
| // Check that compiler understands that this cast always fails |
| // CHECK-LABEL: sil [noinline] @_T017cast_folding_objc37testFailingBridgedCastFromObjCtoSwiftSiSo8NSStringCF |
| // CHECK: builtin "int_trap" |
| // CHECK-NEXT: unreachable |
| // CHECK-NEXT: } |
| @inline(never) |
| public func testFailingBridgedCastFromObjCtoSwift(_ ns: NSString) -> Int { |
| return castObjCToSwift(ns) |
| } |
| |
| // Check that compiler understands that this cast always fails |
| // CHECK-LABEL: sil [noinline] @_T017cast_folding_objc37testFailingBridgedCastFromSwiftToObjCSiSSF |
| // CHECK: builtin "int_trap" |
| // CHECK-NEXT: unreachable |
| // CHECK-NEXT: } |
| @inline(never) |
| public func testFailingBridgedCastFromSwiftToObjC(_ s: String) -> NSInteger { |
| return s as! NSInteger |
| } |
| |
| @inline(never) |
| public func testCastNSObjectToAnyClass(_ o: NSObject) -> AnyClass { |
| return o as! AnyClass |
| } |
| |
| @inline(never) |
| public func testCastNSObjectToClassObject(_ o: NSObject) -> NSObject.Type { |
| return o as! NSObject.Type |
| } |
| |
| @inline(never) |
| public func testCastNSObjectToAnyType(_ o: NSObject) -> Any.Type { |
| return o as! Any.Type |
| } |
| |
| @inline(never) |
| public func testCastNSObjectToEveryType<T>(_ o: NSObject) -> T.Type { |
| return o as! T.Type |
| } |
| |
| @inline(never) |
| public func testCastNSObjectToNonClassType(_ o: NSObject) -> Int.Type { |
| return o as! Int.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyObjectToAnyClass(_ o: AnyObject) -> AnyClass { |
| return o as! AnyClass |
| } |
| |
| @inline(never) |
| public func testCastAnyObjectToClassObject(_ o: AnyObject) -> AnyObject.Type { |
| return o as! AnyObject.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyObjectToAnyType(_ o: AnyObject) -> Any.Type { |
| return o as! Any.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyObjectToEveryType<T>(_ o: AnyObject) -> T.Type { |
| return o as! T.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyObjectToNonClassType(_ o: AnyObject) -> Int.Type { |
| return o as! Int.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyToAny2Class(_ o: Any) -> AnyClass { |
| return o as! AnyClass |
| } |
| |
| @inline(never) |
| public func testCastAnyToClassObject(_ o: Any) -> AnyObject.Type { |
| return o as! AnyObject.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyToAny2Type(_ o: Any) -> Any.Type { |
| return o as! Any.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyToEveryType<T>(_ o: Any) -> T.Type { |
| return o as! T.Type |
| } |
| |
| @inline(never) |
| public func testCastAnyToNonClassType(_ o: Any) -> Int.Type { |
| return o as! Int.Type |
| } |
| |
| @inline(never) |
| public func testCastEveryToAnyClass<T>(_ o: T) -> AnyClass { |
| return o as! AnyClass |
| } |
| |
| @inline(never) |
| public func testCastEveryToClassObject<T>(_ o: T) -> AnyObject.Type { |
| return o as! AnyObject.Type |
| } |
| |
| @inline(never) |
| public func testCastEveryToAnyType<T>(_ o: T) -> Any.Type { |
| return o as! Any.Type |
| } |
| |
| @inline(never) |
| public func testCastEveryToEvery2Type<T, U>(_ o: U) -> T.Type { |
| return o as! T.Type |
| } |
| |
| @inline(never) |
| public func testCastEveryToNonClassType<T>(_ o: T) -> Int.Type { |
| return o as! Int.Type |
| } |
| |
| func cast<U, V>(_ u: U.Type) -> V? { |
| return u as? V |
| } |
| |
| public protocol P { |
| } |
| |
| // Any casts from P.Protocol to P.Type should fail. |
| @inline(never) |
| public func testCastPProtocolToPType() -> ObjCP.Type? { |
| return cast(ObjCP.self) |
| } |
| |
| @objc |
| public protocol ObjCP { |
| } |
| |
| @inline(never) |
| public func testCastObjCPProtocolToObjCPType() -> ObjCP.Type? { |
| return cast(ObjCP.self) |
| } |
| |
| @inline(never) |
| public func testCastProtocolCompositionProtocolToProtocolCompositionType() -> (P & ObjCP).Type? { |
| return cast((P & ObjCP).self) |
| } |
| |
| @inline(never) |
| public func testCastProtocolCompositionProtocolToProtocolType () -> P.Type? { |
| return (P & ObjCP).self as? P.Type |
| } |
| |
| print("test0=\(test0())") |
| |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToEveryType{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToNonClassType |
| // CHECK: builtin "int_trap" |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToEveryType{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToNonClassType |
| // CHECK-NOT: builtin "int_trap" |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToAny2Class{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToClassObject{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToAny2Type{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToEveryType{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToNonClassType |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToAnyClass{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToClassObject{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToAnyType{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToEvery2Type{{.*}} |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToNonClassType |
| // CHECK: unconditional_checked_cast_addr |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastPProtocolToPType |
| // CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt |
| // CHECK-NEXT: return %0 |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastObjCPProtocolTo{{.*}}PType |
| // CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt |
| // CHECK-NEXT: return %0 |
| |
| // CHECK-LABEL: sil [noinline] @{{.*}}testCastProtocolComposition{{.*}}Type |
| // CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt |
| // CHECK-NEXT: return %0 |
| |
| // Check that compiler understands that this cast always succeeds. |
| // Since it is can be statically proven that NSString is bridgeable to String, |
| // _forceBridgeFromObjectiveC from String should be invoked instead of |
| // a more general, but less effective swift_bridgeNonVerbatimFromObjectiveC, which |
| // also performs conformance checks at runtime. |
| @inline(never) |
| public func testBridgedCastFromObjCtoSwift(_ ns: NSString) -> String { |
| return ns as String |
| } |
| |
| // Check that compiler understands that this cast always succeeds |
| |
| // CHECK-LABEL: sil [noinline] @_T017cast_folding_objc30testBridgedCastFromSwiftToObjCSo8NSStringCSSF |
| // CHECK-NOT: {{ cast}} |
| // CHECK: function_ref @_T0SS10FoundationE19_bridgeToObjectiveC{{[_0-9a-zA-Z]*}}F |
| // CHECK: apply |
| // CHECK: return |
| @inline(never) |
| public func testBridgedCastFromSwiftToObjC(_ s: String) -> NSString { |
| return s as NSString |
| } |
| |
| public class MyString: NSString {} |
| |
| // Check that the cast-optimizer bails out on a conditional downcast to a subclass of a |
| // bridged ObjC class. |
| // CHECK-LABEL: sil [noinline] @{{.*}}testConditionalBridgedCastFromSwiftToNSObjectDerivedClass{{.*}} |
| // CHECK: function_ref @_T0SS10FoundationE19_bridgeToObjectiveC{{[_0-9a-zA-Z]*}}F |
| // CHECK: apply |
| // CHECK-NOT: apply |
| // CHECK-NOT: unconditional_checked_cast |
| // CHECK: checked_cast_br |
| // CHECK-NOT: apply |
| // CHECK-NOT: unconditional |
| // CHECK: return |
| @inline(never) |
| public func testConditionalBridgedCastFromSwiftToNSObjectDerivedClass(_ s: String) -> MyString? { |
| return s as? MyString |
| } |
| |
| // Check that the cast-optimizer does not bail out on an unconditional downcast to a subclass of a |
| // bridged ObjC class. |
| // CHECK-LABEL: sil [noinline] @{{.*}}testForcedBridgedCastFromSwiftToNSObjectDerivedClass{{.*}} |
| // CHECK: function_ref @_T0SS10FoundationE19_bridgeToObjectiveC{{[_0-9a-zA-Z]*}}F |
| // CHECK: apply |
| // CHECK-NOT: apply |
| // CHECK-NOT: checked_cast_br |
| // CHECK: unconditional_checked_cast |
| // CHECK-NOT: apply |
| // CHECK-NOT: unconditional |
| // CHECK-NOT: checked_cast |
| // CHECK: return |
| @inline(never) |
| public func testForcedBridgedCastFromSwiftToNSObjectDerivedClass(_ s: String) -> MyString { |
| return s as! MyString |
| } |