Skip to content

Commit 423d6bd

Browse files
committed
[ConstraintSystem] Re-instate the operator type variable merging
hacks for now. There's some more disjunction pruning work to be done before we can remove this.
1 parent a8fcdb8 commit 423d6bd

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

lib/Sema/CSGen.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,72 @@ namespace {
303303
// solver can still make progress.
304304
auto favoredTy = (*lti.collectedTypes.begin())->getWithoutSpecifierType();
305305
CS.setFavoredType(expr, favoredTy.getPointer());
306+
307+
// If we have a chain of identical binop expressions with homogeneous
308+
// argument types, we can directly simplify the associated constraint
309+
// graph.
310+
auto simplifyBinOpExprTyVars = [&]() {
311+
// Don't attempt to do linking if there are
312+
// literals intermingled with other inferred types.
313+
if (lti.hasLiteral)
314+
return;
315+
316+
for (auto binExp1 : lti.binaryExprs) {
317+
for (auto binExp2 : lti.binaryExprs) {
318+
if (binExp1 == binExp2)
319+
continue;
320+
321+
auto fnTy1 = CS.getType(binExp1)->getAs<TypeVariableType>();
322+
auto fnTy2 = CS.getType(binExp2)->getAs<TypeVariableType>();
323+
324+
if (!(fnTy1 && fnTy2))
325+
return;
326+
327+
auto ODR1 = dyn_cast<OverloadedDeclRefExpr>(binExp1->getFn());
328+
auto ODR2 = dyn_cast<OverloadedDeclRefExpr>(binExp2->getFn());
329+
330+
if (!(ODR1 && ODR2))
331+
return;
332+
333+
// TODO: We currently limit this optimization to known arithmetic
334+
// operators, but we should be able to broaden this out to
335+
// logical operators as well.
336+
if (!isArithmeticOperatorDecl(ODR1->getDecls()[0]))
337+
return;
338+
339+
if (ODR1->getDecls()[0]->getBaseName() !=
340+
ODR2->getDecls()[0]->getBaseName())
341+
return;
342+
343+
// All things equal, we can merge the tyvars for the function
344+
// types.
345+
auto rep1 = CS.getRepresentative(fnTy1);
346+
auto rep2 = CS.getRepresentative(fnTy2);
347+
348+
if (rep1 != rep2) {
349+
CS.mergeEquivalenceClasses(rep1, rep2,
350+
/*updateWorkList*/ false);
351+
}
352+
353+
auto odTy1 = CS.getType(ODR1)->getAs<TypeVariableType>();
354+
auto odTy2 = CS.getType(ODR2)->getAs<TypeVariableType>();
355+
356+
if (odTy1 && odTy2) {
357+
auto odRep1 = CS.getRepresentative(odTy1);
358+
auto odRep2 = CS.getRepresentative(odTy2);
359+
360+
// Since we'll be choosing the same overload, we can merge
361+
// the overload tyvar as well.
362+
if (odRep1 != odRep2)
363+
CS.mergeEquivalenceClasses(odRep1, odRep2,
364+
/*updateWorkList*/ false);
365+
}
366+
}
367+
}
368+
};
369+
370+
simplifyBinOpExprTyVars();
371+
306372
return true;
307373
}
308374

lib/Sema/CSStep.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ class DisjunctionStep final : public BindingStep<DisjunctionChoiceProducer> {
649649
: BindingStep(cs, {cs, disjunction}, solutions), Disjunction(disjunction),
650650
AfterDisjunction(erase(disjunction)) {
651651
assert(Disjunction->getKind() == ConstraintKind::Disjunction);
652+
pruneOverloadSet(Disjunction);
652653
++cs.solverState->NumDisjunctions;
653654
}
654655

@@ -696,6 +697,43 @@ class DisjunctionStep final : public BindingStep<DisjunctionChoiceProducer> {
696697
/// simplified further, false otherwise.
697698
bool attempt(const DisjunctionChoice &choice) override;
698699

700+
// Check if selected disjunction has a representative
701+
// this might happen when there are multiple binary operators
702+
// chained together. If so, disable choices which differ
703+
// from currently selected representative.
704+
void pruneOverloadSet(Constraint *disjunction) {
705+
auto *choice = disjunction->getNestedConstraints().front();
706+
auto *typeVar = choice->getFirstType()->getAs<TypeVariableType>();
707+
if (!typeVar)
708+
return;
709+
710+
auto *repr = typeVar->getImpl().getRepresentative(nullptr);
711+
if (!repr || repr == typeVar)
712+
return;
713+
714+
for (auto overload : CS.getResolvedOverloads()) {
715+
auto resolved = overload.second;
716+
if (!resolved.boundType->isEqual(repr))
717+
continue;
718+
719+
auto &representative = resolved.choice;
720+
if (!representative.isDecl())
721+
return;
722+
723+
// Disable all of the overload choices which are different from
724+
// the one which is currently picked for representative.
725+
for (auto *constraint : disjunction->getNestedConstraints()) {
726+
auto choice = constraint->getOverloadChoice();
727+
if (!choice.isDecl() || choice.getDecl() == representative.getDecl())
728+
continue;
729+
730+
constraint->setDisabled();
731+
DisabledChoices.push_back(constraint);
732+
}
733+
break;
734+
}
735+
};
736+
699737
// Figure out which of the solutions has the smallest score.
700738
static Optional<Score> getBestScore(SmallVectorImpl<Solution> &solutions) {
701739
assert(!solutions.empty());

test/Constraints/sr10324.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %target-swift-frontend -typecheck -verify %s
22

3+
// REQUIRES: rdar65007946
4+
35
struct A {
46
static func * (lhs: A, rhs: A) -> B { return B() }
57
static func * (lhs: B, rhs: A) -> B { return B() }

0 commit comments

Comments
 (0)