@@ -393,8 +393,7 @@ UnqualifiedLookupFactory::ResultFinderForTypeContext::getBaseDeclForResult(
393
393
// / unwrapping condition (e.g. `guard let self else { return }`).
394
394
// / If this is true, then we know any implicit self reference in the
395
395
// / following scope is guaranteed to be non-optional.
396
- bool implicitSelfReferenceIsUnwrapped (const ValueDecl *selfDecl,
397
- const AbstractClosureExpr *inClosure) {
396
+ bool implicitSelfReferenceIsUnwrapped (const ValueDecl *selfDecl) {
398
397
ASTContext &Ctx = selfDecl->getASTContext ();
399
398
400
399
// Check if the implicit self decl refers to a var in a conditional stmt
@@ -438,29 +437,12 @@ ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
438
437
const DeclContext *baseDC) const {
439
438
// Perform an unqualified lookup for the base decl of this result. This
440
439
// handles cases where self was rebound (e.g. `guard let self = self`)
441
- // earlier in the scope.
442
- //
443
- // Only do this in closures that capture self weakly, since implicit self
444
- // isn't allowed to be rebound in other contexts. In other contexts, implicit
445
- // self _always_ refers to the context's self `ParamDecl`, even if there
446
- // is another local decl with the name `self` that would be found by
447
- // `lookupSingleLocalDecl`.
440
+ // earlier in this closure or some outer closure.
448
441
auto closureExpr = closestParentClosure (factory->DC );
449
442
if (!closureExpr) {
450
443
return nullptr ;
451
444
}
452
445
453
- bool capturesSelfWeakly = false ;
454
- if (auto decl = closureExpr->getCapturedSelfDecl ()) {
455
- if (auto a = decl->getAttrs ().getAttribute <ReferenceOwnershipAttr>()) {
456
- capturesSelfWeakly = a->get () == ReferenceOwnership::Weak;
457
- }
458
- }
459
-
460
- if (!capturesSelfWeakly) {
461
- return nullptr ;
462
- }
463
-
464
446
auto selfDecl = ASTScope::lookupSingleLocalDecl (
465
447
factory->DC ->getParentSourceFile (), DeclName (factory->Ctx .Id_self ),
466
448
factory->Loc );
@@ -469,16 +451,24 @@ ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
469
451
return nullptr ;
470
452
}
471
453
454
+ bool capturesSelfWeakly = false ;
455
+ if (auto decl = closureExpr->getCapturedSelfDecl ()) {
456
+ if (auto a = decl->getAttrs ().getAttribute <ReferenceOwnershipAttr>()) {
457
+ capturesSelfWeakly = a->get () == ReferenceOwnership::Weak;
458
+ }
459
+ }
460
+
472
461
// In Swift 5 mode, implicit self is allowed within non-escaping
473
- // closures even before self is unwrapped. For example, this is allowed:
462
+ // `weak self` closures even before self is unwrapped.
463
+ // For example, this is allowed:
474
464
//
475
465
// doVoidStuffNonEscaping { [weak self] in
476
466
// method() // implicitly `self.method()`
477
467
// }
478
468
//
479
469
// To support this, we have to preserve the lookup behavior from
480
470
// Swift 5.7 and earlier where implicit self defaults to the closure's
481
- // `ParamDecl`. This causes the closure to capture self strongly, however,
471
+ // `ParamDecl`. This causes the closure to capture self strongly,
482
472
// which is not acceptable for escaping closures.
483
473
//
484
474
// Escaping closures, however, only need to permit implicit self once
@@ -492,11 +482,29 @@ ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
492
482
// In these cases, using the Swift 6 lookup behavior doesn't affect
493
483
// how the body is type-checked, so it can be used in Swift 5 mode
494
484
// without breaking source compatibility for non-escaping closures.
495
- if (!factory->Ctx .LangOpts .isSwiftVersionAtLeast (6 ) &&
496
- !implicitSelfReferenceIsUnwrapped (selfDecl, closureExpr )) {
485
+ if (capturesSelfWeakly && !factory->Ctx .LangOpts .isSwiftVersionAtLeast (6 ) &&
486
+ !implicitSelfReferenceIsUnwrapped (selfDecl)) {
497
487
return nullptr ;
498
488
}
499
489
490
+ // Closures are only allowed to rebind self in specific circumstances:
491
+ // 1. In a capture list with an explicit capture.
492
+ // 2. In a `guard let self = self` / `if let self = self` condition
493
+ // in a closure that captures self weakly.
494
+ //
495
+ // These rebindings can be done by any parent closure, and apply
496
+ // to all nested closures. We only need to check these structural
497
+ // requirements loosely here -- more extensive validation happens
498
+ // later in MiscDiagnostics::diagnoseImplicitSelfUseInClosure.
499
+ //
500
+ // Other types of rebindings, like an arbitrary "let `self` = foo",
501
+ // are never allowed to rebind self.
502
+ if (auto var = dyn_cast<VarDecl>(selfDecl)) {
503
+ if (!(var->isCaptureList () || var->getParentPatternStmt ())) {
504
+ return nullptr ;
505
+ }
506
+ }
507
+
500
508
return selfDecl;
501
509
}
502
510
0 commit comments