[ConstraintSystem] C++ Interop: Binding a string literal to std.string shouldn't increase the score

Since this is a C++ stdlib type we need make sure that any overloads
that use it are preferred over custom types that also conform to
`ExpressibleByStringLiteral` when argument is a string literal.

This is important for operators like `==` which could be heterogenous
and have a custom C++ type that conforms to `ExpressibleByStringLiteral`
on either side together with `std.string` i.e.
`==(std.string, const CustomString &)`, such overloads should only
be selected if argument passed to `CustomString` is non-literal because
literals are convered by a stdlib `==(std.string, std.string)` overload.
This commit is contained in:
Pavel Yaskevich
2025-07-24 00:45:11 -07:00
parent 2e8f74f011
commit cd9c37cac6
6 changed files with 75 additions and 4 deletions

View File

@@ -256,11 +256,28 @@ void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
// If the protocol has a default type, check it.
if (auto defaultType = TypeChecker::getDefaultType(literalProtocol, DC)) {
// Check whether the nominal types match. This makes sure that we
// properly handle Array vs. Array<T>.
if (defaultType->getAnyNominal() != type->getAnyNominal()) {
auto isDefaultType = [&literalProtocol, &defaultType](Type type) {
// Treat `std.string` as a default type just like we do
// Swift standard library `String`. This helps to disambiguate
// operator overloads that use `std.string` vs. a custom C++
// type that conforms to `ExpressibleByStringLiteral` as well.
//
// This doesn't clash with String because inference won't attempt
// C++ types unless we discover them from a constraint and the
// optimizer and old hacks always prefer the actual default type.
if (literalProtocol->getKnownProtocolKind() ==
KnownProtocolKind::ExpressibleByStringLiteral &&
type->isCxxString()) {
return true;
}
// Check whether the nominal types match. This makes sure that we
// properly handle Array vs. Array<T>.
return defaultType->getAnyNominal() == type->getAnyNominal();
};
if (!isDefaultType(type))
increaseScore(SK_NonDefaultLiteral, locator);
}
}
break;