Skip to content

Commit 9a883e6

Browse files
authored
Merge pull request #36193 from xedin/followup-to-incremental-bindings
[ConstraintSystem] Delay inference until let's clear that type variable attempt is successful
2 parents 9ef2b21 + ca16c37 commit 9a883e6

File tree

6 files changed

+128
-62
lines changed

6 files changed

+128
-62
lines changed

include/swift/Sema/ConstraintGraph.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class Constraint;
4444
class ConstraintGraph;
4545
class ConstraintGraphScope;
4646
class ConstraintSystem;
47+
class TypeVariableBinding;
4748

4849
/// A single node in the constraint graph, which represents a type variable.
4950
class ConstraintGraphNode {
@@ -135,6 +136,22 @@ class ConstraintGraphNode {
135136
/// equivalence class changes.
136137
void reintroduceToInference(Constraint *constraint, bool notifyReferencedVars);
137138

139+
/// Similar to \c introduceToInference(Constraint *, ...) this method is going
140+
/// to notify inference that this type variable has been bound to a concrete
141+
/// type.
142+
///
143+
/// The reason why this can't simplify be a part of \c bindTypeVariable
144+
/// is related to the fact that it's sometimes expensive to re-compute
145+
/// bindings (i.e. if `DependentMemberType` is involved, because it requires
146+
/// a conformance lookup), so inference has to be delayed until its clear that
147+
/// type variable has been bound to a valid type and solver can make progress.
148+
void introduceToInference(Type fixedType);
149+
150+
/// Opposite of \c introduceToInference(Type)
151+
void
152+
retractFromInference(Type fixedType,
153+
SmallPtrSetImpl<TypeVariableType *> &referencedVars);
154+
138155
/// Drop all previously collected bindings and re-infer based on the
139156
/// current set constraints associated with this equivalence class.
140157
void resetBindingSet();
@@ -148,6 +165,7 @@ class ConstraintGraphNode {
148165
/// This is useful in situations when type variable gets bound and unbound,
149166
/// or equivalence class changes.
150167
void notifyReferencingVars() const;
168+
151169
/// }
152170

153171
/// The constraint graph this node belongs to.
@@ -192,6 +210,8 @@ class ConstraintGraphNode {
192210
void verify(ConstraintGraph &cg);
193211

194212
friend class ConstraintGraph;
213+
friend class ConstraintSystem;
214+
friend class TypeVariableBinding;
195215
};
196216

197217
/// A graph that describes the relationships among the various type variables

include/swift/Sema/ConstraintSystem.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3631,6 +3631,10 @@ class ConstraintSystem {
36313631

36323632
/// Indicates that we are applying a fix.
36333633
TMF_ApplyingFix = 0x02,
3634+
3635+
/// Indicates that we are attempting a possible type for
3636+
/// a type variable.
3637+
TMF_BindingTypeVariable = 0x04,
36343638
};
36353639

36363640
/// Options that govern how type matching should proceed.
@@ -3702,10 +3706,14 @@ class ConstraintSystem {
37023706
/// \param type The fixed type to which the type variable will be bound.
37033707
///
37043708
/// \param updateState Whether to update the state based on this binding.
3705-
/// False when we're only assigning a type as part of reconstructing
3709+
/// False when we're only assigning a type as part of reconstructing
37063710
/// a complete solution from partial solutions.
3711+
///
3712+
/// \param notifyBindingInference Whether to notify binding inference about
3713+
/// the change to this type variable.
37073714
void assignFixedType(TypeVariableType *typeVar, Type type,
3708-
bool updateState = true);
3715+
bool updateState = true,
3716+
bool notifyBindingInference = true);
37093717

37103718
/// Determine if the type in question is an Array<T> and, if so, provide the
37113719
/// element type of the array.

lib/Sema/CSBindings.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,7 +1793,16 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
17931793
type = type->reconstituteSugar(/*recursive=*/false);
17941794
}
17951795

1796-
cs.addConstraint(ConstraintKind::Bind, TypeVar, type, srcLocator);
1796+
ConstraintSystem::TypeMatchOptions options;
1797+
1798+
options |= ConstraintSystem::TMF_GenerateConstraints;
1799+
options |= ConstraintSystem::TMF_BindingTypeVariable;
1800+
1801+
auto result =
1802+
cs.matchTypes(TypeVar, type, ConstraintKind::Bind, options, srcLocator);
1803+
1804+
if (result.isFailure())
1805+
return false;
17971806

17981807
auto reportHole = [&]() {
17991808
if (cs.isForCodeCompletion()) {
@@ -1825,5 +1834,16 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
18251834
return true;
18261835
}
18271836

1828-
return !cs.failedConstraint && !cs.simplify();
1837+
if (cs.simplify())
1838+
return false;
1839+
1840+
// If all of the re-activated constraints where simplified,
1841+
// let's notify binding inference about the fact that type
1842+
// variable has been bound successfully.
1843+
{
1844+
auto &CG = cs.getConstraintGraph();
1845+
CG[TypeVar].introduceToInference(type);
1846+
}
1847+
1848+
return true;
18291849
}

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3016,7 +3016,8 @@ ConstraintSystem::matchTypesBindTypeVar(
30163016
: getTypeMatchFailure(locator);
30173017
}
30183018

3019-
assignFixedType(typeVar, type);
3019+
assignFixedType(typeVar, type, /*updateState=*/true,
3020+
/*notifyInference=*/!flags.contains(TMF_BindingTypeVariable));
30203021

30213022
return getTypeMatchSuccess();
30223023
}

lib/Sema/ConstraintGraph.cpp

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,13 @@ inference::PotentialBindings &ConstraintGraphNode::getCurrentBindings() {
275275

276276
static bool isUsefulForReferencedVars(Constraint *constraint) {
277277
switch (constraint->getKind()) {
278-
// Don't attempt to propagate information about `Bind`s to referenced
279-
// variables since they are adjacent through that binding already, and
280-
// there is no useful information in trying to process that kind of
278+
// Don't attempt to propagate information about `Bind`s and
279+
// `BindOverload`s to referenced variables since they are
280+
// adjacent through that binding already, and there is no
281+
// useful information in trying to process that kind of
281282
// constraint.
282283
case ConstraintKind::Bind:
284+
case ConstraintKind::BindOverload:
283285
return false;
284286

285287
default:
@@ -335,6 +337,51 @@ void ConstraintGraphNode::reintroduceToInference(Constraint *constraint,
335337
introduceToInference(constraint, notifyReferencedVars);
336338
}
337339

340+
void ConstraintGraphNode::introduceToInference(Type fixedType) {
341+
// Notify all of the type variables that reference this one.
342+
//
343+
// Since this type variable has been replaced with a fixed type
344+
// all of the concrete types that reference it are going to change,
345+
// which means that all of the not-yet-attempted bindings should
346+
// change as well.
347+
notifyReferencingVars();
348+
349+
if (!fixedType->hasTypeVariable())
350+
return;
351+
352+
SmallPtrSet<TypeVariableType *, 4> referencedVars;
353+
fixedType->getTypeVariables(referencedVars);
354+
355+
for (auto *referencedVar : referencedVars) {
356+
auto &node = CG[referencedVar];
357+
358+
// Newly referred vars need to re-introduce all constraints associated
359+
// with this type variable since they are now going to be used in
360+
// all of the constraints that reference bound type variable.
361+
for (auto *constraint : getConstraints()) {
362+
if (isUsefulForReferencedVars(constraint))
363+
node.reintroduceToInference(constraint,
364+
/*notifyReferencedVars=*/false);
365+
}
366+
}
367+
}
368+
369+
void ConstraintGraphNode::retractFromInference(
370+
Type fixedType, SmallPtrSetImpl<TypeVariableType *> &referencedVars) {
371+
// Notify referencing variables (just like in bound case) that this
372+
// type variable has been modified.
373+
notifyReferencingVars();
374+
375+
// TODO: This might be an overkill but it's (currently)
376+
// the simpliest way to reliably ensure that all of the
377+
// no longer related constraints have been retracted.
378+
for (auto *referencedVar : referencedVars) {
379+
auto &node = CG[referencedVar];
380+
if (node.forRepresentativeVar())
381+
node.resetBindingSet();
382+
}
383+
}
384+
338385
void ConstraintGraphNode::resetBindingSet() {
339386
assert(forRepresentativeVar());
340387

@@ -541,65 +588,34 @@ void ConstraintGraph::bindTypeVariable(TypeVariableType *typeVar, Type fixed) {
541588

542589
auto &node = (*this)[typeVar];
543590

544-
// Notify all of the type variables that reference this one.
545-
//
546-
// Since this type variable has been replaced with a fixed type
547-
// all of the concrete types that reference it are going to change,
548-
// which means that all of the not-yet-attempted bindings should
549-
// change as well.
550-
node.notifyReferencingVars();
591+
llvm::SmallPtrSet<TypeVariableType *, 4> referencedVars;
592+
fixed->getTypeVariables(referencedVars);
551593

552-
if (!fixed->hasTypeVariable())
553-
return;
554-
555-
llvm::SmallPtrSet<TypeVariableType *, 4> typeVars;
556-
fixed->getTypeVariables(typeVars);
557-
558-
for (auto otherTypeVar : typeVars) {
594+
for (auto otherTypeVar : referencedVars) {
559595
if (typeVar == otherTypeVar)
560596
continue;
561597

562598
auto &otherNode = (*this)[otherTypeVar];
563599

564600
otherNode.addReferencedBy(typeVar);
565601
node.addReferencedVar(otherTypeVar);
566-
567-
// Newly referred vars need to re-introduce all constraints associated
568-
// with this type variable since they are now going to be used in
569-
// all of the constraints that reference bound type variable.
570-
for (auto *constraint : (*this)[typeVar].getConstraints()) {
571-
if (isUsefulForReferencedVars(constraint))
572-
otherNode.reintroduceToInference(constraint,
573-
/*notifyReferencedVars=*/false);
574-
}
575602
}
576603
}
577604

578605
void ConstraintGraph::unbindTypeVariable(TypeVariableType *typeVar, Type fixed) {
579606
auto &node = (*this)[typeVar];
580607

581-
// Notify referencing variables (just like in bound case) that this
582-
// type variable has been modified.
583-
node.notifyReferencingVars();
584-
585-
if (!fixed->hasTypeVariable())
586-
return;
587-
588-
llvm::SmallPtrSet<TypeVariableType *, 4> typeVars;
589-
fixed->getTypeVariables(typeVars);
608+
llvm::SmallPtrSet<TypeVariableType *, 4> referencedVars;
609+
fixed->getTypeVariables(referencedVars);
590610

591-
for (auto otherTypeVar : typeVars) {
611+
for (auto otherTypeVar : referencedVars) {
592612
auto &otherNode = (*this)[otherTypeVar];
593613

594614
otherNode.removeReferencedBy(typeVar);
595615
node.removeReference(otherTypeVar);
596-
597-
// TODO: This might be an overkill but it's (currently)
598-
// the simpliest way to reliably ensure that all of the
599-
// no longer related constraints have been retracted.
600-
if (otherNode.forRepresentativeVar())
601-
otherNode.resetBindingSet();
602616
}
617+
618+
node.retractFromInference(fixed, referencedVars);
603619
}
604620

605621
#pragma mark Algorithms

lib/Sema/ConstraintSystem.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ bool ConstraintSystem::typeVarOccursInType(TypeVariableType *typeVar,
155155
}
156156

157157
void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
158-
bool updateState) {
158+
bool updateState,
159+
bool notifyBindingInference) {
159160
assert(!type->hasError() &&
160161
"Should not be assigning a type involving ErrorType!");
161162

@@ -167,41 +168,41 @@ void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
167168
if (!type->isTypeVariableOrMember()) {
168169
// If this type variable represents a literal, check whether we picked the
169170
// default literal type. First, find the corresponding protocol.
170-
ProtocolDecl *literalProtocol = nullptr;
171+
//
171172
// If we have the constraint graph, we can check all type variables in
172173
// the equivalence class. This is the More Correct path.
173174
// FIXME: Eliminate the less-correct path.
174175
auto typeVarRep = getRepresentative(typeVar);
175-
for (auto tv : CG[typeVarRep].getEquivalenceClass()) {
176+
for (auto *tv : CG[typeVarRep].getEquivalenceClass()) {
176177
auto locator = tv->getImpl().getLocator();
177-
if (!locator || !locator->getPath().empty())
178-
continue;
178+
if (!(locator && (locator->directlyAt<CollectionExpr>() ||
179+
locator->directlyAt<LiteralExpr>())))
180+
continue;
179181

180-
auto *anchor = getAsExpr(locator->getAnchor());
181-
if (!anchor)
182+
auto *literalProtocol = TypeChecker::getLiteralProtocol(
183+
getASTContext(), castToExpr(locator->getAnchor()));
184+
if (!literalProtocol)
182185
continue;
183186

184-
literalProtocol =
185-
TypeChecker::getLiteralProtocol(getASTContext(), anchor);
186-
if (literalProtocol)
187-
break;
188-
}
189-
190-
// If the protocol has a default type, check it.
191-
if (literalProtocol) {
187+
// If the protocol has a default type, check it.
192188
if (auto defaultType = TypeChecker::getDefaultType(literalProtocol, DC)) {
193189
// Check whether the nominal types match. This makes sure that we
194190
// properly handle Array vs. Array<T>.
195191
if (defaultType->getAnyNominal() != type->getAnyNominal()) {
196192
increaseScore(SK_NonDefaultLiteral);
197193
}
198194
}
195+
196+
break;
199197
}
200198
}
201199

202200
// Notify the constraint graph.
203201
CG.bindTypeVariable(typeVar, type);
204202
addTypeVariableConstraintsToWorkList(typeVar);
203+
204+
if (notifyBindingInference)
205+
CG[typeVar].introduceToInference(type);
205206
}
206207

207208
void ConstraintSystem::addTypeVariableConstraintsToWorkList(

0 commit comments

Comments
 (0)