@@ -1738,7 +1738,8 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
1738
1738
1739
1739
static bool selfDeclAllowsImplicitSelf (const ValueDecl *selfDecl,
1740
1740
const AbstractClosureExpr *inClosure,
1741
- bool validateParentClosures = true ) {
1741
+ bool validateParentClosures = true ,
1742
+ bool validateSelfRebindings = true ) {
1742
1743
ASTContext &ctx = inClosure->getASTContext ();
1743
1744
1744
1745
auto requiresSelfQualification =
@@ -1767,22 +1768,18 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
1767
1768
// be a closure nested in some parent closure with a `weak self`
1768
1769
// capture, so we should always validate the conditional statement
1769
1770
// that defines self if present.
1770
- if (auto conditionalStmt = parentConditionalStmt (selfDecl)) {
1771
- if (!hasValidSelfRebinding (conditionalStmt, inClosure)) {
1772
- return false ;
1771
+ if (validateSelfRebindings) {
1772
+ if (auto conditionalStmt = parentConditionalStmt (selfDecl)) {
1773
+ if (!hasValidSelfRebinding (conditionalStmt, inClosure)) {
1774
+ return false ;
1775
+ }
1773
1776
}
1774
1777
}
1775
1778
1776
- // In Swift 5 mode, due to backwards compatibility requirements,
1777
- // non-escaping closures use an implicit self lookup behavior
1778
- // that makes self non-optional before being unwrapped.
1779
- // - In Swift 5 mode we have to manually validate that the self decl
1780
- // has been unwrapped in a permitted way.
1781
- // - In Swift 6 mode this check isn't necessary because a self decl
1782
- // that hasn't been unwrapped yet is Optional as expected, so this
1783
- // would have already failed to compile elsewhere.
1784
- if (!ctx.LangOpts .isSwiftVersionAtLeast (6 ) &&
1785
- closureHasWeakSelfCapture (inClosure) &&
1779
+ // If this closure has a `weak self` capture, require that the
1780
+ // closure unwraps self. If not, implicit self is not allowed
1781
+ // in this closure or in any nested closure.
1782
+ if (closureHasWeakSelfCapture (inClosure) &&
1786
1783
!hasValidSelfRebinding (parentConditionalStmt (selfDecl), inClosure)) {
1787
1784
return false ;
1788
1785
}
@@ -1832,7 +1829,17 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
1832
1829
1833
1830
static bool implicitSelfDisallowedDueToInvalidParent (
1834
1831
const ValueDecl *selfDecl, const AbstractClosureExpr *inClosure) {
1832
+ return parentClosureDisallowingImplicitSelf (selfDecl, inClosure) !=
1833
+ nullptr ;
1834
+ }
1835
+
1836
+ static const AbstractClosureExpr *
1837
+ parentClosureDisallowingImplicitSelf (const ValueDecl *selfDecl,
1838
+ const AbstractClosureExpr *inClosure) {
1835
1839
ASTContext &ctx = inClosure->getASTContext ();
1840
+ if (!selfDecl) {
1841
+ return nullptr ;
1842
+ }
1836
1843
1837
1844
// Find the outer decl that determines what self refers to in this
1838
1845
// closure.
@@ -1892,7 +1899,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
1892
1899
// this closure nor any of its parents disallow it).
1893
1900
auto parent = parentClosure (outerClosure);
1894
1901
if (!parent) {
1895
- return false ;
1902
+ return nullptr ;
1896
1903
}
1897
1904
1898
1905
outerClosure = parent;
@@ -1901,19 +1908,44 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
1901
1908
outerClosure->getSourceRange ().contains (
1902
1909
outerSelfDecl->getLoc (true ));
1903
1910
1911
+ // We can stop searching because we found the first outer closure
1912
+ // that contains the outer self decl.
1904
1913
if (outerClosureContainsSelfDecl) {
1905
- // We can stop searching because we found the first outer closure
1906
- // that contains the outer self decl
1907
- return !selfDeclAllowsImplicitSelf (outerSelfDecl, outerClosure);
1914
+ // Check whether implicit self is disallowed due to this specific
1915
+ // closure, or if its disallowed due to some parent of this closure,
1916
+ // so we can return the specific closure that is invalid.
1917
+ auto implicitSelfDisallowedDueToThisClosure =
1918
+ !selfDeclAllowsImplicitSelf (outerSelfDecl, outerClosure,
1919
+ /* validateParentClosures:*/ false );
1920
+
1921
+ auto outerParentDisallowingImplicitSelf =
1922
+ parentClosureDisallowingImplicitSelf (outerSelfDecl, outerClosure);
1923
+
1924
+ if (implicitSelfDisallowedDueToThisClosure) {
1925
+ return outerClosure;
1926
+ } else if (outerParentDisallowingImplicitSelf) {
1927
+ return outerParentDisallowingImplicitSelf;
1928
+ } else {
1929
+ return nullptr ;
1930
+ }
1908
1931
}
1909
1932
1910
1933
// Optionally validate this intermediate closure before continuing
1911
1934
// to search upwards. Since we're already validating the chain of
1912
1935
// parent closures, we don't need to do that separate for this closure.
1913
1936
if (validateIntermediateParents) {
1914
- if (!selfDeclAllowsImplicitSelf (selfDecl, outerClosure,
1915
- /* validateParentClosures*/ false )) {
1916
- return true ;
1937
+ // If the self decl is defined in a `let self = self` unwrapping
1938
+ // condition, only validate that condition once we reach the weak
1939
+ // closure that actually contains the condition. This makes sure
1940
+ // that we ultimately return that parent closure as invalid, instead
1941
+ // of this closure that could itself be valid.
1942
+ auto validateSelfRebindings = closureHasWeakSelfCapture (outerClosure);
1943
+
1944
+ if (!selfDeclAllowsImplicitSelf (
1945
+ selfDecl, outerClosure,
1946
+ /* validateParentClosures*/ false ,
1947
+ /* validateSelfRebindings*/ validateSelfRebindings)) {
1948
+ return outerClosure;
1917
1949
}
1918
1950
}
1919
1951
} while (true );
@@ -2151,6 +2183,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
2151
2183
};
2152
2184
2153
2185
SourceLoc memberLoc = SourceLoc ();
2186
+ const ValueDecl *selfDecl;
2154
2187
if (auto *MRE = dyn_cast<MemberRefExpr>(E))
2155
2188
if (isImplicitSelfParamUseLikelyToCauseCycle (MRE->getBase (), ACE)) {
2156
2189
auto baseName = MRE->getMember ().getDecl ()->getBaseName ();
@@ -2159,6 +2192,10 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
2159
2192
diag::property_use_in_closure_without_explicit_self,
2160
2193
baseName.getIdentifier ())
2161
2194
.warnUntilSwiftVersionIf (shouldOnlyWarn (MRE->getBase ()), 6 );
2195
+
2196
+ if (auto DRE = dyn_cast_or_null<DeclRefExpr>(MRE->getBase ())) {
2197
+ selfDecl = DRE->getDecl ();
2198
+ }
2162
2199
}
2163
2200
2164
2201
// Handle method calls with a specific diagnostic + fixit.
@@ -2171,10 +2208,14 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
2171
2208
diag::method_call_in_closure_without_explicit_self,
2172
2209
MethodExpr->getDecl ()->getBaseIdentifier ())
2173
2210
.warnUntilSwiftVersionIf (shouldOnlyWarn (DSCE->getBase ()), 6 );
2211
+
2212
+ if (auto DRE = dyn_cast_or_null<DeclRefExpr>(DSCE->getBase ())) {
2213
+ selfDecl = DRE->getDecl ();
2214
+ }
2174
2215
}
2175
2216
2176
2217
if (memberLoc.isValid ()) {
2177
- emitFixIts (Diags, memberLoc, ACE);
2218
+ emitFixIts (Diags, memberLoc, selfDecl, ACE);
2178
2219
return Action::SkipNode (E);
2179
2220
}
2180
2221
@@ -2232,38 +2273,51 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
2232
2273
}
2233
2274
2234
2275
// / Emit any fix-its for this error.
2235
- void emitFixIts (DiagnosticEngine &Diags,
2236
- SourceLoc memberLoc,
2237
- const AbstractClosureExpr *ACE) {
2276
+ void emitFixIts (DiagnosticEngine &Diags, SourceLoc memberLoc,
2277
+ const ValueDecl *selfDecl, const AbstractClosureExpr *ACE) {
2278
+ // These fix-its have to be diagnosed on the closure that requires,
2279
+ // but is currently missing, self qualification. It's possible that
2280
+ // ACE doesn't require self qualification (e.g. because it's
2281
+ // non-escaping) but is nested inside a closure that does require self
2282
+ // qualification. In that case we have to emit the fixit for the parent
2283
+ // closure.
2284
+ // - Even if this closure requires self qualification, if there's an
2285
+ // invalid parent we emit the diagnostic on that parent first.
2286
+ // To enable implicit self you'd have to fix the parent anyway.
2287
+ // This lets us avoid bogus diagnostics on this closure when
2288
+ // it's actually _just_ the parent that's invalid.
2289
+ auto closureForDiagnostics = ACE;
2290
+ if (auto invalidParentClosure =
2291
+ parentClosureDisallowingImplicitSelf (selfDecl, ACE)) {
2292
+ // Don't do this for escaping autoclosures, which are never allowed
2293
+ // to use implicit self, even after fixing any invalid parents.
2294
+ auto isEscapingAutoclosure =
2295
+ isa<AutoClosureExpr>(ACE) &&
2296
+ isClosureRequiringSelfQualification (ACE, Ctx);
2297
+ if (!isEscapingAutoclosure) {
2298
+ closureForDiagnostics = invalidParentClosure;
2299
+ }
2300
+ }
2301
+
2238
2302
// This error can be fixed by either capturing self explicitly (if in an
2239
2303
// explicit closure), or referencing self explicitly.
2240
- if (auto *CE = dyn_cast<const ClosureExpr>(ACE)) {
2241
- // These fix-its have to be diagnosed on the closure that requires,
2242
- // but is currently missing, self qualification. It's possible that
2243
- // ACE doesn't require self qualification (e.g. because it's
2244
- // non-escaping) but is nested inside a closure that does require self
2245
- // qualification. In that case we have to emit the fixit for the parent
2246
- // closure.
2247
- auto closureForDiagnostics =
2248
- closestParentClosureRequiringSelfQualification (CE);
2249
-
2250
- if (diagnoseAlmostMatchingCaptures (Diags, memberLoc,
2251
- closureForDiagnostics)) {
2304
+ if (auto *CE = dyn_cast<const ClosureExpr>(closureForDiagnostics)) {
2305
+ if (diagnoseAlmostMatchingCaptures (Diags, memberLoc, CE)) {
2252
2306
// Bail on the rest of the diagnostics. Offering the option to
2253
2307
// capture 'self' explicitly will result in an error, and using
2254
2308
// 'self.' explicitly will be accessing something other than the
2255
2309
// self param.
2256
2310
return ;
2257
2311
}
2258
- emitFixItsForExplicitClosure (Diags, memberLoc, closureForDiagnostics );
2312
+ emitFixItsForExplicitClosure (Diags, memberLoc, CE );
2259
2313
} else {
2260
2314
// If this wasn't an explicit closure, just offer the fix-it to
2261
2315
// reference self explicitly.
2262
2316
Diags.diagnose (memberLoc, diag::note_reference_self_explicitly)
2263
2317
.fixItInsert (memberLoc, " self." );
2264
2318
}
2265
2319
}
2266
-
2320
+
2267
2321
// / Diagnose any captures which might have been an attempt to capture
2268
2322
// / \c self strongly, but do not actually enable implicit \c self. Returns
2269
2323
// / whether there were any such captures to diagnose.
@@ -2313,24 +2367,6 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
2313
2367
}
2314
2368
}
2315
2369
2316
- static const ClosureExpr *closestParentClosureRequiringSelfQualification (
2317
- const ClosureExpr *closureExpr) {
2318
- auto &ctx = closureExpr->getASTContext ();
2319
- const ClosureExpr *closureForDiagnostic = closureExpr;
2320
-
2321
- // Find the closest parent closure that requires self qualification
2322
- while (!isClosureRequiringSelfQualification (closureExpr, ctx)) {
2323
- auto parent = parentClosure (closureForDiagnostic);
2324
- if (!parent) {
2325
- break ;
2326
- }
2327
-
2328
- closureForDiagnostic = parent;
2329
- }
2330
-
2331
- return closureForDiagnostic;
2332
- }
2333
-
2334
2370
// / Emit a fix-it for inserting \c self into in existing capture list, along
2335
2371
// / with a trailing comma if needed. The fix-it will be attached to the
2336
2372
// / provided diagnostic \c diag.
0 commit comments