Files
swift-mirror/test/SILGen/objc_protocols.swift
Joe Groff a9f0cc0ae7 SILGen: Open existentials when invoking their methods.
This simplifies the code generation path for existential methods by allowing it to shared more code with the generic case, (It'll be even simpler when Sema opens the existentials for SILGen...) turning protocol_method lookups into open_existential + witness_method sequences. In this patch, we handle normal generic method lookups, but property accesses still go through protocol_method.

Swift SVN r22437
2014-10-01 20:15:58 +00:00

211 lines
8.3 KiB
Swift

// RUN: rm -rf %t/clang-module-cache
// RUN: %swift -module-cache-path %t/clang-module-cache -target x86_64-apple-macosx10.9 -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen | FileCheck %s
import gizmo
import objc_protocols_Bas
@objc protocol NSRuncing {
func runce() -> NSObject
func copyRuncing() -> NSObject
func foo()
}
@objc protocol NSFunging {
func funge()
func foo()
}
protocol Ansible {
func anse()
}
// CHECK-LABEL: sil hidden @_TF14objc_protocols12objc_generic
func objc_generic<T : NSRuncing>(x: T) -> (NSObject, NSObject) {
return (x.runce(), x.copyRuncing())
// -- Result of runce is retain_autoreleased according to default objc conv
// CHECK: [[METHOD:%.*]] = witness_method [volatile] {{\$.*}}, #NSRuncing.runce!1.foreign
// CHECK: [[RESULT1:%.*]] = apply [[METHOD]]<T>([[THIS1:%.*]]) : $@cc(objc_method) @thin <τ_0_0 where τ_0_0 : NSRuncing> (τ_0_0) -> @autoreleased NSObject
// CHECK: retain_autoreleased [[RESULT1]] : $NSObject
// -- Result of copyRuncing is received retained according to -copy family
// CHECK: [[METHOD:%.*]] = witness_method [volatile] {{\$.*}}, #NSRuncing.copyRuncing!1.foreign
// CHECK: [[RESULT2:%.*]] = apply [[METHOD]]<T>([[THIS2:%.*]]) : $@cc(objc_method) @thin <τ_0_0 where τ_0_0 : NSRuncing> (τ_0_0) -> @owned NSObject
// CHECK-NOT: retain_autoreleased
// -- Arguments are not consumed by objc calls
// CHECK: release [[THIS2]]
}
// CHECK-LABEL: sil hidden @_TF14objc_protocols13objc_protocol
func objc_protocol(x: NSRuncing) -> (NSObject, NSObject) {
return (x.runce(), x.copyRuncing())
// -- Result of runce is retain_autoreleased according to default objc conv
// CHECK: [[THIS1:%.*]] = open_existential_ref [[THIS1_ORIG:%.*]] : $NSRuncing to $[[OPENED:@opened(.*) NSRuncing]]
// CHECK: [[METHOD:%.*]] = witness_method [volatile] $[[OPENED]], #NSRuncing.runce!1.foreign
// CHECK: [[RESULT1:%.*]] = apply [[METHOD]]<[[OPENED]]>([[THIS1]])
// CHECK: retain_autoreleased [[RESULT1]] : $NSObject
// -- Result of copyRuncing is received retained according to -copy family
// CHECK: [[THIS2:%.*]] = open_existential_ref [[THIS2_ORIG:%.*]] : $NSRuncing to $[[OPENED2:@opened(.*) NSRuncing]]
// CHECK: [[METHOD:%.*]] = witness_method [volatile] $[[OPENED2]], #NSRuncing.copyRuncing!1.foreign
// CHECK: [[RESULT2:%.*]] = apply [[METHOD]]<[[OPENED2]]>([[THIS2:%.*]])
// CHECK-NOT: retain_autoreleased
// -- Arguments are not consumed by objc calls
// CHECK: release [[THIS2_ORIG]]
}
// CHECK-LABEL: sil hidden @_TF14objc_protocols25objc_protocol_composition
func objc_protocol_composition(x: protocol<NSRuncing, NSFunging>) {
// CHECK: [[THIS:%.*]] = open_existential_ref [[THIS_ORIG:%.*]] : $protocol<NSFunging, NSRuncing> to $[[OPENED:@opened(.*) protocol<NSFunging, NSRuncing>]]
// CHECK: [[METHOD:%.*]] = witness_method [volatile] $[[OPENED]], #NSRuncing.runce!1.foreign
// CHECK: apply [[METHOD]]<[[OPENED]]>([[THIS]])
x.runce()
// CHECK: [[THIS:%.*]] = open_existential_ref [[THIS_ORIG:%.*]] : $protocol<NSFunging, NSRuncing> to $[[OPENED:@opened(.*) protocol<NSFunging, NSRuncing>]]
// CHECK: [[METHOD:%.*]] = witness_method [volatile] $[[OPENED]], #NSFunging.funge!1.foreign
// CHECK: apply [[METHOD]]<[[OPENED]]>([[THIS]])
x.funge()
}
// -- ObjC thunks get emitted for ObjC protocol conformances
class Foo : NSRuncing, NSFunging, Ansible {
// -- NSRuncing
func runce() -> NSObject { return NSObject() }
func copyRuncing() -> NSObject { return NSObject() }
// -- NSFunging
func funge() {}
// -- Both NSRuncing and NSFunging
func foo() {}
// -- Ansible
func anse() {}
}
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Foo5runcefS0_FT_CSo8NSObject
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Foo11copyRuncingfS0_FT_CSo8NSObject
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Foo5fungefS0_FT_T_
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Foo3foofS0_FT_T_
// CHECK-NOT: sil hidden @_TToF{{.*}}anse{{.*}}
class Bar { }
extension Bar : NSRuncing {
func runce() -> NSObject { return NSObject() }
func copyRuncing() -> NSObject { return NSObject() }
func foo() {}
}
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Bar5runcefS0_FT_CSo8NSObject
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Bar11copyRuncingfS0_FT_CSo8NSObject
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Bar3foofS0_FT_T_
// class Bas from objc_protocols_Bas module
extension Bas : NSRuncing {
// runce() implementation from the original definition of Bas
func copyRuncing() -> NSObject { return NSObject() }
func foo() {}
}
// CHECK-LABEL: sil hidden @_TToFE14objc_protocolsC18objc_protocols_Bas3Bas11copyRuncingfS1_FT_CSo8NSObject
// CHECK-LABEL: sil hidden @_TToFE14objc_protocolsC18objc_protocols_Bas3Bas3foofS1_FT_T_
// -- Inherited objc protocols
protocol Fungible : NSFunging { }
class Zim : Fungible {
func funge() {}
func foo() {}
}
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Zim5fungefS0_FT_T_
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols3Zim3foofS0_FT_T_
// class Zang from objc_protocols_Bas module
extension Zang : Fungible {
// funge() implementation from the original definition of Zim
func foo() {}
}
// CHECK-LABEL: sil hidden @_TToFE14objc_protocolsC18objc_protocols_Bas4Zang3foofS1_FT_T_
// -- objc protocols with property requirements in extensions
// <rdar://problem/16284574>
@objc protocol NSCounting {
var count: Int {get}
}
class StoredPropertyCount {
let count = 0
}
extension StoredPropertyCount: NSCounting {}
// CHECK-LABEL: sil hidden [transparent] @_TToFC14objc_protocols19StoredPropertyCountg5countSi
class ComputedPropertyCount {
var count: Int { return 0 }
}
extension ComputedPropertyCount: NSCounting {}
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols21ComputedPropertyCountg5countSi
// -- adding @objc protocol conformances to native ObjC classes should not
// emit thunks since the methods are already available to ObjC.
// Gizmo declared in Inputs/usr/include/Gizmo.h
extension Gizmo : NSFunging { }
// CHECK-NOT: _TTo{{.*}}5Gizmo{{.*}}
@objc class InformallyFunging {
@objc func funge() {}
@objc func foo() {}
}
extension InformallyFunging: NSFunging { }
@objc protocol Initializable {
init(int: Int)
}
// CHECK-LABEL: sil hidden @_TF14objc_protocols28testInitializableExistential
func testInitializableExistential(im: Initializable.Type, i: Int) -> Initializable {
// CHECK: bb0([[META:%[0-9]+]] : $@thick Initializable.Type, [[I:%[0-9]+]] : $Int):
// CHECK: [[I2_BOX:%[0-9]+]] = alloc_box $Initializable
// CHECK: [[ARCHETYPE_META:%[0-9]+]] = open_existential_ref [[META]] : $@thick Initializable.Type to $@thick @opened([[N:".*"]]) Initializable.Type
// CHECK: [[ARCHETYPE_META_OBJC:%[0-9]+]] = thick_to_objc_metatype [[ARCHETYPE_META]] : $@thick @opened([[N]]) Initializable.Type to $@objc_metatype @opened([[N]]) Initializable.Type
// CHECK: [[I2_ALLOC:%[0-9]+]] = alloc_ref_dynamic [objc] [[ARCHETYPE_META_OBJC]] : $@objc_metatype @opened([[N]]) Initializable.Type, $@opened([[N]]) Initializable
// CHECK: [[INIT_WITNESS:%[0-9]+]] = witness_method [volatile] $@opened([[N]]) Initializable, #Initializable.init!initializer.1.foreign : $@cc(objc_method) @thin <τ_0_0 where τ_0_0 : Initializable> (Int, @owned τ_0_0) -> @owned τ_0_0
// CHECK: [[I2:%[0-9]+]] = apply [[INIT_WITNESS]]<@opened([[N]]) Initializable>([[I]], [[I2_ALLOC]]) : $@cc(objc_method) @thin <τ_0_0 where τ_0_0 : Initializable> (Int, @owned τ_0_0) -> @owned τ_0_0
// CHECK: [[I2_EXIST_CONTAINER:%[0-9]+]] = init_existential_ref [[I2]] : $@opened([[N]]) Initializable : $@opened([[N]]) Initializable, $Initializable
// CHECK: store [[I2_EXIST_CONTAINER]] to [[I2_BOX]]#1 : $*Initializable
// CHECK: [[I2:%[0-9]+]] = load [[I2_BOX]]#1 : $*Initializable
// CHECK: strong_retain [[I2]] : $Initializable
// CHECK: strong_release [[I2_BOX]]#0 : $Builtin.NativeObject
// CHECK: return [[I2]] : $Initializable
var i2 = im(int: i)
return i2
}
class InitializableConformer: Initializable {
required init(int: Int) {}
}
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols22InitializableConformercfMS0_FT3intSi_S0_
final class InitializableConformerByExtension {
init() {}
}
extension InitializableConformerByExtension: Initializable {
convenience init(int: Int) {
self.init()
}
}
// CHECK-LABEL: sil hidden @_TToFC14objc_protocols33InitializableConformerByExtensioncfMS0_FT3intSi_S0_