Skip to content

Commit d098129

Browse files
committed
[Constraint generation] Collect all closure body references to type variables.
Collect all references to parameters whose types involve type variables, including in closures that aren’t single-expression. This fixes a type checker assertion that occurs when the constraint graph can get disconnected with the combination of delayed constraint generation for single-expression closures and the use of function builders. Fixes rdar://problem/58695803.
1 parent 2b70025 commit d098129

File tree

2 files changed

+57
-26
lines changed

2 files changed

+57
-26
lines changed

lib/Sema/CSGen.cpp

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2455,43 +2455,43 @@ namespace {
24552455
return tryFinder.foundThrow();
24562456
}
24572457

2458-
void collectParameterRefs(Expr *expr,
2459-
llvm::SmallVectorImpl<TypeVariableType *> &refs) {
2460-
expr->forEachChildExpr([&](Expr *childExpr) -> Expr * {
2461-
if (auto *closure = dyn_cast<ClosureExpr>(childExpr)) {
2462-
if (closure->hasSingleExpressionBody()) {
2463-
collectParameterRefs(closure->getSingleExpressionBody(), refs);
2464-
return childExpr;
2465-
}
2466-
}
2467-
2468-
if (auto *DRE = dyn_cast<DeclRefExpr>(childExpr)) {
2469-
if (auto *PD = dyn_cast<ParamDecl>(DRE->getDecl())) {
2470-
if (CS.hasType(PD)) {
2471-
if (auto *paramType = CS.getType(PD)->getAs<TypeVariableType>())
2472-
refs.push_back(paramType);
2473-
}
2474-
}
2475-
}
2476-
2477-
return childExpr;
2478-
});
2479-
}
2480-
24812458
Type visitClosureExpr(ClosureExpr *closure) {
24822459
auto *locator = CS.getConstraintLocator(closure);
24832460
auto closureType = CS.createTypeVariable(locator, TVO_CanBindToNoEscape);
24842461

2485-
llvm::SmallVector<TypeVariableType *, 4> paramRefs;
2486-
collectParameterRefs(closure, paramRefs);
2462+
// Collect any references to closure parameters whose types involve type
2463+
// variables from the closure, because there will be a dependency on
2464+
// those type variables once we have generated constraints for the
2465+
// closure body.
2466+
struct CollectParameterRefs : public ASTWalker {
2467+
ConstraintSystem &cs;
2468+
llvm::SmallVector<TypeVariableType *, 4> paramRefs;
2469+
2470+
CollectParameterRefs(ConstraintSystem &cs) : cs(cs) { }
2471+
2472+
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
2473+
// Retrieve type variables from references to parameter declarations.
2474+
if (auto *declRef = dyn_cast<DeclRefExpr>(expr)) {
2475+
if (auto *paramDecl = dyn_cast<ParamDecl>(declRef->getDecl())) {
2476+
if (Type paramType = cs.getTypeIfAvailable(paramDecl)) {
2477+
paramType->getTypeVariables(paramRefs);
2478+
}
2479+
}
2480+
}
2481+
2482+
return { true, expr };
2483+
}
2484+
} collectParameterRefs(CS);
2485+
closure->walk(collectParameterRefs);
24872486

24882487
auto inferredType = inferClosureType(closure);
24892488
if (!inferredType || inferredType->hasError())
24902489
return Type();
24912490

24922491
CS.addUnsolvedConstraint(
24932492
Constraint::create(CS, ConstraintKind::DefaultClosureType,
2494-
closureType, inferredType, locator, paramRefs));
2493+
closureType, inferredType, locator,
2494+
collectParameterRefs.paramRefs));
24952495

24962496
CS.setClosureType(closure, inferredType);
24972497
return closureType;

test/Constraints/function_builder.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ enum Either<T,U> {
88

99
@_functionBuilder
1010
struct TupleBuilder {
11+
static func buildBlock<T1>(_ t1: T1) -> (T1) {
12+
return (t1)
13+
}
14+
1115
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
1216
return (t1, t2)
1317
}
@@ -430,3 +434,30 @@ func test_single_stmt_closure_support() {
430434

431435
let _ = test { 0 } // ok
432436
}
437+
438+
// Check a case involving nested closures that refer to parameters of their
439+
// enclosing closures.
440+
struct X<C: Collection, T> {
441+
init(_ c: C, @TupleBuilder body: (C.Element) -> T) { }
442+
}
443+
444+
struct Y<T> {
445+
init(@TupleBuilder body: () -> T) { }
446+
}
447+
448+
struct Z<T> {
449+
init(@TupleBuilder body: () -> T) { }
450+
}
451+
452+
func testNestedClosuresWithDependencies(cond: Bool) {
453+
tuplify(cond) { _ in
454+
X([1, 2, 3]) { x in
455+
Y {
456+
Z {
457+
x
458+
1
459+
}
460+
}
461+
}
462+
}
463+
}

0 commit comments

Comments
 (0)