Skip to content

Commit 5f43627

Browse files
committed
[Sema] Revise #15280 in response to feedback
Instead of passing the base expression of a member access to `getAccessSemanticsFromContext`, we now just pass a bool flag for whether this is a member access on the implicit 'self' declaration.
1 parent 8a78e15 commit 5f43627

File tree

4 files changed

+31
-25
lines changed

4 files changed

+31
-25
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2354,10 +2354,10 @@ class ValueDecl : public Decl {
23542354
///
23552355
/// \param DC The declaration context.
23562356
///
2357-
/// \param base If querying for a MemberRefExpr, this is its base expression.
2358-
/// Otherwise, \c nullptr.
2357+
/// \param isAccessOnSelf Whether this is a member access on the implicit
2358+
/// 'self' declaration of the declaration context.
23592359
AccessSemantics getAccessSemanticsFromContext(const DeclContext *DC,
2360-
Expr *base) const;
2360+
bool isAccessOnSelf) const;
23612361

23622362
/// Print a reference to the given declaration.
23632363
std::string printRef() const;

lib/AST/Decl.cpp

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,33 +1297,30 @@ static bool isPolymorphic(const AbstractStorageDecl *storage) {
12971297
/// MemberRefExpr use of this value in the specified context.
12981298
AccessSemantics
12991299
ValueDecl::getAccessSemanticsFromContext(const DeclContext *UseDC,
1300-
Expr *base) const {
1300+
bool isAccessOnSelf) const {
13011301
// If we're inside a @_transparent function, use the most conservative
13021302
// access pattern, since we may be inlined from a different resilience
13031303
// domain.
13041304
ResilienceExpansion expansion = UseDC->getResilienceExpansion();
13051305

13061306
if (auto *var = dyn_cast<AbstractStorageDecl>(this)) {
1307-
// Prevent variable mutations from within their own didSet/willSet
1308-
// specifiers from becoming infinite loops by accessing directly.
1309-
if (auto *UseFD = dyn_cast<AccessorDecl>(UseDC)) {
1310-
if (var->hasStorage() && var->hasAccessorFunctions() &&
1311-
UseFD->getStorage() == var) {
1312-
// A plain variable access from within its own observer is direct.
1313-
if (!base)
1307+
auto isMember = var->getDeclContext()->isTypeContext();
1308+
if (isAccessOnSelf)
1309+
assert(isMember && "Access on self, but var isn't a member");
1310+
1311+
// Within a variable's own didSet/willSet specifier, access its storage
1312+
// directly if it's either:
1313+
// 1) A 'plain variable' (i.e a variable that's not a member).
1314+
// 2) An access to the member on the implicit 'self' declaration. If it's a
1315+
// member access on some other base, we want to call the setter as we
1316+
// might be accessing the member on a *different* instance.
1317+
// This prevents assignments from becoming infinite loops in most cases.
1318+
if (!isMember || isAccessOnSelf)
1319+
if (auto *UseFD = dyn_cast<AccessorDecl>(UseDC))
1320+
if (var->hasStorage() && var->hasAccessorFunctions() &&
1321+
UseFD->getStorage() == var)
13141322
return AccessSemantics::DirectToStorage;
13151323

1316-
// A member access on the implicit 'self' declaration within its own
1317-
// observer is direct. If the base is some other expression, we want
1318-
// to call the setter, as we might be accessing the member on a
1319-
// *different* instance.
1320-
base = base->getValueProvidingExpr();
1321-
if (auto baseDRE = dyn_cast<DeclRefExpr>(base))
1322-
if (baseDRE->getDecl() == UseFD->getImplicitSelfDecl())
1323-
return AccessSemantics::DirectToStorage;
1324-
}
1325-
}
1326-
13271324
// "StoredWithTrivialAccessors" are generally always accessed indirectly,
13281325
// but if we know that the trivial accessor will always produce the same
13291326
// thing as the getter/setter (i.e., it can't be overridden), then just do a

lib/Sema/CSApply.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,16 @@ getImplicitMemberReferenceAccessSemantics(Expr *base, VarDecl *member,
247247
}
248248
}
249249

250+
// Check whether this is a member access on 'self'.
251+
bool isAccessOnSelf = false;
252+
if (auto *baseDRE = dyn_cast<DeclRefExpr>(base->getValueProvidingExpr()))
253+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC))
254+
if (auto *selfDecl = AFD->getImplicitSelfDecl())
255+
if (baseDRE->getDecl() == selfDecl)
256+
isAccessOnSelf = true;
257+
250258
// If the value is always directly accessed from this context, do it.
251-
return member->getAccessSemanticsFromContext(DC, base);
259+
return member->getAccessSemanticsFromContext(DC, isAccessOnSelf);
252260
}
253261

254262
void ConstraintSystem::propagateLValueAccessKind(Expr *E, AccessKind accessKind,

lib/Sema/TypeCheckExpr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,8 @@ bool TypeChecker::requireArrayLiteralIntrinsics(SourceLoc loc) {
516516
Expr *TypeChecker::buildCheckedRefExpr(VarDecl *value, DeclContext *UseDC,
517517
DeclNameLoc loc, bool Implicit) {
518518
auto type = getUnopenedTypeOfReference(value, Type(), UseDC);
519-
auto semantics = value->getAccessSemanticsFromContext(UseDC, /*base*/nullptr);
519+
auto semantics = value->getAccessSemanticsFromContext(UseDC,
520+
/*isAccessOnSelf*/false);
520521
return new (Context) DeclRefExpr(value, loc, Implicit, semantics, type);
521522
}
522523

@@ -527,7 +528,7 @@ Expr *TypeChecker::buildRefExpr(ArrayRef<ValueDecl *> Decls,
527528

528529
if (Decls.size() == 1 && !isa<ProtocolDecl>(Decls[0]->getDeclContext())) {
529530
auto semantics = Decls[0]->getAccessSemanticsFromContext(UseDC,
530-
/*base*/nullptr);
531+
/*isAccessOnSelf*/false);
531532
return new (Context) DeclRefExpr(Decls[0], NameLoc, Implicit, semantics);
532533
}
533534

0 commit comments

Comments
 (0)