@@ -4019,6 +4019,47 @@ static bool isForKeyPathSubscript(ConstraintSystem &cs,
4019
4019
return false ;
4020
4020
}
4021
4021
4022
+ // / Determine whether all of the given candidate overloads
4023
+ // / found through conditional conformances of a given base type.
4024
+ // / This is useful to figure out whether it makes sense to
4025
+ // / perform dynamic member lookup or not.
4026
+ static bool
4027
+ allFromConditionalConformances (DeclContext *DC, Type baseTy,
4028
+ ArrayRef<OverloadChoice> candidates) {
4029
+ auto *NTD = baseTy->getAnyNominal ();
4030
+ if (!NTD)
4031
+ return false ;
4032
+
4033
+ return llvm::all_of (candidates, [&](const OverloadChoice &choice) {
4034
+ auto *decl = choice.getDeclOrNull ();
4035
+ if (!decl)
4036
+ return false ;
4037
+
4038
+ auto *candidateDC = decl->getDeclContext ();
4039
+
4040
+ if (auto *extension = dyn_cast<ExtensionDecl>(candidateDC)) {
4041
+ if (extension->isConstrainedExtension ())
4042
+ return true ;
4043
+ }
4044
+
4045
+ if (auto *protocol = candidateDC->getSelfProtocolDecl ()) {
4046
+ SmallVector<ProtocolConformance *, 4 > conformances;
4047
+ if (!NTD->lookupConformance (DC->getParentModule (), protocol,
4048
+ conformances))
4049
+ return false ;
4050
+
4051
+ // This is opportunistic, there should be a way to narrow the
4052
+ // list down to a particular declaration member comes from.
4053
+ return llvm::any_of (
4054
+ conformances, [](const ProtocolConformance *conformance) {
4055
+ return !conformance->getConditionalRequirements ().empty ();
4056
+ });
4057
+ }
4058
+
4059
+ return false ;
4060
+ });
4061
+ }
4062
+
4022
4063
// / Given a ValueMember, UnresolvedValueMember, or TypeMember constraint,
4023
4064
// / perform a lookup into the specified base type to find a candidate list.
4024
4065
// / The list returned includes the viable candidates as well as the unviable
@@ -4479,30 +4520,32 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
4479
4520
}
4480
4521
}
4481
4522
}
4482
-
4483
- // If we're about to fail lookup, but we are looking for members in a type
4484
- // with the @dynamicMemberLookup attribute, then we resolve a reference
4485
- // to a `subscript(dynamicMember:)` method and pass the member name as a
4486
- // string parameter.
4487
- if (result.ViableCandidates .empty () &&
4488
- constraintKind == ConstraintKind::ValueMember &&
4489
- memberName.isSimpleName () && !memberName.isSpecial ()) {
4490
- auto name = memberName.getBaseIdentifier ();
4491
- if (::hasDynamicMemberLookupAttribute (instanceTy,
4492
- DynamicMemberLookupCache)) {
4523
+
4524
+ // If we're about to fail lookup because there are no viable candidates
4525
+ // or if all of the candidates come from conditional conformances (which
4526
+ // might not be applicable), and we are looking for members in a type with
4527
+ // the @dynamicMemberLookup attribute, then we resolve a reference to a
4528
+ // `subscript(dynamicMember:)` method and pass the member name as a string
4529
+ // parameter.
4530
+ if (constraintKind == ConstraintKind::ValueMember &&
4531
+ memberName.isSimpleName () && !memberName.isSpecial () &&
4532
+ ::hasDynamicMemberLookupAttribute (instanceTy, DynamicMemberLookupCache)) {
4533
+ const auto &candidates = result.ViableCandidates ;
4534
+
4535
+ if (candidates.empty () ||
4536
+ allFromConditionalConformances (DC, instanceTy, candidates)) {
4493
4537
auto &ctx = getASTContext ();
4494
4538
4495
4539
// Recursively look up `subscript(dynamicMember:)` methods in this type.
4496
4540
auto subscriptName =
4497
- DeclName (ctx, DeclBaseName::createSubscript (), ctx.Id_dynamicMember );
4498
- auto subscripts = performMemberLookup (constraintKind,
4499
- subscriptName,
4500
- baseTy, functionRefKind,
4501
- memberLocator,
4502
- includeInaccessibleMembers);
4541
+ DeclName (ctx, DeclBaseName::createSubscript (), ctx.Id_dynamicMember );
4542
+ auto subscripts = performMemberLookup (
4543
+ constraintKind, subscriptName, baseTy, functionRefKind, memberLocator,
4544
+ includeInaccessibleMembers);
4503
4545
4504
4546
// Reflect the candidates found as `DynamicMemberLookup` results.
4505
- for (auto candidate : subscripts.ViableCandidates ) {
4547
+ auto name = memberName.getBaseIdentifier ();
4548
+ for (const auto &candidate : subscripts.ViableCandidates ) {
4506
4549
auto *SD = cast<SubscriptDecl>(candidate.getDecl ());
4507
4550
bool isKeyPathBased = isValidKeyPathDynamicMemberLookup (SD, TC);
4508
4551
@@ -4512,9 +4555,10 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
4512
4555
}
4513
4556
4514
4557
for (auto index : indices (subscripts.UnviableCandidates )) {
4515
- auto *SD = cast<SubscriptDecl>(subscripts.UnviableCandidates [index].getDecl ());
4558
+ auto *SD =
4559
+ cast<SubscriptDecl>(subscripts.UnviableCandidates [index].getDecl ());
4516
4560
auto choice = OverloadChoice::getDynamicMemberLookup (
4517
- baseTy, SD, name, isValidKeyPathDynamicMemberLookup (SD, TC));
4561
+ baseTy, SD, name, isValidKeyPathDynamicMemberLookup (SD, TC));
4518
4562
result.addUnviable (choice, subscripts.UnviableReasons [index]);
4519
4563
}
4520
4564
}
0 commit comments