Skip to content

Commit e7986b3

Browse files
authored
Merge pull request swiftlang#9201 from rudkx/fix-source-compat-for-operators-with-literals
[Constraint solver] Fix Swift 3 compatibility issue with overloaded o…
2 parents 57fa43c + 44882d2 commit e7986b3

File tree

2 files changed

+46
-22
lines changed

2 files changed

+46
-22
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,27 +2348,6 @@ static bool shortCircuitDisjunctionAt(Constraint *constraint,
23482348
if (constraint->getKind() == ConstraintKind::CheckedCast)
23492349
return true;
23502350

2351-
// Binding an operator overloading to a generic operator is weaker than
2352-
// binding to a non-generic operator, always.
2353-
// FIXME: this is a hack to improve performance when we're dealing with
2354-
// overloaded operators.
2355-
if (constraint->getKind() == ConstraintKind::BindOverload &&
2356-
constraint->getOverloadChoice().getKind() == OverloadChoiceKind::Decl &&
2357-
constraint->getOverloadChoice().getDecl()->isOperator() &&
2358-
successfulConstraint->getKind() == ConstraintKind::BindOverload &&
2359-
successfulConstraint->getOverloadChoice().getKind()
2360-
== OverloadChoiceKind::Decl &&
2361-
successfulConstraint->getOverloadChoice().getDecl()->isOperator()) {
2362-
auto decl = constraint->getOverloadChoice().getDecl();
2363-
auto successfulDecl = successfulConstraint->getOverloadChoice().getDecl();
2364-
auto &ctx = decl->getASTContext();
2365-
if (decl->getInterfaceType()->is<GenericFunctionType>() &&
2366-
!successfulDecl->getInterfaceType()->is<GenericFunctionType>() &&
2367-
(!successfulDecl->getAttrs().isUnavailable(ctx) ||
2368-
decl->getAttrs().isUnavailable(ctx)))
2369-
return true;
2370-
}
2371-
23722351
return false;
23732352
}
23742353

@@ -2486,6 +2465,21 @@ static unsigned countUnboundTypes(ConstraintSystem &CS,
24862465
return count;
24872466
}
24882467

2468+
// Is this constraint a bind overload to a generic operator or one
2469+
// that is unavailable?
2470+
static bool isGenericOperatorOrUnavailable(Constraint *constraint) {
2471+
if (constraint->getKind() != ConstraintKind::BindOverload ||
2472+
constraint->getOverloadChoice().getKind() != OverloadChoiceKind::Decl ||
2473+
!constraint->getOverloadChoice().getDecl()->isOperator())
2474+
return false;
2475+
2476+
auto decl = constraint->getOverloadChoice().getDecl();
2477+
auto &ctx = decl->getASTContext();
2478+
2479+
return decl->getInterfaceType()->is<GenericFunctionType>() ||
2480+
decl->getAttrs().isUnavailable(ctx);
2481+
}
2482+
24892483
bool ConstraintSystem::solveSimplified(
24902484
SmallVectorImpl<Solution> &solutions,
24912485
FreeTypeVariableBinding allowFreeTypeVariables) {
@@ -2620,6 +2614,7 @@ bool ConstraintSystem::solveSimplified(
26202614

26212615
// Try each of the constraints within the disjunction.
26222616
Constraint *firstSolvedConstraint = nullptr;
2617+
Constraint *firstNonGenericOperatorSolution = nullptr;
26232618
++solverState->NumDisjunctions;
26242619
auto constraints = disjunction->getNestedConstraints();
26252620
for (auto index : indices(constraints)) {
@@ -2635,12 +2630,24 @@ bool ConstraintSystem::solveSimplified(
26352630
continue;
26362631
}
26372632

2633+
// Don't attempt to solve for generic operators if we already have
2634+
// a non-generic solution.
2635+
2636+
// FIXME: Less-horrible but still horrible hack to attempt to
2637+
// speed things up. Skip the generic operators if we
2638+
// already have a solution involving non-generic operators,
2639+
// but continue looking for a better non-generic operator
2640+
// solution.
2641+
if (firstNonGenericOperatorSolution &&
2642+
isGenericOperatorOrUnavailable(constraint))
2643+
continue;
2644+
26382645
// We already have a solution; check whether we should
26392646
// short-circuit the disjunction.
26402647
if (firstSolvedConstraint &&
26412648
shortCircuitDisjunctionAt(constraint, firstSolvedConstraint))
26422649
break;
2643-
2650+
26442651
// If the expression was deemed "too complex", stop now and salvage.
26452652
if (getExpressionTooComplex(solutions))
26462653
break;
@@ -2686,6 +2693,10 @@ bool ConstraintSystem::solveSimplified(
26862693
solverState->addGeneratedConstraint(constraint);
26872694

26882695
if (!solveRec(solutions, allowFreeTypeVariables)) {
2696+
if (!firstNonGenericOperatorSolution &&
2697+
!isGenericOperatorOrUnavailable(constraint))
2698+
firstNonGenericOperatorSolution = constraint;
2699+
26892700
firstSolvedConstraint = constraint;
26902701

26912702
// If we see a tuple-to-tuple conversion that succeeded, we're done.

test/Constraints/overload.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,16 @@ func test_f6() {
209209
let _: (X1a) -> Void = f6
210210
let _: (X1a) -> X6 = X6.init
211211
}
212+
213+
func curry<LHS, RHS, R>(_ f: @escaping (LHS, RHS) -> R) -> (LHS) -> (RHS) -> R {
214+
return { lhs in { rhs in f(lhs, rhs) } }
215+
}
216+
217+
// We need to have an alternative version of this to ensure that there's an overload disjunction created.
218+
func curry<F, S, T, R>(_ f: @escaping (F, S, T) -> R) -> (F) -> (S) -> (T) -> R {
219+
return { fst in { snd in { thd in f(fst, snd, thd) } } }
220+
}
221+
222+
// Ensure that we consider these unambiguous
223+
let _ = curry(+)(1)
224+
let _ = [0].reduce(0, +)

0 commit comments

Comments
 (0)