Skip to content

Commit a7e4e61

Browse files
committed
Sema: Use capture list to represent dynamic metatype bases for partial applications.
1 parent cef7ecc commit a7e4e61

File tree

6 files changed

+250
-54
lines changed

6 files changed

+250
-54
lines changed

lib/Sema/CSApply.cpp

Lines changed: 108 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,10 +1186,30 @@ namespace {
11861186
thunk->setParameterList(thunkParamList);
11871187
thunk->setThunkKind(AutoClosureExpr::Kind::SingleCurryThunk);
11881188
cs.cacheType(thunk);
1189+
1190+
// If the `self` type is existential, it must be opened.
1191+
OpaqueValueExpr *baseOpened = nullptr;
1192+
Expr *origBaseExpr = baseExpr;
1193+
if (baseExpr) {
1194+
auto baseTy = cs.getType(baseExpr);
1195+
if (baseTy->isAnyExistentialType()) {
1196+
Type openedTy = solution.OpenedExistentialTypes.lookup(
1197+
cs.getConstraintLocator(locator));
1198+
assert(openedTy);
1199+
1200+
Type opaqueValueTy = openedTy;
1201+
if (baseTy->is<ExistentialMetatypeType>())
1202+
opaqueValueTy = MetatypeType::get(opaqueValueTy);
1203+
1204+
baseOpened = new (ctx) OpaqueValueExpr(SourceLoc(), opaqueValueTy);
1205+
cs.cacheType(baseOpened);
1206+
baseExpr = baseOpened;
1207+
}
1208+
}
11891209

11901210
Expr *thunkBody = buildSingleCurryThunkBodyCall(
11911211
baseExpr, fnExpr, declOrClosure, thunkParamList, locator);
1192-
1212+
11931213
// If we called a function with a dynamic 'Self' result, we may need some
11941214
// special handling.
11951215
if (baseExpr) {
@@ -1219,6 +1239,15 @@ namespace {
12191239
// Now, coerce to the result type of the thunk.
12201240
thunkBody = coerceToType(thunkBody, thunkTy->getResult(), locator);
12211241

1242+
// Close up the existential if necessary.
1243+
if (baseOpened) {
1244+
thunkBody = new (ctx) OpenExistentialExpr(origBaseExpr,
1245+
baseOpened,
1246+
thunkBody,
1247+
thunkBody->getType());
1248+
cs.cacheType(thunkBody);
1249+
}
1250+
12221251
if (thunkTy->getExtInfo().isThrowing()) {
12231252
thunkBody = new (ctx)
12241253
TryExpr(thunkBody->getStartLoc(), thunkBody, cs.getType(thunkBody),
@@ -1529,13 +1558,14 @@ namespace {
15291558
// inside the curry thunk as well. This reduces abstraction and
15301559
// post-factum function type conversions, and results in better SILGen.
15311560
//
1532-
// For a partial application of a class method, however, we always want
1533-
// the thunk to accept a class to avoid potential abstraction, so the
1534-
// existential base must be opened eagerly in order to be upcast to the
1535-
// appropriate class reference type before it is passed to the thunk.
1561+
// For a partial application of a class instance method, however, we
1562+
// always want the thunk to accept a class to avoid potential
1563+
// abstraction, so the existential base must be opened eagerly in order
1564+
// to be upcast to the appropriate class reference type before it is
1565+
// passed to the thunk.
15361566
if (!needsCurryThunk ||
15371567
(!member->getDeclContext()->getSelfProtocolDecl() &&
1538-
!isUnboundInstanceMember)) {
1568+
baseIsInstance && member->isInstanceMember())) {
15391569
// Open the existential before performing the member reference.
15401570
base = openExistentialReference(base, knownOpened->second, member);
15411571
baseTy = knownOpened->second;
@@ -1745,26 +1775,79 @@ namespace {
17451775
memberLocator);
17461776
} else if (needsCurryThunk) {
17471777
// Another case where we want to build a single closure is when
1748-
// we have a partial application of a static member on a statically-
1749-
// derived metatype value. Again, there are no order of evaluation
1750-
// concerns here, and keeping the call and base together in the AST
1751-
// improves SILGen.
1752-
if ((isa<ConstructorDecl>(member)
1753-
|| member->isStatic()) &&
1754-
cs.isStaticallyDerivedMetatype(base)) {
1755-
// Add a useless ".self" to avoid downstream diagnostics.
1756-
base = new (context) DotSelfExpr(base, SourceLoc(), base->getEndLoc(),
1757-
cs.getType(base));
1758-
cs.setType(base, base->getType());
1759-
1760-
auto *closure = buildSingleCurryThunk(
1761-
base, declRefExpr, cast<AbstractFunctionDecl>(member),
1778+
// we have a partial application of a static member. It is better
1779+
// to either push the base reference down into the closure (if it's
1780+
// just a literal type reference, in which case there are no order of
1781+
// operation concerns with capturing vs. evaluating it in the closure),
1782+
// or to evaluate the base as a capture and hand it down via the
1783+
// capture list.
1784+
if (isa<ConstructorDecl>(member) || member->isStatic()) {
1785+
if (cs.isStaticallyDerivedMetatype(base)) {
1786+
// Add a useless ".self" to avoid downstream diagnostics.
1787+
base = new (context) DotSelfExpr(base, SourceLoc(), base->getEndLoc(),
1788+
cs.getType(base));
1789+
cs.setType(base, base->getType());
1790+
1791+
auto *closure = buildSingleCurryThunk(
1792+
base, declRefExpr, cast<AbstractFunctionDecl>(member),
1793+
memberLocator);
1794+
1795+
// Skip the code below -- we're not building an extra level of
1796+
// call by applying the metatype; instead, the closure we just
1797+
// built is the curried reference.
1798+
return closure;
1799+
} else {
1800+
// Add a useless ".self" to avoid downstream diagnostics, in case
1801+
// the type ref is still a TypeExpr.
1802+
base = new (context) DotSelfExpr(base, SourceLoc(), base->getEndLoc(),
1803+
cs.getType(base));
1804+
// Introduce a capture variable.
1805+
cs.cacheType(base);
1806+
solution.setExprTypes(base);
1807+
auto capture = new (context) VarDecl(/*static*/ false,
1808+
VarDecl::Introducer::Let,
1809+
SourceLoc(),
1810+
context.getIdentifier("$base$"),
1811+
dc);
1812+
capture->setImplicit();
1813+
capture->setInterfaceType(base->getType()->mapTypeOutOfContext());
1814+
1815+
NamedPattern *capturePat = new (context) NamedPattern(capture);
1816+
capturePat->setImplicit();
1817+
capturePat->setType(base->getType());
1818+
1819+
auto capturePBE = PatternBindingEntry(capturePat,
1820+
SourceLoc(), base, dc);
1821+
auto captureDecl = PatternBindingDecl::create(context, SourceLoc(),
1822+
{}, SourceLoc(),
1823+
capturePBE,
1824+
dc);
1825+
captureDecl->setImplicit();
1826+
1827+
// Write the closure in terms of the capture.
1828+
auto baseRef = new (context)
1829+
DeclRefExpr(capture, DeclNameLoc(base->getLoc()), /*implicit*/ true);
1830+
baseRef->setType(base->getType());
1831+
cs.cacheType(baseRef);
1832+
1833+
auto *closure = buildSingleCurryThunk(
1834+
baseRef, declRefExpr, cast<AbstractFunctionDecl>(member),
1835+
simplifyType(adjustedOpenedType)->castTo<FunctionType>(),
17621836
memberLocator);
1763-
1764-
// Skip the code below -- we're not building an extra level of
1765-
// call by applying the metatype; instead, the closure we just
1766-
// built is the curried reference.
1767-
return closure;
1837+
1838+
// Wrap the closure in a capture list.
1839+
auto captureEntry = CaptureListEntry(captureDecl);
1840+
auto captureExpr = CaptureListExpr::create(context, captureEntry,
1841+
closure);
1842+
captureExpr->setImplicit();
1843+
captureExpr->setType(cs.getType(closure));
1844+
cs.cacheType(captureExpr);
1845+
1846+
Expr *finalExpr = captureExpr;
1847+
closeExistentials(finalExpr, locator,
1848+
/*force*/ openedExistential);
1849+
return finalExpr;
1850+
}
17681851
}
17691852

17701853
FunctionType *curryThunkTy = nullptr;

test/SILGen/closure_literal_reabstraction.swift

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,24 @@ struct Butt {
1414
static prefix func !=< (a: Butt) -> Butt { return a }
1515
}
1616

17+
class AbstractButt {
18+
required init(x: Int) {}
19+
20+
class func create(x: Int) -> Self { return self.init(x: x) }
21+
}
22+
23+
class AbstractGenericButt<T> {
24+
required init(c: Int) {}
25+
class func create(c: Int) -> Self { return self.init(c: c) }
26+
}
27+
28+
func abstractButtFactory() -> AbstractButt.Type { return AbstractButt.self }
29+
30+
protocol Buttable {
31+
init(p: Int)
32+
static func create(p: Int) -> Self
33+
}
34+
1735
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractCaptureListExprArgument
1836
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}U_
1937
// CHECK: [[CLOSURE:%.*]] = partial_apply {{.*}}[[CLOSURE_FN]]
@@ -65,7 +83,110 @@ func reabstractCoercedMemberOperatorRef() {
6583
gen(f: (!=<) as (Butt) -> Butt)
6684
}
6785

86+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractDynamicMetatypeInitializerRef
87+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
88+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]
89+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE]]
90+
// CHECK: apply {{.*}}<Int, AbstractButt>([[CLOSURE_NE]])
91+
func reabstractDynamicMetatypeInitializerRef() {
92+
gen(f: abstractButtFactory().init)
93+
}
94+
95+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractDynamicMetatypeStaticMemberRef
96+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
97+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]
98+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE]]
99+
// CHECK: apply {{.*}}<Int, AbstractButt>([[CLOSURE_NE]])
100+
func reabstractDynamicMetatypeStaticMemberRef() {
101+
gen(f: abstractButtFactory().create)
102+
}
103+
104+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractGenericInitializerRef
105+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
106+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]
107+
// CHECK: [[CLOSURE_C:%.*]] = convert_function [[CLOSURE]]
108+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE_C]]
109+
// CHECK: apply {{.*}}<Int, T>([[CLOSURE_NE]])
110+
func reabstractGenericInitializerRef<T: Buttable>(butt: T) {
111+
gen(f: T.init)
112+
}
113+
114+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractGenericStaticMemberRef
115+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
116+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]
117+
// CHECK: [[CLOSURE_C:%.*]] = convert_function [[CLOSURE]]
118+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE_C]]
119+
// CHECK: apply {{.*}}<Int, T>([[CLOSURE_NE]])
120+
func reabstractGenericStaticMemberRef<T: Buttable>(butt: T) {
121+
gen(f: T.create)
122+
}
123+
124+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractDynamicGenericStaticMemberRef
125+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
126+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]<T>(%0)
127+
// CHECK: [[CLOSURE_C:%.*]] = convert_function [[CLOSURE]]
128+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE_C]]
129+
// CHECK: apply {{.*}}<Int, T>([[CLOSURE_NE]])
130+
func reabstractDynamicGenericStaticMemberRef<T: Buttable>(t: T.Type) {
131+
gen(f: t.create)
132+
}
133+
134+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractExistentialInitializerRef
135+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
136+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]](%0)
137+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE]]
138+
// CHECK: apply {{.*}}<Int, any Buttable>([[CLOSURE_NE]])
139+
func reabstractExistentialInitializerRef(butt: any Buttable.Type) {
140+
gen(f: butt.init)
141+
}
142+
143+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractExistentialStaticMemberRef
144+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
145+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]](%0)
146+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE]]
147+
// CHECK: apply {{.*}}<Int, any Buttable>([[CLOSURE_NE]])
148+
func reabstractExistentialStaticMemberRef(butt: any Buttable.Type) {
149+
gen(f: butt.create)
150+
}
151+
152+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractClassCompInitializerRefs
153+
func reabstractClassCompInitializerRefs<T>(
154+
butt: any (AbstractGenericButt<T> & Buttable).Type
155+
) {
156+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
157+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]<T>(%0)
158+
// CHECK: [[CLOSURE_C:%.*]] = convert_function [[CLOSURE]]
159+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE_C]]
160+
// CHECK: apply {{.*}}<Int, any (AbstractGenericButt<T> & Buttable)>([[CLOSURE_NE]])
161+
gen(f: butt.init(c:))
162+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u0_
163+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]<T>(%0)
164+
// CHECK: [[CLOSURE_C:%.*]] = convert_function [[CLOSURE]]
165+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE_C]]
166+
// CHECK: apply {{.*}}<Int, any (AbstractGenericButt<T> & Buttable)>([[CLOSURE_NE]])
167+
gen(f: butt.init(p:))
168+
}
169+
170+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractClassCompStaticMemberRefs
171+
func reabstractClassCompStaticMemberRefs<T>(
172+
butt: any (AbstractGenericButt<T> & Buttable).Type
173+
) {
174+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
175+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]<T>(%0)
176+
// CHECK: [[CLOSURE_C:%.*]] = convert_function [[CLOSURE]]
177+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE_C]]
178+
// CHECK: apply {{.*}}<Int, any (AbstractGenericButt<T> & Buttable)>([[CLOSURE_NE]])
179+
gen(f: butt.create(c:))
180+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u0_
181+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]<T>(%0)
182+
// CHECK: [[CLOSURE_C:%.*]] = convert_function [[CLOSURE]]
183+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[CLOSURE_C]]
184+
// CHECK: apply {{.*}}<Int, any (AbstractGenericButt<T> & Buttable)>([[CLOSURE_NE]])
185+
gen(f: butt.create(p:))
186+
}
187+
68188
// TODO
189+
69190
func reabstractInstanceMethodRef(instance: Butt) {
70191
gen(f: instance.getX)
71192
}

