Skip to content

Commit d759522

Browse files
authored
Merge pull request #7655 from DougGregor/orphaned-constraints
[Constraint solver] Handle disjunctions as separate connected components
2 parents 8858137 + 40b6764 commit d759522

File tree

4 files changed

+109
-21
lines changed

4 files changed

+109
-21
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,15 @@ bool ConstraintSystem::solveRec(SmallVectorImpl<Solution> &solutions,
20892089
constraintComponent[constraint] = components[i];
20902090
}
20912091

2092+
// Add the orphaned components to the mapping from constraints to components.
2093+
unsigned firstOrphanedConstraint =
2094+
numComponents - CG.getOrphanedConstraints().size();
2095+
{
2096+
unsigned component = firstOrphanedConstraint;
2097+
for (auto constraint : CG.getOrphanedConstraints())
2098+
constraintComponent[constraint] = component++;
2099+
}
2100+
20922101
// Sort the constraints into buckets based on component number.
20932102
std::unique_ptr<ConstraintList[]> constraintBuckets(
20942103
new ConstraintList[numComponents]);
@@ -2098,6 +2107,9 @@ bool ConstraintSystem::solveRec(SmallVectorImpl<Solution> &solutions,
20982107
constraintBuckets[constraintComponent[constraint]].push_back(constraint);
20992108
}
21002109

2110+
// Remove all of the orphaned constraints; we'll introduce them as needed.
2111+
auto allOrphanedConstraints = CG.takeOrphanedConstraints();
2112+
21012113
// Function object that returns all constraints placed into buckets
21022114
// back to the list of constraints.
21032115
auto returnAllConstraints = [&] {
@@ -2106,6 +2118,7 @@ bool ConstraintSystem::solveRec(SmallVectorImpl<Solution> &solutions,
21062118
InactiveConstraints.splice(InactiveConstraints.end(),
21072119
constraintBuckets[component]);
21082120
}
2121+
CG.setOrphanedConstraints(std::move(allOrphanedConstraints));
21092122
};
21102123

