@@ -902,11 +902,10 @@ namespace {
902902 bool shouldBuildCurryThunk (OverloadChoice choice,
903903 bool baseIsInstance) {
904904 ValueDecl *member = choice.getDecl ();
905- auto isDynamic = choice.getKind () == OverloadChoiceKind::DeclViaDynamic;
906905
907906 // FIXME: We should finish plumbing this through for dynamic
908907 // lookup as well.
909- if (isDynamic || member-> getAttrs (). hasAttribute <OptionalAttr>() )
908+ if (choice. getKind () == OverloadChoiceKind::DeclViaDynamic )
910909 return false ;
911910
912911 // If we're inside a selector expression, don't build the thunk.
@@ -922,6 +921,11 @@ namespace {
922921 if (!baseIsInstance && member->isInstanceMember ())
923922 return true ;
924923
924+ // Bound optional method references are represented via
925+ // DynamicMemberRefExpr instead of a curry thunk.
926+ if (member->getAttrs ().hasAttribute <OptionalAttr>())
927+ return false ;
928+
925929 // Figure out how many argument lists we need.
926930 unsigned maxArgCount = member->getNumCurryLevels ();
927931
@@ -1224,7 +1228,8 @@ namespace {
12241228 AutoClosureExpr *
12251229 buildDoubleCurryThunk (DeclRefExpr *memberRef, ValueDecl *member,
12261230 FunctionType *outerThunkTy,
1227- ConstraintLocatorBuilder memberLocator) {
1231+ ConstraintLocatorBuilder memberLocator,
1232+ DeclNameLoc memberLoc, bool isDynamicLookup) {
12281233 auto &ctx = cs.getASTContext ();
12291234
12301235 const auto selfThunkParam = outerThunkTy->getParams ().front ();
@@ -1256,15 +1261,15 @@ namespace {
12561261 cs.cacheType (selfParamRef);
12571262 }
12581263
1259- const auto selfCalleeParam =
1260- cs. getType (memberRef)-> castTo <FunctionType>() ->getParams ().front ();
1264+ auto * const selfCalleeTy = cs. getType (memberRef)-> castTo <FunctionType>();
1265+ const auto selfCalleeParam = selfCalleeTy ->getParams ().front ();
12611266 const auto selfCalleeParamTy = selfCalleeParam.getPlainType ();
12621267
12631268 // Open the 'self' parameter reference if warranted.
12641269 Expr *selfOpenedRef = selfParamRef;
12651270 if (selfCalleeParamTy->hasOpenedExistential ()) {
12661271 // If we're opening an existential:
1267- // - The type of 'ref ' inside the thunk is written in terms of the
1272+ // - The type of 'memberRef ' inside the thunk is written in terms of the
12681273 // open existental archetype.
12691274 // - The type of the thunk is written in terms of the
12701275 // erased existential bounds.
@@ -1281,25 +1286,56 @@ namespace {
12811286 adjustExprOwnershipForParam (selfParamRef, selfThunkParam);
12821287 }
12831288
1284- // The inner thunk, "{ args... in self.member(args...) }".
1285- auto *const innerThunk = buildSingleCurryThunk (
1286- selfOpenedRef, memberRef, cast<DeclContext>(member),
1287- outerThunkTy->getResult ()->castTo <FunctionType>(), memberLocator);
1288-
1289- // Rewrite the body to close the existential if warranted.
1290- if (selfCalleeParamTy->hasOpenedExistential ()) {
1291- auto *body = innerThunk->getSingleExpressionBody ();
1292- body = new (ctx) OpenExistentialExpr (
1293- selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef), body,
1294- body->getType ());
1295- cs.cacheType (body);
1289+ Expr *outerThunkBody = nullptr ;
1290+
1291+ // For an @objc optional member or a member found via dynamic lookup,
1292+ // build a dynamic member reference. Otherwise, build a nested
1293+ // "{ args... in self.member(args...) }" thunk that calls the member.
1294+ if (isDynamicLookup || member->getAttrs ().hasAttribute <OptionalAttr>()) {
1295+ outerThunkBody = new (ctx) DynamicMemberRefExpr (
1296+ selfOpenedRef, SourceLoc (),
1297+ resolveConcreteDeclRef (member, memberLocator), memberLoc);
1298+ outerThunkBody->setImplicit (true );
1299+ outerThunkBody->setType (selfCalleeTy->getResult ());
1300+ cs.cacheType (outerThunkBody);
1301+
1302+ outerThunkBody = coerceToType (outerThunkBody, outerThunkTy->getResult (),
1303+ memberLocator);
1304+
1305+ // Close the existential if warranted.
1306+ if (selfCalleeParamTy->hasOpenedExistential ()) {
1307+ // If the callee's 'self' parameter has non-trivial ownership, adjust
1308+ // the argument type accordingly.
1309+ adjustExprOwnershipForParam (selfOpenedRef, selfCalleeParam);
1310+
1311+ outerThunkBody = new (ctx) OpenExistentialExpr (
1312+ selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef),
1313+ outerThunkBody, outerThunkBody->getType ());
1314+ cs.cacheType (outerThunkBody);
1315+ }
1316+ } else {
1317+ auto *innerThunk = buildSingleCurryThunk (
1318+ selfOpenedRef, memberRef, cast<DeclContext>(member),
1319+ outerThunkTy->getResult ()->castTo <FunctionType>(), memberLocator);
1320+
1321+ // Rewrite the body to close the existential if warranted.
1322+ if (selfCalleeParamTy->hasOpenedExistential ()) {
1323+ auto *body = innerThunk->getSingleExpressionBody ();
1324+ body = new (ctx) OpenExistentialExpr (
1325+ selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef), body,
1326+ body->getType ());
1327+ cs.cacheType (body);
1328+
1329+ innerThunk->setBody (body);
1330+ }
12961331
1297- innerThunk-> setBody (body) ;
1332+ outerThunkBody = innerThunk;
12981333 }
12991334
13001335 // Finally, construct the outer thunk.
1301- auto outerThunk = new (ctx) AutoClosureExpr (
1302- innerThunk, outerThunkTy, AutoClosureExpr::InvalidDiscriminator, dc);
1336+ auto *outerThunk =
1337+ new (ctx) AutoClosureExpr (outerThunkBody, outerThunkTy,
1338+ AutoClosureExpr::InvalidDiscriminator, dc);
13031339 outerThunk->setThunkKind (AutoClosureExpr::Kind::DoubleCurryThunk);
13041340 outerThunk->setParameterList (
13051341 ParameterList::create (ctx, SourceLoc (), selfParamDecl, SourceLoc ()));
@@ -1488,8 +1524,28 @@ namespace {
14881524 }
14891525 assert (base && " Unable to convert base?" );
14901526
1491- // Handle dynamic references.
14921527 if (isDynamic || member->getAttrs ().hasAttribute <OptionalAttr>()) {
1528+ // If the @objc attribute was inferred based on deprecated Swift 3
1529+ // rules, complain at this use site.
1530+ if (auto attr = member->getAttrs ().getAttribute <ObjCAttr>()) {
1531+ if (attr->isSwift3Inferred () &&
1532+ context.LangOpts .WarnSwift3ObjCInference ==
1533+ Swift3ObjCInferenceWarnings::Minimal) {
1534+ context.Diags .diagnose (
1535+ memberLoc, diag::expr_dynamic_lookup_swift3_objc_inference,
1536+ member->getDescriptiveKind (), member->getName (),
1537+ member->getDeclContext ()->getSelfNominalTypeDecl ()->getName ());
1538+ context.Diags
1539+ .diagnose (member, diag::make_decl_objc,
1540+ member->getDescriptiveKind ())
1541+ .fixItInsert (member->getAttributeInsertionLoc (false ), " @objc " );
1542+ }
1543+ }
1544+ }
1545+
1546+ // Handle dynamic references.
1547+ if (isDynamic || (!isPartialApplication &&
1548+ member->getAttrs ().hasAttribute <OptionalAttr>())) {
14931549 base = cs.coerceToRValue (base);
14941550 Expr *ref = new (context) DynamicMemberRefExpr (base, dotLoc, memberRef,
14951551 memberLoc);
@@ -1510,23 +1566,6 @@ namespace {
15101566
15111567 closeExistentials (ref, locator, /* force=*/ openedExistential);
15121568
1513- // If this attribute was inferred based on deprecated Swift 3 rules,
1514- // complain.
1515- if (auto attr = member->getAttrs ().getAttribute <ObjCAttr>()) {
1516- if (attr->isSwift3Inferred () &&
1517- context.LangOpts .WarnSwift3ObjCInference ==
1518- Swift3ObjCInferenceWarnings::Minimal) {
1519- context.Diags .diagnose (
1520- memberLoc, diag::expr_dynamic_lookup_swift3_objc_inference,
1521- member->getDescriptiveKind (), member->getName (),
1522- member->getDeclContext ()->getSelfNominalTypeDecl ()->getName ());
1523- context.Diags
1524- .diagnose (member, diag::make_decl_objc,
1525- member->getDescriptiveKind ())
1526- .fixItInsert (member->getAttributeInsertionLoc (false ), " @objc " );
1527- }
1528- }
1529-
15301569 // We also need to handle the implicitly unwrap of the result
15311570 // of the called function if that's the type checking solution
15321571 // we ended up with.
@@ -1649,7 +1688,7 @@ namespace {
16491688 // Replace the DeclRefExpr with a closure expression which SILGen
16501689 // knows how to emit.
16511690 ref = buildDoubleCurryThunk (declRefExpr, member, curryThunkTy,
1652- memberLocator);
1691+ memberLocator, memberLoc, isDynamic );
16531692 }
16541693
16551694 // If the member is a method with a dynamic 'Self' result type, wrap an
0 commit comments