Skip to content

Commit 67a7214

Browse files
committed
[ConstraintSystem] Compute variables referenced by conjunction elements incrementally
Attempting to pre-compute a set of referenced type variables upfront is incorrect because parameter(s) and/or result type could be bound before conjunction is attempted. Let's compute a set of referenced variables before each element gets attempted.
1 parent da3cef2 commit 67a7214

File tree

6 files changed

+94
-80
lines changed

6 files changed

+94
-80
lines changed

include/swift/Sema/Constraint.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -583,16 +583,14 @@ class Constraint final : public llvm::ilist_node<Constraint>,
583583
Optional<TrailingClosureMatching> trailingClosureMatching,
584584
ConstraintLocator *locator);
585585

586-
static Constraint *
587-
createClosureBodyElement(ConstraintSystem &cs, ASTNode node,
588-
ConstraintLocator *locator,
589-
ArrayRef<TypeVariableType *> referencedVars = {});
590-
591-
static Constraint *
592-
createClosureBodyElement(ConstraintSystem &cs, ASTNode node,
593-
ContextualTypeInfo context,
594-
ConstraintLocator *locator,
595-
ArrayRef<TypeVariableType *> referencedVars = {});
586+
static Constraint *createClosureBodyElement(ConstraintSystem &cs,
587+
ASTNode node,
588+
ConstraintLocator *locator);
589+
590+
static Constraint *createClosureBodyElement(ConstraintSystem &cs,
591+
ASTNode node,
592+
ContextualTypeInfo context,
593+
ConstraintLocator *locator);
596594

597595
/// Determine the kind of constraint.
598596
ConstraintKind getKind() const { return Kind; }

