Skip to content

Commit 3b35891

Browse files
committed
Improve diagnostics for weak captures and captures under different names
1 parent 18b31c7 commit 3b35891

File tree

7 files changed

+44
-339
lines changed

7 files changed

+44
-339
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3033,6 +3033,11 @@ NOTE(note_capture_self_explicitly,none,
30333033
"capture 'self' explicitly to enable implicit 'self' in this closure", ())
30343034
NOTE(note_reference_self_explicitly,none,
30353035
"reference 'self.' explicitly", ())
3036+
NOTE(note_other_self_capture,none,
3037+
"variable other than 'self' captured here under the name 'self' does not "
3038+
"enable implicit 'self'", ())
3039+
NOTE(note_self_captured_weakly,none,
3040+
"weak capture of 'self' here does not enable implicit 'self'", ())
30363041
ERROR(implicit_use_of_self_in_closure,none,
30373042
"implicit use of 'self' in closure; use 'self.' to make"
30383043
" capture semantics explicit", ())

include/swift/AST/Expr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3688,6 +3688,7 @@ class ClosureExpr : public AbstractClosureExpr {
36883688
/// Is this a completely empty closure?
36893689
bool hasEmptyBody() const;
36903690

3691+
/// VarDecl captured by this closure under the literal name \c self , if any.
36913692
VarDecl *getCapturedSelfDecl() const { return CapturedSelfDecl; }
36923693

36933694
static bool classof(const Expr *E) {
@@ -3794,7 +3795,7 @@ class CaptureListExpr final : public Expr,
37943795
const ClosureExpr *getClosureBody() const { return closureBody; }
37953796

37963797
void setClosureBody(ClosureExpr *body) { closureBody = body; }
3797-
3798+
37983799
/// This is a bit weird, but the capture list is lexically contained within
37993800
/// the closure, so the ClosureExpr has the full source range.
38003801
SWIFT_FORWARD_SOURCE_LOCS_TO(closureBody)

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,7 @@ VarDecl *PatternBindingDecl::getSingleInitializerVar() const {
15321532
return dyn_cast<VarDecl>(dyn_cast<DeclRefExpr>(getInit(0))->getDecl());
15331533
return nullptr;
15341534
}
1535-
1535+
15361536
bool VarDecl::isInitExposedToClients() const {
15371537
auto parent = dyn_cast<NominalTypeDecl>(getDeclContext());
15381538
if (!parent) return false;

lib/AST/Expr.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,10 +1233,8 @@ bool CaptureListEntry::isSimpleSelfCapture() const {
12331233
return false;
12341234
if (auto *DRE = dyn_cast<DeclRefExpr>(Init->getInit(0)))
12351235
if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
1236-
auto *ownership = Var->getAttrs().getAttribute<ReferenceOwnershipAttr>();
12371236
return (VD->isSelfParameter() || VD->isSelfParamCapture())
1238-
&& VD->getName() == Var->getName()
1239-
&& (!ownership || ownership->get() != ReferenceOwnership::Weak);
1237+
&& VD->getName() == Var->getName();
12401238
}
12411239
return false;
12421240
}

lib/AST/UnqualifiedLookup.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -700,8 +700,7 @@ void UnqualifiedLookupFactory::lookupNamesIntroducedByMemberFunction(
700700
// for lookup.
701701
DeclContext *const BaseDC =
702702
isOutsideBodyOfFunction(AFD) ? fnDeclContext
703-
: capturedSelfContext == nullptr ? AFD
704-
: capturedSelfContext;
703+
: capturedSelfContext ?: AFD;
705704
// If we are inside of a method, check to see if there are any ivars in
706705
// scope, and if so, whether this is a reference to one of them.
707706
// FIXME: We should persist this information between lookups.
@@ -733,8 +732,12 @@ void UnqualifiedLookupFactory::lookupNamesIntroducedByClosure(
733732
AbstractClosureExpr *ACE, Optional<bool> isCascadingUse) {
734733
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
735734
lookForLocalVariablesIn(CE);
736-
if (capturedSelfContext == nullptr && CE->getCapturedSelfDecl())
737-
capturedSelfContext = CE;
735+
// If we don't already have a captured self context, and this closure
736+
// captures the self param, remember that.
737+
if (capturedSelfContext == nullptr)
738+
if (auto *VD = CE->getCapturedSelfDecl())
739+
if (VD->isSelfParamCapture() && !VD->getType()->is<WeakStorageType>())
740+
capturedSelfContext = CE;
738741
}
739742
ifNotDoneYet([&] {
740743
// clang-format off

lib/Sema/MiscDiagnostics.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,7 @@ static void diagnoseImplicitSelfUseInClosure(TypeChecker &TC, const Expr *E,
13861386
diag::property_use_in_closure_without_explicit_self,
13871387
MRE->getMember().getDecl()->getBaseName().getIdentifier());
13881388
}
1389-
1389+
13901390
// Handle method calls with a specific diagnostic + fixit.
13911391
if (auto *DSCE = dyn_cast<DotSyntaxCallExpr>(E))
13921392
if (isImplicitSelfParamUse(DSCE->getBase()) &&
@@ -1403,10 +1403,22 @@ static void diagnoseImplicitSelfUseInClosure(TypeChecker &TC, const Expr *E,
14031403
if (memberLoc.isValid()) {
14041404
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
14051405
// If we've already captured something with the name "self" other than
1406-
// the actual self param, don't bother with any fix-its.
1407-
auto *VD = CE->getCapturedSelfDecl();
1408-
if (VD && !VD->isSelfParamCapture())
1406+
// the actual self param, offer special diagnostics.
1407+
if (auto *VD = CE->getCapturedSelfDecl()) {
1408+
// Either this is a weak capture of self...
1409+
if (VD->getType()->is<WeakStorageType>()) {
1410+
TC.diagnose(VD->getLoc(), diag::note_self_captured_weakly);
1411+
// ...or something completely different.
1412+
} else {
1413+
TC.diagnose(VD->getLoc(), diag::note_other_self_capture);
1414+
}
1415+
// Bail on the rest of the diagnostics. Offering the option to
1416+
// capture 'self' explicitly will result in an error, and using
1417+
// 'self.' explicitly will be accessing something other than the
1418+
// self param.
1419+
// FIXME: We could offer a special fixit in the [weak self] case to insert 'self?.'...
14091420
return { false, E };
1421+
}
14101422

14111423
auto diag = TC.diagnose(CE->getLoc(),
14121424
diag::note_capture_self_explicitly);

0 commit comments

Comments
 (0)