21112124
// Compute the partial solutions produced for each connected component.
@@ -2118,24 +2131,31 @@ bool ConstraintSystem::solveRec(SmallVectorImpl<Solution> &solutions,
21182131
++solverState->NumComponentsSplit;
21192132

21202133
// Collect the constraints for this component.
2121-
InactiveConstraints.splice(InactiveConstraints.end(),
2134+
InactiveConstraints.splice(InactiveConstraints.end(),
21222135
constraintBuckets[component]);
21232136

2124-
// Collect the type variables that are not part of a different
2125-
// component; this includes type variables that are part of the
2126-
// component as well as already-resolved type variables.
2127-
// FIXME: The latter could be avoided if we had already
2128-
// substituted all of those other type variables through.
2129-
llvm::SmallVector<TypeVariableType *, 16> allTypeVariables
2137+
llvm::SmallVector<TypeVariableType *, 16> allTypeVariables
21302138
= std::move(TypeVariables);
2131-
for (auto typeVar : allTypeVariables) {
2132-
auto known = typeVarComponent.find(typeVar);
2133-
if (known != typeVarComponent.end() && known->second != component)
2134-
continue;
21352139

2136-
TypeVariables.push_back(typeVar);
2140+
Constraint *orphaned = nullptr;
2141+
if (component < firstOrphanedConstraint) {
2142+
// Collect the type variables that are not part of a different
2143+
// component; this includes type variables that are part of the
2144+
// component as well as already-resolved type variables.
2145+
for (auto typeVar : allTypeVariables) {
2146+
auto known = typeVarComponent.find(typeVar);
2147+
if (known != typeVarComponent.end() && known->second != component)
2148+
continue;
2149+
2150+
TypeVariables.push_back(typeVar);
2151+
}
2152+
} else {
2153+
// Get the orphaned constraint.
2154+
assert(InactiveConstraints.size() == 1 && "supposed to be an orphan!");
2155+
orphaned = &InactiveConstraints.front();
21372156
}
2138-
2157+
CG.setOrphanedConstraint(orphaned);
2158+
21392159
// Solve for this component. If it fails, we're done.
21402160
bool failed;
21412161
if (TC.getLangOpts().DebugConstraintSolver) {

lib/Sema/ConstraintGraph.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,12 @@ void ConstraintGraph::addConstraint(Constraint *constraint) {
349349
}
350350
}
351351

352+
// If the constraint doesn't reference any type variables, it's orphaned;
353+
// track it as such.
354+
if (referencedTypeVars.empty()) {
355+
OrphanedConstraints.push_back(constraint);
356+
}
357+
352358
// Record the change, if there are active scopes.
353359
if (ActiveScope)
354360
Changes.push_back(Change::addedConstraint(constraint));
@@ -375,6 +381,16 @@ void ConstraintGraph::removeConstraint(Constraint *constraint) {
375381
}
376382
}
377383

384+
// If this is an orphaned constraint, remove it from the list.
385+
if (referencedTypeVars.empty()) {
386+
auto known = std::find(OrphanedConstraints.begin(),
387+
OrphanedConstraints.end(),
388+
constraint);
389+
assert(known != OrphanedConstraints.end() && "missing orphaned constraint");
390+
*known = OrphanedConstraints.back();
391+
OrphanedConstraints.pop_back();
392+
}
393+
378394
// Record the change, if there are active scopes.
379395
if (ActiveScope)
380396
Changes.push_back(Change::removedConstraint(constraint));
@@ -578,9 +594,9 @@ unsigned ConstraintGraph::computeConnectedComponents(
578594
if (CS.getFixedType(TypeVariables[i]))
579595
continue;
580596

581-
// If we only care about a subset, and this type variable isn't in that
582-
// subset, skip it.
583-
if (!typeVarSubset.empty() && typeVarSubset.count(TypeVariables[i]) == 0)
597+
// If this type variable isn't in the subset of type variables we care
598+
// about, skip it.
599+
if (typeVarSubset.count(TypeVariables[i]) == 0)
584600
continue;
585601

586602
componentHasUnboundTypeVar[components[i]] = true;
@@ -611,7 +627,7 @@ unsigned ConstraintGraph::computeConnectedComponents(
611627
}
612628
components.erase(components.begin() + outIndex, components.end());
613629

614-
return numComponents;
630+
return numComponents + getOrphanedConstraints().size();
615631
}
616632

617633

@@ -861,6 +877,7 @@ void ConstraintGraph::dump() {
861877

862878
void ConstraintGraph::printConnectedComponents(llvm::raw_ostream &out) {
863879
SmallVector<TypeVariableType *, 16> typeVars;
880+
typeVars.append(TypeVariables.begin(), TypeVariables.end());
864881
SmallVector<unsigned, 16> components;
865882
unsigned numComponents = computeConnectedComponents(typeVars, components);
866883
for (unsigned component = 0; component != numComponents; ++component) {

lib/Sema/ConstraintGraph.h

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,18 +237,47 @@ class ConstraintGraph {
237237

238238
/// Compute the connected components of the graph.
239239
///
240-
/// \param typeVars The type variables that occur within the
241-
/// connected components. If a non-empty vector is passed in, the algorithm
242-
/// will only consider type variables reachable from the initial set.
240+
/// \param typeVars The type variables that should be included in the
241+
/// set of connected components that are returned.
243242
///
244243
/// \param components Receives the component numbers for each type variable
245244
/// in \c typeVars.
246245
///
247-
/// \returns the number of connected components in the graph.
246+
/// \returns the number of connected components in the graph, which includes
247+
/// one component for each of the constraints produced by
248+
/// \c getOrphanedConstraints().
248249
unsigned computeConnectedComponents(
249250
SmallVectorImpl<TypeVariableType *> &typeVars,
250251
SmallVectorImpl<unsigned> &components);
251252

253+
/// Retrieve the set of "orphaned" constraints, which are known to the
254+
/// constraint graph but have no type variables to anchor them.
255+
ArrayRef<Constraint *> getOrphanedConstraints() const {
256+
return OrphanedConstraints;
257+
}
258+
259+
/// Replace the orphaned constraints with the constraints in the given list,
260+
/// returning the old set of orphaned constraints.
261+
SmallVector<Constraint *, 4> takeOrphanedConstraints() {
262+
auto result = std::move(OrphanedConstraints);
263+
OrphanedConstraints.clear();
264+
return result;
265+
}
266+
267+
/// Set the orphaned constraints.
268+
void setOrphanedConstraints(SmallVector<Constraint *, 4> &&newConstraints) {
269+
OrphanedConstraints = std::move(newConstraints);
270+
}
271+
272+
/// Set the list of orphaned constraints to a single constraint.
273+
///
274+
/// If \c orphaned is null, just clear out the list.
275+
void setOrphanedConstraint(Constraint *orphaned) {
276+
OrphanedConstraints.clear();
277+
if (orphaned)
278+
OrphanedConstraints.push_back(orphaned);
279+
}
280+
252281
/// Print the graph.
253282
void print(llvm::raw_ostream &out);
254283

@@ -300,6 +329,9 @@ class ConstraintGraph {
300329
/// The type variables in this graph, in stable order.
301330
SmallVector<TypeVariableType *, 4> TypeVariables;
302331

332+
/// Constraints that are "orphaned" because they contain no type variables.
333+
SmallVector<Constraint *, 4> OrphanedConstraints;
334+
303335
/// The kind of change made to the graph.
304336
enum class ChangeKind {
305337
/// Added a type variable.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-swift-frontend -typecheck %s
2+
3+
public class Foo : CustomReflectable {
4+
public var booleanValue : Bool?
5+
public var customMirror: Mirror {
6+
return Mirror(self, children: [
7+
"booleanValue": booleanValue as Bool? as Any,
8+
"booleanValue": booleanValue as Bool? as Any,
9+
"booleanValue": booleanValue as Bool? as Any,
10+
"booleanValue": booleanValue as Bool? as Any,
11+
"booleanValue": booleanValue as Bool? as Any,
12+
"booleanValue": booleanValue as Bool? as Any,
13+
"booleanValue": booleanValue as Bool? as Any,
14+
"booleanValue": booleanValue as Bool? as Any,
15+
"booleanValue": booleanValue as Bool? as Any,
16+
"booleanValue": booleanValue as Bool? as Any
17+
])
18+
}
19+
}

0 commit comments

Comments
 (0)