@@ -1188,6 +1188,29 @@ namespace {
11881188 thunkTy, locator);
11891189 }
11901190
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+
11911214 AutoClosureExpr *buildCurryThunk (ValueDecl *member,
11921215 FunctionType *selfFnTy,
11931216 Expr *selfParamRef,
@@ -1221,8 +1244,7 @@ namespace {
12211244 // FIXME: selfParamRef ownership
12221245
12231246 auto *const thunk = buildSingleCurryThunk (
1224- selfOpenedRef, ref, dyn_cast<AbstractFunctionDecl>(member), selfFnTy,
1225- locator);
1247+ selfOpenedRef, ref, cast<DeclContext>(member), selfFnTy, locator);
12261248
12271249 if (selfParam.getPlainType ()->hasOpenedExistential ()) {
12281250 auto *body = thunk->getSingleExpressionBody ();
@@ -1516,56 +1538,54 @@ namespace {
15161538 cs.setType (declRefExpr, refTy);
15171539 Expr *ref = declRefExpr;
15181540
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.
15191559 const auto isSuperPartialApplication = isPartialApplication && isSuper;
15201560 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);
15431564 } else if (isPartialApplication) {
1544- auto curryThunkTy = refTy->castTo <FunctionType>();
1545-
15461565 // Another case where we want to build a single closure is when
15471566 // we have a partial application of a constructor on a statically-
15481567 // derived metatype value. Again, there are no order of evaluation
15491568 // concerns here, and keeping the call and base together in the AST
15501569 // improves SILGen.
15511570 if (isa<ConstructorDecl>(member) &&
15521571 cs.isStaticallyDerivedMetatype (base)) {
1553- auto selfFnTy = curryThunkTy->getResult ()->castTo <FunctionType>();
1554-
15551572 // Add a useless ".self" to avoid downstream diagnostics.
15561573 base = new (context) DotSelfExpr (base, SourceLoc (), base->getEndLoc (),
15571574 cs.getType (base));
15581575 cs.setType (base, base->getType ());
15591576
1560- auto closure = buildCurryThunk (member, selfFnTy, base, ref,
1561- memberLocator);
1577+ auto *closure = buildSingleCurryThunk (
1578+ base, declRefExpr, cast<AbstractFunctionDecl>(member),
1579+ memberLocator);
15621580
15631581 // Skip the code below -- we're not building an extra level of
15641582 // call by applying the metatype; instead, the closure we just
15651583 // built is the curried reference.
15661584 return closure;
15671585 }
15681586
1587+ auto *curryThunkTy = refTy->castTo <FunctionType>();
1588+
15691589 // Check if we need to open an existential stored inside 'self'.
15701590 auto knownOpened = solution.OpenedExistentialTypes .find (
15711591 getConstraintSystem ().getConstraintLocator (
0 commit comments