Skip to content

Commit daf4610

Browse files
committed
[Constraint solver] Don't remove/reintroduce disjunction when favoring.
When favoring particular constraints in a disjunction, don't remove the old disjunction and create a new one---it's just churn in the constraint system. Instead, favor the constraints that need it. This technically flips the SR-139 test case from "too complex" to being fast enough, but it's still fairly slow.
1 parent 0f31416 commit daf4610

File tree

3 files changed

+30
-45
lines changed

3 files changed

+30
-45
lines changed

lib/Sema/CSGen.cpp

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -615,60 +615,45 @@ namespace {
615615
if (!disjunction)
616616
return;
617617

618-
auto oldConstraints = disjunction->getNestedConstraints();
619-
auto csLoc = CS.getConstraintLocator(expr->getFn());
620-
621-
if (mustConsider) {
622-
bool hasMustConsider = false;
623-
for (auto oldConstraint : oldConstraints) {
624-
auto overloadChoice = oldConstraint->getOverloadChoice();
625-
if (overloadChoice.isDecl() &&
626-
mustConsider(overloadChoice.getDecl()))
627-
hasMustConsider = true;
628-
}
629-
if (hasMustConsider) {
618+
// Find the favored constraints and mark them.
619+
SmallVector<Constraint *, 4> newlyFavoredConstraints;
620+
unsigned numFavoredConstraints = 0;
621+
Constraint *firstFavored = nullptr;
622+
for (auto constraint : disjunction->getNestedConstraints()) {
623+
if (!constraint->getOverloadChoice().isDecl())
630624
return;
631-
}
632-
}
625+
auto decl = constraint->getOverloadChoice().getDecl();
626+
627+
if (mustConsider && mustConsider(decl)) {
628+
// Roll back any constraints we favored.
629+
for (auto favored : newlyFavoredConstraints)
630+
favored->setFavored(false);
633631

634-
// Copy over the existing bindings, dividing the constraints up
635-
// into "favored" and non-favored lists.
636-
SmallVector<Constraint *, 4> favoredConstraints;
637-
SmallVector<Constraint *, 4> fallbackConstraints;
638-
for (auto oldConstraint : oldConstraints) {
639-
if (!oldConstraint->getOverloadChoice().isDecl())
640632
return;
641-
auto decl = oldConstraint->getOverloadChoice().getDecl();
633+
}
634+
642635
if (!decl->getAttrs().isUnavailable(CS.getASTContext()) &&
643636
isFavored(decl)) {
644-
favoredConstraints.push_back(oldConstraint);
645-
oldConstraint->setFavored();
646-
} else
647-
fallbackConstraints.push_back(oldConstraint);
648-
}
637+
// If we might need to roll back the favored constraints, keep
638+
// track of those we are favoring.
639+
if (mustConsider && !constraint->isFavored())
640+
newlyFavoredConstraints.push_back(constraint);
649641

650-
// If we did not find any favored constraints, we're done.
651-
if (favoredConstraints.empty()) return;
642+
constraint->setFavored();
643+
++numFavoredConstraints;
644+
if (!firstFavored)
645+
firstFavored = constraint;
646+
}
647+
}
652648

653-
if (favoredConstraints.size() == 1) {
654-
auto overloadChoice = favoredConstraints[0]->getOverloadChoice();
649+
// If there was one favored constraint, set the favored type based on its
650+
// result type.
651+
if (numFavoredConstraints == 1) {
652+
auto overloadChoice = firstFavored->getOverloadChoice();
655653
auto overloadType = overloadChoice.getDecl()->getInterfaceType();
656654
auto resultType = overloadType->getAs<AnyFunctionType>()->getResult();
657655
CS.setFavoredType(expr, resultType.getPointer());
658656
}
659-
660-
// Remove the original constraint from the inactive constraint
661-
// list and add the new one.
662-
CS.removeInactiveConstraint(disjunction);
663-
664-
llvm::SmallVector<Constraint *, 2> aggregateConstraints;
665-
aggregateConstraints.insert(aggregateConstraints.end(),
666-
favoredConstraints.begin(),
667-
favoredConstraints.end());
668-
aggregateConstraints.insert(aggregateConstraints.end(),
669-
fallbackConstraints.begin(),
670-
fallbackConstraints.end());
671-
CS.addDisjunctionConstraint(aggregateConstraints, csLoc);
672657
}
673658

674659
size_t getOperandCount(Type t) {

lib/Sema/Constraint.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
444444
}
445445

446446
/// Mark or retrieve whether this constraint should be favored in the system.
447-
void setFavored() { IsFavored = true; }
447+
void setFavored(bool favored = true) { IsFavored = favored; }
448448
bool isFavored() const { return IsFavored; }
449449

450450
/// Whether the solver should remember which choice was taken for

validation-test/Sema/type_checker_perf/slow/sr139.swift renamed to validation-test/Sema/type_checker_perf/fast/sr139.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33

44
// SR-139:
55
// Infinite recursion parsing bitwise operators
6-
let x = UInt32(0x1FF)&0xFF << 24 | UInt32(0x1FF)&0xFF << 16 | UInt32(0x1FF)&0xFF << 8 | (UInt32(0x1FF)&0xFF); // expected-error {{reasonable time}}
6+
let x = UInt32(0x1FF)&0xFF << 24 | UInt32(0x1FF)&0xFF << 16 | UInt32(0x1FF)&0xFF << 8 | (UInt32(0x1FF)&0xFF)
77

0 commit comments

Comments
 (0)