@@ -389,15 +389,18 @@ static bool paramIsIUO(Decl *decl, int paramNum) {
389
389
// /
390
390
// / "Specialized" is essentially a form of subtyping, defined below.
391
391
static bool isDeclAsSpecializedAs (TypeChecker &tc, DeclContext *dc,
392
- ValueDecl *decl1, ValueDecl *decl2) {
392
+ ValueDecl *decl1, ValueDecl *decl2,
393
+ bool isDynamicOverloadComparison = false ) {
393
394
394
395
if (tc.getLangOpts ().DebugConstraintSolver ) {
395
396
auto &log = tc.Context .TypeCheckerDebug ->getStream ();
396
397
log << " Comparing declarations\n " ;
397
398
decl1->print (log);
398
399
log << " \n and\n " ;
399
400
decl2->print (log);
400
- log << " \n " ;
401
+ log << " \n (isDynamicOverloadComparison: " ;
402
+ log << isDynamicOverloadComparison;
403
+ log << " )\n " ;
401
404
}
402
405
403
406
auto *innerDC1 = decl1->getInnermostDeclContext ();
@@ -406,7 +409,9 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
406
409
auto *outerDC1 = decl1->getDeclContext ();
407
410
auto *outerDC2 = decl2->getDeclContext ();
408
411
409
- if (!tc.specializedOverloadComparisonCache .count ({decl1, decl2})) {
412
+ auto overloadComparisonKey =
413
+ std::make_tuple (decl1, decl2, isDynamicOverloadComparison);
414
+ if (!tc.specializedOverloadComparisonCache .count (overloadComparisonKey)) {
410
415
411
416
auto compareSpecializations = [&] () -> bool {
412
417
// If the kinds are different, there's nothing we can do.
@@ -451,7 +456,21 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
451
456
// exactly one member is in a protocol extension). Only apply this rule in
452
457
// Swift 5 mode to better maintain source compatibility under Swift 4
453
458
// mode.
454
- if (tc.Context .isSwiftVersionAtLeast (5 )) {
459
+ //
460
+ // Don't apply this rule when comparing two overloads found through
461
+ // dynamic lookup to ensure we keep cases like this ambiguous:
462
+ //
463
+ // @objc protocol P {
464
+ // var i: String { get }
465
+ // }
466
+ // class C {
467
+ // @objc var i: Int { return 0 }
468
+ // }
469
+ // func foo(_ x: AnyObject) {
470
+ // x.i // ensure ambiguous.
471
+ // }
472
+ //
473
+ if (tc.Context .isSwiftVersionAtLeast (5 ) && !isDynamicOverloadComparison) {
455
474
auto *proto1 = dyn_cast<ProtocolDecl>(outerDC1);
456
475
auto *proto2 = dyn_cast<ProtocolDecl>(outerDC2);
457
476
if (proto1 != proto2)
@@ -709,21 +728,21 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
709
728
return false ;
710
729
};
711
730
712
- tc.specializedOverloadComparisonCache [{decl1, decl2} ] =
731
+ tc.specializedOverloadComparisonCache [overloadComparisonKey ] =
713
732
compareSpecializations ();
714
733
} else if (tc.getLangOpts ().DebugConstraintSolver ) {
715
734
auto &log = tc.Context .TypeCheckerDebug ->getStream ();
716
- log << " Found cached comparison: "
717
- << tc.specializedOverloadComparisonCache [{decl1, decl2} ] << " \n " ;
735
+ log << " Found cached comparison: "
736
+ << tc.specializedOverloadComparisonCache [overloadComparisonKey ] << " \n " ;
718
737
}
719
738
720
739
if (tc.getLangOpts ().DebugConstraintSolver ) {
721
740
auto &log = tc.Context .TypeCheckerDebug ->getStream ();
722
- auto result = tc.specializedOverloadComparisonCache [{decl1, decl2} ];
741
+ auto result = tc.specializedOverloadComparisonCache [overloadComparisonKey ];
723
742
log << " comparison result: " << (result ? " better" : " not better" ) << " \n " ;
724
743
}
725
744
726
- return tc.specializedOverloadComparisonCache [{decl1, decl2} ];
745
+ return tc.specializedOverloadComparisonCache [overloadComparisonKey ];
727
746
}
728
747
729
748
Comparison TypeChecker::compareDeclarations (DeclContext *dc,
@@ -861,15 +880,23 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
861
880
case OverloadChoiceKind::DynamicMemberLookup:
862
881
break ;
863
882
}
864
-
883
+
884
+ // We don't apply some ranking rules to overloads found through dynamic
885
+ // lookup in order to keep a few potentially ill-formed cases ambiguous.
886
+ bool isDynamicOverloadComparison =
887
+ choice1.getKind () == OverloadChoiceKind::DeclViaDynamic &&
888
+ choice2.getKind () == OverloadChoiceKind::DeclViaDynamic;
889
+
865
890
// Determine whether one declaration is more specialized than the other.
866
891
bool firstAsSpecializedAs = false ;
867
892
bool secondAsSpecializedAs = false ;
868
- if (isDeclAsSpecializedAs (tc, cs.DC , decl1, decl2)) {
893
+ if (isDeclAsSpecializedAs (tc, cs.DC , decl1, decl2,
894
+ isDynamicOverloadComparison)) {
869
895
score1 += weight;
870
896
firstAsSpecializedAs = true ;
871
897
}
872
- if (isDeclAsSpecializedAs (tc, cs.DC , decl2, decl1)) {
898
+ if (isDeclAsSpecializedAs (tc, cs.DC , decl2, decl1,
899
+ isDynamicOverloadComparison)) {
873
900
score2 += weight;
874
901
secondAsSpecializedAs = true ;
875
902
}
0 commit comments