@@ -1002,7 +1002,10 @@ namespace {
10021002 auto *calleeFnTy = fnTy;
10031003
10041004 if (baseExpr) {
1005+ // Coerce the base expression to the container type.
10051006 const auto calleeSelfParam = calleeFnTy->getParams ().front ();
1007+ baseExpr =
1008+ coerceToType (baseExpr, calleeSelfParam.getOldType (), locator);
10061009
10071010 // If the 'self' parameter has non-trivial ownership, adjust the
10081011 // argument type accordingly.
@@ -1159,7 +1162,33 @@ namespace {
11591162 Expr *thunkBody = buildSingleCurryThunkBodyCall (
11601163 baseExpr, fnExpr, declOrClosure, thunkParamList, locator);
11611164
1162- // Coerce to the result type of the thunk.
1165+ // If we called a function with a dynamic 'Self' result, we may need some
1166+ // special handling.
1167+ if (baseExpr) {
1168+ if (auto *fnDecl = dyn_cast<AbstractFunctionDecl>(declOrClosure)) {
1169+ if (fnDecl->hasDynamicSelfResult ()) {
1170+ Type convTy;
1171+
1172+ if (cs.getType (baseExpr)->hasOpenedExistential ()) {
1173+ // FIXME: Sometimes we need to convert to an opened existential
1174+ // first, because CovariantReturnConversionExpr does not support
1175+ // direct conversions from a class C to an existential C & P.
1176+ convTy = cs.getType (baseExpr)->getMetatypeInstanceType ();
1177+ convTy =
1178+ thunkTy->getResult ()->replaceCovariantResultType (convTy, 0 );
1179+ } else {
1180+ convTy = thunkTy->getResult ();
1181+ }
1182+
1183+ if (!thunkBody->getType ()->isEqual (convTy)) {
1184+ thunkBody = cs.cacheType (
1185+ new (ctx) CovariantReturnConversionExpr (thunkBody, convTy));
1186+ }
1187+ }
1188+ }
1189+ }
1190+
1191+ // Now, coerce to the result type of the thunk.
11631192 thunkBody = coerceToType (thunkBody, thunkTy->getResult (), locator);
11641193
11651194 if (thunkTy->getExtInfo ().isThrowing ()) {
@@ -1261,20 +1290,27 @@ namespace {
12611290 cs.cacheType (selfParamRef);
12621291 }
12631292
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.
1293+ bool hasOpenedExistential = false ;
12691294 Expr *selfOpenedRef = selfParamRef;
1270- if (selfCalleeParamTy->hasOpenedExistential ()) {
1295+
1296+ // If the 'self' parameter type is existential, it must be opened.
1297+ if (selfThunkParamTy->isAnyExistentialType ()) {
1298+ Type openedTy = solution.OpenedExistentialTypes .lookup (
1299+ cs.getConstraintLocator (memberLocator));
1300+ assert (openedTy);
1301+
1302+ hasOpenedExistential = true ;
1303+
12711304 // If we're opening an existential:
12721305 // - The type of 'memberRef' inside the thunk is written in terms of the
1273- // open existental archetype.
1306+ // opened existental archetype.
12741307 // - The type of the thunk is written in terms of the
12751308 // erased existential bounds.
1276- auto opaqueValueTy = selfCalleeParamTy;
1277- if (selfCalleeParam.isInOut ())
1309+ Type opaqueValueTy = openedTy;
1310+ if (selfThunkParamTy->is <ExistentialMetatypeType>())
1311+ opaqueValueTy = MetatypeType::get (opaqueValueTy);
1312+
1313+ if (selfThunkParam.isInOut ())
12781314 opaqueValueTy = LValueType::get (opaqueValueTy);
12791315
12801316 selfOpenedRef = new (ctx) OpaqueValueExpr (SourceLoc (), opaqueValueTy);
@@ -1292,6 +1328,9 @@ namespace {
12921328 // build a dynamic member reference. Otherwise, build a nested
12931329 // "{ args... in self.member(args...) }" thunk that calls the member.
12941330 if (isDynamicLookup || member->getAttrs ().hasAttribute <OptionalAttr>()) {
1331+ auto *const selfCalleeTy =
1332+ cs.getType (memberRef)->castTo <FunctionType>();
1333+
12951334 outerThunkBody = new (ctx) DynamicMemberRefExpr (
12961335 selfOpenedRef, SourceLoc (),
12971336 resolveConcreteDeclRef (member, memberLocator), memberLoc);
@@ -1303,10 +1342,11 @@ namespace {
13031342 memberLocator);
13041343
13051344 // Close the existential if warranted.
1306- if (selfCalleeParamTy-> hasOpenedExistential () ) {
1345+ if (hasOpenedExistential) {
13071346 // If the callee's 'self' parameter has non-trivial ownership, adjust
13081347 // the argument type accordingly.
1309- adjustExprOwnershipForParam (selfOpenedRef, selfCalleeParam);
1348+ adjustExprOwnershipForParam (selfOpenedRef,
1349+ selfCalleeTy->getParams ().front ());
13101350
13111351 outerThunkBody = new (ctx) OpenExistentialExpr (
13121352 selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef),
@@ -1319,7 +1359,7 @@ namespace {
13191359 outerThunkTy->getResult ()->castTo <FunctionType>(), memberLocator);
13201360
13211361 // Rewrite the body to close the existential if warranted.
1322- if (selfCalleeParamTy-> hasOpenedExistential () ) {
1362+ if (hasOpenedExistential) {
13231363 auto *body = innerThunk->getSingleExpressionBody ();
13241364 body = new (ctx) OpenExistentialExpr (
13251365 selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef), body,
@@ -1452,24 +1492,28 @@ namespace {
14521492 // the base accordingly.
14531493 bool openedExistential = false ;
14541494
1455- // For a partial application, we have to open the existential inside
1456- // the thunk itself.
14571495 auto knownOpened = solution.OpenedExistentialTypes .find (
14581496 getConstraintSystem ().getConstraintLocator (
14591497 memberLocator));
14601498 if (knownOpened != solution.OpenedExistentialTypes .end ()) {
14611499 // Determine if we're going to have an OpenExistentialExpr around
14621500 // this member reference.
14631501 //
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.
1502+ // For an unbound reference to a method, always open the existential
1503+ // inside the curry thunk, because we won't have a 'self' value until
1504+ // the curry thunk is applied.
1505+ //
1506+ // For a partial application of a protocol method, open the existential
1507+ // inside the curry thunk as well. This reduces abstraction and
1508+ // post-factum function type conversions, and results in better SILGen.
14681509 //
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 ()) {
1510+ // For a partial application of a class method, however, we always want
1511+ // the thunk to accept a class to avoid potential abstraction, so the
1512+ // existential base must be opened eagerly in order to be upcast to the
1513+ // appropriate class reference type before it is passed to the thunk.
1514+ if (!isPartialApplication ||
1515+ (!member->getDeclContext ()->getSelfProtocolDecl () &&
1516+ !isUnboundInstanceMember)) {
14731517 // Open the existential before performing the member reference.
14741518 base = openExistentialReference (base, knownOpened->second , member);
14751519 baseTy = knownOpened->second ;
@@ -1508,13 +1552,15 @@ namespace {
15081552 base, selfParamTy, member,
15091553 locator.withPathElement (ConstraintLocator::MemberRefBase));
15101554 } 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));
1555+ // The base of an unbound reference is unused, and thus a conversion
1556+ // is not necessary.
1557+ if (!isUnboundInstanceMember) {
1558+ if (!isExistentialMetatype || openedExistential) {
1559+ // Convert the base to an rvalue of the appropriate metatype.
1560+ base = coerceToType (
1561+ base, MetatypeType::get (isDynamic ? selfTy : containerTy),
1562+ locator.withPathElement (ConstraintLocator::MemberRefBase));
1563+ }
15181564 }
15191565
15201566 if (!base)
@@ -1635,7 +1681,7 @@ namespace {
16351681 //
16361682 // { self in { args... in self.method(args...) } }(foo)
16371683 //
1638- // This is done instead of just hoising the expression 'foo' up
1684+ // This is done instead of just hoisting the expression 'foo' up
16391685 // into the closure, which would change evaluation order.
16401686 //
16411687 // However, for a super method reference, eg, 'let fn = super.foo',
@@ -1672,17 +1718,28 @@ namespace {
16721718 return closure;
16731719 }
16741720
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>();
1721+ FunctionType *curryThunkTy = nullptr ;
1722+ if (isUnboundInstanceMember) {
1723+ // For an unbound reference to a method, all conversions, including
1724+ // dynamic 'Self' handling, are done within the thunk to support
1725+ // the edge case of an unbound reference to a 'Self'-returning class
1726+ // method on a protocol metatype. The result of calling the method
1727+ // must be downcast to the opened archetype before being erased to the
1728+ // subclass existential to cope with the expectations placed
1729+ // on 'CovariantReturnConversionExpr'.
1730+ curryThunkTy = simplifyType (openedType)->castTo <FunctionType>();
1731+ } else {
1732+ curryThunkTy = refTy->castTo <FunctionType>();
1733+
1734+ // Check if we need to open an existential stored inside 'self'.
1735+ auto knownOpened = solution.OpenedExistentialTypes .find (
1736+ getConstraintSystem ().getConstraintLocator (memberLocator));
1737+ if (knownOpened != solution.OpenedExistentialTypes .end ()) {
1738+ curryThunkTy =
1739+ curryThunkTy
1740+ ->typeEraseOpenedArchetypesWithRoot (knownOpened->second , dc)
1741+ ->castTo <FunctionType>();
1742+ }
16861743 }
16871744
16881745 // Replace the DeclRefExpr with a closure expression which SILGen
@@ -1695,7 +1752,10 @@ namespace {
16951752 // implicit function type conversion around the resulting expression,
16961753 // with the destination type having 'Self' swapped for the appropriate
16971754 // replacement type -- usually the base object type.
1698- if (!member->getDeclContext ()->getSelfProtocolDecl ()) {
1755+ //
1756+ // Note: For unbound references this is handled inside the thunk.
1757+ if (!isUnboundInstanceMember &&
1758+ !member->getDeclContext ()->getSelfProtocolDecl ()) {
16991759 if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
17001760 if (func->hasDynamicSelfResult () &&
17011761 !baseTy->getOptionalObjectType ()) {
0 commit comments