blob: 14d3a0dd9ac4e8fc6147966303fdb0664436ce2d [file] [log] [blame]
// 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>() -> 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")