| // RUN: rm -rf %t && mkdir -p %t |
| // RUN: cp -R %S/Inputs/FakeUnavailableObjCFramework.framework %t |
| // RUN: %target-clang -dynamiclib %S/Inputs/FakeUnavailableObjCFramework.m -fmodules -F %t -framework Foundation -o %t/FakeUnavailableObjCFramework.framework/FakeUnavailableObjCFramework |
| |
| // RUN: %target-build-swift -F %t %s -o %t/UseWeaklinkedUnavailableObjCFramework |
| // RUN: %target-build-swift -O -F %t %s -o %t/UseWeaklinkedUnavailableObjCFramework.opt |
| |
| // These tests emulate deploying back to an older OS where newer APIs are not |
| // available by linking to an Objective-C framework where APIs have been |
| // annotated to only be available in the far future (version 1066.0 of all |
| // platforms) and then moving the framework aside so that it can't be found |
| // at run time. |
| // RUN: mv %t/FakeUnavailableObjCFramework.framework %t/FakeUnavailableObjCFramework-MovedAside.framework |
| |
| // RUN: %target-run %t/UseWeaklinkedUnavailableObjCFramework | FileCheck %s |
| // RUN: %target-run %t/UseWeaklinkedUnavailableObjCFramework.opt | FileCheck %s |
| |
| // REQUIRES: objc_interop |
| // REQUIRES: executable_test |
| |
| import StdlibUnittest |
| |
| |
| import FakeUnavailableObjCFramework |
| import Foundation |
| |
| // CHECK: Running |
| print("Running...") |
| |
| func useUnavailableObjCGlobal() { |
| if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) { |
| let g = UnavailableObjCGlobalVariable |
| _blackHole(g) |
| } |
| } |
| |
| useUnavailableObjCGlobal() |
| |
| @objc |
| class ClassConformingToUnavailableObjCProtocol : NSObject, UnavailableObjCProtocol { |
| func someMethod() { |
| print("Executed ClassConformingToUnavailableObjCProtocol.someMethod()") |
| } |
| } |
| |
| func useClassConformingToUnavailableObjCProtocol() { |
| let o = ClassConformingToUnavailableObjCProtocol() |
| o.someMethod() |
| |
| if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) { |
| let oAsUP: UnavailableObjCProtocol = o as UnavailableObjCProtocol |
| oAsUP.someMethod() |
| } |
| } |
| |
| // CHECK-NEXT: Executed ClassConformingToUnavailableObjCProtocol.someMethod() |
| useClassConformingToUnavailableObjCProtocol() |
| |
| @objc |
| class ClassThatWillBeExtendedToConformToUnavailableObjCProtocol : NSObject { |
| } |
| |
| extension ClassThatWillBeExtendedToConformToUnavailableObjCProtocol : UnavailableObjCProtocol { |
| func someMethod() { |
| print("Executed ClassThatWillBeExtendedToConformToUnavailableObjCProtocol.someMethod()") |
| } |
| } |
| |
| func useClassThatWillBeExtendedToConformToUnavailableObjCProtocol() { |
| let o = ClassThatWillBeExtendedToConformToUnavailableObjCProtocol() |
| o.someMethod() |
| |
| if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) { |
| let oAsUP: UnavailableObjCProtocol = o as UnavailableObjCProtocol |
| oAsUP.someMethod() |
| } |
| } |
| |
| // CHECK-NEXT: Executed ClassThatWillBeExtendedToConformToUnavailableObjCProtocol.someMethod() |
| useClassThatWillBeExtendedToConformToUnavailableObjCProtocol() |
| |
| // We need to gracefully handle ObjC protocols missing availability annotations |
| // because it is quite common in frameworks. (Historically, for Objective-C, |
| // missing availability annotations on protocols has not been problematic |
| // because Objective-C protocol metadata is compiled into any code that |
| // references it -- it is not weakly linked.) |
| |
| @objc |
| class ClassConformingToUnannotatedUnavailableObjCProtocol : NSObject, UnannotatedUnavailableObjCProtocol { |
| func someMethod() { |
| print("Executed ClassConformingToUnannotatedUnavailableObjCProtocol.someMethod()") |
| } |
| } |
| |
| func useClassConformingToUnannotatedUnavailableObjCProtocol() { |
| let o = ClassConformingToUnannotatedUnavailableObjCProtocol() |
| o.someMethod() |
| |
| let oAsUP: UnannotatedUnavailableObjCProtocol = (o as AnyObject) as! UnannotatedUnavailableObjCProtocol |
| oAsUP.someMethod() |
| } |
| |
| // CHECK-NEXT: Executed ClassConformingToUnannotatedUnavailableObjCProtocol.someMethod() |
| // CHECK-NEXT: Executed ClassConformingToUnannotatedUnavailableObjCProtocol.someMethod() |
| useClassConformingToUnannotatedUnavailableObjCProtocol() |
| |
| func printClassMetadataViaGeneric<T>() -> T { |
| print("\(T.self)") |
| fatalError("This should never be called") |
| } |
| |
| func useUnavailableObjCClass() { |
| if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) { |
| let o = UnavailableObjCClass() |
| o.someMethod() |
| } |
| |
| for i in 0 ..< getInt(5) { |
| if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) { |
| let o: UnavailableObjCClass = printClassMetadataViaGeneric() |
| _blackHole(o) |
| } |
| } |
| |
| class SomeClass { } |
| let someObject: AnyObject = _opaqueIdentity(SomeClass() as AnyObject) |
| |
| for i in 0 ..< getInt(5) { |
| if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) { |
| let isUnavailable = someObject is UnavailableObjCClass |
| _blackHole(isUnavailable) |
| } |
| } |
| |
| for i in 0 ..< getInt(5) { |
| if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) { |
| let asUnavailable = someObject as? UnavailableObjCClass |
| _blackHole(asUnavailable) |
| } |
| } |
| } |
| |
| @available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) |
| func wrapUnavailableFunction() { |
| someFunction() |
| } |
| |
| useUnavailableObjCClass() |
| |
| // Allow extending a weakly-linked class to conform to a protocol. |
| protocol SomeSwiftProtocol { } |
| @available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) |
| extension UnavailableObjCClass : SomeSwiftProtocol { |
| } |
| |
| // CHECK-NEXT: Done |
| print("Done") |