Skip to content

Commit df1732b

Browse files
committed
Update method names and comments following PR feedback
1 parent 22e4313 commit df1732b

File tree

1 file changed

+62
-20
lines changed

1 file changed

+62
-20
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,11 +1538,13 @@ static bool closureHasWeakSelfCapture(const AbstractClosureExpr *ACE) {
15381538
return false;
15391539
}
15401540

1541-
/// Whether or not implicit self DREs in this closure are incorrect,
1542-
/// and need to be looked-up manually. This applies to weak self
1543-
/// closures in Swift 5 mode, where the AST is incorrect.
1541+
/// Whether or not impliciy self decls in this closure require manual
1542+
/// lookup in order to perform diagnostics with the semantics described
1543+
/// in SE-0365. This is necessary for closures that capture self weakly
1544+
/// in Swift 5 language modes, since implicit self decls in weak self
1545+
//// closures has different semantics in Swift 5 than in Swift 6.
15441546
static bool
1545-
closureHasIncorrectImplicitSelfDecls(const AbstractClosureExpr *ACE) {
1547+
closureRequiresManualLookupForImplicitSelf(const AbstractClosureExpr *ACE) {
15461548
if (ACE->getASTContext().LangOpts.isSwiftVersionAtLeast(6)) {
15471549
return false;
15481550
}
@@ -1561,15 +1563,16 @@ static bool isImplicitSelf(const Expr *E) {
15611563
return DRE->getDecl()->getName().isSimpleName(Ctx.Id_self);
15621564
}
15631565

1564-
// When inside a closure with incorrect implicit self decls
1566+
// When inside a closure that requires manual lookup for implicit self,
15651567
// (any closure with a weak self capture, in Swift 5 mode),
15661568
// we have to manually lookup what self refers to at the location
1567-
// of a given DRE instead of using the decl in the AST (which is incorrect).
1568-
static ValueDecl *valueDeclForDRE(const DeclRefExpr *DRE,
1569-
const AbstractClosureExpr *ACE) {
1569+
// according to the semantics of Swift 6 in order to avoid confusing
1570+
// 'variable self is unused' warnings in Swift 5 mode.
1571+
static ValueDecl *lookupSelfDeclIfNecessary(const DeclRefExpr *DRE,
1572+
const AbstractClosureExpr *ACE) {
15701573
ASTContext &Ctx = DRE->getDecl()->getASTContext();
15711574

1572-
if (closureHasIncorrectImplicitSelfDecls(ACE) && isImplicitSelf(DRE)) {
1575+
if (closureRequiresManualLookupForImplicitSelf(ACE) && isImplicitSelf(DRE)) {
15731576
auto lookupResult = ASTScope::lookupSingleLocalDecl(
15741577
ACE->getParentSourceFile(), DeclName(Ctx.Id_self), DRE->getLoc());
15751578

@@ -1680,7 +1683,24 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
16801683
static bool
16811684
implicitWeakSelfReferenceIsValid(const DeclRefExpr *DRE,
16821685
const AbstractClosureExpr *inClosure) {
1683-
auto selfDecl = valueDeclForDRE(DRE, inClosure);
1686+
// Implicit self DREs have different semantics in Swift 5 language modes
1687+
// than they have in Swift 6 mode. Take this example:
1688+
//
1689+
// doVoidStuff { [weak self] in
1690+
// guard let self else { return }
1691+
// method()
1692+
// }
1693+
//
1694+
// In Swift 6, the implicit self DRE refers to the self decl
1695+
// defined in the guard statement. In Swift 5 mode, the implicit
1696+
// self DRE instead refers to closure's self `ParamDecl`.
1697+
//
1698+
// In order to perform these diagnostics according to the semantics
1699+
// defined in SE-0365, we need to know the decl that the DRE refers
1700+
// to in Swift 6. In Swift 5 mode, that requires performing a manual
1701+
// lookup of what implicit self refers to at this location (according
1702+
// to the semantics of Swift 6).
1703+
auto selfDecl = lookupSelfDeclIfNecessary(DRE, inClosure);
16841704
ASTContext &Ctx = selfDecl->getASTContext();
16851705

16861706
// Check if the implicit self decl refers to a var in a conditional stmt
@@ -2706,20 +2726,42 @@ class VarDeclUsageChecker : public ASTWalker {
27062726
VarDecls[vd] |= Flag;
27072727
}
27082728

2709-
// When inside a closure with incorrect implicit self decls
2710-
// (any closure with a weak self capture, in Swift 5 mode),
2711-
// we have to manually lookup what self refers to at this location
2712-
// rather than using the decl in the AST. Otherwise the usage checker
2713-
// will emit incorrect "value 'self' was defined but never used" warnings.
2714-
ValueDecl *getDecl(DeclRefExpr *DRE) {
2729+
/// The `ValueDecl` to use when performing usage analysis of the given DRE.
2730+
/// When inside a closure that requires manual lookup for implcit self decls
2731+
/// (a closure that captures self weakly in Swift 5 language modes), we
2732+
/// look up the `ValueDecl` that implicit self refers to according to
2733+
/// Swift 6 semantics.
2734+
ValueDecl *getDeclForUsageAnalysis(DeclRefExpr *DRE) {
27152735
if (ClosureStack.size() == 0) {
27162736
return DRE->getDecl();
27172737
}
27182738

27192739
auto closure = ClosureStack[ClosureStack.size() - 1];
27202740
assert(closure);
27212741

2722-
return valueDeclForDRE(DRE, closure);
2742+
if (isImplicitSelf(DRE)) {
2743+
// Implicit self DREs have different semantics in Swift 5 language modes
2744+
// than they have in Swift 6 mode. Take this example:
2745+
//
2746+
// doVoidStuff { [weak self] in
2747+
// guard let self else { return }
2748+
// method()
2749+
// }
2750+
//
2751+
// In Swift 6, the implicit self DRE refers to the self decl
2752+
// defined in the guard statement. In Swift 5 mode, the implicit
2753+
// self DRE instead refers to closure's self `ParamDecl`.
2754+
//
2755+
// If we perform usage analysis using Swift 5 semantics, we'd
2756+
// get a confusing "value 'self' was defined but never used;
2757+
// consider replacing with boolean test" warning. To suppress this
2758+
// warning, we instead perform usage analysis using Swift 6 semantics
2759+
// (by performing a manual lookup of what implicit self refers to
2760+
// at this location according to Swift 6 semantics).
2761+
return lookupSelfDeclIfNecessary(DRE, closure);
2762+
} else {
2763+
return DRE->getDecl();
2764+
}
27232765
}
27242766

27252767
void markBaseOfStorageUse(Expr *E, ConcreteDeclRef decl, unsigned flags);
@@ -3633,7 +3675,7 @@ void VarDeclUsageChecker::markStoredOrInOutExpr(Expr *E, unsigned Flags) {
36333675

36343676
// If we found a decl that is being assigned to, then mark it.
36353677
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
3636-
addMark(getDecl(DRE), Flags);
3678+
addMark(getDeclForUsageAnalysis(DRE), Flags);
36373679
return;
36383680
}
36393681

@@ -3718,7 +3760,7 @@ ASTWalker::PreWalkResult<Expr *> VarDeclUsageChecker::walkToExprPre(Expr *E) {
37183760
// If this is a DeclRefExpr found in a random place, it is a load of the
37193761
// vardecl.
37203762
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
3721-
addMark(getDecl(DRE), RK_Read);
3763+
addMark(getDeclForUsageAnalysis(DRE), RK_Read);
37223764

37233765
// If the Expression is a read of a getter, track for diagnostics
37243766
if (auto VD = dyn_cast<VarDecl>(DRE->getDecl())) {
@@ -3809,7 +3851,7 @@ void VarDeclUsageChecker::handleIfConfig(IfConfigDecl *ICD) {
38093851
// conservatively mark it read and written. This will silence "variable
38103852
// unused" and "could be marked let" warnings for it.
38113853
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
3812-
VDUC.addMark(VDUC.getDecl(DRE), RK_Read | RK_Written);
3854+
VDUC.addMark(VDUC.getDeclForUsageAnalysis(DRE), RK_Read | RK_Written);
38133855
else if (auto *declRef = dyn_cast<UnresolvedDeclRefExpr>(E)) {
38143856
auto name = declRef->getName();
38153857
auto loc = declRef->getLoc();

0 commit comments

Comments
 (0)