@@ -1188,6 +1188,29 @@ namespace {
1188
1188
thunkTy, locator);
1189
1189
}
1190
1190
1191
+ // / Build a "{ args in base.fn(args) }" single-expression curry thunk.
1192
+ // /
1193
+ // / \param baseExpr The base expression to be captured.
1194
+ // / \param fnExpr The expression to be called by consecutively applying
1195
+ // / the \p baseExpr and thunk parameters.
1196
+ // / \param declOrClosure The underlying function-like declaration or
1197
+ // / closure we're going to call.
1198
+ // / \param locator The locator pinned on the function reference carried
1199
+ // / by \p fnExpr. If the function has associated applied property wrappers,
1200
+ // / the locator is used to pull them in.
1201
+ AutoClosureExpr *buildSingleCurryThunk (Expr *baseExpr, Expr *fnExpr,
1202
+ DeclContext *declOrClosure,
1203
+ ConstraintLocatorBuilder locator) {
1204
+ assert (baseExpr);
1205
+ auto *const thunkTy = cs.getType (fnExpr)
1206
+ ->castTo <FunctionType>()
1207
+ ->getResult ()
1208
+ ->castTo <FunctionType>();
1209
+
1210
+ return buildSingleCurryThunk (baseExpr, fnExpr, declOrClosure, thunkTy,
1211
+ locator);
1212
+ }
1213
+
1191
1214
AutoClosureExpr *buildCurryThunk (ValueDecl *member,
1192
1215
FunctionType *selfFnTy,
1193
1216
Expr *selfParamRef,
@@ -1221,8 +1244,7 @@ namespace {
1221
1244
// FIXME: selfParamRef ownership
1222
1245
1223
1246
auto *const thunk = buildSingleCurryThunk (
1224
- selfOpenedRef, ref, dyn_cast<AbstractFunctionDecl>(member), selfFnTy,
1225
- locator);
1247
+ selfOpenedRef, ref, cast<DeclContext>(member), selfFnTy, locator);
1226
1248
1227
1249
if (selfParam.getPlainType ()->hasOpenedExistential ()) {
1228
1250
auto *body = thunk->getSingleExpressionBody ();
@@ -1516,56 +1538,54 @@ namespace {
1516
1538
cs.setType (declRefExpr, refTy);
1517
1539
Expr *ref = declRefExpr;
1518
1540
1541
+ // A partial application thunk consists of two nested closures:
1542
+ //
1543
+ // { self in { args... in self.method(args...) } }
1544
+ //
1545
+ // If the reference has an applied 'self', eg 'let fn = foo.method',
1546
+ // the outermost closure is wrapped inside a single ApplyExpr:
1547
+ //
1548
+ // { self in { args... in self.method(args...) } }(foo)
1549
+ //
1550
+ // This is done instead of just hoising the expression 'foo' up
1551
+ // into the closure, which would change evaluation order.
1552
+ //
1553
+ // However, for a super method reference, eg, 'let fn = super.foo',
1554
+ // the base expression is always a SuperRefExpr, possibly wrapped
1555
+ // by an upcast. Since SILGen expects super method calls to have a
1556
+ // very specific shape, we only emit a single closure here and
1557
+ // capture the original SuperRefExpr, since its evaluation does not
1558
+ // have side effects, instead of abstracting out a 'self' parameter.
1519
1559
const auto isSuperPartialApplication = isPartialApplication && isSuper;
1520
1560
if (isSuperPartialApplication) {
1521
- // A partial application thunk consists of two nested closures:
1522
- //
1523
- // { self in { args... in self.method(args...) } }
1524
- //
1525
- // If the reference has an applied 'self', eg 'let fn = foo.method',
1526
- // the outermost closure is wrapped inside a single ApplyExpr:
1527
- //
1528
- // { self in { args... in self.method(args...) } }(foo)
1529
- //
1530
- // This is done instead of just hoising the expression 'foo' up
1531
- // into the closure, which would change evaluation order.
1532
- //
1533
- // However, for a super method reference, eg, 'let fn = super.foo',
1534
- // the base expression is always a SuperRefExpr, possibly wrapped
1535
- // by an upcast. Since SILGen expects super method calls to have a
1536
- // very specific shape, we only emit a single closure here and
1537
- // capture the original SuperRefExpr, since its evaluation does not
1538
- // have side effects, instead of abstracting out a 'self' parameter.
1539
- const auto selfFnTy =
1540
- refTy->castTo <FunctionType>()->getResult ()->castTo <FunctionType>();
1541
-
1542
- ref = buildCurryThunk (member, selfFnTy, base, ref, memberLocator);
1561
+ ref = buildSingleCurryThunk (base, declRefExpr,
1562
+ cast<AbstractFunctionDecl>(member),
1563
+ memberLocator);
1543
1564
} else if (isPartialApplication) {
1544
- auto curryThunkTy = refTy->castTo <FunctionType>();
1545
-
1546
1565
// Another case where we want to build a single closure is when
1547
1566
// we have a partial application of a constructor on a statically-
1548
1567
// derived metatype value. Again, there are no order of evaluation
1549
1568
// concerns here, and keeping the call and base together in the AST
1550
1569
// improves SILGen.
1551
1570
if (isa<ConstructorDecl>(member) &&
1552
1571
cs.isStaticallyDerivedMetatype (base)) {
1553
- auto selfFnTy = curryThunkTy->getResult ()->castTo <FunctionType>();
1554
-
1555
1572
// Add a useless ".self" to avoid downstream diagnostics.
1556
1573
base = new (context) DotSelfExpr (base, SourceLoc (), base->getEndLoc (),
1557
1574
cs.getType (base));
1558
1575
cs.setType (base, base->getType ());
1559
1576
1560
- auto closure = buildCurryThunk (member, selfFnTy, base, ref,
1561
- memberLocator);
1577
+ auto *closure = buildSingleCurryThunk (
1578
+ base, declRefExpr, cast<AbstractFunctionDecl>(member),
1579
+ memberLocator);
1562
1580
1563
1581
// Skip the code below -- we're not building an extra level of
1564
1582
// call by applying the metatype; instead, the closure we just
1565
1583
// built is the curried reference.
1566
1584
return closure;
1567
1585
}
1568
1586
1587
+ auto *curryThunkTy = refTy->castTo <FunctionType>();
1588
+
1569
1589
// Check if we need to open an existential stored inside 'self'.
1570
1590
auto knownOpened = solution.OpenedExistentialTypes .find (
1571
1591
getConstraintSystem ().getConstraintLocator (
0 commit comments