@@ -902,11 +902,10 @@ namespace {
902
902
bool shouldBuildCurryThunk (OverloadChoice choice,
903
903
bool baseIsInstance) {
904
904
ValueDecl *member = choice.getDecl ();
905
- auto isDynamic = choice.getKind () == OverloadChoiceKind::DeclViaDynamic;
906
905
907
906
// FIXME: We should finish plumbing this through for dynamic
908
907
// lookup as well.
909
- if (isDynamic || member-> getAttrs (). hasAttribute <OptionalAttr>() )
908
+ if (choice. getKind () == OverloadChoiceKind::DeclViaDynamic )
910
909
return false ;
911
910
912
911
// If we're inside a selector expression, don't build the thunk.
@@ -922,6 +921,11 @@ namespace {
922
921
if (!baseIsInstance && member->isInstanceMember ())
923
922
return true ;
924
923
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
+
925
929
// Figure out how many argument lists we need.
926
930
unsigned maxArgCount = member->getNumCurryLevels ();
927
931
@@ -1224,7 +1228,8 @@ namespace {
1224
1228
AutoClosureExpr *
1225
1229
buildDoubleCurryThunk (DeclRefExpr *memberRef, ValueDecl *member,
1226
1230
FunctionType *outerThunkTy,
1227
- ConstraintLocatorBuilder memberLocator) {
1231
+ ConstraintLocatorBuilder memberLocator,
1232
+ DeclNameLoc memberLoc, bool isDynamicLookup) {
1228
1233
auto &ctx = cs.getASTContext ();
1229
1234
1230
1235
const auto selfThunkParam = outerThunkTy->getParams ().front ();
@@ -1256,15 +1261,15 @@ namespace {
1256
1261
cs.cacheType (selfParamRef);
1257
1262
}
1258
1263
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 ();
1261
1266
const auto selfCalleeParamTy = selfCalleeParam.getPlainType ();
1262
1267
1263
1268
// Open the 'self' parameter reference if warranted.
1264
1269
Expr *selfOpenedRef = selfParamRef;
1265
1270
if (selfCalleeParamTy->hasOpenedExistential ()) {
1266
1271
// 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
1268
1273
// open existental archetype.
1269
1274
// - The type of the thunk is written in terms of the
1270
1275
// erased existential bounds.
@@ -1281,25 +1286,56 @@ namespace {
1281
1286
adjustExprOwnershipForParam (selfParamRef, selfThunkParam);
1282
1287
}
1283
1288
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
+ }
1296
1331
1297
- innerThunk-> setBody (body) ;
1332
+ outerThunkBody = innerThunk;
1298
1333
}
1299
1334
1300
1335
// 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);
1303
1339
outerThunk->setThunkKind (AutoClosureExpr::Kind::DoubleCurryThunk);
1304
1340
outerThunk->setParameterList (
1305
1341
ParameterList::create (ctx, SourceLoc (), selfParamDecl, SourceLoc ()));
@@ -1488,8 +1524,28 @@ namespace {
1488
1524
}
1489
1525
assert (base && " Unable to convert base?" );
1490
1526
1491
- // Handle dynamic references.
1492
1527
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>())) {
1493
1549
base = cs.coerceToRValue (base);
1494
1550
Expr *ref = new (context) DynamicMemberRefExpr (base, dotLoc, memberRef,
1495
1551
memberLoc);
@@ -1510,23 +1566,6 @@ namespace {
1510
1566
1511
1567
closeExistentials (ref, locator, /* force=*/ openedExistential);
1512
1568
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
-
1530
1569
// We also need to handle the implicitly unwrap of the result
1531
1570
// of the called function if that's the type checking solution
1532
1571
// we ended up with.
@@ -1649,7 +1688,7 @@ namespace {
1649
1688
// Replace the DeclRefExpr with a closure expression which SILGen
1650
1689
// knows how to emit.
1651
1690
ref = buildDoubleCurryThunk (declRefExpr, member, curryThunkTy,
1652
- memberLocator);
1691
+ memberLocator, memberLoc, isDynamic );
1653
1692
}
1654
1693
1655
1694
// If the member is a method with a dynamic 'Self' result type, wrap an
0 commit comments