Skip to content

Commit 425dd9c

Browse files
authored
Merge pull request swiftlang#79446 from hamishknight/context-again
[CS] Fix DeclContext for multi-statement closure captures
2 parents 9153155 + 11a4415 commit 425dd9c

File tree

2 files changed

+70
-16
lines changed

2 files changed

+70
-16
lines changed

lib/Sema/CSSyntacticElement.cpp

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,8 @@ ElementInfo makeJoinElement(ConstraintSystem &cs, TypeJoinExpr *join,
436436

437437
struct SyntacticElementContext
438438
: public llvm::PointerUnion<AbstractFunctionDecl *, AbstractClosureExpr *,
439-
SingleValueStmtExpr *, ExprPattern *, TapExpr *> {
439+
SingleValueStmtExpr *, ExprPattern *, TapExpr *,
440+
CaptureListExpr *> {
440441
// Inherit the constructors from PointerUnion.
441442
using PointerUnion::PointerUnion;
442443

@@ -461,6 +462,10 @@ struct SyntacticElementContext
461462
return {func};
462463
}
463464

465+
static SyntacticElementContext forCaptureList(CaptureListExpr *CLE) {
466+
return {CLE};
467+
}
468+
464469
static SyntacticElementContext
465470
forSingleValueStmtExpr(SingleValueStmtExpr *SVE,
466471
TypeJoinExpr *Join = nullptr) {
@@ -484,6 +489,9 @@ struct SyntacticElementContext
484489
return EP->getDeclContext();
485490
} else if (auto *tap = this->dyn_cast<TapExpr *>()) {
486491
return tap->getVar()->getDeclContext();
492+
} else if (auto *CLE = this->dyn_cast<CaptureListExpr *>()) {
493+
// The capture list is part of the closure's parent context.
494+
return CLE->getClosureBody()->getParent();
487495
} else {
488496
llvm_unreachable("unsupported kind");
489497
}
@@ -552,6 +560,8 @@ class SyntacticElementConstraintGenerator
552560
SyntacticElementContext context;
553561
ConstraintLocator *locator;
554562

563+
std::optional<llvm::SaveAndRestore<DeclContext *>> DCScope;
564+
555565
/// Whether a conjunction was generated.
556566
bool generatedConjunction = false;
557567

@@ -562,7 +572,17 @@ class SyntacticElementConstraintGenerator
562572
SyntacticElementConstraintGenerator(ConstraintSystem &cs,
563573
SyntacticElementContext context,
564574
ConstraintLocator *locator)
565-
: cs(cs), context(context), locator(locator) {}
575+
: cs(cs), context(context), locator(locator) {
576+
// Capture list bindings in multi-statement closures get solved as part of
577+
// the closure's conjunction, which has the DeclContext set to the closure.
578+
// This is wrong for captures though, which are semantically bound outside
579+
// of the closure body. So we need to re-adjust their DeclContext here for
580+
// constraint generation. The constraint system's DeclContext will be wrong
581+
// for solving, but CSGen should ensure that constraints carry the correct
582+
// DeclContext.
583+
if (context.is<CaptureListExpr *>())
584+
DCScope.emplace(cs.DC, context.getAsDeclContext());
585+
}
566586

567587
void createConjunction(ArrayRef<ElementInfo> elements,
568588
ConstraintLocator *locator, bool isIsolated = false,
@@ -1616,26 +1636,40 @@ bool isConditionOfStmt(ConstraintLocatorBuilder locator) {
16161636
return false;
16171637
}
16181638

1639+
static std::optional<SyntacticElementContext>
1640+
getSyntacticElementContext(ASTNode element, ConstraintLocatorBuilder locator) {
1641+
/// Capture list bindings are part of the capture list, which is semantically
1642+
/// outside the closure it's part of. As such, it needs its own context.
1643+
if (auto *PBD = getAsDecl<PatternBindingDecl>(element)) {
1644+
if (auto *VD = PBD->getSingleVar()) {
1645+
if (auto *CLE = VD->getParentCaptureList())
1646+
return SyntacticElementContext::forCaptureList(CLE);
1647+
}
1648+
}
1649+
1650+
auto anchor = locator.getAnchor();
1651+
if (auto *closure = getAsExpr<ClosureExpr>(anchor))
1652+
return SyntacticElementContext::forClosure(closure);
1653+
if (auto *fn = getAsDecl<AbstractFunctionDecl>(anchor))
1654+
return SyntacticElementContext::forFunction(fn);
1655+
if (auto *SVE = getAsExpr<SingleValueStmtExpr>(anchor))
1656+
return SyntacticElementContext::forSingleValueStmtExpr(SVE);
1657+
if (auto *EP = getAsPattern<ExprPattern>(anchor))
1658+
return SyntacticElementContext::forExprPattern(EP);
1659+
if (auto *tap = getAsExpr<TapExpr>(anchor))
1660+
return SyntacticElementContext::forTapExpr(tap);
1661+
1662+
return std::nullopt;
1663+
}
1664+
16191665
ConstraintSystem::SolutionKind
16201666
ConstraintSystem::simplifySyntacticElementConstraint(
16211667
ASTNode element, ContextualTypeInfo contextInfo, bool isDiscarded,
16221668
TypeMatchOptions flags, ConstraintLocatorBuilder locator) {
1623-
auto anchor = locator.getAnchor();
16241669

1625-
std::optional<SyntacticElementContext> context;
1626-
if (auto *closure = getAsExpr<ClosureExpr>(anchor)) {
1627-
context = SyntacticElementContext::forClosure(closure);
1628-
} else if (auto *fn = getAsDecl<AbstractFunctionDecl>(anchor)) {
1629-
context = SyntacticElementContext::forFunction(fn);
1630-
} else if (auto *SVE = getAsExpr<SingleValueStmtExpr>(anchor)) {
1631-
context = SyntacticElementContext::forSingleValueStmtExpr(SVE);
1632-
} else if (auto *EP = getAsPattern<ExprPattern>(anchor)) {
1633-
context = SyntacticElementContext::forExprPattern(EP);
1634-
} else if (auto *tap = getAsExpr<TapExpr>(anchor)) {
1635-
context = SyntacticElementContext::forTapExpr(tap);
1636-
} else {
1670+
auto context = getSyntacticElementContext(element, locator);
1671+
if (!context)
16371672
return SolutionKind::Error;
1638-
}
16391673

16401674
SyntacticElementConstraintGenerator generator(*this, *context,
16411675
getConstraintLocator(locator));

test/Constraints/issue-79444.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// https://github.com/swiftlang/swift/issues/79444
4+
class C {
5+
func foo() {
6+
_ = { [x = "\(self)"] in } // expected-warning {{capture 'x' was never used}}
7+
_ = { [x = "\(self)"] in x }
8+
_ = { [x = "\(self)"] in
9+
let y = x
10+
return y
11+
}
12+
_ = { [x = "\(self)"] in
13+
let fn = { [y = "\(x)"] in
14+
let z = y
15+
return z
16+
}
17+
return fn()
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)