Skip to content

Commit 3e97b1f

Browse files
authored
Merge pull request #65355 from calda/cal--cp-SE-0356-fixes
[5.9] SE-0365 bug fixes
2 parents 6cdb33f + 5061622 commit 3e97b1f

File tree

6 files changed

+483
-31
lines changed

6 files changed

+483
-31
lines changed

include/swift/AST/Stmt.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,11 +556,17 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
556556
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
557557
ThePattern = P;
558558
}
559+
560+
/// Pattern Binding Accessors.
561+
Expr *getInitializerOrNull() const {
562+
return getKind() == CK_PatternBinding ? Condition.get<Expr *>() : nullptr;
563+
}
559564

560565
Expr *getInitializer() const {
561566
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
562567
return Condition.get<Expr *>();
563568
}
569+
564570
void setInitializer(Expr *E) {
565571
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
566572
Condition = E;
@@ -588,6 +594,11 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
588594
Condition = Info;
589595
}
590596

597+
/// Whether or not this conditional stmt rebinds self with a `let self`
598+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
599+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
600+
bool rebindsSelf(ASTContext &Ctx, bool requireLoadExpr = false) const;
601+
591602
SourceLoc getStartLoc() const;
592603
SourceLoc getEndLoc() const;
593604
SourceRange getSourceRange() const;
@@ -691,6 +702,11 @@ class LabeledConditionalStmt : public LabeledStmt {
691702
/// stored in \c ASTNode.
692703
StmtCondition *getCondPointer() { return &Cond; }
693704

705+
/// Whether or not this conditional stmt rebinds self with a `let self`
706+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
707+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
708+
bool rebindsSelf(ASTContext &Ctx, bool requireLoadExpr = false) const;
709+
694710
static bool classof(const Stmt *S) {
695711
return S->getKind() >= StmtKind::First_LabeledConditionalStmt &&
696712
S->getKind() <= StmtKind::Last_LabeledConditionalStmt;

lib/AST/Stmt.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,66 @@ void LabeledConditionalStmt::setCond(StmtCondition e) {
466466
Cond = e;
467467
}
468468

469+
/// Whether or not this conditional stmt rebinds self with a `let self`
470+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
471+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
472+
bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
473+
bool requireLoadExpr) const {
474+
return llvm::any_of(getCond(), [&Ctx, requireLoadExpr](const auto &cond) {
475+
return cond.rebindsSelf(Ctx, requireLoadExpr);
476+
});
477+
}
478+
479+
/// Whether or not this conditional stmt rebinds self with a `let self`
480+
/// or `let self = self` condition. If `requireLoadExpr` is `true`,
481+
/// additionally requires that the RHS of the self condition is a `LoadExpr`.
482+
bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
483+
bool requireLoadExpr) const {
484+
auto pattern = getPatternOrNull();
485+
if (!pattern) {
486+
return false;
487+
}
488+
489+
// Check whether or not this pattern defines a new `self` decl
490+
bool isSelfRebinding = false;
491+
if (pattern->getBoundName() == Ctx.Id_self) {
492+
isSelfRebinding = true;
493+
}
494+
495+
else if (auto OSP = dyn_cast<OptionalSomePattern>(pattern)) {
496+
if (auto subPattern = OSP->getSubPattern()) {
497+
isSelfRebinding = subPattern->getBoundName() == Ctx.Id_self;
498+
}
499+
}
500+
501+
if (!isSelfRebinding) {
502+
return false;
503+
}
504+
505+
// Check that the RHS expr is exactly `self` and not something else
506+
Expr *exprToCheckForDRE = getInitializerOrNull();
507+
if (!exprToCheckForDRE) {
508+
return false;
509+
}
510+
511+
if (requireLoadExpr && !isa<LoadExpr>(exprToCheckForDRE)) {
512+
return false;
513+
}
514+
515+
if (auto *load = dyn_cast<LoadExpr>(exprToCheckForDRE)) {
516+
exprToCheckForDRE = load->getSubExpr();
517+
}
518+
519+
if (auto *DRE = dyn_cast<DeclRefExpr>(
520+
exprToCheckForDRE->getSemanticsProvidingExpr())) {
521+
auto *decl = DRE->getDecl();
522+
return decl && decl->hasName() ? decl->getName().isSimpleName(Ctx.Id_self)
523+
: false;
524+
}
525+
526+
return false;
527+
}
528+
469529
PoundAvailableInfo *
470530
PoundAvailableInfo::create(ASTContext &ctx, SourceLoc PoundLoc,
471531
SourceLoc LParenLoc,

lib/AST/UnqualifiedLookup.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -397,21 +397,29 @@ 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 (auto pattern = cond.getPattern()) {
404-
if (pattern->getBoundName() != Ctx.Id_self) {
405-
continue;
406-
}
407-
}
400+
return conditionalStmt->rebindsSelf(Ctx);
401+
}
408402

409-
if (auto selfDRE = dyn_cast<DeclRefExpr>(cond.getInitializer())) {
410-
return (selfDRE->getDecl()->getName().isSimpleName(Ctx.Id_self));
411-
}
403+
// Finds the nearest parent closure, which would define the
404+
// permitted usage of implicit self. In closures this is most
405+
// often just `dc` itself, but in functions defined in the
406+
// closure body this would be some parent context.
407+
ClosureExpr *closestParentClosure(DeclContext *dc) {
408+
if (!dc) {
409+
return nullptr;
412410
}
413411

414-
return false;
412+
if (auto closure = dyn_cast<ClosureExpr>(dc)) {
413+
return closure;
414+
}
415+
416+
// Stop searching if we find a type decl, since types always
417+
// redefine what 'self' means, even when nested inside a closure.
418+
if (dc->getContextKind() == DeclContextKind::GenericTypeDecl) {
419+
return nullptr;
420+
}
421+
422+
return closestParentClosure(dc->getParent());
415423
}
416424

417425
ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
@@ -425,7 +433,7 @@ ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
425433
// self _always_ refers to the context's self `ParamDecl`, even if there
426434
// is another local decl with the name `self` that would be found by
427435
// `lookupSingleLocalDecl`.
428-
auto closureExpr = dyn_cast<ClosureExpr>(factory->DC);
436+
auto closureExpr = closestParentClosure(factory->DC);
429437
if (!closureExpr) {
430438
return nullptr;
431439
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,23 +1689,14 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
16891689
return false;
16901690
}
16911691

1692-
// Find the condition that defined the self decl,
1693-
// and check that both its LHS and RHS are 'self'
1694-
for (auto cond : conditionalStmt->getCond()) {
1695-
if (auto OSP = dyn_cast<OptionalSomePattern>(cond.getPattern())) {
1696-
if (OSP->getSubPattern()->getBoundName() != Ctx.Id_self) {
1697-
continue;
1698-
}
1699-
1700-
if (auto LE = dyn_cast<LoadExpr>(cond.getInitializer())) {
1701-
if (auto selfDRE = dyn_cast<DeclRefExpr>(LE->getSubExpr())) {
1702-
return (selfDRE->getDecl()->getName().isSimpleName(Ctx.Id_self));
1703-
}
1704-
}
1705-
}
1706-
}
1707-
1708-
return false;
1692+
// Require `LoadExpr`s when validating the self binding.
1693+
// This lets us reject invalid examples like:
1694+
//
1695+
// let `self` = self ?? .somethingElse
1696+
// guard let self = self else { return }
1697+
// method() // <- implicit self is not allowed
1698+
//
1699+
return conditionalStmt->rebindsSelf(Ctx, /*requireLoadExpr*/ true);
17091700
}
17101701

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

0 commit comments

Comments
 (0)