@@ -1297,33 +1297,30 @@ static bool isPolymorphic(const AbstractStorageDecl *storage) {
1297
1297
// / MemberRefExpr use of this value in the specified context.
1298
1298
AccessSemantics
1299
1299
ValueDecl::getAccessSemanticsFromContext (const DeclContext *UseDC,
1300
- Expr *base ) const {
1300
+ bool isAccessOnSelf ) const {
1301
1301
// If we're inside a @_transparent function, use the most conservative
1302
1302
// access pattern, since we may be inlined from a different resilience
1303
1303
// domain.
1304
1304
ResilienceExpansion expansion = UseDC->getResilienceExpansion ();
1305
1305
1306
1306
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)
1314
1322
return AccessSemantics::DirectToStorage;
1315
1323
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
-
1327
1324
// "StoredWithTrivialAccessors" are generally always accessed indirectly,
1328
1325
// but if we know that the trivial accessor will always produce the same
1329
1326
// thing as the getter/setter (i.e., it can't be overridden), then just do a
0 commit comments