Skip to content

Commit b9b8f08

Browse files
committed
[Constraint system] Switch closure constraint generation to a visitor.
In preparation for implementing support for multiple-statement closure inference, switch closure constraint generation over to a statement visitor. Only the subset of statements that correspond to single-expression closures is currently handled; there is no way to enable this for multiple-statement closures yet.
1 parent 451e3cc commit b9b8f08

File tree

1 file changed

+105
-12
lines changed

1 file changed

+105
-12
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 105 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,111 @@
2020
using namespace swift;
2121
using namespace swift::constraints;
2222

23+
namespace {
24+
25+
/// Statement visitor that generates constraints for a given closure body.
26+
class ClosureConstraintGenerator
27+
: public StmtVisitor<ClosureConstraintGenerator, void> {
28+
friend StmtVisitor<ClosureConstraintGenerator, void>;
29+
30+
ConstraintSystem &cs;
31+
ClosureExpr *closure;
32+
Type closureResultType;
33+
34+
public:
35+
/// Whether an error was encountered while generating constraints.
36+
bool hadError = false;
37+
38+
ClosureConstraintGenerator(ConstraintSystem &cs, ClosureExpr *closure,
39+
Type closureResultType)
40+
: cs(cs), closure(closure), closureResultType(closureResultType) { }
41+
42+
private:
43+
void visitDecl(Decl *decl) {
44+
// Just ignore #if; the chosen children should appear in the
45+
// surrounding context. This isn't good for source tools but it
46+
// at least works.
47+
if (isa<IfConfigDecl>(decl))
48+
return;
49+
50+
// Skip #warning/#error; we'll handle them when applying the closure.
51+
if (isa<PoundDiagnosticDecl>(decl))
52+
return;
53+
54+
// Ignore variable declarations, because they're always handled within
55+
// their enclosing pattern bindings.
56+
if (isa<VarDecl>(decl))
57+
return;
58+
59+
llvm_unreachable("Unimplemented case for closure body");
60+
}
61+
62+
void visitBraceStmt(BraceStmt *braceStmt) {
63+
for (auto node : braceStmt->getElements()) {
64+
if (auto expr = node.dyn_cast<Expr *>()) {
65+
auto generatedExpr = cs.generateConstraints(
66+
expr, closure, /*isInputExpression=*/false);
67+
if (!generatedExpr) {
68+
hadError = true;
69+
}
70+
} else if (auto stmt = node.dyn_cast<Stmt *>()) {
71+
visit(stmt);
72+
} else {
73+
visitDecl(node.get<Decl *>());
74+
}
75+
}
76+
}
77+
78+
void visitReturnStmt(ReturnStmt *returnStmt) {
79+
auto expr = returnStmt->getResult();
80+
81+
// FIXME: Implies Void return?
82+
if (!expr)
83+
return;
84+
85+
expr = cs.generateConstraints(expr, closure, /*isInputExpression=*/false);
86+
if (!expr) {
87+
hadError = true;
88+
return;
89+
}
90+
91+
// FIXME: Locator should point at the return statement?
92+
bool hasReturn = hasExplicitResult(closure);
93+
cs.addConstraint(
94+
ConstraintKind::Conversion, cs.getType(expr),
95+
closureResultType,
96+
cs.getConstraintLocator(
97+
closure, LocatorPathElt::ClosureBody(hasReturn)));
98+
}
99+
100+
#define UNSUPPORTED_STMT(STMT) void visit##STMT##Stmt(STMT##Stmt *) { \
101+
llvm_unreachable("Unsupported statement kind " #STMT); \
102+
}
103+
UNSUPPORTED_STMT(Yield)
104+
UNSUPPORTED_STMT(Defer)
105+
UNSUPPORTED_STMT(If)
106+
UNSUPPORTED_STMT(Guard)
107+
UNSUPPORTED_STMT(While)
108+
UNSUPPORTED_STMT(Do)
109+
UNSUPPORTED_STMT(DoCatch)
110+
UNSUPPORTED_STMT(RepeatWhile)
111+
UNSUPPORTED_STMT(ForEach)
112+
UNSUPPORTED_STMT(Switch)
113+
UNSUPPORTED_STMT(Case)
114+
UNSUPPORTED_STMT(Break)
115+
UNSUPPORTED_STMT(Continue)
116+
UNSUPPORTED_STMT(Fallthrough)
117+
UNSUPPORTED_STMT(Fail)
118+
UNSUPPORTED_STMT(Throw)
119+
UNSUPPORTED_STMT(PoundAssert)
120+
#undef UNSUPPORTED_STMT
121+
};
122+
123+
}
124+
23125
bool ConstraintSystem::generateConstraints(
24126
ClosureExpr *closure, Type resultType) {
25-
assert(closure->hasSingleExpressionBody());
26-
auto closureBody = generateConstraints(
27-
closure->getSingleExpressionBody(), closure, /*isInputExpression=*/false);
28-
if (!closureBody)
29-
return true;
30-
31-
bool hasReturn = hasExplicitResult(closure);
32-
addConstraint(
33-
ConstraintKind::Conversion, getType(closureBody),
34-
resultType,
35-
getConstraintLocator(closure, LocatorPathElt::ClosureBody(hasReturn)));
36-
return false;
127+
ClosureConstraintGenerator generator(*this, closure, resultType);
128+
generator.visit(closure->getBody());
129+
return generator.hadError;
37130
}

0 commit comments

Comments
 (0)