@@ -802,6 +802,9 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
802
802
bool isStdlibOptionalMPlusOperator1 = false ;
803
803
bool isStdlibOptionalMPlusOperator2 = false ;
804
804
805
+ bool isVarAndNotProtocol1 = false ;
806
+ bool isVarAndNotProtocol2 = false ;
807
+
805
808
auto getWeight = [&](ConstraintLocator *locator) -> unsigned {
806
809
if (auto *anchor = locator->getAnchor ()) {
807
810
auto weight = weights.find (anchor);
@@ -1016,6 +1019,32 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
1016
1019
}
1017
1020
}
1018
1021
1022
+ // Swift 4.1 compatibility hack: If everything else is considered equal,
1023
+ // favour a property on a concrete type over a protocol property member.
1024
+ //
1025
+ // This hack is required due to changes in shadowing behaviour where a
1026
+ // protocol property member will no longer shadow a property on a concrete
1027
+ // type, which created unintentional ambiguities in 4.2. This hack ensures
1028
+ // we at least keep these cases unambiguous in Swift 5 under Swift 4
1029
+ // compatibility mode. Don't however apply this hack for decls found through
1030
+ // dynamic lookup, as we want the user to have to disambiguate those.
1031
+ //
1032
+ // This is intentionally narrow in order to best preserve source
1033
+ // compatibility under Swift 4 mode by ensuring we don't introduce any new
1034
+ // ambiguities. This will become a more general "is more specialised" rule
1035
+ // in Swift 5 mode.
1036
+ if (!tc.Context .isSwiftVersionAtLeast (5 ) &&
1037
+ choice1.getKind () != OverloadChoiceKind::DeclViaDynamic &&
1038
+ choice2.getKind () != OverloadChoiceKind::DeclViaDynamic &&
1039
+ isa<VarDecl>(decl1) && isa<VarDecl>(decl2)) {
1040
+ auto *nominal1 = dc1->getSelfNominalTypeDecl ();
1041
+ auto *nominal2 = dc2->getSelfNominalTypeDecl ();
1042
+ if (nominal1 && nominal2 && nominal1 != nominal2) {
1043
+ isVarAndNotProtocol1 = !isa<ProtocolDecl>(nominal1);
1044
+ isVarAndNotProtocol2 = !isa<ProtocolDecl>(nominal2);
1045
+ }
1046
+ }
1047
+
1019
1048
// FIXME: Lousy hack for ?? to prefer the catamorphism (flattening)
1020
1049
// over the mplus (non-flattening) overload if all else is equal.
1021
1050
if (decl1->getBaseName () == " ??" ) {
@@ -1172,6 +1201,14 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
1172
1201
score1 += isStdlibOptionalMPlusOperator2;
1173
1202
}
1174
1203
1204
+ // All other things being equal, apply the Swift 4.1 compatibility hack for
1205
+ // preferring var members in concrete types over a protocol requirement
1206
+ // (see the comment above for the rationale of this hack).
1207
+ if (!tc.Context .isSwiftVersionAtLeast (5 ) && score1 == score2) {
1208
+ score1 += isVarAndNotProtocol1;
1209
+ score2 += isVarAndNotProtocol2;
1210
+ }
1211
+
1175
1212
// FIXME: There are type variables and overloads not common to both solutions
1176
1213
// that haven't been considered. They make the systems different, but don't
1177
1214
// affect ranking. We need to handle this.
0 commit comments