Skip to content

Commit 870dbcc

Browse files
committed
Consolidate LabeledConditionalStmt::rebindsSelf logic into shared helper
1 parent d1677c6 commit 870dbcc

File tree

4 files changed

+84
-40
lines changed

4 files changed

+84
-40
lines changed

include/swift/AST/Stmt.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,11 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
583583
Condition = Info;
584584
}
585585

586+
/// Whether or not this conditional stmt rebinds self with a `let self`
587+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
588+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
589+
bool rebindsSelf(ASTContext &Ctx, bool requireLoadExpr = false) const;
590+
586591
SourceLoc getStartLoc() const;
587592
SourceLoc getEndLoc() const;
588593
SourceRange getSourceRange() const;
@@ -686,6 +691,11 @@ class LabeledConditionalStmt : public LabeledStmt {
686691
/// stored in \c ASTNode.
687692
StmtCondition *getCondPointer() { return &Cond; }
688693

694+
/// Whether or not this conditional stmt rebinds self with a `let self`
695+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
696+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
697+
bool rebindsSelf(ASTContext &Ctx, bool requireLoadExpr = false) const;
698+
689699
static bool classof(const Stmt *S) {
690700
return S->getKind() >= StmtKind::First_LabeledConditionalStmt &&
691701
S->getKind() <= StmtKind::Last_LabeledConditionalStmt;

lib/AST/Stmt.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,71 @@ void LabeledConditionalStmt::setCond(StmtCondition e) {
440440
Cond = e;
441441
}
442442

443+
/// Whether or not this conditional stmt rebinds self with a `let self`
444+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
445+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
446+
bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
447+
bool requireLoadExpr) const {
448+
return llvm::any_of(getCond(), [&Ctx, requireLoadExpr](const auto &cond) {
449+
return cond.rebindsSelf(Ctx, requireLoadExpr);
450+
});
451+
}
452+
453+
/// Whether or not this conditional stmt rebinds self with a `let self`
454+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
455+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
456+
bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
457+
bool requireLoadExpr) const {
458+
auto pattern = getPatternOrNull();
459+
if (!pattern) {
460+
return false;
461+
}
462+
463+
// Check whether or not this pattern defines a new `self` decl
464+
bool isSelfRebinding = false;
465+
if (pattern->getBoundName() == Ctx.Id_self) {
466+
isSelfRebinding = true;
467+
}
468+
469+
else if (auto OSP = dyn_cast<OptionalSomePattern>(pattern)) {
470+
if (auto subPattern = OSP->getSubPattern()) {
471+
isSelfRebinding = subPattern->getBoundName() == Ctx.Id_self;
472+
}
473+
}
474+
475+
if (!isSelfRebinding) {
476+
return false;
477+
}
478+
479+
// Check that the RHS expr is exactly `self` and not something else
480+
Expr *exprToCheckForDRE = getInitializerOrNull();
481+
if (!exprToCheckForDRE) {
482+
return false;
483+
}
484+
485+
// The RHS could be a `LoadExpr` or `DeclRefExpr`
486+
Expr *loadExprSubExpr = nullptr;
487+
if (auto LE = dyn_cast<LoadExpr>(exprToCheckForDRE)) {
488+
loadExprSubExpr = LE->getSubExpr();
489+
}
490+
491+
if (requireLoadExpr) {
492+
exprToCheckForDRE = loadExprSubExpr;
493+
} else {
494+
if (loadExprSubExpr) {
495+
exprToCheckForDRE = loadExprSubExpr;
496+
}
497+
exprToCheckForDRE = exprToCheckForDRE->getSemanticsProvidingExpr();
498+
}
499+
500+
DeclRefExpr *condDRE = dyn_cast_or_null<DeclRefExpr>(exprToCheckForDRE);
501+
if (!condDRE || !condDRE->getDecl()->hasName()) {
502+
return false;
503+
}
504+
505+
return condDRE->getDecl()->getName().isSimpleName(Ctx.Id_self);
506+
}
507+
443508
PoundAvailableInfo *
444509
PoundAvailableInfo::create(ASTContext &ctx, SourceLoc PoundLoc,
445510
SourceLoc LParenLoc,

lib/AST/UnqualifiedLookup.cpp

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -397,25 +397,7 @@ bool implicitSelfReferenceIsUnwrapped(const ValueDecl *selfDecl,
397397
return false;
398398
}
399399

400-
// Find the condition that defined the self decl,
401-
// and check that both its LHS and RHS are 'self'
402-
for (auto cond : conditionalStmt->getCond()) {
403-
if (cond.getKind() != StmtConditionElement::CK_PatternBinding) {
404-
continue;
405-
}
406-
407-
if (auto pattern = cond.getPattern()) {
408-
if (pattern->getBoundName() != Ctx.Id_self) {
409-
continue;
410-
}
411-
}
412-
413-
if (auto selfDRE = dyn_cast<DeclRefExpr>(cond.getInitializer())) {
414-
return (selfDRE->getDecl()->getName().isSimpleName(Ctx.Id_self));
415-
}
416-
}
417-
418-
return false;
400+
return conditionalStmt->rebindsSelf(Ctx);
419401
}
420402

421403
ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(

lib/Sema/MiscDiagnostics.cpp

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,27 +1700,14 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
17001700
return false;
17011701
}
17021702

1703-
// Find the condition that defined the self decl,
1704-
// and check that both its LHS and RHS are 'self'
1705-
for (auto cond : conditionalStmt->getCond()) {
1706-
if (cond.getKind() != StmtConditionElement::CK_PatternBinding) {
1707-
continue;
1708-
}
1709-
1710-
if (auto OSP = dyn_cast<OptionalSomePattern>(cond.getPattern())) {
1711-
if (OSP->getSubPattern()->getBoundName() != Ctx.Id_self) {
1712-
continue;
1713-
}
1714-
1715-
if (auto LE = dyn_cast<LoadExpr>(cond.getInitializer())) {
1716-
if (auto selfDRE = dyn_cast<DeclRefExpr>(LE->getSubExpr())) {
1717-
return (selfDRE->getDecl()->getName().isSimpleName(Ctx.Id_self));
1718-
}
1719-
}
1720-
}
1721-
}
1722-
1723-
return false;
1703+
// Require `LoadExpr`s when validating the self binding.
1704+
// This lets us reject invalid examples like:
1705+
//
1706+
// let `self` = self ?? .somethingElse
1707+
// guard let self = self else { return }
1708+
// method() // <- implicit self is not allowed
1709+
//
1710+
return conditionalStmt->rebindsSelf(Ctx, /*requireLoadExpr*/ true);
17241711
}
17251712

17261713
/// Return true if this is a closure expression that will require explicit

0 commit comments

Comments
 (0)