Skip to content

Commit 46731e0

Browse files
committed
Fix edge cases related to nested autoclosures, invalid weak self unwrapping
1 parent 8c5f783 commit 46731e0

File tree

10 files changed

+560
-123
lines changed

10 files changed

+560
-123
lines changed

include/swift/AST/DeclContext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,14 @@ class alignas(1 << DeclContextAlignInBits) DeclContext
504504
const_cast<DeclContext *>(this)->getInnermostSkippedFunctionContext();
505505
}
506506

507+
/// Returns the innermost context that is a ClosureExpr, which defines how
508+
/// self behaves, unless within a type context that redefines self.
509+
LLVM_READONLY
510+
DeclContext *getInnermostClosureForSelfCapture();
511+
const DeclContext *getInnermostClosureForSelfCapture() const {
512+
return const_cast<DeclContext *>(this)->getInnermostClosureForSelfCapture();
513+
}
514+
507515
/// Returns the semantic parent of this context. A context has a
508516
/// parent if and only if it is not a module context.
509517
DeclContext *getParent() const {

include/swift/AST/Expr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4356,7 +4356,7 @@ struct CaptureListEntry {
43564356
explicit CaptureListEntry(PatternBindingDecl *PBD);
43574357

43584358
VarDecl *getVar() const;
4359-
bool isSimpleSelfCapture() const;
4359+
bool isSimpleSelfCapture(bool excludeWeakCaptures = true) const;
43604360
};
43614361

43624362
/// CaptureListExpr - This expression represents the capture list on an explicit

include/swift/AST/Stmt.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -709,9 +709,13 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
709709
}
710710

711711
/// Whether or not this conditional stmt rebinds self with a `let self`
712-
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
713-
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
714-
bool rebindsSelf(ASTContext &Ctx, bool requireLoadExpr = false) const;
712+
/// or `let self = self` condition.
713+
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
714+
/// RHS of the self condition references a var defined in a capture list.
715+
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
716+
/// the self condition is a `LoadExpr`.
717+
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
718+
bool requireLoadExpr = false) const;
715719

716720
SourceLoc getStartLoc() const;
717721
SourceLoc getEndLoc() const;
@@ -817,9 +821,13 @@ class LabeledConditionalStmt : public LabeledStmt {
817821
StmtCondition *getCondPointer() { return &Cond; }
818822

819823
/// Whether or not this conditional stmt rebinds self with a `let self`
820-
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
821-
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
822-
bool rebindsSelf(ASTContext &Ctx, bool requireLoadExpr = false) const;
824+
/// or `let self = self` condition.
825+
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
826+
/// RHS of the self condition references a var defined in a capture list.
827+
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
828+
/// the self condition is a `LoadExpr`.
829+
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
830+
bool requireLoadExpr = false) const;
823831

