@@ -903,11 +903,6 @@ namespace {
903903 bool baseIsInstance) {
904904 ValueDecl *member = choice.getDecl ();
905905
906- // FIXME: We should finish plumbing this through for dynamic
907- // lookup as well.
908- if (choice.getKind () == OverloadChoiceKind::DeclViaDynamic)
909- return false ;
910-
911906 // If we're inside a selector expression, don't build the thunk.
912907 // Were not actually going to emit the member reference, just
913908 // look at the AST.
@@ -921,9 +916,11 @@ namespace {
921916 if (!baseIsInstance && member->isInstanceMember ())
922917 return true ;
923918
924- // Bound optional method references are represented via
925- // DynamicMemberRefExpr instead of a curry thunk.
926- if (member->getAttrs ().hasAttribute <OptionalAttr>())
919+ // Bound member references that are '@objc optional' or found via dynamic
920+ // lookup are always represented via DynamicMemberRefExpr instead of a
921+ // curry thunk.
922+ if (member->getAttrs ().hasAttribute <OptionalAttr>() ||
923+ choice.getKind () == OverloadChoiceKind::DeclViaDynamic)
927924 return false ;
928925
929926 // Figure out how many argument lists we need.
@@ -1002,7 +999,10 @@ namespace {
1002999 auto *calleeFnTy = fnTy;
10031000
10041001 if (baseExpr) {
1002+ // Coerce the base expression to the container type.
10051003 const auto calleeSelfParam = calleeFnTy->getParams ().front ();
1004+ baseExpr =
1005+ coerceToType (baseExpr, calleeSelfParam.getOldType (), locator);
10061006
10071007 // If the 'self' parameter has non-trivial ownership, adjust the
10081008 // argument type accordingly.
@@ -1159,7 +1159,33 @@ namespace {
11591159 Expr *thunkBody = buildSingleCurryThunkBodyCall (
11601160 baseExpr, fnExpr, declOrClosure, thunkParamList, locator);
11611161
1162- // Coerce to the result type of the thunk.
1162+ // If we called a function with a dynamic 'Self' result, we may need some
1163+ // special handling.
1164+ if (baseExpr) {
1165+ if (auto *fnDecl = dyn_cast<AbstractFunctionDecl>(declOrClosure)) {
1166+ if (fnDecl->hasDynamicSelfResult ()) {
1167+ Type convTy;
1168+
1169+ if (cs.getType (baseExpr)->hasOpenedExistential ()) {
1170+ // FIXME: Sometimes we need to convert to an opened existential
1171+ // first, because CovariantReturnConversionExpr does not support
1172+ // direct conversions from a class C to an existential C & P.
1173+ convTy = cs.getType (baseExpr)->getMetatypeInstanceType ();
1174+ convTy =
1175+ thunkTy->getResult ()->replaceCovariantResultType (convTy, 0 );
1176+ } else {
1177+ convTy = thunkTy->getResult ();
1178+ }
1179+
1180+ if (!thunkBody->getType ()->isEqual (convTy)) {
1181+ thunkBody = cs.cacheType (
1182+ new (ctx) CovariantReturnConversionExpr (thunkBody, convTy));
1183+ }
1184+ }
1185+ }
1186+ }
1187+
1188+ // Now, coerce to the result type of the thunk.
11631189 thunkBody = coerceToType (thunkBody, thunkTy->getResult (), locator);
11641190
11651191 if (thunkTy->getExtInfo ().isThrowing ()) {
@@ -1261,20 +1287,27 @@ namespace {
12611287 cs.cacheType (selfParamRef);
12621288 }
12631289
1264- auto *const selfCalleeTy = cs.getType (memberRef)->castTo <FunctionType>();
1265- const auto selfCalleeParam = selfCalleeTy->getParams ().front ();
1266- const auto selfCalleeParamTy = selfCalleeParam.getPlainType ();
1267-
1268- // Open the 'self' parameter reference if warranted.
1290+ bool hasOpenedExistential = false ;
12691291 Expr *selfOpenedRef = selfParamRef;
1270- if (selfCalleeParamTy->hasOpenedExistential ()) {
1292+
1293+ // If the 'self' parameter type is existential, it must be opened.
1294+ if (selfThunkParamTy->isAnyExistentialType ()) {
1295+ Type openedTy = solution.OpenedExistentialTypes .lookup (
1296+ cs.getConstraintLocator (memberLocator));
1297+ assert (openedTy);
1298+
1299+ hasOpenedExistential = true ;
1300+
12711301 // If we're opening an existential:
12721302 // - The type of 'memberRef' inside the thunk is written in terms of the
1273- // open existental archetype.
1303+ // opened existental archetype.
12741304 // - The type of the thunk is written in terms of the
12751305 // erased existential bounds.
1276- auto opaqueValueTy = selfCalleeParamTy;
1277- if (selfCalleeParam.isInOut ())
1306+ Type opaqueValueTy = openedTy;
1307+ if (selfThunkParamTy->is <ExistentialMetatypeType>())
1308+ opaqueValueTy = MetatypeType::get (opaqueValueTy);
1309+
1310+ if (selfThunkParam.isInOut ())
12781311 opaqueValueTy = LValueType::get (opaqueValueTy);
12791312
12801313 selfOpenedRef = new (ctx) OpaqueValueExpr (SourceLoc (), opaqueValueTy);
@@ -1292,6 +1325,9 @@ namespace {
12921325 // build a dynamic member reference. Otherwise, build a nested
12931326 // "{ args... in self.member(args...) }" thunk that calls the member.
12941327 if (isDynamicLookup || member->getAttrs ().hasAttribute <OptionalAttr>()) {
1328+ auto *const selfCalleeTy =
1329+ cs.getType (memberRef)->castTo <FunctionType>();
1330+
12951331 outerThunkBody = new (ctx) DynamicMemberRefExpr (
12961332 selfOpenedRef, SourceLoc (),
12971333 resolveConcreteDeclRef (member, memberLocator), memberLoc);
@@ -1303,10 +1339,11 @@ namespace {
13031339 memberLocator);
13041340
13051341 // Close the existential if warranted.
1306- if (selfCalleeParamTy-> hasOpenedExistential () ) {
1342+ if (hasOpenedExistential) {
13071343 // If the callee's 'self' parameter has non-trivial ownership, adjust
13081344 // the argument type accordingly.
1309- adjustExprOwnershipForParam (selfOpenedRef, selfCalleeParam);
1345+ adjustExprOwnershipForParam (selfOpenedRef,
1346+ selfCalleeTy->getParams ().front ());
13101347
13111348 outerThunkBody = new (ctx) OpenExistentialExpr (
13121349 selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef),
@@ -1319,7 +1356,7 @@ namespace {
13191356 outerThunkTy->getResult ()->castTo <FunctionType>(), memberLocator);
13201357
13211358 // Rewrite the body to close the existential if warranted.
1322- if (selfCalleeParamTy-> hasOpenedExistential () ) {
1359+ if (hasOpenedExistential) {
13231360 auto *body = innerThunk->getSingleExpressionBody ();
13241361 body = new (ctx) OpenExistentialExpr (
13251362 selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef), body,
@@ -1438,7 +1475,7 @@ namespace {
14381475
14391476 const bool isUnboundInstanceMember =
14401477 (!baseIsInstance && member->isInstanceMember ());
1441- const bool isPartialApplication =
1478+ const bool needsCurryThunk =
14421479 shouldBuildCurryThunk (choice, baseIsInstance);
14431480
14441481 // The formal type of the 'self' value for the member's declaration.
@@ -1452,24 +1489,28 @@ namespace {
14521489 // the base accordingly.
14531490 bool openedExistential = false ;
14541491
1455- // For a partial application, we have to open the existential inside
1456- // the thunk itself.
14571492 auto knownOpened = solution.OpenedExistentialTypes .find (
14581493 getConstraintSystem ().getConstraintLocator (
14591494 memberLocator));
14601495 if (knownOpened != solution.OpenedExistentialTypes .end ()) {
14611496 // Determine if we're going to have an OpenExistentialExpr around
14621497 // this member reference.
14631498 //
1464- // If we have a partial application of a protocol method, we open
1465- // the existential in the curry thunk, instead of opening it here,
1466- // because we won't have a 'self' value until the curry thunk is
1467- // applied.
1499+ // For an unbound reference to a method, always open the existential
1500+ // inside the curry thunk, because we won't have a 'self' value until
1501+ // the curry thunk is applied.
1502+ //
1503+ // For a partial application of a protocol method, open the existential
1504+ // inside the curry thunk as well. This reduces abstraction and
1505+ // post-factum function type conversions, and results in better SILGen.
14681506 //
1469- // However, a partial application of a class method on a subclass
1470- // existential does need to open the existential, so that it can be
1471- // upcast to the appropriate class reference type.
1472- if (!isPartialApplication || !containerTy->hasOpenedExistential ()) {
1507+ // For a partial application of a class method, however, we always want
1508+ // the thunk to accept a class to avoid potential abstraction, so the
1509+ // existential base must be opened eagerly in order to be upcast to the
1510+ // appropriate class reference type before it is passed to the thunk.
1511+ if (!needsCurryThunk ||
1512+ (!member->getDeclContext ()->getSelfProtocolDecl () &&
1513+ !isUnboundInstanceMember)) {
14731514 // Open the existential before performing the member reference.
14741515 base = openExistentialReference (base, knownOpened->second , member);
14751516 baseTy = knownOpened->second ;
@@ -1508,13 +1549,15 @@ namespace {
15081549 base, selfParamTy, member,
15091550 locator.withPathElement (ConstraintLocator::MemberRefBase));
15101551 } else {
1511- if (!isExistentialMetatype || openedExistential) {
1512- // Convert the base to an rvalue of the appropriate metatype.
1513- base = coerceToType (base,
1514- MetatypeType::get (
1515- isDynamic ? selfTy : containerTy),
1516- locator.withPathElement (
1517- ConstraintLocator::MemberRefBase));
1552+ // The base of an unbound reference is unused, and thus a conversion
1553+ // is not necessary.
1554+ if (!isUnboundInstanceMember) {
1555+ if (!isExistentialMetatype || openedExistential) {
1556+ // Convert the base to an rvalue of the appropriate metatype.
1557+ base = coerceToType (
1558+ base, MetatypeType::get (isDynamic ? selfTy : containerTy),
1559+ locator.withPathElement (ConstraintLocator::MemberRefBase));
1560+ }
15181561 }
15191562
15201563 if (!base)
@@ -1544,8 +1587,8 @@ namespace {
15441587 }
15451588
15461589 // Handle dynamic references.
1547- if (isDynamic || (!isPartialApplication &&
1548- member->getAttrs ().hasAttribute <OptionalAttr>())) {
1590+ if (!needsCurryThunk &&
1591+ (isDynamic || member->getAttrs ().hasAttribute <OptionalAttr>())) {
15491592 base = cs.coerceToRValue (base);
15501593 Expr *ref = new (context) DynamicMemberRefExpr (base, dotLoc, memberRef,
15511594 memberLoc);
@@ -1635,7 +1678,7 @@ namespace {
16351678 //
16361679 // { self in { args... in self.method(args...) } }(foo)
16371680 //
1638- // This is done instead of just hoising the expression 'foo' up
1681+ // This is done instead of just hoisting the expression 'foo' up
16391682 // into the closure, which would change evaluation order.
16401683 //
16411684 // However, for a super method reference, eg, 'let fn = super.foo',
@@ -1644,12 +1687,12 @@ namespace {
16441687 // very specific shape, we only emit a single closure here and
16451688 // capture the original SuperRefExpr, since its evaluation does not
16461689 // have side effects, instead of abstracting out a 'self' parameter.
1647- const auto isSuperPartialApplication = isPartialApplication && isSuper;
1690+ const auto isSuperPartialApplication = needsCurryThunk && isSuper;
16481691 if (isSuperPartialApplication) {
16491692 ref = buildSingleCurryThunk (base, declRefExpr,
16501693 cast<AbstractFunctionDecl>(member),
16511694 memberLocator);
1652- } else if (isPartialApplication ) {
1695+ } else if (needsCurryThunk ) {
16531696 // Another case where we want to build a single closure is when
16541697 // we have a partial application of a constructor on a statically-
16551698 // derived metatype value. Again, there are no order of evaluation
@@ -1672,17 +1715,28 @@ namespace {
16721715 return closure;
16731716 }
16741717
1675- auto *curryThunkTy = refTy->castTo <FunctionType>();
1676-
1677- // Check if we need to open an existential stored inside 'self'.
1678- auto knownOpened = solution.OpenedExistentialTypes .find (
1679- getConstraintSystem ().getConstraintLocator (
1680- memberLocator));
1681- if (knownOpened != solution.OpenedExistentialTypes .end ()) {
1682- curryThunkTy = curryThunkTy
1683- ->typeEraseOpenedArchetypesWithRoot (
1684- knownOpened->second , dc)
1685- ->castTo <FunctionType>();
1718+ FunctionType *curryThunkTy = nullptr ;
1719+ if (isUnboundInstanceMember) {
1720+ // For an unbound reference to a method, all conversions, including
1721+ // dynamic 'Self' handling, are done within the thunk to support
1722+ // the edge case of an unbound reference to a 'Self'-returning class
1723+ // method on a protocol metatype. The result of calling the method
1724+ // must be downcast to the opened archetype before being erased to the
1725+ // subclass existential to cope with the expectations placed
1726+ // on 'CovariantReturnConversionExpr'.
1727+ curryThunkTy = simplifyType (openedType)->castTo <FunctionType>();
1728+ } else {
1729+ curryThunkTy = refTy->castTo <FunctionType>();
1730+
1731+ // Check if we need to open an existential stored inside 'self'.
1732+ auto knownOpened = solution.OpenedExistentialTypes .find (
1733+ getConstraintSystem ().getConstraintLocator (memberLocator));
1734+ if (knownOpened != solution.OpenedExistentialTypes .end ()) {
1735+ curryThunkTy =
1736+ curryThunkTy
1737+ ->typeEraseOpenedArchetypesWithRoot (knownOpened->second , dc)
1738+ ->castTo <FunctionType>();
1739+ }
16861740 }
16871741
16881742 // Replace the DeclRefExpr with a closure expression which SILGen
@@ -1695,7 +1749,10 @@ namespace {
16951749 // implicit function type conversion around the resulting expression,
16961750 // with the destination type having 'Self' swapped for the appropriate
16971751 // replacement type -- usually the base object type.
1698- if (!member->getDeclContext ()->getSelfProtocolDecl ()) {
1752+ //
1753+ // Note: For unbound references this is handled inside the thunk.
1754+ if (!isUnboundInstanceMember &&
1755+ !member->getDeclContext ()->getSelfProtocolDecl ()) {
16991756 if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
17001757 if (func->hasDynamicSelfResult () &&
17011758 !baseTy->getOptionalObjectType ()) {
0 commit comments