mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ConstraintSystem] Narrowly disable tryOptimizeGenericDisjunction when some of the arguments are number literals
Don't attempt this optimization if call has number literals.
This is intended to narrowly fix situations like:
```swift
func test<T: FloatingPoint>(_: T) { ... }
func test<T: Numeric>(_: T) { ... }
test(42)
```
The call should use `<T: Numeric>` overload even though the
`<T: FloatingPoint>` is a more specialized version because
selecting `<T: Numeric>` doesn't introduce non-default literal
types.
This commit is contained in:
@@ -497,6 +497,10 @@ public:
|
||||
/// literal (represented by `ArrayExpr` and `DictionaryExpr` in AST).
|
||||
bool isCollectionLiteralType() const;
|
||||
|
||||
/// Determine whether this type variable represents a literal such
|
||||
/// as an integer value, a floating-point value with and without a sign.
|
||||
bool isNumberLiteralType() const;
|
||||
|
||||
/// Determine whether this type variable represents a result type of a
|
||||
/// function call.
|
||||
bool isFunctionResult() const;
|
||||
|
||||
@@ -1402,6 +1402,27 @@ tryOptimizeGenericDisjunction(ConstraintSystem &cs, Constraint *disjunction,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Don't attempt this optimization if call has number literals.
|
||||
// This is intended to narrowly fix situations like:
|
||||
//
|
||||
// func test<T: FloatingPoint>(_: T) { ... }
|
||||
// func test<T: Numeric>(_: T) { ... }
|
||||
//
|
||||
// test(42)
|
||||
//
|
||||
// The call should use `<T: Numeric>` overload even though the
|
||||
// `<T: FloatingPoint>` is a more specialized version because
|
||||
// selecting `<T: Numeric>` doesn't introduce non-default literal
|
||||
// types.
|
||||
if (auto *argFnType = cs.getAppliedDisjunctionArgumentFunction(disjunction)) {
|
||||
if (llvm::any_of(
|
||||
argFnType->getParams(), [](const AnyFunctionType::Param ¶m) {
|
||||
auto *typeVar = param.getPlainType()->getAs<TypeVariableType>();
|
||||
return typeVar && typeVar->getImpl().isNumberLiteralType();
|
||||
}))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::SmallVector<Constraint *, 4> choices;
|
||||
for (auto *choice : constraints) {
|
||||
if (choices.size() > 2)
|
||||
|
||||
@@ -204,6 +204,10 @@ bool TypeVariableType::Implementation::isCollectionLiteralType() const {
|
||||
locator->directlyAt<DictionaryExpr>());
|
||||
}
|
||||
|
||||
bool TypeVariableType::Implementation::isNumberLiteralType() const {
|
||||
return locator && locator->directlyAt<NumberLiteralExpr>();
|
||||
}
|
||||
|
||||
bool TypeVariableType::Implementation::isFunctionResult() const {
|
||||
return locator && locator->isLastElement<LocatorPathElt::FunctionResult>();
|
||||
}
|
||||
|
||||
@@ -178,3 +178,12 @@ do {
|
||||
}
|
||||
}
|
||||
|
||||
// `tryOptimizeGenericDisjunction` is too aggressive sometimes, make sure that `<T: FloatingPoint>`
|
||||
// overload is _not_ selected in this case.
|
||||
do {
|
||||
func test<T: FloatingPoint>(_ expression1: @autoclosure () throws -> T, accuracy: T) -> T {}
|
||||
func test<T: Numeric>(_ expression1: @autoclosure () throws -> T, accuracy: T) -> T {}
|
||||
|
||||
let result = test(10, accuracy: 1)
|
||||
let _: Int = result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user