824832
static bool classof(const Stmt *S) {
825833
return S->getKind() >= StmtKind::First_LabeledConditionalStmt &&

lib/AST/DeclContext.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,25 @@ DeclContext *DeclContext::getInnermostSkippedFunctionContext() {
263263
return nullptr;
264264
}
265265

266+
DeclContext *DeclContext::getInnermostClosureForSelfCapture() {
267+
auto dc = this;
268+
if (auto closure = dyn_cast<ClosureExpr>(dc)) {
269+
return closure;
270+
}
271+
272+
// Stop searching if we find a type decl, since types always
273+
// redefine what 'self' means, even when nested inside a closure.
274+
if (dc->isTypeContext()) {
275+
return nullptr;
276+
}
277+
278+
if (auto parent = dc->getParent()) {
279+
return parent->getInnermostClosureForSelfCapture();
280+
}
281+
282+
return nullptr;
283+
}
284+
266285
DeclContext *DeclContext::getParentForLookup() const {
267286
if (isa<ExtensionDecl>(this)) {
268287
// If we are inside an extension, skip directly

lib/AST/Expr.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,22 +1350,31 @@ VarDecl *CaptureListEntry::getVar() const {
13501350
return PBD->getSingleVar();
13511351
}
13521352

1353-
bool CaptureListEntry::isSimpleSelfCapture() const {
1353+
bool CaptureListEntry::isSimpleSelfCapture(bool excludeWeakCaptures) const {
13541354
auto *Var = getVar();
13551355
auto &ctx = Var->getASTContext();
13561356

13571357
if (Var->getName() != ctx.Id_self)
13581358
return false;
13591359

1360-
if (auto *attr = Var->getAttrs().getAttribute<ReferenceOwnershipAttr>())
1361-
if (attr->get() == ReferenceOwnership::Weak)
1362-
return false;
1363-
13641360
if (PBD->getPatternList().size() != 1)
13651361
return false;
13661362

13671363
auto *expr = PBD->getInit(0);
13681364

1365+
if (auto *attr = Var->getAttrs().getAttribute<ReferenceOwnershipAttr>()) {
1366+
if (attr->get() == ReferenceOwnership::Weak) {
1367+
if (excludeWeakCaptures) {
1368+
return false;
1369+
}
1370+
1371+
// If not excluding weak captures, look through any InjectIntoOptionalExpr
1372+
if (auto injectExpr = dyn_cast_or_null<InjectIntoOptionalExpr>(expr)) {
1373+
expr = injectExpr->getSubExpr();
1374+
}
1375+
}
1376+
}
1377+
13691378
if (auto *DRE = dyn_cast<DeclRefExpr>(expr)) {
13701379
if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
13711380
return VD->getName() == ctx.Id_self;

lib/AST/Stmt.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -526,19 +526,28 @@ void LabeledConditionalStmt::setCond(StmtCondition e) {
526526
}
527527

528528
/// Whether or not this conditional stmt rebinds self with a `let self`
529-
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
530-
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
529+
/// or `let self = self` condition.
530+
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
531+
/// RHS of the self condition references a var defined in a capture list.
532+
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
533+
/// the self condition is a `LoadExpr`.
531534
bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
535+
bool requiresCaptureListRef,
532536
bool requireLoadExpr) const {
533-
return llvm::any_of(getCond(), [&Ctx, requireLoadExpr](const auto &cond) {
534-
return cond.rebindsSelf(Ctx, requireLoadExpr);
537+
return llvm::any_of(getCond(), [&Ctx, requiresCaptureListRef,
538+
requireLoadExpr](const auto &cond) {
539+
return cond.rebindsSelf(Ctx, requiresCaptureListRef, requireLoadExpr);
535540
});
536541
}
537542

538543
/// Whether or not this conditional stmt rebinds self with a `let self`
539-
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
540-
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
544+
/// or `let self = self` condition.
545+
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
546+
/// RHS of the self condition references a var defined in a capture list.
547+
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
548+
/// the self condition is a `LoadExpr`.
541549
bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
550+
bool requiresCaptureListRef,
542551
bool requireLoadExpr) const {
543552
auto pattern = getPatternOrNull();
544553
if (!pattern) {
@@ -578,8 +587,22 @@ bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
578587
if (auto *DRE = dyn_cast<DeclRefExpr>(
579588
exprToCheckForDRE->getSemanticsProvidingExpr())) {
580589
auto *decl = DRE->getDecl();
581-
return decl && decl->hasName() ? decl->getName().isSimpleName(Ctx.Id_self)
582-
: false;
590+
591+
bool definedInCaptureList = false;
592+
if (auto varDecl = dyn_cast_or_null<VarDecl>(DRE->getDecl())) {
593+
definedInCaptureList = varDecl->isCaptureList();
594+
}
595+
596+
if (requiresCaptureListRef && !definedInCaptureList) {
597+
return false;
598+
}
599+
600+
bool isVariableNamedSelf = false;
601+
if (decl && decl->hasName()) {
602+
isVariableNamedSelf = decl->getName().isSimpleName(Ctx.Id_self);
603+
}
604+
605+
return isVariableNamedSelf;
583606
}
584607

585608
return false;

lib/AST/UnqualifiedLookup.cpp

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -411,34 +411,18 @@ bool implicitSelfReferenceIsUnwrapped(const ValueDecl *selfDecl) {
411411
return conditionalStmt->rebindsSelf(Ctx);
412412
}
413413

414-
// Finds the nearest parent closure, which would define the
415-
// permitted usage of implicit self. In closures this is most
416-
// often just `dc` itself, but in functions defined in the
417-
// closure body this would be some parent context.
418-
ClosureExpr *closestParentClosure(DeclContext *dc) {
414+
ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
415+
const DeclContext *baseDC) const {
416+
auto dc = factory->DC;
419417
if (!dc) {
420418
return nullptr;
421419
}
422420

423-
if (auto closure = dyn_cast<ClosureExpr>(dc)) {
424-
return closure;
425-
}
426-
427-
// Stop searching if we find a type decl, since types always
428-
// redefine what 'self' means, even when nested inside a closure.
429-
if (dc->getContextKind() == DeclContextKind::GenericTypeDecl) {
430-
return nullptr;
431-
}
432-
433-
return closestParentClosure(dc->getParent());
434-
}
435-
436-
ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
437-
const DeclContext *baseDC) const {
438421
// Perform an unqualified lookup for the base decl of this result. This
439422
// handles cases where self was rebound (e.g. `guard let self = self`)
440423
// earlier in this closure or some outer closure.
441-
auto closureExpr = closestParentClosure(factory->DC);
424+
auto closureExpr =
425+
dyn_cast_or_null<ClosureExpr>(dc->getInnermostClosureForSelfCapture());
442426
if (!closureExpr) {
443427
return nullptr;
444428
}

0 commit comments

Comments
 (0)