@@ -1186,10 +1186,30 @@ namespace {
1186
1186
thunk->setParameterList (thunkParamList);
1187
1187
thunk->setThunkKind (AutoClosureExpr::Kind::SingleCurryThunk);
1188
1188
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
+ }
1189
1209
1190
1210
Expr *thunkBody = buildSingleCurryThunkBodyCall (
1191
1211
baseExpr, fnExpr, declOrClosure, thunkParamList, locator);
1192
-
1212
+
1193
1213
// If we called a function with a dynamic 'Self' result, we may need some
1194
1214
// special handling.
1195
1215
if (baseExpr) {
@@ -1219,6 +1239,15 @@ namespace {
1219
1239
// Now, coerce to the result type of the thunk.
1220
1240
thunkBody = coerceToType (thunkBody, thunkTy->getResult (), locator);
1221
1241
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
+
1222
1251
if (thunkTy->getExtInfo ().isThrowing ()) {
1223
1252
thunkBody = new (ctx)
1224
1253
TryExpr (thunkBody->getStartLoc (), thunkBody, cs.getType (thunkBody),
@@ -1529,13 +1558,14 @@ namespace {
1529
1558
// inside the curry thunk as well. This reduces abstraction and
1530
1559
// post-factum function type conversions, and results in better SILGen.
1531
1560
//
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.
1536
1566
if (!needsCurryThunk ||
1537
1567
(!member->getDeclContext ()->getSelfProtocolDecl () &&
1538
- !isUnboundInstanceMember )) {
1568
+ baseIsInstance && member-> isInstanceMember () )) {
1539
1569
// Open the existential before performing the member reference.
1540
1570
base = openExistentialReference (base, knownOpened->second , member);
1541
1571
baseTy = knownOpened->second ;
@@ -1745,26 +1775,79 @@ namespace {
1745
1775
memberLocator);
1746
1776
} else if (needsCurryThunk) {
1747
1777
// 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>(),
1762
1836
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
+ }
1768
1851
}
1769
1852
1770
1853
FunctionType *curryThunkTy = nullptr ;
0 commit comments