include/swift/Sema/ConstraintSystem.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,6 +2226,7 @@ class ConstraintSystem {
22262226
friend class ComponentStep;
22272227
friend class TypeVariableStep;
22282228
friend class ConjunctionStep;
2229+
friend class ConjunctionElement;
22292230
friend class RequirementFailure;
22302231
friend class MissingMemberFailure;
22312232

@@ -5609,14 +5610,17 @@ class ConjunctionElement {
56095610

56105611
bool attempt(ConstraintSystem &cs) const;
56115612

5612-
ArrayRef<TypeVariableType *> getReferencedVars() const {
5613-
return Element->getTypeVariables();
5614-
}
5615-
56165613
void print(llvm::raw_ostream &Out, SourceManager *SM) const {
56175614
Out << "conjunction element ";
56185615
Element->print(Out, SM);
56195616
}
5617+
5618+
private:
5619+
/// Find type variables referenced by this conjunction element.
5620+
/// If this is a closure body element, it would look inside \c ASTNode.
5621+
void
5622+
findReferencedVariables(ConstraintSystem &cs,
5623+
SmallPtrSetImpl<TypeVariableType *> &typeVars) const;
56205624
};
56215625

56225626
class TypeVariableBinding {

lib/Sema/CSClosure.cpp

Lines changed: 60 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -29,46 +29,18 @@ class TypeVariableRefFinder : public ASTWalker {
2929
ConstraintSystem &CS;
3030
ASTNode Parent;
3131

32-
llvm::SmallSetVector<TypeVariableType *, 2> referencedVars;
32+
llvm::SmallPtrSetImpl<TypeVariableType *> &ReferencedVars;
3333

3434
public:
35-
TypeVariableRefFinder(ConstraintSystem &cs, ASTNode parent)
36-
: CS(cs), Parent(parent) {}
35+
TypeVariableRefFinder(
36+
ConstraintSystem &cs, ASTNode parent,
37+
llvm::SmallPtrSetImpl<TypeVariableType *> &referencedVars)
38+
: CS(cs), Parent(parent), ReferencedVars(referencedVars) {}
3739

3840
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
3941
if (auto *DRE = dyn_cast<DeclRefExpr>(expr)) {
40-
if (auto type = CS.getTypeIfAvailable(DRE->getDecl())) {
41-
// The logic below is handling not-yet resolved parameter
42-
// types referenced in the body e.g. `$0` or `x`.
43-
if (auto *typeVar = type->getAs<TypeVariableType>()) {
44-
referencedVars.insert(typeVar);
45-
46-
// It is possible that contextual type of a parameter
47-
// has been assigned to an anonymous of named argument
48-
// early, to facilitate closure type checking. Such a
49-
// type can have type variables inside e.g.
50-
//
51-
// func test<T>(_: (UnsafePointer<T>) -> Void) {}
52-
//
53-
// test { ptr in
54-
// ...
55-
// }
56-
//
57-
// Type variable representing `ptr` in the body of
58-
// this closure would be bound to `UnsafePointer<$T>`
59-
// in this case, where `$T` is a type variable for a
60-
// generic parameter `T`.
61-
auto simplifiedTy =
62-
CS.getFixedTypeRecursive(typeVar, /*wantRValue=*/false);
63-
64-
if (!simplifiedTy->isEqual(typeVar) &&
65-
simplifiedTy->hasTypeVariable()) {
66-
SmallPtrSet<TypeVariableType *, 4> typeVars;
67-
simplifiedTy->getTypeVariables(typeVars);
68-
referencedVars.insert(typeVars.begin(), typeVars.end());
69-
}
70-
}
71-
}
42+
if (auto type = CS.getTypeIfAvailable(DRE->getDecl()))
43+
inferVariables(type);
7244
}
7345

7446
return {true, expr};
@@ -80,17 +52,45 @@ class TypeVariableRefFinder : public ASTWalker {
8052
// explicitly.
8153
if (isa<ReturnStmt>(stmt)) {
8254
if (auto *closure = getAsExpr<ClosureExpr>(Parent)) {
83-
auto resultTy = CS.getClosureType(closure)->getResult();
84-
if (auto *typeVar = resultTy->getAs<TypeVariableType>())
85-
referencedVars.insert(typeVar);
55+
inferVariables(CS.getClosureType(closure)->getResult());
8656
}
8757
}
8858

8959
return {true, stmt};
9060
}
9161

92-
ArrayRef<TypeVariableType *> getReferencedVars() const {
93-
return referencedVars.getArrayRef();
62+
private:
63+
void inferVariables(Type type) {
64+
auto *typeVar = type->getWithoutSpecifierType()->getAs<TypeVariableType>();
65+
if (!typeVar)
66+
return;
67+
68+
// Record the type variable itself because it has to
69+
// be in scope even when already bound.
70+
ReferencedVars.insert(typeVar);
71+
72+
// It is possible that contextual type of a parameter/result
73+
// has been assigned to e.g. an anonymous or named argument
74+
// early, to facilitate closure type checking. Such a
75+
// type can have type variables inside e.g.
76+
//
77+
// func test<T>(_: (UnsafePointer<T>) -> Void) {}
78+
//
79+
// test { ptr in
80+
// ...
81+
// }
82+
//
83+
// Type variable representing `ptr` in the body of
84+
// this closure would be bound to `UnsafePointer<$T>`
85+
// in this case, where `$T` is a type variable for a
86+
// generic parameter `T`.
87+
auto simplifiedTy = CS.getFixedTypeRecursive(typeVar, /*wantRValue=*/false);
88+
89+
if (!simplifiedTy->isEqual(typeVar) && simplifiedTy->hasTypeVariable()) {
90+
SmallPtrSet<TypeVariableType *, 4> typeVars;
91+
simplifiedTy->getTypeVariables(typeVars);
92+
ReferencedVars.insert(typeVars.begin(), typeVars.end());
93+
}
9494
}
9595
};
9696

@@ -151,16 +151,8 @@ static void createConjunction(ConstraintSystem &cs,
151151
if (!isViableElement(element))
152152
continue;
153153

154-
TypeVariableRefFinder refFinder(cs, locator->getAnchor());
155-
156-
// Solvable elements have to bring any of the referenced
157-
// outer context type variables into scope.
158-
if (element.is<Decl *>() || element.is<StmtCondition *>() ||
159-
element.is<Expr *>() || element.isStmt(StmtKind::Return))
160-
element.walk(refFinder);
161-
162-
constraints.push_back(Constraint::createClosureBodyElement(
163-
cs, element, context, elementLoc, refFinder.getReferencedVars()));
154+
constraints.push_back(
155+
Constraint::createClosureBodyElement(cs, element, context, elementLoc));
164156
}
165157

166158
cs.addUnsolvedConstraint(Constraint::createConjunction(
@@ -1334,3 +1326,21 @@ bool ConstraintSystem::applySolutionToBody(Solution &solution,
13341326
closure->setBodyState(ClosureExpr::BodyState::TypeCheckedWithSignature);
13351327
return false;
13361328
}
1329+
1330+
void ConjunctionElement::findReferencedVariables(
1331+
ConstraintSystem &cs, SmallPtrSetImpl<TypeVariableType *> &typeVars) const {
1332+
auto referencedVars = Element->getTypeVariables();
1333+
typeVars.insert(referencedVars.begin(), referencedVars.end());
1334+
1335+
if (Element->getKind() != ConstraintKind::ClosureBodyElement)
1336+
return;
1337+
1338+
ASTNode element = Element->getClosureElement();
1339+
auto *locator = Element->getLocator();
1340+
1341+
TypeVariableRefFinder refFinder(cs, locator->getAnchor(), typeVars);
1342+
1343+
if (element.is<Decl *>() || element.is<StmtCondition *>() ||
1344+
element.is<Expr *>() || element.isStmt(StmtKind::Return))
1345+
element.walk(refFinder);
1346+
}

lib/Sema/CSSolver.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,6 +2313,15 @@ void DisjunctionChoice::propagateConversionInfo(ConstraintSystem &cs) const {
23132313
}
23142314

23152315
bool ConjunctionElement::attempt(ConstraintSystem &cs) const {
2316+
// First, let's bring all referenced variables into scope.
2317+
{
2318+
llvm::SmallPtrSet<TypeVariableType *, 4> referencedVars;
2319+
findReferencedVariables(cs, referencedVars);
2320+
2321+
for (auto *typeVar : referencedVars)
2322+
cs.addTypeVariable(typeVar);
2323+
}
2324+
23162325
auto result = cs.simplifyConstraint(*Element);
23172326
return result != ConstraintSystem::SolutionKind::Error;
23182327
}

lib/Sema/CSStep.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -799,10 +799,6 @@ bool ConjunctionStep::attempt(const ConjunctionElement &element) {
799799
CS.applySolution(Solutions.pop_back_val());
800800
}
801801

802-
// Bring all of the referenced variables into scope.
803-
for (auto *typeVar : element.getReferencedVars())
804-
CS.addTypeVariable(typeVar);
805-
806802
// Make sure that element is solved in isolation
807803
// by dropping all scoring information.
808804
CS.CurrentScore = Score();

lib/Sema/Constraint.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
346346
getLocator());
347347

348348
case ConstraintKind::ClosureBodyElement:
349-
return createClosureBodyElement(cs, getClosureElement(), getLocator(),
350-
getTypeVariables());
349+
return createClosureBodyElement(cs, getClosureElement(), getLocator());
351350
}
352351

353352
llvm_unreachable("Unhandled ConstraintKind in switch.");
@@ -1015,19 +1014,17 @@ Constraint *Constraint::createApplicableFunction(
10151014
return constraint;
10161015
}
10171016

1018-
Constraint *Constraint::createClosureBodyElement(
1019-
ConstraintSystem &cs, ASTNode node, ConstraintLocator *locator,
1020-
ArrayRef<TypeVariableType *> referencedVars) {
1021-
return createClosureBodyElement(cs, node, ContextualTypeInfo(), locator,
1022-
referencedVars);
1017+
Constraint *Constraint::createClosureBodyElement(ConstraintSystem &cs,
1018+
ASTNode node,
1019+
ConstraintLocator *locator) {
1020+
return createClosureBodyElement(cs, node, ContextualTypeInfo(), locator);
10231021
}
10241022

1025-
Constraint *Constraint::createClosureBodyElement(
1026-
ConstraintSystem &cs, ASTNode node, ContextualTypeInfo context,
1027-
ConstraintLocator *locator, ArrayRef<TypeVariableType *> referencedVars) {
1023+
Constraint *Constraint::createClosureBodyElement(ConstraintSystem &cs,
1024+
ASTNode node,
1025+
ContextualTypeInfo context,
1026+
ConstraintLocator *locator) {
10281027
SmallPtrSet<TypeVariableType *, 4> typeVars;
1029-
typeVars.insert(referencedVars.begin(), referencedVars.end());
1030-
10311028
unsigned size = totalSizeToAlloc<TypeVariableType *>(typeVars.size());
10321029
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
10331030
return new (mem) Constraint(node, context, locator, typeVars);

0 commit comments

Comments
 (0)