Skip to content

Commit d17bc35

Browse files
committed
Refactor and simplify shouldOnlyWarn logic
1 parent 7e95f9b commit d17bc35

File tree

1 file changed

+136
-123
lines changed

1 file changed

+136
-123
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 136 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,7 +2075,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
20752075
// If the closure's type was inferred to be noescape, then it doesn't
20762076
// need qualification.
20772077
if (AnyFunctionRef(const_cast<AbstractClosureExpr *>(CE))
2078-
.isKnownNoEscape())
2078+
.isKnownNoEscape())
20792079
return false;
20802080

20812081
if (auto autoclosure = dyn_cast<AutoClosureExpr>(CE)) {
@@ -2128,122 +2128,6 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21282128
return Action::Continue(E);
21292129
}
21302130

2131-
// Until Swift 6, only emit a warning when we get this with an
2132-
// explicit capture, since we used to not diagnose this at all.
2133-
auto shouldOnlyWarn = [&](Expr *selfRef) {
2134-
auto DRE = dyn_cast_or_null<DeclRefExpr>(selfRef);
2135-
if (!DRE) {
2136-
return false;
2137-
}
2138-
2139-
auto selfDecl = dyn_cast_or_null<VarDecl>(DRE->getDecl());
2140-
auto ty = DRE->getType();
2141-
if (!selfDecl || !ty) {
2142-
return false;
2143-
}
2144-
2145-
// Implicit self was always allowed in structs and metadata types
2146-
// even if the self capture was invalid.
2147-
if (!ty->hasReferenceSemantics() || ty->is<MetatypeType>()) {
2148-
return true;
2149-
}
2150-
2151-
// If this implicit self decl is from a closure that captured self
2152-
// weakly, then we should always emit an error, since implicit self was
2153-
// only allowed starting in Swift 5.8 and later.
2154-
if (auto weakSelfDecl = weakSelfCapture(ACE)) {
2155-
// However implicit self was incorrectly permitted for weak self
2156-
// captures in non-escaping closures in Swift 5.7, so in that case we
2157-
// can only warn until Swift 6.
2158-
if (AnyFunctionRef(const_cast<AbstractClosureExpr *>(ACE))
2159-
.isKnownNoEscape()) {
2160-
return true;
2161-
}
2162-
2163-
// If this is a capture like `[weak self = somethingElse]`,
2164-
// this unintentionally permitted implicit self in Swift 5.8 - 5.10,
2165-
// so we have to only warn until Swift 6.
2166-
if (!isSimpleSelfCapture(weakSelfDecl)) {
2167-
return true;
2168-
}
2169-
2170-
if (auto conditionalStmt = parentConditionalStmt(selfDecl)) {
2171-
auto isValidSelfRebinding =
2172-
hasValidSelfRebinding(conditionalStmt, ACE);
2173-
2174-
if (isValidSelfRebinding) {
2175-
// In Swift 5.8 - 5.10 we unintentionally permitted implicit
2176-
// self without validating any parent closures. To preserve
2177-
// source compatibility, in this case we only warn until Swift 6.
2178-
if (implicitSelfDisallowedDueToInvalidParent(selfDecl, ty, ACE)) {
2179-
return true;
2180-
}
2181-
}
2182-
2183-
// In Swift 5.8 - 5.10 we used `requiresLoadExpr` instead
2184-
// of `requiresCaptureListRef` to validate self unwrap
2185-
// conditions. For source compatibility, if the legacy check
2186-
// succeeds but the current check fails, we should only warn
2187-
// until Swift 6.
2188-
auto legacyRebindsSelfResult =
2189-
conditionalStmt->rebindsSelf(ACE->getASTContext(),
2190-
/*requiresCaptureListRef*/ false,
2191-
/*requiresLoadExpr*/ true);
2192-
2193-
if (!isValidSelfRebinding && legacyRebindsSelfResult) {
2194-
return true;
2195-
}
2196-
}
2197-
}
2198-
2199-
// If the self decl refers to a weak self unwrapping
2200-
// condition in some parent closure, then there is no
2201-
// source-compatibility requirement to avoid an error.
2202-
if (hasValidSelfRebinding(parentConditionalStmt(selfDecl), ACE)) {
2203-
return false;
2204-
}
2205-
2206-
// In Swift 5 mode we didn't validate the outermost capture in
2207-
// nonescaping closures, so if only the outermost capture is invalid
2208-
// then we must only warn.
2209-
if (!isClosureRequiringSelfQualification(ACE, Ctx)) {
2210-
auto invalidParentClosure = parentClosureDisallowingImplicitSelf(selfDecl, ty, ACE);
2211-
2212-
if (invalidParentClosure) {
2213-
auto excludingOutermostCapture = parentClosureDisallowingImplicitSelf(selfDecl, ty, ACE, /*validateOutermostCapture:*/ false);
2214-
2215-
if (invalidParentClosure != excludingOutermostCapture) {
2216-
return true;
2217-
}
2218-
}
2219-
}
2220-
2221-
// Implicit self was accidentially allowed in examples like this
2222-
// in Swift 5.3-5.5, so check for this case and emit a warning
2223-
// instead of an error:
2224-
//
2225-
// withEscaping { [self] in
2226-
// withEscaping {
2227-
// x += 1
2228-
// }
2229-
// }
2230-
//
2231-
bool isEscapingClosureWithExplicitSelfCapture = false;
2232-
if (isClosureRequiringSelfQualification(ACE, Ctx)) {
2233-
if (auto closureExpr = dyn_cast<ClosureExpr>(ACE)) {
2234-
if (closureExpr->getCapturedSelfDecl()) {
2235-
isEscapingClosureWithExplicitSelfCapture = true;
2236-
}
2237-
}
2238-
}
2239-
2240-
if (!selfDecl->isSelfParameter() && !isEscapingClosureWithExplicitSelfCapture) {
2241-
return true;
2242-
}
2243-
2244-
return false;
2245-
};
2246-
22472131
SourceLoc memberLoc = SourceLoc();
22482132
const DeclRefExpr *selfDRE = nullptr;
22492133
if (auto *MRE = dyn_cast<MemberRefExpr>(E))
@@ -2255,7 +2139,8 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
22552139
.diagnose(memberLoc,
22562140
diag::property_use_in_closure_without_explicit_self,
22572141
baseName.getIdentifier())
2258-
.warnUntilSwiftVersionIf(shouldOnlyWarn(MRE->getBase()), 6);
2142+
.warnUntilSwiftVersionIf(
2143+
invalidImplicitSelfShouldOnlyWarn(MRE->getBase(), ACE), 6);
22592144
}
22602145

