mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[CS] Fix DeclContext for multi-statement closure captures
Make sure we set the correct DeclContext for CSGen of multi-statement closure captures, since otherwise the DeclContext is set to the closure itself, which is wrong.
This commit is contained in:
@@ -436,7 +436,8 @@ ElementInfo makeJoinElement(ConstraintSystem &cs, TypeJoinExpr *join,
|
|||||||
|
|
||||||
struct SyntacticElementContext
|
struct SyntacticElementContext
|
||||||
: public llvm::PointerUnion<AbstractFunctionDecl *, AbstractClosureExpr *,
|
: public llvm::PointerUnion<AbstractFunctionDecl *, AbstractClosureExpr *,
|
||||||
SingleValueStmtExpr *, ExprPattern *, TapExpr *> {
|
SingleValueStmtExpr *, ExprPattern *, TapExpr *,
|
||||||
|
CaptureListExpr *> {
|
||||||
// Inherit the constructors from PointerUnion.
|
// Inherit the constructors from PointerUnion.
|
||||||
using PointerUnion::PointerUnion;
|
using PointerUnion::PointerUnion;
|
||||||
|
|
||||||
@@ -461,6 +462,10 @@ struct SyntacticElementContext
|
|||||||
return {func};
|
return {func};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SyntacticElementContext forCaptureList(CaptureListExpr *CLE) {
|
||||||
|
return {CLE};
|
||||||
|
}
|
||||||
|
|
||||||
static SyntacticElementContext
|
static SyntacticElementContext
|
||||||
forSingleValueStmtExpr(SingleValueStmtExpr *SVE,
|
forSingleValueStmtExpr(SingleValueStmtExpr *SVE,
|
||||||
TypeJoinExpr *Join = nullptr) {
|
TypeJoinExpr *Join = nullptr) {
|
||||||
@@ -484,6 +489,9 @@ struct SyntacticElementContext
|
|||||||
return EP->getDeclContext();
|
return EP->getDeclContext();
|
||||||
} else if (auto *tap = this->dyn_cast<TapExpr *>()) {
|
} else if (auto *tap = this->dyn_cast<TapExpr *>()) {
|
||||||
return tap->getVar()->getDeclContext();
|
return tap->getVar()->getDeclContext();
|
||||||
|
} else if (auto *CLE = this->dyn_cast<CaptureListExpr *>()) {
|
||||||
|
// The capture list is part of the closure's parent context.
|
||||||
|
return CLE->getClosureBody()->getParent();
|
||||||
} else {
|
} else {
|
||||||
llvm_unreachable("unsupported kind");
|
llvm_unreachable("unsupported kind");
|
||||||
}
|
}
|
||||||
@@ -552,6 +560,8 @@ class SyntacticElementConstraintGenerator
|
|||||||
SyntacticElementContext context;
|
SyntacticElementContext context;
|
||||||
ConstraintLocator *locator;
|
ConstraintLocator *locator;
|
||||||
|
|
||||||
|
std::optional<llvm::SaveAndRestore<DeclContext *>> DCScope;
|
||||||
|
|
||||||
/// Whether a conjunction was generated.
|
/// Whether a conjunction was generated.
|
||||||
bool generatedConjunction = false;
|
bool generatedConjunction = false;
|
||||||
|
|
||||||
@@ -562,7 +572,17 @@ public:
|
|||||||
SyntacticElementConstraintGenerator(ConstraintSystem &cs,
|
SyntacticElementConstraintGenerator(ConstraintSystem &cs,
|
||||||
SyntacticElementContext context,
|
SyntacticElementContext context,
|
||||||
ConstraintLocator *locator)
|
ConstraintLocator *locator)
|
||||||
: cs(cs), context(context), locator(locator) {}
|
: cs(cs), context(context), locator(locator) {
|
||||||
|
// Capture list bindings in multi-statement closures get solved as part of
|
||||||
|
// the closure's conjunction, which has the DeclContext set to the closure.
|
||||||
|
// This is wrong for captures though, which are semantically bound outside
|
||||||
|
// of the closure body. So we need to re-adjust their DeclContext here for
|
||||||
|
// constraint generation. The constraint system's DeclContext will be wrong
|
||||||
|
// for solving, but CSGen should ensure that constraints carry the correct
|
||||||
|
// DeclContext.
|
||||||
|
if (context.is<CaptureListExpr *>())
|
||||||
|
DCScope.emplace(cs.DC, context.getAsDeclContext());
|
||||||
|
}
|
||||||
|
|
||||||
void createConjunction(ArrayRef<ElementInfo> elements,
|
void createConjunction(ArrayRef<ElementInfo> elements,
|
||||||
ConstraintLocator *locator, bool isIsolated = false,
|
ConstraintLocator *locator, bool isIsolated = false,
|
||||||
@@ -1616,26 +1636,40 @@ bool isConditionOfStmt(ConstraintLocatorBuilder locator) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<SyntacticElementContext>
|
||||||
|
getSyntacticElementContext(ASTNode element, ConstraintLocatorBuilder locator) {
|
||||||
|
/// Capture list bindings are part of the capture list, which is semantically
|
||||||
|
/// outside the closure it's part of. As such, it needs its own context.
|
||||||
|
if (auto *PBD = getAsDecl<PatternBindingDecl>(element)) {
|
||||||
|
if (auto *VD = PBD->getSingleVar()) {
|
||||||
|
if (auto *CLE = VD->getParentCaptureList())
|
||||||
|
return SyntacticElementContext::forCaptureList(CLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto anchor = locator.getAnchor();
|
||||||
|
if (auto *closure = getAsExpr<ClosureExpr>(anchor))
|
||||||
|
return SyntacticElementContext::forClosure(closure);
|
||||||
|
if (auto *fn = getAsDecl<AbstractFunctionDecl>(anchor))
|
||||||
|
return SyntacticElementContext::forFunction(fn);
|
||||||
|
if (auto *SVE = getAsExpr<SingleValueStmtExpr>(anchor))
|
||||||
|
return SyntacticElementContext::forSingleValueStmtExpr(SVE);
|
||||||
|
if (auto *EP = getAsPattern<ExprPattern>(anchor))
|
||||||
|
return SyntacticElementContext::forExprPattern(EP);
|
||||||
|
if (auto *tap = getAsExpr<TapExpr>(anchor))
|
||||||
|
return SyntacticElementContext::forTapExpr(tap);
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
ConstraintSystem::SolutionKind
|
ConstraintSystem::SolutionKind
|
||||||
ConstraintSystem::simplifySyntacticElementConstraint(
|
ConstraintSystem::simplifySyntacticElementConstraint(
|
||||||
ASTNode element, ContextualTypeInfo contextInfo, bool isDiscarded,
|
ASTNode element, ContextualTypeInfo contextInfo, bool isDiscarded,
|
||||||
TypeMatchOptions flags, ConstraintLocatorBuilder locator) {
|
TypeMatchOptions flags, ConstraintLocatorBuilder locator) {
|
||||||
auto anchor = locator.getAnchor();
|
|
||||||
|
|
||||||
std::optional<SyntacticElementContext> context;
|
auto context = getSyntacticElementContext(element, locator);
|
||||||
if (auto *closure = getAsExpr<ClosureExpr>(anchor)) {
|
if (!context)
|
||||||
context = SyntacticElementContext::forClosure(closure);
|
|
||||||
} else if (auto *fn = getAsDecl<AbstractFunctionDecl>(anchor)) {
|
|
||||||
context = SyntacticElementContext::forFunction(fn);
|
|
||||||
} else if (auto *SVE = getAsExpr<SingleValueStmtExpr>(anchor)) {
|
|
||||||
context = SyntacticElementContext::forSingleValueStmtExpr(SVE);
|
|
||||||
} else if (auto *EP = getAsPattern<ExprPattern>(anchor)) {
|
|
||||||
context = SyntacticElementContext::forExprPattern(EP);
|
|
||||||
} else if (auto *tap = getAsExpr<TapExpr>(anchor)) {
|
|
||||||
context = SyntacticElementContext::forTapExpr(tap);
|
|
||||||
} else {
|
|
||||||
return SolutionKind::Error;
|
return SolutionKind::Error;
|
||||||
}
|
|
||||||
|
|
||||||
SyntacticElementConstraintGenerator generator(*this, *context,
|
SyntacticElementConstraintGenerator generator(*this, *context,
|
||||||
getConstraintLocator(locator));
|
getConstraintLocator(locator));
|
||||||
|
|||||||
20
test/Constraints/issue-79444.swift
Normal file
20
test/Constraints/issue-79444.swift
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift
|
||||||
|
|
||||||
|
// https://github.com/swiftlang/swift/issues/79444
|
||||||
|
class C {
|
||||||
|
func foo() {
|
||||||
|
_ = { [x = "\(self)"] in } // expected-warning {{capture 'x' was never used}}
|
||||||
|
_ = { [x = "\(self)"] in x }
|
||||||
|
_ = { [x = "\(self)"] in
|
||||||
|
let y = x
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
_ = { [x = "\(self)"] in
|
||||||
|
let fn = { [y = "\(x)"] in
|
||||||
|
let z = y
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user