Skip to content

Commit ac24a8e

Browse files
committed
[CSOptimizer] Introduce _OptionalNilComparisonType as candidate for nil while ranking == and != operators
`==` and `!=` operators have special overloads that allow matching `nil` literal on either side even if wrapped type on the other side doesn't conform to `Equatable`.
1 parent aedc4fe commit ac24a8e

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

include/swift/AST/KnownStdlibTypes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ KNOWN_STDLIB_TYPE_DECL(WritableKeyPath, NominalTypeDecl, 2)
7070
KNOWN_STDLIB_TYPE_DECL(ReferenceWritableKeyPath, NominalTypeDecl, 2)
7171

7272
KNOWN_STDLIB_TYPE_DECL(Optional, EnumDecl, 1)
73+
KNOWN_STDLIB_TYPE_DECL(_OptionalNilComparisonType, NominalTypeDecl, 0)
7374

7475
KNOWN_STDLIB_TYPE_DECL(OptionSet, NominalTypeDecl, 1)
7576

lib/Sema/CSOptimizer.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ static bool isStandardComparisonOperator(ValueDecl *decl) {
113113
decl->getBaseIdentifier().isStandardComparisonOperator();
114114
}
115115

116+
static bool isOperatorNamed(Constraint *disjunction, StringRef name) {
117+
auto *choice = disjunction->getNestedConstraints()[0];
118+
if (auto *decl = getOverloadChoiceDecl(choice))
119+
return decl->isOperator() && decl->getBaseIdentifier().is(name);
120+
return false;
121+
}
122+
116123
static bool isArithmeticOperator(ValueDecl *decl) {
117124
return decl->isOperator() && decl->getBaseIdentifier().isArithmeticOperator();
118125
}
@@ -622,6 +629,19 @@ static void determineBestChoicesInContext(
622629
optionals.size());
623630
types.push_back({type,
624631
/*fromLiteral=*/true});
632+
} else if (literal.first ==
633+
cs.getASTContext().getProtocol(
634+
KnownProtocolKind::ExpressibleByNilLiteral) &&
635+
literal.second.IsDirectRequirement) {
636+
// `==` and `!=` operators have special overloads that accept `nil`
637+
// as `_OptionalNilComparisonType` which is preferred over a
638+
// generic form `(T?, T?)`.
639+
if (isOperatorNamed(disjunction, "==") ||
640+
isOperatorNamed(disjunction, "!=")) {
641+
auto nilComparisonTy =
642+
cs.getASTContext().get_OptionalNilComparisonTypeType();
643+
types.push_back({nilComparisonTy, /*fromLiteral=*/true});
644+
}
625645
}
626646
}
627647

0 commit comments

Comments
 (0)