Files
swift-mirror/test/SILGen/cf_members.swift
Slava Pestov c543838854 Sema: Rewrite partial applications into closures
When a method is called with fewer than two parameter lists,
transform it into a fully-applied call by wrapping it in a
closure.

Eg,

Foo.bar => { self in { args... self.bar(args...) } }
foo.bar => { self in { args... self.bar(args...) } }(self)

super.bar => { args... in super.bar(args...) }

With this change, SILGen only ever sees fully-applied calls,
which will allow ripping out some code.

This new way of doing curry thunks fixes a long-standing bug
where unbound references to protocol methods did not work.

This is because such a reference must open the existential
*inside* the closure, after 'self' has been applied, whereas
the old SILGen implementation of curry thunks really wanted
the type of the method reference to match the opened type of
the method.

A follow-up cleanup will remove the SILGen curry thunk
implementation.

Fixes rdar://21289579 and https://bugs.swift.org/browse/SR-75.
2020-03-18 09:29:22 -04:00

302 lines
14 KiB
Swift

// RUN: %target-swift-emit-silgen -I %S/../IDE/Inputs/custom-modules %s -enable-objc-interop -I %S/Inputs/usr/include | %FileCheck %s
import ImportAsMember
func makeMetatype() -> Struct1.Type { return Struct1.self }
// CHECK-LABEL: sil [ossa] @$s10cf_members17importAsUnaryInityyF
public func importAsUnaryInit() {
// CHECK: function_ref @CCPowerSupplyCreateDangerous : $@convention(c) () -> @owned CCPowerSupply
var a = CCPowerSupply(dangerous: ())
let f: (()) -> CCPowerSupply = CCPowerSupply.init(dangerous:)
a = f(())
}
// CHECK-LABEL: sil [ossa] @$s10cf_members3foo{{[_0-9a-zA-Z]*}}F
public func foo(_ x: Double) {
// CHECK: bb0([[X:%.*]] : $Double):
// CHECK: [[GLOBALVAR:%.*]] = global_addr @IAMStruct1GlobalVar
// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[GLOBALVAR]] : $*Double
// CHECK: [[ZZ:%.*]] = load [trivial] [[READ]]
let zz = Struct1.globalVar
// CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[GLOBALVAR]] : $*Double
// CHECK: assign [[ZZ]] to [[WRITE]]
Struct1.globalVar = zz
// CHECK: [[Z:%.*]] = project_box
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1CreateSimple
// CHECK: apply [[FN]]([[X]])
var z = Struct1(value: x)
// The metatype expression should still be evaluated even if it isn't
// used.
// CHECK: [[MAKE_METATYPE:%.*]] = function_ref @$s10cf_members12makeMetatype{{[_0-9a-zA-Z]*}}F
// CHECK: apply [[MAKE_METATYPE]]()
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1CreateSimple
// CHECK: apply [[FN]]([[X]])
z = makeMetatype().init(value: x)
// CHECK: [[FN:%.*]] = function_ref @$s10cf_members3fooyySdFSo10IAMStruct1VSdcfu_ : $@convention(thin) (Double) -> Struct1
// CHECK: [[A:%.*]] = thin_to_thick_function [[FN]]
// CHECK: [[BORROWED_A:%.*]] = begin_borrow [[A]]
// CHECK: [[A_COPY:%.*]] = copy_value [[BORROWED_A]]
// CHECK: [[BORROWED_A2:%.*]] = begin_borrow [[A_COPY]]
let a: (Double) -> Struct1 = Struct1.init(value:)
// CHECK: apply [[BORROWED_A2]]([[X]])
// CHECK: destroy_value [[A_COPY]]
// CHECK: end_borrow [[BORROWED_A]]
z = a(x)
// TODO: Support @convention(c) references that only capture thin metatype
// let b: @convention(c) (Double) -> Struct1 = Struct1.init(value:)
// z = b(x)
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[Z]] : $*Struct1
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1InvertInPlace
// CHECK: apply [[FN]]([[WRITE]])
z.invert()
// CHECK: [[WRITE:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[WRITE]]
// CHECK: store [[ZVAL]] to [trivial] [[ZTMP:%.*]] :
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1Rotate : $@convention(c) (@in Struct1, Double) -> Struct1
// CHECK: apply [[FN]]([[ZTMP]], [[X]])
z = z.translate(radians: x)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[THUNK:%.*]] = function_ref @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu0_ : $@convention(thin) (Struct1) -> @owned @callee_guaranteed (Double) -> Struct1
// CHECK: [[C:%.*]] = apply [[THUNK]]([[ZVAL]])
// CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
// CHECK: [[C_COPY:%.*]] = copy_value [[BORROWED_C]]
// CHECK: [[BORROWED_C2:%.*]] = begin_borrow [[C_COPY]]
let c: (Double) -> Struct1 = z.translate(radians:)
// CHECK: apply [[BORROWED_C2]]([[X]])
// CHECK: destroy_value [[C_COPY]]
// CHECK: end_borrow [[BORROWED_C]]
z = c(x)
// CHECK: [[THUNK:%.*]] = function_ref @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu2_ : $@convention(thin) (Struct1) -> @owned @callee_guaranteed (Double) -> Struct1
// CHECK: [[THICK:%.*]] = thin_to_thick_function [[THUNK]]
// CHECK: [[BORROW:%.*]] = begin_borrow [[THICK]]
// CHECK: [[COPY:%.*]] = copy_value [[BORROW]]
let d: (Struct1) -> (Double) -> Struct1 = Struct1.translate(radians:)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[BORROW_COPY:%.*]] = begin_borrow [[COPY]]
// CHECK: apply [[BORROW_COPY]]([[ZVAL]])
// CHECK: destroy_value [[COPY]]
z = d(z)(x)
// TODO: If we implement SE-0042, this should thunk the value Struct1 param
// to a const* param to the underlying C symbol.
//
// let e: @convention(c) (Struct1, Double) -> Struct1
// = Struct1.translate(radians:)
// z = e(z, x)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1Scale
// CHECK: apply [[FN]]([[ZVAL]], [[X]])
z = z.scale(x)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[THUNK:%.*]] = function_ref @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu4_ : $@convention(thin) (Struct1) -> @owned @callee_guaranteed (Double) -> Struct1
// CHECK: [[F:%.*]] = apply [[THUNK]]([[ZVAL]])
// CHECK: [[BORROWED_F:%.*]] = begin_borrow [[F]]
// CHECK: [[F_COPY:%.*]] = copy_value [[BORROWED_F]]
// CHECK: [[BORROWED_F2:%.*]] = begin_borrow [[F_COPY]]
let f = z.scale
// CHECK: apply [[BORROWED_F2]]([[X]])
// CHECK: destroy_value [[F_COPY]]
// CHECK: end_borrow [[BORROWED_F]]
z = f(x)
// CHECK: [[THUNK:%.*]] = function_ref @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu6_ : $@convention(thin) (Struct1) -> @owned @callee_guaranteed (Double) -> Struct1
// CHECK: thin_to_thick_function [[THUNK]]
let g = Struct1.scale
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
z = g(z)(x)
// TODO: If we implement SE-0042, this should directly reference the
// underlying C function.
// let h: @convention(c) (Struct1, Double) -> Struct1 = Struct1.scale
// z = h(z, x)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: store [[ZVAL]] to [trivial] [[ZTMP:%.*]] :
// CHECK: [[ZVAL_2:%.*]] = load [trivial] [[ZTMP]]
// CHECK: store [[ZVAL_2]] to [trivial] [[ZTMP_2:%.*]] :
// CHECK: [[GET:%.*]] = function_ref @IAMStruct1GetRadius : $@convention(c) (@in Struct1) -> Double
// CHECK: apply [[GET]]([[ZTMP_2]])
_ = z.radius
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[SET:%.*]] = function_ref @IAMStruct1SetRadius : $@convention(c) (Struct1, Double) -> ()
// CHECK: apply [[SET]]([[ZVAL]], [[X]])
z.radius = x
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[GET:%.*]] = function_ref @IAMStruct1GetAltitude : $@convention(c) (Struct1) -> Double
// CHECK: apply [[GET]]([[ZVAL]])
_ = z.altitude
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[Z]] : $*Struct1
// CHECK: [[SET:%.*]] = function_ref @IAMStruct1SetAltitude : $@convention(c) (@inout Struct1, Double) -> ()
// CHECK: apply [[SET]]([[WRITE]], [[X]])
z.altitude = x
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[GET:%.*]] = function_ref @IAMStruct1GetMagnitude : $@convention(c) (Struct1) -> Double
// CHECK: apply [[GET]]([[ZVAL]])
_ = z.magnitude
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1StaticMethod
// CHECK: apply [[FN]]()
var y = Struct1.staticMethod()
// CHECK: [[SELF:%.*]] = metatype
// CHECK: [[THUNK:%.*]] = function_ref @$s10cf_members3fooyySdFs5Int32VycSo10IAMStruct1Vmcfu8_ : $@convention(thin) (@thin Struct1.Type) -> @owned @callee_guaranteed () -> Int32
// CHECK: [[I:%.*]] = apply [[THUNK]]([[SELF]])
// CHECK: [[BORROWED_I:%.*]] = begin_borrow [[I]]
// CHECK: [[I_COPY:%.*]] = copy_value [[BORROWED_I]]
// CHECK: [[BORROWED_I2:%.*]] = begin_borrow [[I_COPY]]
let i = Struct1.staticMethod
// CHECK: apply [[BORROWED_I2]]()
// CHECK: destroy_value [[I_COPY]]
// CHECK: end_borrow [[BORROWED_I]]
y = i()
// TODO: Support @convention(c) references that only capture thin metatype
// let j: @convention(c) () -> Int32 = Struct1.staticMethod
// y = j()
// CHECK: [[GET:%.*]] = function_ref @IAMStruct1StaticGetProperty
// CHECK: apply [[GET]]()
_ = Struct1.property
// CHECK: [[SET:%.*]] = function_ref @IAMStruct1StaticSetProperty
// CHECK: apply [[SET]](%{{[0-9]+}})
Struct1.property = y
// CHECK: [[GET:%.*]] = function_ref @IAMStruct1StaticGetOnlyProperty
// CHECK: apply [[GET]]()
_ = Struct1.getOnlyProperty
// CHECK: [[MAKE_METATYPE:%.*]] = function_ref @$s10cf_members12makeMetatype{{[_0-9a-zA-Z]*}}F
// CHECK: apply [[MAKE_METATYPE]]()
// CHECK: [[GET:%.*]] = function_ref @IAMStruct1StaticGetProperty
// CHECK: apply [[GET]]()
_ = makeMetatype().property
// CHECK: [[MAKE_METATYPE:%.*]] = function_ref @$s10cf_members12makeMetatype{{[_0-9a-zA-Z]*}}F
// CHECK: apply [[MAKE_METATYPE]]()
// CHECK: [[SET:%.*]] = function_ref @IAMStruct1StaticSetProperty
// CHECK: apply [[SET]](%{{[0-9]+}})
makeMetatype().property = y
// CHECK: [[MAKE_METATYPE:%.*]] = function_ref @$s10cf_members12makeMetatype{{[_0-9a-zA-Z]*}}F
// CHECK: apply [[MAKE_METATYPE]]()
// CHECK: [[GET:%.*]] = function_ref @IAMStruct1StaticGetOnlyProperty
// CHECK: apply [[GET]]()
_ = makeMetatype().getOnlyProperty
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1SelfComesLast : $@convention(c) (Double, Struct1) -> ()
// CHECK: apply [[FN]]([[X]], [[ZVAL]])
z.selfComesLast(x: x)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
let k: (Double) -> () = z.selfComesLast(x:)
k(x)
let l: (Struct1) -> (Double) -> () = Struct1.selfComesLast(x:)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
l(z)(x)
// TODO: If we implement SE-0042, this should thunk to reorder the arguments.
// let m: @convention(c) (Struct1, Double) -> () = Struct1.selfComesLast(x:)
// m(z, x)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] : $*Struct1
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
// CHECK: [[FN:%.*]] = function_ref @IAMStruct1SelfComesThird : $@convention(c) (Int32, Float, Struct1, Double) -> ()
// CHECK: apply [[FN]]({{.*}}, {{.*}}, [[ZVAL]], [[X]])
z.selfComesThird(a: y, b: 0, x: x)
let n: (Int32, Float, Double) -> () = z.selfComesThird(a:b:x:)
n(y, 0, x)
let o: (Struct1) -> (Int32, Float, Double) -> ()
= Struct1.selfComesThird(a:b:x:)
o(z)(y, 0, x)
// TODO: If we implement SE-0042, this should thunk to reorder the arguments.
// let p: @convention(c) (Struct1, Int, Float, Double) -> ()
// = Struct1.selfComesThird(a:b:x:)
// p(z, y, 0, x)
}
// CHECK: } // end sil function '$s10cf_members3foo{{[_0-9a-zA-Z]*}}F'
// CHECK-LABEL: sil private [ossa] @$s10cf_members3fooyySdFSo10IAMStruct1VSdcfu_ : $@convention(thin) (Double) -> Struct1 {
// CHECK: bb0([[X:%.*]] : $Double):
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1CreateSimple
// CHECK: [[RET:%.*]] = apply [[CFUNC]]([[X]])
// CHECK: return [[RET]]
// CHECK-LABEL: sil private [ossa] @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu0_ADSdcfu1_ : $@convention(thin) (Double, Struct1) -> Struct1 {
// CHECK: bb0([[X:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
// CHECK: store [[SELF]] to [trivial] [[TMP:%.*]] :
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1Rotate
// CHECK: [[RET:%.*]] = apply [[CFUNC]]([[TMP]], [[X]])
// CHECK: return [[RET]]
// CHECK-LABEL: sil private [ossa] @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu4_ADSdcfu5_ : $@convention(thin) (Double, Struct1) -> Struct1 {
// CHECK: bb0([[X:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1Scale
// CHECK: [[RET:%.*]] = apply [[CFUNC]]([[SELF]], [[X]])
// CHECK: return [[RET]]
// CHECK-LABEL: sil private [ossa] @$s10cf_members3fooyySdFs5Int32VycSo10IAMStruct1Vmcfu8_ADycfu9_ : $@convention(thin) (@thin Struct1.Type) -> Int32 {
// CHECK: bb0([[SELF:%.*]] : $@thin Struct1.Type):
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1StaticMethod
// CHECK: [[RET:%.*]] = apply [[CFUNC]]()
// CHECK: return [[RET]]
// CHECK-LABEL:sil private [ossa] @$s10cf_members3fooyySdFySdcSo10IAMStruct1Vcfu10_ySdcfu11_ : $@convention(thin) (Double, Struct1) -> () {
// CHECK: bb0([[X:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1SelfComesLast
// CHECK: apply [[CFUNC]]([[X]], [[SELF]])
// CHECK-LABEL: sil private [ossa] @$s10cf_members3fooyySdFys5Int32V_SfSdtcSo10IAMStruct1Vcfu14_yAD_SfSdtcfu15_ : $@convention(thin) (Int32, Float, Double, Struct1) -> () {
// CHECK: bb0([[X:%.*]] : $Int32, [[Y:%.*]] : $Float, [[Z:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1SelfComesThird
// CHECK: apply [[CFUNC]]([[X]], [[Y]], [[SELF]], [[Z]])
// CHECK-LABEL: sil [ossa] @$s10cf_members3bar{{[_0-9a-zA-Z]*}}F
public func bar(_ x: Double) {
// CHECK: function_ref @CCPowerSupplyCreate : $@convention(c) (Double) -> @owned CCPowerSupply
let ps = CCPowerSupply(watts: x)
// CHECK: function_ref @CCRefrigeratorCreate : $@convention(c) (CCPowerSupply) -> @owned CCRefrigerator
let fridge = CCRefrigerator(powerSupply: ps)
// CHECK: function_ref @CCRefrigeratorOpen : $@convention(c) (CCRefrigerator) -> ()
fridge.open()
// CHECK: function_ref @CCRefrigeratorGetPowerSupply : $@convention(c) (CCRefrigerator) -> @autoreleased CCPowerSupply
let ps2 = fridge.powerSupply
// CHECK: function_ref @CCRefrigeratorSetPowerSupply : $@convention(c) (CCRefrigerator, CCPowerSupply) -> ()
fridge.powerSupply = ps2
let a: (Double) -> CCPowerSupply = CCPowerSupply.init(watts:)
let _ = a(x)
let b: (CCRefrigerator) -> () -> () = CCRefrigerator.open
b(fridge)()
let c = fridge.open
c()
}
// CHECK-LABEL: sil [ossa] @$s10cf_members28importGlobalVarsAsProperties{{[_0-9a-zA-Z]*}}F
public func importGlobalVarsAsProperties()
-> (Double, CCPowerSupply, CCPowerSupply?) {
// CHECK: global_addr @kCCPowerSupplyDC
// CHECK: global_addr @kCCPowerSupplyAC
// CHECK: global_addr @kCCPowerSupplyDefaultPower
return (CCPowerSupply.defaultPower, CCPowerSupply.AC, CCPowerSupply.DC)
}