test/SILGen/objc_protocols.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
21
// RUN: %target-swift-emit-silgen -module-name objc_protocols -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
3-
42
// REQUIRES: objc_interop
53

64
import gizmo
@@ -50,7 +48,7 @@ func objc_generic_partial_apply<T : NSRuncing>(_ x: T) {
5048
// CHECK: [[FN:%.*]] = function_ref @$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxcfu1_
5149
_ = T.runce
5250

53-
// CHECK: [[FN:%.*]] = function_ref @$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxmcfu3_
51+
// CHECK: [[FN:%.*]] = function_ref @$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycfu3_
5452
_ = T.mince
5553
// CHECK-NOT: destroy_value [[ARG]]
5654
}
@@ -75,13 +73,9 @@ func objc_generic_partial_apply<T : NSRuncing>(_ x: T) {
7573
// CHECK: } // end sil function '$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxcfu1_AEycfu2_'
7674

7775

78-
// CHECK-LABEL: sil private [ossa] @$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxmcfu3_ : $@convention(thin) <T where T : NSRuncing> (@thick T.Type) -> @owned @callee_guaranteed () -> @owned NSObject
79-
// CHECK: function_ref @$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxmcfu3_AEycfu4_ : $@convention(thin) <τ_0_0 where τ_0_0 : NSRuncing> (@thick τ_0_0.Type) -> @owned NSObject
80-
// CHECK: } // end sil function '$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxmcfu3_'
81-
82-
// CHECK-LABEL: sil private [ossa] @$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxmcfu3_AEycfu4_ : $@convention(thin) <T where T : NSRuncing> (@thick T.Type) -> @owned NSObject
76+
// CHECK-LABEL: sil private [ossa] @$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycfu3_ : $@convention(thin) <T where T : NSRuncing> (@thick T.Type) -> @owned NSObject
8377
// CHECK: objc_method %2 : $@objc_metatype T.Type, #NSRuncing.mince!foreign : <Self where Self : NSRuncing> (Self.Type) -> () -> NSObject, $@convention(objc_method) <τ_0_0 where τ_0_0 : NSRuncing> (@objc_metatype τ_0_0.Type) -> @autoreleased NSObject
84-
// CHECK: } // end sil function '$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycxmcfu3_AEycfu4_'
78+
// CHECK: } // end sil function '$s14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlFSo8NSObjectCycfu3_'
8579

8680

8781
// CHECK-LABEL: sil hidden [ossa] @$s14objc_protocols0A9_protocol{{[_0-9a-zA-Z]*}}F

test/SILGen/partial_apply_generic.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ protocol Foo {
1414

1515
// CHECK-LABEL: sil hidden [ossa] @$s21partial_apply_generic14getStaticFunc1{{[_0-9a-zA-Z]*}}F
1616
func getStaticFunc1<T: Foo>(t: T.Type) -> () -> () {
17-
// CHECK: function_ref @$s21partial_apply_generic14getStaticFunc11tyycxm_tAA3FooRzlFyycxmcfu_ : $@convention(thin) <τ_0_0 where τ_0_0 : Foo> (@thick τ_0_0.Type) -> @owned @callee_guaranteed () -> ()
17+
// CHECK: function_ref @$s21partial_apply_generic14getStaticFunc11tyycxm_tAA3FooRzlFyycfu_ : $@convention(thin) <τ_0_0 where τ_0_0 : Foo> (@thick τ_0_0.Type) -> ()
1818
return t.staticFunc
1919
}
2020

21-
// CHECK-LABEL: sil private [ossa] @$s21partial_apply_generic14getStaticFunc11tyycxm_tAA3FooRzlFyycxmcfu_yycfu0_ : $@convention(thin) <T where T : Foo> (@thick T.Type) -> ()
21+
// CHECK-LABEL: sil private [ossa] @$s21partial_apply_generic14getStaticFunc11tyycxm_tAA3FooRzlFyycfu_ : $@convention(thin) <T where T : Foo> (@thick T.Type) -> ()
2222
// CHECK: witness_method $T, #Foo.staticFunc :
2323

2424

2525
// CHECK-LABEL: sil hidden [ossa] @$s21partial_apply_generic14getStaticFunc2{{[_0-9a-zA-Z]*}}F
2626
func getStaticFunc2<T: Foo>(t: T) -> () -> () {
27-
// CHECK: function_ref @$s21partial_apply_generic14getStaticFunc21tyycx_tAA3FooRzlFyycxmcfu_ : $@convention(thin) <τ_0_0 where τ_0_0 : Foo> (@thick τ_0_0.Type) -> @owned @callee_guaranteed () -> ()
27+
// CHECK: function_ref @$s21partial_apply_generic14getStaticFunc21tyycx_tAA3FooRzlFyycfu_ : $@convention(thin) <τ_0_0 where τ_0_0 : Foo> (@thick τ_0_0.Type) -> ()
2828
return T.staticFunc
2929
}
3030

31-
// CHECK-LABEL: sil private [ossa] @$s21partial_apply_generic14getStaticFunc21tyycx_tAA3FooRzlFyycxmcfu_yycfu0_ : $@convention(thin) <T where T : Foo> (@thick T.Type) -> ()
31+
// CHECK-LABEL: sil private [ossa] @$s21partial_apply_generic14getStaticFunc21tyycx_tAA3FooRzlFyycfu_ : $@convention(thin) <T where T : Foo> (@thick T.Type) -> ()
3232
// CHECK: witness_method $T, #Foo.staticFunc :
3333

3434

0 commit comments

Comments
 (0)