@@ -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,8 @@ 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
+ if (!tc.specializedOverloadComparisonCache .count (
413
+ {decl1, decl2, isDynamicOverloadComparison})) {
410
414
411
415
auto compareSpecializations = [&] () -> bool {
412
416
// If the kinds are different, there's nothing we can do.
@@ -451,7 +455,21 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
451
455
// exactly one member is in a protocol extension). Only apply this rule in
452
456
// Swift 5 mode to better maintain source compatibility under Swift 4
453
457
// mode.
454
- if (tc.Context .isSwiftVersionAtLeast (5 )) {
458
+ //
459
+ // Don't apply this rule when comparing two overloads found through
460
+ // dynamic lookup to ensure we keep cases like this ambiguous:
461
+ //
462
+ // @objc protocol P {
463
+ // var i: String { get }
464
+ // }
465
+ // class C {
466
+ // @objc var i: Int { return 0 }
467
+ // }
468
+ // func foo(_ x: AnyObject) {
469
+ // x.i // ensure ambiguous.
470
+ // }
471
+ //
472
+ if (tc.Context .isSwiftVersionAtLeast (5 ) && !isDynamicOverloadComparison) {
455
473
auto *proto1 = dyn_cast<ProtocolDecl>(outerDC1);
456
474
auto *proto2 = dyn_cast<ProtocolDecl>(outerDC2);
457
475
if (proto1 != proto2)
@@ -709,21 +727,25 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
709
727
return false ;
710
728
};
711
729
712
- tc.specializedOverloadComparisonCache [{decl1, decl2}] =
713
- compareSpecializations ();
730
+ tc.specializedOverloadComparisonCache [{
731
+ decl1, decl2, isDynamicOverloadComparison}] = compareSpecializations ();
714
732
} else if (tc.getLangOpts ().DebugConstraintSolver ) {
715
733
auto &log = tc.Context .TypeCheckerDebug ->getStream ();
716
- log << " Found cached comparison: "
717
- << tc.specializedOverloadComparisonCache [{decl1, decl2}] << " \n " ;
734
+ log << " Found cached comparison: "
735
+ << tc.specializedOverloadComparisonCache [{decl1, decl2,
736
+ isDynamicOverloadComparison}]
737
+ << " \n " ;
718
738
}
719
739
720
740
if (tc.getLangOpts ().DebugConstraintSolver ) {
721
741
auto &log = tc.Context .TypeCheckerDebug ->getStream ();
722
- auto result = tc.specializedOverloadComparisonCache [{decl1, decl2}];
742
+ auto result = tc.specializedOverloadComparisonCache [{
743
+ decl1, decl2, isDynamicOverloadComparison}];
723
744
log << " comparison result: " << (result ? " better" : " not better" ) << " \n " ;
724
745
}
725
746
726
- return tc.specializedOverloadComparisonCache [{decl1, decl2}];
747
+ return tc.specializedOverloadComparisonCache [{decl1, decl2,
748
+ isDynamicOverloadComparison}];
727
749
}
728
750
729
751
Comparison TypeChecker::compareDeclarations (DeclContext *dc,
@@ -864,15 +886,23 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
864
886
case OverloadChoiceKind::DynamicMemberLookup:
865
887
break ;
866
888
}
867
-
889
+
890
+ // We don't apply some ranking rules to overloads found through dynamic
891
+ // lookup in order to keep a few potentially ill-formed cases ambiguous.
892
+ bool isDynamicOverloadComparison =
893
+ choice1.getKind () == OverloadChoiceKind::DeclViaDynamic &&
894
+ choice2.getKind () == OverloadChoiceKind::DeclViaDynamic;
895
+
868
896
// Determine whether one declaration is more specialized than the other.
869
897
bool firstAsSpecializedAs = false ;
870
898
bool secondAsSpecializedAs = false ;
871
- if (isDeclAsSpecializedAs (tc, cs.DC , decl1, decl2)) {
899
+ if (isDeclAsSpecializedAs (tc, cs.DC , decl1, decl2,
900
+ isDynamicOverloadComparison)) {
872
901
score1 += weight;
873
902
firstAsSpecializedAs = true ;
874
903
}
875
- if (isDeclAsSpecializedAs (tc, cs.DC , decl2, decl1)) {
904
+ if (isDeclAsSpecializedAs (tc, cs.DC , decl2, decl1,
905
+ isDynamicOverloadComparison)) {
876
906
score2 += weight;
877
907
secondAsSpecializedAs = true ;
878
908
}
0 commit comments