Skip to content

Commit 8d69776

Browse files
committed
[Sema] Restore 5.10 implicit self behavior prior to Swift 6 mode
Unfortunately we've encountered another source breaking case here: ``` class C { func method() {} func foo() { Task { [weak self] in Task { method() } } } } ``` In 5.10 we'd only do the unqualified lookup for `self` when directly in a `weak self` closure, but with the implicit self rework, we'd start using the `weak self` here, leading to a type-checker error. At this point, adding more edge cases to the existing logic is going to make things much more complicated. Instead, reinstate the 5.10 implicit self lookup behavior and diagnostic logic, switching over to the new logic only under Swift 6 mode. rdar://129475277
1 parent ad71c2e commit 8d69776

File tree

6 files changed

+343
-262
lines changed

6 files changed

+343
-262
lines changed

lib/AST/UnqualifiedLookup.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -369,20 +369,24 @@ ValueDecl *UnqualifiedLookupFactory::lookupBaseDecl(const DeclContext *baseDC) c
369369
return nullptr;
370370
}
371371

372-
auto selfDecl = ASTScope::lookupSingleLocalDecl(
373-
DC->getParentSourceFile(), DeclName(Ctx.Id_self), Loc);
374-
375-
if (!selfDecl) {
376-
return nullptr;
377-
}
378-
379372
bool capturesSelfWeakly = false;
380373
if (auto decl = closureExpr->getCapturedSelfDecl()) {
381374
if (auto a = decl->getAttrs().getAttribute<ReferenceOwnershipAttr>()) {
382375
capturesSelfWeakly = a->get() == ReferenceOwnership::Weak;
383376
}
384377
}
385378

