Skip to content

Commit 8a03ac0

Browse files
committed
[CSOptimizer] Favor choices that don't require application
When disjunction is not applied, don't only bump its score but also favor all of the choices that don't require application because selection algorithm uses that for comparison. This is important for situation when property is overload with a method i.e. `Array.count`.
1 parent 55189ba commit 8a03ac0

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "TypeChecker.h"
18+
#include "swift/AST/ConformanceLookup.h"
1819
#include "swift/AST/ExistentialLayout.h"
1920
#include "swift/AST/GenericSignature.h"
2021
#include "swift/Basic/OptionSet.h"
@@ -61,6 +62,12 @@ static bool isFloatType(Type type) {
6162
return type->isFloat() || type->isDouble() || type->isFloat80();
6263
}
6364

65+
static bool isUnboundArrayType(Type type) {
66+
if (auto *UGT = type->getAs<UnboundGenericType>())
67+
return UGT->getDecl() == type->getASTContext().getArrayDecl();
68+
return false;
69+
}
70+
6471
static bool isSupportedOperator(Constraint *disjunction) {
6572
if (!isOperatorDisjunction(disjunction))
6673
return false;
@@ -298,9 +305,19 @@ static void determineBestChoicesInContext(
298305
case ExprKind::Binary:
299306
case ExprKind::PrefixUnary:
300307
case ExprKind::PostfixUnary:
301-
case ExprKind::UnresolvedDot:
302-
recordResult(disjunction, {/*score=*/1.0});
308+
case ExprKind::UnresolvedDot: {
309+
llvm::SmallVector<Constraint *, 2> favoredChoices;
310+
// Favor choices that don't require application.
311+
llvm::copy_if(
312+
disjunction->getNestedConstraints(),
313+
std::back_inserter(favoredChoices), [](Constraint *choice) {
314+
auto *decl = getOverloadChoiceDecl(choice);
315+
return decl &&
316+
!decl->getInterfaceType()->is<AnyFunctionType>();
317+
});
318+
recordResult(disjunction, {/*score=*/1.0, favoredChoices});
303319
continue;
320+
}
304321

305322
default:
306323
break;
@@ -538,8 +555,33 @@ static void determineBestChoicesInContext(
538555
}
539556
}
540557

541-
if (options.contains(MatchFlag::ExactOnly))
558+
// Match `[...]` to Array<...> and/or `ExpressibleByArrayLiteral`
559+
// conforming types.
560+
if (options.contains(MatchFlag::OnParam) &&
561+
options.contains(MatchFlag::Literal) &&
562+
isUnboundArrayType(candidateType)) {
563+
// If an exact match is requested favor only `[...]` to `Array<...>`
564+
// since everything else is going to increase to score.
565+
if (options.contains(MatchFlag::ExactOnly))
566+
return paramType->isArrayType() ? 1 : 0;
567+
568+
Type type = paramType->lookThroughAllOptionalTypes();
569+
// Otherwise, check if the other side conforms to
570+
// `ExpressibleByArrayLiteral` protocol (in some way).
571+
if (auto *nominal = type->getAnyNominal()) {
572+
auto &ctx = cs.getASTContext();
573+
SmallVector<ProtocolConformance *> conformances;
574+
575+
nominal->lookupConformance(
576+
ctx.getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral),
577+
conformances);
578+
return conformances.empty() ? 0 : 0.3;
579+
}
580+
}
581+
582+
if (options.contains(MatchFlag::ExactOnly)) {
542583
return areEqual(candidateType, paramType) ? 1 : 0;
584+
}
543585

544586
// Exact match between candidate and parameter types.
545587
if (areEqual(candidateType, paramType)) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %target-typecheck-verify-swift -solver-scope-threshold=11000
2+
// REQUIRES: tools-release,no_asan
3+
4+
func f(n: Int, a: [Int]) {
5+
let _ = [(0 ..< n + a.count).map { Int8($0) }] +
6+
[(0 ..< n + a.count).map { Int8($0) }.reversed()] // Ok
7+
}

0 commit comments

Comments
 (0)