// RUN: %empty-directory(%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-codesign %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-codesign %t/UseWeaklinkedUnavailableObjCFramework // RUN: %target-codesign %t/UseWeaklinkedUnavailableObjCFramework.opt // 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 { 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")