379+
// Previously we didn't perform the lookup of 'self' for anything outside
380+
// of a '[weak self]' closure, maintain that behavior until Swift 6 mode.
381+
if (!Ctx.LangOpts.isSwiftVersionAtLeast(6) && !capturesSelfWeakly)
382+
return nullptr;
383+
384+
auto selfDecl = ASTScope::lookupSingleLocalDecl(DC->getParentSourceFile(),
385+
DeclName(Ctx.Id_self), Loc);
386+
if (!selfDecl) {
387+
return nullptr;
388+
}
389+
386390
// In Swift 5 mode, implicit self is allowed within non-escaping
387391
// `weak self` closures even before self is unwrapped.
388392
// For example, this is allowed:
@@ -407,7 +411,7 @@ ValueDecl *UnqualifiedLookupFactory::lookupBaseDecl(const DeclContext *baseDC) c
407411
// In these cases, using the Swift 6 lookup behavior doesn't affect
408412
// how the body is type-checked, so it can be used in Swift 5 mode
409413
// without breaking source compatibility for non-escaping closures.
410-
if (capturesSelfWeakly && !Ctx.LangOpts.isSwiftVersionAtLeast(6) &&
414+
if (!Ctx.LangOpts.isSwiftVersionAtLeast(6) &&
411415
!implicitSelfReferenceIsUnwrapped(selfDecl)) {
412416
return nullptr;
413417
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 131 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,91 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
17151715
Closures.push_back(ACE);
17161716
}
17171717

1718+
static bool
1719+
implicitWeakSelfReferenceIsValid510(const DeclRefExpr *DRE,
1720+
const AbstractClosureExpr *inClosure) {
1721+
ASTContext &Ctx = DRE->getDecl()->getASTContext();
1722+
1723+
// Check if the implicit self decl refers to a var in a conditional stmt
1724+
LabeledConditionalStmt *conditionalStmt = nullptr;
1725+
if (auto var = dyn_cast<VarDecl>(DRE->getDecl())) {
1726+
if (auto parentStmt = var->getParentPatternStmt()) {
1727+
conditionalStmt = dyn_cast<LabeledConditionalStmt>(parentStmt);
1728+
}
1729+
}
1730+
1731+
if (!conditionalStmt) {
1732+
return false;
1733+
}
1734+
1735+
// Require `LoadExpr`s when validating the self binding.
1736+
// This lets us reject invalid examples like:
1737+
//
1738+
// let `self` = self ?? .somethingElse
1739+
// guard let self = self else { return }
1740+
// method() // <- implicit self is not allowed
1741+
//
1742+
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false,
1743+
/*requireLoadExpr*/ true);
1744+
}
1745+
1746+
static bool
1747+
isEnclosingSelfReference510(VarDecl *var,
1748+
const AbstractClosureExpr *inClosure) {
1749+
if (var->isSelfParameter())
1750+
return true;
1751+
1752+
// Capture variables have a DC of the parent function.
1753+
if (inClosure && var->isSelfParamCapture() &&
1754+
var->getDeclContext() != inClosure->getParent())
1755+
return true;
1756+
1757+
return false;
1758+
}
1759+
1760+
static bool
1761+
selfDeclAllowsImplicitSelf510(DeclRefExpr *DRE, Type ty,
1762+
const AbstractClosureExpr *inClosure) {
1763+
// If this is an explicit `weak self` capture, then implicit self is
1764+
// allowed once the closure's self param is unwrapped. We need to validate
1765+
// that the unwrapped `self` decl specifically refers to an unwrapped copy
1766+
// of the closure's `self` param, and not something else like in `guard
1767+
// let self = .someOptionalVariable else { return }` or `let self =
1768+
// someUnrelatedVariable`. If self hasn't been unwrapped yet and is still
1769+
// an optional, we would have already hit an error elsewhere.
1770+
if (closureHasWeakSelfCapture(inClosure)) {
1771+
return implicitWeakSelfReferenceIsValid510(DRE, inClosure);
1772+
}
1773+
1774+
// Metatype self captures don't extend the lifetime of an object.
1775+
if (ty->is<MetatypeType>())
1776+
return true;
1777+
1778+
// If self does not have reference semantics, it is very unlikely that
1779+
// capturing it will create a reference cycle.
1780+
if (!ty->hasReferenceSemantics())
1781+
return true;
1782+
1783+
if (auto closureExpr = dyn_cast<ClosureExpr>(inClosure)) {
1784+
if (auto selfDecl = closureExpr->getCapturedSelfDecl()) {
1785+
// If this capture is using the name `self` actually referring
1786+
// to some other variable (e.g. with `[self = "hello"]`)
1787+
// then implicit self is not allowed.
1788+
if (!selfDecl->isSelfParamCapture()) {
1789+
return false;
1790+
}
1791+
}
1792+
}
1793+
1794+
if (auto var = dyn_cast<VarDecl>(DRE->getDecl())) {
1795+
if (!isEnclosingSelfReference510(var, inClosure)) {
1796+
return true;
1797+
}
1798+
}
1799+
1800+
return false;
1801+
}
1802+
17181803
/// Whether or not implicit self is allowed for self decl
17191804
static bool
17201805
selfDeclAllowsImplicitSelf(Expr *E, const AbstractClosureExpr *inClosure) {
@@ -1731,6 +1816,11 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
17311816
if (!ty)
17321817
return true;
17331818

1819+
// Prior to Swift 6, use the old validation logic.
1820+
auto &ctx = inClosure->getASTContext();
1821+
if (!ctx.isSwiftVersionAtLeast(6))
1822+
return selfDeclAllowsImplicitSelf510(DRE, ty, inClosure);
1823+
17341824
return selfDeclAllowsImplicitSelf(DRE->getDecl(), ty, inClosure,
17351825
/*validateParentClosures:*/ true,
17361826
/*validateSelfRebindings:*/ true);
@@ -2063,8 +2153,9 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
20632153
/// Return true if this is a closure expression that will require explicit
20642154
/// use or capture of "self." for qualification of member references.
20652155
static bool
2066-
isClosureRequiringSelfQualification(const AbstractClosureExpr *CE) {
2067-
if (closureHasWeakSelfCapture(CE)) {
2156+
isClosureRequiringSelfQualification(const AbstractClosureExpr *CE,
2157+
bool ignoreWeakSelf = false) {
2158+
if (!ignoreWeakSelf && closureHasWeakSelfCapture(CE)) {
20682159
return true;
20692160
}
20702161

@@ -2102,9 +2193,20 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21022193

21032194
bool shouldWalkCaptureInitializerExpressions() override { return true; }
21042195

2196+
bool shouldRecordClosure(const AbstractClosureExpr *E) {
2197+
// Record all closures in Swift 6 mode.
2198+
if (Ctx.isSwiftVersionAtLeast(6))
2199+
return true;
2200+
2201+
// Only record closures requiring self qualification prior to Swift 6
2202+
// mode.
2203+
return isClosureRequiringSelfQualification(E);
2204+
}
2205+
21052206
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
21062207
if (auto *CE = dyn_cast<AbstractClosureExpr>(E)) {
2107-
Closures.push_back(CE);
2208+
if (shouldRecordClosure(CE))
2209+
Closures.push_back(CE);
21082210
}
21092211

21102212
// If we aren't in a closure, no diagnostics will be produced.
@@ -2136,7 +2238,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21362238
diag::property_use_in_closure_without_explicit_self,
21372239
baseName.getIdentifier())
21382240
.warnUntilSwiftVersionIf(
2139-
invalidImplicitSelfShouldOnlyWarn(MRE->getBase(), ACE), 6);
2241+
invalidImplicitSelfShouldOnlyWarn510(MRE->getBase(), ACE), 6);
21402242
}
21412243

21422244
// Handle method calls with a specific diagnostic + fixit.
@@ -2151,12 +2253,13 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21512253
diag::method_call_in_closure_without_explicit_self,
21522254
MethodExpr->getDecl()->getBaseIdentifier())
21532255
.warnUntilSwiftVersionIf(
2154-
invalidImplicitSelfShouldOnlyWarn(DSCE->getBase(), ACE), 6);
2256+
invalidImplicitSelfShouldOnlyWarn510(DSCE->getBase(), ACE),
2257+
6);
21552258
}
21562259

