Skip to content

[Constraint solver] Simplify one-way constraints to Equal, not Bind. #26700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4635,7 +4635,8 @@ namespace {
}

Expr *visitOneWayExpr(OneWayExpr *E) {
return E->getSubExpr();
auto type = simplifyType(cs.getType(E));
return coerceToType(E->getSubExpr(), type, cs.getConstraintLocator(E));
}

Expr *visitTapExpr(TapExpr *E) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
}
break;

case ConstraintKind::OneWayBind: {
case ConstraintKind::OneWayEqual: {
// Don't produce any bindings if this type variable is on the left-hand
// side of a one-way binding.
auto firstType = constraint->getFirstType();
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3083,7 +3083,7 @@ namespace {
Type visitOneWayExpr(OneWayExpr *expr) {
auto locator = CS.getConstraintLocator(expr);
auto resultTypeVar = CS.createTypeVariable(locator, 0);
CS.addConstraint(ConstraintKind::OneWayBind, resultTypeVar,
CS.addConstraint(ConstraintKind::OneWayEqual, resultTypeVar,
CS.getType(expr->getSubExpr()), locator);
return resultTypeVar;
}
Expand Down
14 changes: 7 additions & 7 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
case ConstraintKind::BridgingConversion:
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
llvm_unreachable("Not a conversion");
}

Expand Down Expand Up @@ -1209,7 +1209,7 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
case ConstraintKind::ValueMember:
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
return false;
}

Expand Down Expand Up @@ -1394,7 +1394,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
case ConstraintKind::BridgingConversion:
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
llvm_unreachable("Not a relational constraint");
}

Expand Down Expand Up @@ -2811,7 +2811,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
case ConstraintKind::ValueMember:
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
llvm_unreachable("Not a relational constraint");
}
}
Expand Down Expand Up @@ -5248,7 +5248,7 @@ ConstraintSystem::simplifyOneWayConstraint(
}

// Translate this constraint into a one-way binding constraint.
return matchTypes(first, secondSimplified, ConstraintKind::Bind, flags,
return matchTypes(first, secondSimplified, ConstraintKind::Equal, flags,
locator);
}

Expand Down Expand Up @@ -7296,7 +7296,7 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
return simplifyFunctionComponentConstraint(kind, first, second,
subflags, locator);

case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
return simplifyOneWayConstraint(kind, first, second, subflags, locator);

case ConstraintKind::ValueMember:
Expand Down Expand Up @@ -7655,7 +7655,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
// Disjunction constraints are never solved here.
return SolutionKind::Unsolved;

case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
return simplifyOneWayConstraint(constraint.getKind(),
constraint.getFirstType(),
constraint.getSecondType(),
Expand Down
14 changes: 6 additions & 8 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Solution ConstraintSystem::finalize() {
}
}

