Skip to content

Commit 9f75e4a

Browse files
authored
Merge pull request #17975 from rudkx/disjunction-ordering
[ConstraintSystem] Change the order in which we attempt disjunctions to be stable.
2 parents c2767f1 + 8b2b4a7 commit 9f75e4a

File tree

4 files changed

+55
-56
lines changed

4 files changed

+55
-56
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
// This file implements the constraint solver used in the type checker.
1414
//
1515
//===----------------------------------------------------------------------===//
16-
#include "ConstraintSystem.h"
1716
#include "ConstraintGraph.h"
17+
#include "ConstraintSystem.h"
1818
#include "swift/AST/ParameterList.h"
1919
#include "swift/AST/TypeWalker.h"
2020
#include "llvm/ADT/Statistic.h"
2121
#include "llvm/Support/Compiler.h"
22-
#include "llvm/Support/raw_ostream.h"
2322
#include "llvm/Support/SaveAndRestore.h"
23+
#include "llvm/Support/raw_ostream.h"
24+
#include <algorithm>
2425
#include <memory>
2526
#include <tuple>
2627

@@ -1492,13 +1493,8 @@ bool ConstraintSystem::solveRec(SmallVectorImpl<Solution> &solutions,
14921493

14931494
// If we don't have more than one component, just solve the whole
14941495
// system.
1495-
if (numComponents < 2) {
1496-
SmallVector<Constraint *, 8> disjunctions;
1497-
collectDisjunctions(disjunctions);
1498-
1499-
return solveSimplified(selectDisjunction(disjunctions), solutions,
1500-
allowFreeTypeVariables);
1501-
}
1496+
if (numComponents < 2)
1497+
return solveSimplified(solutions, allowFreeTypeVariables);
15021498

15031499
if (TC.Context.LangOpts.DebugConstraintSolver) {
15041500
auto &log = getASTContext().TypeCheckerDebug->getStream();
@@ -1819,6 +1815,9 @@ static bool shouldSkipDisjunctionChoice(ConstraintSystem &cs,
18191815
static Constraint *selectBestBindingDisjunction(
18201816
ConstraintSystem &cs, SmallVectorImpl<Constraint *> &disjunctions) {
18211817

1818+
if (disjunctions.empty())
1819+
return nullptr;
1820+
18221821
// Collect any disjunctions that simply attempt bindings for a
18231822
// type variable.
18241823
SmallVector<Constraint *, 8> bindingDisjunctions;
@@ -1885,46 +1884,40 @@ static Constraint *selectBestBindingDisjunction(
18851884
return nullptr;
18861885
}
18871886

1888-
Constraint *ConstraintSystem::selectDisjunction(
1889-
SmallVectorImpl<Constraint *> &disjunctions) {
1890-
if (disjunctions.empty())
1891-
return nullptr;
1887+
Constraint *ConstraintSystem::selectDisjunction() {
1888+
SmallVector<Constraint *, 4> disjunctions;
18921889

1893-
auto *disjunction =
1894-
selectBestBindingDisjunction(*this, disjunctions);
1895-
if (disjunction)
1890+
collectDisjunctions(disjunctions);
1891+
if (auto *disjunction = selectBestBindingDisjunction(*this, disjunctions))
18961892
return disjunction;
18971893

1898-
// Pick the smallest disjunction.
1899-
// FIXME: This heuristic isn't great, but it helped somewhat for
1900-
// overload sets.
1901-
disjunction = disjunctions[0];
1902-
auto bestSize = disjunction->countActiveNestedConstraints();
1903-
if (bestSize > 2) {
1904-
for (auto contender : llvm::makeArrayRef(disjunctions).slice(1)) {
1905-
unsigned newSize = contender->countActiveNestedConstraints();
1906-
if (newSize < bestSize) {
1907-
bestSize = newSize;
1908-
disjunction = contender;
1909-
1910-
if (bestSize == 2)
1911-
break;
1912-
}
1913-
}
1914-
}
1894+
// Pick the disjunction with the lowest disjunction number in order
1895+
// to solve them in the order they were created (which should be
1896+
// stable within an expression).
1897+
auto minDisjunction =
1898+
std::min_element(disjunctions.begin(), disjunctions.end(),
1899+
[&](Constraint *first, Constraint *second) -> bool {
1900+
auto firstFound = DisjunctionNumber.find(first);
1901+
auto secondFound = DisjunctionNumber.find(second);
19151902

1916-
// If there are no active constraints in the disjunction, there is
1917-
// no solution.
1918-
if (bestSize == 0)
1919-
return nullptr;
1903+
assert(firstFound != DisjunctionNumber.end() &&
1904+
secondFound != DisjunctionNumber.end());
1905+
1906+
return firstFound->second < secondFound->second;
1907+
});
19201908

1921-
return disjunction;
1909+
if (minDisjunction != disjunctions.end())
1910+
return *minDisjunction;
1911+
1912+
return nullptr;
19221913
}
19231914

19241915
bool ConstraintSystem::solveSimplified(
1925-
Constraint *disjunction, SmallVectorImpl<Solution> &solutions,
1916+
SmallVectorImpl<Solution> &solutions,
19261917
FreeTypeVariableBinding allowFreeTypeVariables) {
19271918

1919+
auto *disjunction = selectDisjunction();
1920+
19281921
auto bestBindings = determineBestBindings();
19291922

19301923
// If we have a binding that does not involve type variables, and is
@@ -1937,6 +1930,8 @@ bool ConstraintSystem::solveSimplified(
19371930
allowFreeTypeVariables);
19381931
}
19391932

1933+
1934+
19401935
// If there are no disjunctions we can't solve this system unless we have
19411936
// free type variables and are allowing them in the solution.
19421937
if (!disjunction) {

lib/Sema/Constraint.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -798,6 +798,7 @@ Constraint *Constraint::createDisjunction(ConstraintSystem &cs,
798798
auto disjunction = new (mem) Constraint(ConstraintKind::Disjunction,
799799
cs.allocateCopy(constraints), locator, typeVars);
800800
disjunction->RememberChoice = (bool) rememberChoice;
801+
cs.noteNewDisjunction(disjunction);
801802
return disjunction;
802803
}
803804

lib/Sema/ConstraintSystem.h

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,13 @@ class ConstraintSystem {
902902
/// The original CS if this CS was created as a simplification of another CS
903903
ConstraintSystem *baseCS = nullptr;
904904

905+
/// \brief The total number of disjunctions created.
906+
unsigned CountDisjunctions = 0;
907+
908+
/// \brief Map from disjunction to the number indicating the order it
909+
// was created in.
910+
llvm::DenseMap<Constraint *, unsigned> DisjunctionNumber;
911+
905912
private:
906913

907914
/// \brief Allocator used for all of the related constraint systems.
@@ -1852,6 +1859,11 @@ class ConstraintSystem {
18521859
bool allowFixes,
18531860
ConstraintLocatorBuilder locator);
18541861

1862+
void noteNewDisjunction(Constraint *constraint) {
1863+
assert(constraint->getKind() == ConstraintKind::Disjunction);
1864+
DisjunctionNumber[constraint] = CountDisjunctions++;
1865+
}
1866+
18551867
/// \brief Add a disjunction constraint.
18561868
void addDisjunctionConstraint(ArrayRef<Constraint *> constraints,
18571869
ConstraintLocatorBuilder locator,
@@ -2920,17 +2932,13 @@ class ConstraintSystem {
29202932
/// \brief Solve the system of constraints after it has already been
29212933
/// simplified.
29222934
///
2923-
/// \param disjunction The disjunction to try and solve using simplified
2924-
/// constraint system.
2925-
///
29262935
/// \param solutions The set of solutions to this system of constraints.
29272936
///
29282937
/// \param allowFreeTypeVariables How to bind free type variables in
29292938
/// the solution.
29302939
///
29312940
/// \returns true if an error occurred, false otherwise.
2932-
bool solveSimplified(Constraint *disjunction,
2933-
SmallVectorImpl<Solution> &solutions,
2941+
bool solveSimplified(SmallVectorImpl<Solution> &solutions,
29342942
FreeTypeVariableBinding allowFreeTypeVariables);
29352943

29362944
/// \brief Find reduced domains of disjunction constraints for given
@@ -2942,15 +2950,10 @@ class ConstraintSystem {
29422950
/// \param expr The expression to find reductions for.
29432951
void shrink(Expr *expr);
29442952

2945-
/// \brief Pick a disjunction from the given list, which,
2946-
/// based on the associated constraints, is the most viable to
2947-
/// reduce depth of the search tree.
2948-
///
2949-
/// \param disjunctions A collection of disjunctions to examine.
2953+
/// \brief Pick a disjunction from the InactiveConstraints list.
29502954
///
2951-
/// \returns The disjunction with most weight relative to others, based
2952-
/// on the number of constraints associated with it, or nullptr otherwise.
2953-
Constraint *selectDisjunction(SmallVectorImpl<Constraint *> &disjunctions);
2955+
/// \returns The selected disjunction.
2956+
Constraint *selectDisjunction();
29542957

29552958
bool simplifyForConstraintPropagation();
29562959
void collectNeighboringBindOverloadDisjunctions(
@@ -3345,8 +3348,7 @@ class Component {
33453348
llvm::SaveAndRestore<ConstraintSystem::SolverScope *>
33463349
partialSolutionScope(cs.solverState->PartialSolutionScope, &scope);
33473350

3348-
failed = cs.solveSimplified(cs.selectDisjunction(Disjunctions), solutions,
3349-
allowFreeTypeVariables);
3351+
failed = cs.solveSimplified(solutions, allowFreeTypeVariables);
33503352
}
33513353

33523354
// Put the constraints back into their original bucket.

validation-test/stdlib/AnyHashable.swift.gyb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,8 +757,9 @@ AnyHashableTests.test("AnyHashable(MinimalHashableRCSwiftError)/Hashable") {
757757
xs,
758758
equalityOracle: { $0 / 2 == $1 / 2 },
759759
hashEqualityOracle: { $0 / 4 == $1 / 4 })
760+
let mapped = xs.map(AnyHashable.init)
760761
checkHashable(
761-
xs.map(AnyHashable.init),
762+
mapped,
762763
equalityOracle: { $0 / 2 == $1 / 2 },
763764
hashEqualityOracle: { $0 / 4 == $1 / 4 })
764765
}

0 commit comments

Comments
 (0)