21572260
if (memberLoc.isValid()) {
21582261
const AbstractClosureExpr *parentDisallowingImplicitSelf = nullptr;
2159-
if (selfDRE && selfDRE->getDecl()) {
2262+
if (Ctx.isSwiftVersionAtLeast(6) && selfDRE && selfDRE->getDecl()) {
21602263
parentDisallowingImplicitSelf = parentClosureDisallowingImplicitSelf(
21612264
selfDRE->getDecl(), selfDRE->getType(), ACE);
21622265
}
@@ -2165,11 +2268,11 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21652268
return Action::SkipNode(E);
21662269
}
21672270

2168-
if (!selfDeclAllowsImplicitSelf(E, ACE))
2271+
if (!selfDeclAllowsImplicitSelf(E, ACE)) {
21692272
Diags.diagnose(E->getLoc(), diag::implicit_use_of_self_in_closure)
2170-
.warnUntilSwiftVersionIf(invalidImplicitSelfShouldOnlyWarn(E, ACE),
2171-
6);
2172-
2273+
.warnUntilSwiftVersionIf(
2274+
invalidImplicitSelfShouldOnlyWarn510(E, ACE), 6);
2275+
}
21732276
return Action::Continue(E);
21742277
}
21752278

@@ -2179,9 +2282,10 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21792282
return Action::Continue(E);
21802283
}
21812284

2182-
assert(Closures.size() > 0);
2183-
Closures.pop_back();
2184-
2285+
if (shouldRecordClosure(ACE)) {
2286+
assert(Closures.size() > 0);
2287+
Closures.pop_back();
2288+
}
21852289
return Action::Continue(E);
21862290
}
21872291

@@ -2359,134 +2463,28 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
23592463