for (auto tv : TypeVariables) {
for (auto tv : getTypeVariables()) {
if (getFixedType(tv))
continue;

Expand All @@ -95,7 +95,7 @@ Solution ConstraintSystem::finalize() {
}

// For each of the type variables, get its fixed type.
for (auto tv : TypeVariables) {
for (auto tv : getTypeVariables()) {
solution.typeBindings[tv] = simplifyType(tv)->reconstituteSugar(false);
}

Expand Down Expand Up @@ -198,12 +198,9 @@ void ConstraintSystem::applySolution(const Solution &solution) {
CurrentScore += solution.getFixedScore();

// Assign fixed types to the type variables solved by this solution.
llvm::SmallPtrSet<TypeVariableType *, 4>
knownTypeVariables(TypeVariables.begin(), TypeVariables.end());
for (auto binding : solution.typeBindings) {
// If we haven't seen this type variable before, record it now.
if (knownTypeVariables.insert(binding.first).second)
TypeVariables.push_back(binding.first);
addTypeVariable(binding.first);

// If we don't already have a fixed type for this type variable,
// assign the fixed type from the solution.
Expand Down Expand Up @@ -475,7 +472,8 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
ConstraintSystem::SolverScope::~SolverScope() {
// Erase the end of various lists.
cs.resolvedOverloadSets = resolvedOverloadSets;
truncate(cs.TypeVariables, numTypeVariables);
while (cs.TypeVariables.size() > numTypeVariables)
cs.TypeVariables.pop_back();

// Restore bindings.
cs.restoreTypeVariableBindings(cs.solverState->savedBindings.size() -
Expand Down Expand Up @@ -1683,7 +1681,7 @@ void ConstraintSystem::ArgumentInfoCollector::walk(Type argType) {
case ConstraintKind::SelfObjectOfProtocol:
case ConstraintKind::ConformsTo:
case ConstraintKind::Defaultable:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
break;
}
}
Expand Down
10 changes: 5 additions & 5 deletions lib/Sema/CSStep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ComponentStep::Scope::Scope(ComponentStep &component)
TypeVars = std::move(CS.TypeVariables);

for (auto *typeVar : component.TypeVars)
CS.TypeVariables.push_back(typeVar);
CS.addTypeVariable(typeVar);

auto &workList = CS.InactiveConstraints;
workList.splice(workList.end(), *component.Constraints);
Expand Down Expand Up @@ -92,7 +92,7 @@ void SplitterStep::computeFollowupSteps(
CG.optimize();

// Compute the connected components of the constraint graph.
auto components = CG.computeConnectedComponents(CS.TypeVariables);
auto components = CG.computeConnectedComponents(CS.getTypeVariables());
unsigned numComponents = components.size();
if (numComponents < 2) {
steps.push_back(llvm::make_unique<ComponentStep>(
Expand All @@ -106,10 +106,10 @@ void SplitterStep::computeFollowupSteps(
CG.verify();

log << "---Constraint graph---\n";
CG.print(CS.TypeVariables, log);
CG.print(CS.getTypeVariables(), log);

log << "---Connected components---\n";
CG.printConnectedComponents(CS.TypeVariables, log);
CG.printConnectedComponents(CS.getTypeVariables(), log);
}

// Take the orphaned constraints, because they'll go into a component now.
Expand Down Expand Up @@ -312,7 +312,7 @@ StepResult ComponentStep::take(bool prevFailed) {
// Activate all of the one-way constraints.
SmallVector<Constraint *, 4> oneWayConstraints;
for (auto &constraint : CS.InactiveConstraints) {
if (constraint.getKind() == ConstraintKind::OneWayBind)
if (constraint.isOneWayConstraint())
oneWayConstraints.push_back(&constraint);
}
for (auto constraint : oneWayConstraints) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSStep.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ class ComponentStep final : public SolverStep {
ConstraintSystem &CS;
ConstraintSystem::SolverScope *SolverScope;

std::vector<TypeVariableType *> TypeVars;
SetVector<TypeVariableType *> TypeVars;
ConstraintSystem::SolverScope *PrevPartialScope = nullptr;

// The component this scope is associated with.
Expand Down
10 changes: 5 additions & 5 deletions lib/Sema/Constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
assert(!First.isNull());
assert(!Second.isNull());
break;
Expand Down Expand Up @@ -135,7 +135,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
llvm_unreachable("Wrong constructor");

case ConstraintKind::KeyPath:
Expand Down Expand Up @@ -239,7 +239,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());

case ConstraintKind::BindOverload:
Expand Down Expand Up @@ -312,7 +312,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
case ConstraintKind::DynamicTypeOf: Out << " dynamicType type of "; break;
case ConstraintKind::EscapableFunctionOf: Out << " @escaping type of "; break;
case ConstraintKind::OpenedExistentialOf: Out << " opened archetype of "; break;
case ConstraintKind::OneWayBind: Out << " one-way bind to "; break;
case ConstraintKind::OneWayEqual: Out << " one-way bind to "; break;
case ConstraintKind::KeyPath:
Out << " key path from ";
getSecondType()->print(Out);
Expand Down Expand Up @@ -521,7 +521,7 @@ gatherReferencedTypeVars(Constraint *constraint,
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
constraint->getFirstType()->getTypeVariables(typeVars);
constraint->getSecondType()->getTypeVariables(typeVars);
break;
Expand Down
13 changes: 9 additions & 4 deletions lib/Sema/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,11 @@ enum class ConstraintKind : char {
/// The first type is a type that's a candidate to be the underlying type of
/// the second opaque archetype.
OpaqueUnderlyingType,
/// The first type will be bound to the second type, but only when the
/// The first type will be equal to the second type, but only when the
/// second type has been fully determined (and mapped down to a concrete
/// type). At that point, this constraint will be treated like a `Bind`
/// type). At that point, this constraint will be treated like an `Equal`
/// constraint.
OneWayBind,
OneWayEqual,
};

/// Classification of the different kinds of constraints.
Expand Down Expand Up @@ -495,7 +495,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
case ConstraintKind::BindOverload:
case ConstraintKind::OptionalObject:
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::OneWayBind:
case ConstraintKind::OneWayEqual:
return ConstraintClassification::Relational;

case ConstraintKind::ValueMember:
Expand Down Expand Up @@ -609,6 +609,11 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// e.g. coercion constraint "as X" which forms a disjunction.
bool isExplicitConversion() const;

/// Whether this is a one-way constraint.
bool isOneWayConstraint() const {
return Kind == ConstraintKind::OneWayEqual;
}

/// Retrieve the overload choice for an overload-binding constraint.
OverloadChoice getOverloadChoice() const {
assert(Kind == ConstraintKind::BindOverload);
Expand Down
30 changes: 19 additions & 11 deletions lib/Sema/ConstraintGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,18 +379,24 @@ llvm::TinyPtrVector<Constraint *> ConstraintGraph::gatherConstraints(
llvm::TinyPtrVector<Constraint *> constraints;

// Whether we should consider this constraint at all.
auto &reprNode = (*this)[CS.getRepresentative(typeVar)];
auto equivClass = reprNode.getEquivalenceClass();
auto rep = CS.getRepresentative(typeVar);
auto shouldConsiderConstraint = [&](Constraint *constraint) {
// For a one-way constraint, only consider it when the type variable
// is on the left-hand side of the the binding. Otherwise, it is not
// relevant.
if (constraint->getKind() == ConstraintKind::OneWayBind) {
// is on the right-hand side of the the binding, and the left-hand side of
// the binding is one of the type variables currently under consideration.
if (constraint->isOneWayConstraint()) {
auto lhsTypeVar =
constraint->getFirstType()->castTo<TypeVariableType>();
if (std::find(equivClass.begin(), equivClass.end(), lhsTypeVar)
== equivClass.end())
if (!CS.isActiveTypeVariable(lhsTypeVar))
return false;

SmallVector<TypeVariableType *, 2> rhsTypeVars;
constraint->getSecondType()->getTypeVariables(rhsTypeVars);
for (auto rhsTypeVar : rhsTypeVars) {
if (CS.getRepresentative(rhsTypeVar) == rep)
return true;
}
return false;
}

return true;
Expand Down Expand Up @@ -421,6 +427,8 @@ llvm::TinyPtrVector<Constraint *> ConstraintGraph::gatherConstraints(
}
};

auto &reprNode = (*this)[CS.getRepresentative(typeVar)];
auto equivClass = reprNode.getEquivalenceClass();
for (auto typeVar : equivClass) {
auto &node = (*this)[typeVar];
for (auto constraint : node.getConstraints()) {
Expand Down Expand Up @@ -625,7 +633,7 @@ namespace {
continue;

TypeVariableType *typeVar;
if (constraint.getKind() == ConstraintKind::OneWayBind) {
if (constraint.isOneWayConstraint()) {
// For one-way constraints, associate the constraint with the
// left-hand type variable.
typeVar = constraint.getFirstType()->castTo<TypeVariableType>();
Expand Down Expand Up @@ -772,7 +780,7 @@ namespace {
},
[&](Constraint *constraint) {
// Record and skip one-way constraints.
if (constraint->getKind() == ConstraintKind::OneWayBind) {
if (constraint->isOneWayConstraint()) {
oneWayConstraints.push_back(constraint);
return false;
}
Expand Down Expand Up @@ -1275,7 +1283,7 @@ void ConstraintGraph::dump() {
void ConstraintGraph::dump(llvm::raw_ostream &out) {
llvm::SaveAndRestore<bool>
debug(CS.getASTContext().LangOpts.DebugConstraintSolver, true);
print(CS.TypeVariables, out);
print(CS.getTypeVariables(), out);
}

void ConstraintGraph::printConnectedComponents(
Expand Down Expand Up @@ -1314,7 +1322,7 @@ void ConstraintGraph::printConnectedComponents(
void ConstraintGraph::dumpConnectedComponents() {
llvm::SaveAndRestore<bool>
debug(CS.getASTContext().LangOpts.DebugConstraintSolver, true);
printConnectedComponents(CS.TypeVariables, llvm::dbgs());
printConnectedComponents(CS.getTypeVariables(), llvm::dbgs());
}

#pragma mark Verification of graph invariants
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/ConstraintGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ class ConstraintGraph {
ConstraintSystem &CS;

/// The type variables in this graph, in stable order.
SmallVector<TypeVariableType *, 4> TypeVariables;
std::vector<TypeVariableType *> TypeVariables;

/// Constraints that are "orphaned" because they contain no type variables.
SmallVector<Constraint *, 4> OrphanedConstraints;
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ bool ConstraintSystem::hasFreeTypeVariables() {
}

void ConstraintSystem::addTypeVariable(TypeVariableType *typeVar) {
TypeVariables.push_back(typeVar);
TypeVariables.insert(typeVar);

// Notify the constraint graph.
(void)CG[typeVar];
Expand Down
12 changes: 9 additions & 3 deletions lib/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,7 @@ class ConstraintSystem {
/// solution it represents.
Score CurrentScore;

std::vector<TypeVariableType *> TypeVariables;
llvm::SetVector<TypeVariableType *> TypeVariables;

/// Maps expressions to types for choosing a favored overload
/// type in a disjunction constraint.
Expand Down Expand Up @@ -1766,9 +1766,15 @@ class ConstraintSystem {

/// Retrieve the set of active type variables.
ArrayRef<TypeVariableType *> getTypeVariables() const {
return TypeVariables;
return TypeVariables.getArrayRef();
}


/// Whether the given type variable is active in the constraint system at
/// the moment.
bool isActiveTypeVariable(TypeVariableType *typeVar) const {
return TypeVariables.count(typeVar) > 0;
}

TypeBase* getFavoredType(Expr *E) {
assert(E != nullptr);
return this->FavoredTypes[E];
Expand Down
Loading