mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Fix the condition for warning about implicit capture of self captures.
We've always emitted an error if we saw an implicit use of a self parameter of class type from an escaping closure. In PR #35898, I fixed this to also emit an error if the reference was to an explicit capture of self that wasn't made in the current closure. That was causing some source incompatibilities that we decided were too severe, so in PR #38947 I weakened that to a warning when the diagnostic walk was within multiple levels of closures, because I have always thought of this as a fix to nested closures. However, this was the wrong condition in two ways. First, the diagnostic walk does not always start from the outermost function declaration; it can also start from a multi-statement closure. In that case, we'll still end up emitting an error when we see uses of explicit captures from the closure when we walk it, and so we still have a source incompatibility. That is rdar://82545600. Second, the old diagnostic did actually fire correctly in nested closures as long as the code was directly referring to the original self parameter and not any intervening captures. Therefore, #38947 actually turned some things into warnings that had always been errors. The fix is to produce a warning exactly when the referenced declaration was an explicit capture.
This commit is contained in:
@@ -1615,6 +1615,15 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
|
||||
// Diagnostics should correct the innermost closure
|
||||
auto *ACE = Closures[Closures.size() - 1];
|
||||
assert(ACE);
|
||||
|
||||
// Until Swift 6, only emit a warning when we get this with an
|
||||
// explicit capture, since we used to not diagnose this at all.
|
||||
auto shouldOnlyWarn = [&](Expr *selfRef) {
|
||||
// We know that isImplicitSelfParamUseLikelyToCauseCycle is true,
|
||||
// which means all these casts are valid.
|
||||
return !cast<VarDecl>(cast<DeclRefExpr>(selfRef)->getDecl())
|
||||
->isSelfParameter();
|
||||
};
|
||||
|
||||
SourceLoc memberLoc = SourceLoc();
|
||||
if (auto *MRE = dyn_cast<MemberRefExpr>(E))
|
||||
@@ -1624,7 +1633,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
|
||||
Diags.diagnose(memberLoc,
|
||||
diag::property_use_in_closure_without_explicit_self,
|
||||
baseName.getIdentifier())
|
||||
.warnUntilSwiftVersionIf(Closures.size() > 1, 6);
|
||||
.warnUntilSwiftVersionIf(shouldOnlyWarn(MRE->getBase()), 6);
|
||||
}
|
||||
|
||||
// Handle method calls with a specific diagnostic + fixit.
|
||||
@@ -1636,7 +1645,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
|
||||
Diags.diagnose(DSCE->getLoc(),
|
||||
diag::method_call_in_closure_without_explicit_self,
|
||||
MethodExpr->getDecl()->getBaseIdentifier())
|
||||
.warnUntilSwiftVersionIf(Closures.size() > 1, 6);
|
||||
.warnUntilSwiftVersionIf(shouldOnlyWarn(DSCE->getBase()), 6);
|
||||
}
|
||||
|
||||
if (memberLoc.isValid()) {
|
||||
@@ -1647,7 +1656,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
|
||||
// Catch any other implicit uses of self with a generic diagnostic.
|
||||
if (isImplicitSelfParamUseLikelyToCauseCycle(E, ACE))
|
||||
Diags.diagnose(E->getLoc(), diag::implicit_use_of_self_in_closure)
|
||||
.warnUntilSwiftVersionIf(Closures.size() > 1, 6);
|
||||
.warnUntilSwiftVersionIf(shouldOnlyWarn(E), 6);
|
||||
|
||||
return { true, E };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user