23602464
/// Whether or not this invalid usage of implicit self should be a warning
23612465
/// in Swift 5 mode, to preserve source compatibility.
2362-
bool invalidImplicitSelfShouldOnlyWarn(Expr *selfRef,
2363-
AbstractClosureExpr *ACE) {
2466+
bool invalidImplicitSelfShouldOnlyWarn510(Expr *selfRef,
2467+
AbstractClosureExpr *ACE) {
23642468
auto DRE = dyn_cast_or_null<DeclRefExpr>(selfRef);
2365-
if (!DRE) {
2469+
if (!DRE)
23662470
return false;
2367-
}
23682471

23692472
auto selfDecl = dyn_cast_or_null<VarDecl>(DRE->getDecl());
2370-
auto ty = DRE->getType();
2371-
if (!selfDecl) {
2372-
return false;
2373-
}
2374-
2375-
if (isInTypePreviouslyLackingValidation(ty)) {
2376-
return true;
2377-
}
2378-
2379-
if (isPreviouslyPermittedWeakSelfUsage(ACE, selfDecl, ty)) {
2380-
return true;
2381-
}
2382-
2383-
if (isUsageAlwaysPreviouslyRejected(selfDecl)) {
2473+
if (!selfDecl)
23842474
return false;
2385-
}
2386-
2387-
if (isPreviouslyPermittedStrongSelfUsage(selfDecl, ACE)) {
2388-
return true;
2389-
}
2390-
2391-
return false;
2392-
}
23932475

2394-
bool isInTypePreviouslyLackingValidation(Type ty) {
2395-
// We previously didn't validate captures at all in structs or metadata
2396-
// types, so we must only warn in this case.
2397-
return !ty->hasReferenceSemantics() || ty->is<MetatypeType>();
2398-
}
2399-
2400-
/// Checks if this usage of implicit self in a weak self closure
2401-
/// was previously permitted in Swift 5.8.
2402-
bool isPreviouslyPermittedWeakSelfUsage(AbstractClosureExpr *ACE,
2403-
ValueDecl *selfDecl, Type ty) {
2404-
auto weakSelfDecl = weakSelfCapture(ACE);
2405-
if (!weakSelfDecl) {
2406-
return false;
2407-
}
2408-
2409-
// Implicit self was permitted for weak self captures in
2410-
// non-escaping closures in Swift 5.7, so we must only warn.
2411-
if (AnyFunctionRef(const_cast<AbstractClosureExpr *>(ACE))
2412-
.isKnownNoEscape()) {
2413-
return true;
2414-
}
2415-
2416-
// Implicit self was also permitted for weak self captures in closures
2417-
// passed to @_implicitSelfCapture parameters in Swift 5.7.
2418-
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
2419-
if (CE->allowsImplicitSelfCapture())
2420-
return true;
2421-
}
2422-
2423-
// Invalid captures like `[weak self = somethingElse]`
2424-
// were permitted in Swift 5.8, so we must only warn.
2425-
if (!isSimpleSelfCapture(weakSelfDecl)) {
2426-
return true;
2427-
}
2428-
2429-
if (auto condStmt = parentConditionalStmt(selfDecl)) {
2430-
auto isValidSelfRebinding = hasValidSelfRebinding(condStmt, Ctx);
2431-
2432-
// Swfit 5.8 permitted implicit self without validating any
2433-
// parent closures. If implicit self is only disallowed due to
2434-
// an invalid parent, we must only warn.
2435-
if (isValidSelfRebinding &&
2436-
implicitSelfDisallowedDueToInvalidParent(selfDecl, ty, ACE)) {
2437-
return true;
2438-
}
2439-
2440-
// Swift 5.8 used `requiresLoadExpr` to validate self bindings.
2441-
// If the binding is valid when only checking for a load expr,
2442-
// then we must only warn.
2443-
auto usesLoadExpr =
2444-
condStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false,
2445-
/*requireLoadExpr*/ true);
2446-
2447-
if (!isValidSelfRebinding && usesLoadExpr) {
2448-
return true;
2449-
}
2450-
}
2451-
2452-
return false;
2453-
}
2454-
2455-
/// Checks if this implicit self usage was always previously rejected as
2456-
/// invalid, so can continue to be treated an error.
2457-
bool isUsageAlwaysPreviouslyRejected(ValueDecl *selfDecl) {
2458-
// If the self decl refers to a weak self unwrap condition
2459-
// in some parent closure, then there is no source-compatibility
2460-
// requirement to avoid an error.
2461-
return hasValidSelfRebinding(parentConditionalStmt(selfDecl), Ctx);
2462-
}
2463-
2464-
/// Checks if this is a usage of implicit self in a strong self closure
2465-
/// that was previously permitted in older versions like Swift 5.3.
2466-
bool isPreviouslyPermittedStrongSelfUsage(VarDecl *selfDecl,
2467-
AbstractClosureExpr *ACE) {
2468-
// Implicit self was accidentially allowed in examples like this
2469-
// in Swift 5.3-5.5, so check for this case and emit a warning
2470-
// instead of an error:
2471-
//
2472-
// withEscaping { [self] in
2473-
// withEscaping {
2474-
// x += 1
2475-
// }
2476-
// }
2477-
//
2478-
bool isEscapingClosureWithExplicitSelfCapture = false;
2479-
if (!AnyFunctionRef(const_cast<AbstractClosureExpr *>(ACE))
2480-
.isKnownNoEscape()) {
2481-
if (auto closureExpr = dyn_cast<ClosureExpr>(ACE)) {
2482-
if (closureExpr->getCapturedSelfDecl()) {
2483-
isEscapingClosureWithExplicitSelfCapture = true;
2484-
}
2485-
}
2476+
// If this implicit self decl is from a closure that captured self
2477+
// weakly, then we should always emit an error, since implicit self was
2478+
// only allowed starting in Swift 5.8 and later.
2479+
if (closureHasWeakSelfCapture(ACE)) {
2480+
// Implicit self was incorrectly permitted for weak self captures
2481+
// in non-escaping closures in Swift 5.7, so in that case we can
2482+
// only warn until Swift 6.
2483+
return !isClosureRequiringSelfQualification(ACE,
2484+
/*ignoreWeakSelf*/ true);
24862485
}
24872486

2488-
return !selfDecl->isSelfParameter() &&
2489-
!isEscapingClosureWithExplicitSelfCapture;
2487+
return !selfDecl->isSelfParameter();
24902488
}
24912489
};
24922490

0 commit comments

Comments
 (0)