22612146
// Handle method calls with a specific diagnostic + fixit.
@@ -2269,7 +2154,8 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
22692154
.diagnose(DSCE->getLoc(),
22702155
diag::method_call_in_closure_without_explicit_self,
22712156
MethodExpr->getDecl()->getBaseIdentifier())
2272-
.warnUntilSwiftVersionIf(shouldOnlyWarn(DSCE->getBase()), 6);
2157+
.warnUntilSwiftVersionIf(
2158+
invalidImplicitSelfShouldOnlyWarn(DSCE->getBase(), ACE), 6);
22732159
}
22742160

22752161
if (memberLoc.isValid()) {
@@ -2285,7 +2171,8 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
22852171

22862172
if (!selfDeclAllowsImplicitSelf(E, ACE))
22872173
Diags.diagnose(E->getLoc(), diag::implicit_use_of_self_in_closure)
2288-
.warnUntilSwiftVersionIf(shouldOnlyWarn(E), 6);
2174+
.warnUntilSwiftVersionIf(invalidImplicitSelfShouldOnlyWarn(E, ACE),
2175+
6);
22892176

22902177
return Action::Continue(E);
22912178
}
@@ -2444,9 +2331,8 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
24442331
// insert 'self,'. If it wasn't a valid entry, then we will at least not
24452332
// be introducing any new errors/warnings...
24462333
const auto locAfterBracket = brackets.Start.getAdvancedLoc(1);
2447-
const auto nextAfterBracket =
2448-
Lexer::getTokenAtLocation(Ctx.SourceMgr, locAfterBracket,
2449-
CommentRetentionMode::None);
2334+
const auto nextAfterBracket = Lexer::getTokenAtLocation(
2335+
Ctx.SourceMgr, locAfterBracket, CommentRetentionMode::None);
24502336
if (nextAfterBracket.getLoc() != brackets.End)
24512337
diag.fixItInsertAfter(brackets.Start, "self, ");
24522338
else
@@ -2474,6 +2360,133 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
24742360

24752361
diag.fixItInsertAfter(closureExpr->getLoc(), " [self] in" + trailing);
24762362
}
2363+
2364+
/// Whether or not this invalid usage of implicit self should be a warning
2365+
/// in Swift 5 mode, to preserve source compatibility.
2366+
bool invalidImplicitSelfShouldOnlyWarn(Expr *selfRef,
2367+
AbstractClosureExpr *ACE) {
2368+
auto DRE = dyn_cast_or_null<DeclRefExpr>(selfRef);
2369+
if (!DRE) {
2370+
return false;
2371+
}
2372+
2373+
auto selfDecl = dyn_cast_or_null<VarDecl>(DRE->getDecl());
2374+
auto ty = DRE->getType();
2375+
if (!selfDecl) {
2376+
return false;
2377+
}
2378+
2379+
if (isInTypePreviouslyLackingValidation(ty)) {
2380+
return true;
2381+
}
2382+
2383+
if (isPreviouslyPermittedWeakSelfUsage(ACE, selfDecl, ty)) {
2384+
return true;
2385+
}
2386+
2387+
if (isUsageAlwaysPreviouslyRejected(selfDecl, ACE)) {
2388+
return false;
2389+
}
2390+
2391+
if (isPreviouslyPermittedStrongSelfUsage(selfDecl, ACE)) {
2392+
return true;
2393+
}
2394+
2395+
return false;
2396+
}
2397+
2398+
bool isInTypePreviouslyLackingValidation(Type ty) {
2399+
// We previously didn't validate captures at all in structs or metadata
2400+
// types, so we must only warn in this case.
2401+
return !ty->hasReferenceSemantics() || ty->is<MetatypeType>();
2402+
}
2403+
2404+
/// Checks if this usage of implicit self in a weak self closure
2405+
/// was previously permitted in Swift 5.8.
2406+
bool isPreviouslyPermittedWeakSelfUsage(AbstractClosureExpr *ACE,
2407+
ValueDecl *selfDecl, Type ty) {
2408+
auto weakSelfDecl = weakSelfCapture(ACE);
2409+
if (!weakSelfDecl) {
2410+
return false;
2411+
}
2412+
2413+
// Implicit self was permitted for weak self captures in
2414+
// non-escaping closures in Swift 5.7, so we must only warn.
2415+
if (AnyFunctionRef(const_cast<AbstractClosureExpr *>(ACE))
2416+
.isKnownNoEscape()) {
2417+
return true;
2418+
}
2419+
2420+
// Invalid captures like `[weak self = somethingElse]`
2421+
// were permitted in Swift 5.8, so we must only warn.
2422+
if (!isSimpleSelfCapture(weakSelfDecl)) {
2423+
return true;
2424+
}
2425+
2426+
if (auto condStmt = parentConditionalStmt(selfDecl)) {
2427+
auto isValidSelfRebinding = hasValidSelfRebinding(condStmt, ACE);
2428+
2429+
// Swfit 5.8 permitted implicit self without validating any
2430+
// parent closures. If implicit self is only disallowed due to
2431+
// an invalid parent, we must only warn.
2432+
if (isValidSelfRebinding &&
2433+
implicitSelfDisallowedDueToInvalidParent(selfDecl, ty, ACE)) {
2434+
return true;
2435+
}
2436+
2437+
// Swift 5.8 used `requiresLoadExpr` to validate self bindings.
2438+
// If the binding is valid when only checking for a load expr,
2439+
// then we must only warn.
2440+
auto usesLoadExpr =
2441+
condStmt->rebindsSelf(ACE->getASTContext(),
2442+
/*requiresCaptureListRef*/ false,
2443+
/*requireLoadExpr*/ true);
2444+
2445+
if (!isValidSelfRebinding && usesLoadExpr) {
2446+
return true;
2447+
}
2448+
}
2449+
2450+
return false;
2451+
}
2452+
2453+
/// Checks if this implicit self usage was always previously rejected as
2454+
/// invalid, so can continue to be treated an error.
2455+
bool isUsageAlwaysPreviouslyRejected(ValueDecl *selfDecl,
2456+
AbstractClosureExpr *ACE) {
2457+
// If the self decl refers to a weak self unwrap condition
2458+
// in some parent closure, then there is no source-compatibility
2459+
// requirement to avoid an error.
2460+
return hasValidSelfRebinding(parentConditionalStmt(selfDecl), ACE);
2461+
}
2462+
2463+
/// Checks if this is a usage of implicit self in a strong self closure
2464+
/// that was previously permitted in older versions like Swift 5.3.
2465+
bool isPreviouslyPermittedStrongSelfUsage(VarDecl *selfDecl,
2466+
AbstractClosureExpr *ACE) {
2467+
// Implicit self was accidentially allowed in examples like this
2468+
// in Swift 5.3-5.5, so check for this case and emit a warning
2469+
// instead of an error:
2470+
//
2471+
// withEscaping { [self] in
2472+
// withEscaping {
2473+
// x += 1
2474+
// }
2475+
// }
2476+
//
2477+
bool isEscapingClosureWithExplicitSelfCapture = false;
2478+
if (!AnyFunctionRef(const_cast<AbstractClosureExpr *>(ACE))
2479+
.isKnownNoEscape()) {
2480+
if (auto closureExpr = dyn_cast<ClosureExpr>(ACE)) {
2481+
if (closureExpr->getCapturedSelfDecl()) {
2482+
isEscapingClosureWithExplicitSelfCapture = true;
2483+
}
2484+
}
2485+
}
2486+
2487+
return !selfDecl->isSelfParameter() &&
2488+
!isEscapingClosureWithExplicitSelfCapture;
2489+
}
24772490
};
24782491

24792492
auto &ctx = DC->getASTContext();

0 commit comments

Comments
 (0)