Skip to content

Sema: Merge shouldAccessStorageDirectly() into isDirectToStorageAccess() #31212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 41 additions & 23 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1972,45 +1972,63 @@ static bool isPolymorphic(const AbstractStorageDecl *storage) {
return false;
}

static bool isDirectToStorageAccess(const AccessorDecl *accessor,
static bool isDirectToStorageAccess(const DeclContext *UseDC,
const VarDecl *var, bool isAccessOnSelf) {
// All accesses have ordinary semantics except those to variables
// with storage from within their own accessors.
if (accessor->getStorage() != var)
if (!var->hasStorage())
return false;

if (!var->hasStorage())
auto *AFD = dyn_cast<AbstractFunctionDecl>(UseDC);
if (AFD == nullptr)
return false;

// In Swift 5 and later, the access must also be a member access on 'self'.
if (!isAccessOnSelf &&
var->getDeclContext()->isTypeContext() &&
var->getASTContext().isSwiftVersionAtLeast(5))
// The property reference is for immediate class, not a derived class.
if (AFD->getParent()->getSelfNominalTypeDecl() !=
var->getDeclContext()->getSelfNominalTypeDecl())
return false;

// As a special case, 'read' and 'modify' coroutines with forced static
// dispatch must use ordinary semantics, so that the 'modify' coroutine for a
// 'dynamic' property uses Objective-C message sends and not direct access to
// storage.
if (accessor->hasForcedStaticDispatch())
// If the storage is resilient, we cannot access it directly at all.
if (var->isResilient(UseDC->getParentModule(),
UseDC->getResilienceExpansion()))
return false;

return true;
if (isa<ConstructorDecl>(AFD) || isa<DestructorDecl>(AFD)) {
// The access must also be a member access on 'self' in all language modes.
if (!isAccessOnSelf)
return false;

return true;
} else if (auto *accessor = dyn_cast<AccessorDecl>(AFD)) {
// The accessor must be for the variable itself.
if (accessor->getStorage() != var)
return false;

// In Swift 5 and later, the access must also be a member access on 'self'.
if (!isAccessOnSelf &&
var->getDeclContext()->isTypeContext() &&
var->getASTContext().isSwiftVersionAtLeast(5))
return false;

// As a special case, 'read' and 'modify' coroutines with forced static
// dispatch must use ordinary semantics, so that the 'modify' coroutine for a
// 'dynamic' property uses Objective-C message sends and not direct access to
// storage.
if (accessor->hasForcedStaticDispatch())
return false;

return true;
}

return false;
}

/// Determines the access semantics to use in a DeclRefExpr or
/// MemberRefExpr use of this value in the specified context.
AccessSemantics
ValueDecl::getAccessSemanticsFromContext(const DeclContext *UseDC,
bool isAccessOnSelf) const {
// The condition most likely to fast-path us is not being in an accessor,
// so we check that first.
if (auto *accessor = dyn_cast<AccessorDecl>(UseDC)) {
if (auto *var = dyn_cast<VarDecl>(this)) {
if (isDirectToStorageAccess(accessor, var, isAccessOnSelf))
return AccessSemantics::DirectToStorage;
}
}
if (auto *var = dyn_cast<VarDecl>(this))
if (isDirectToStorageAccess(UseDC, var, isAccessOnSelf))
return AccessSemantics::DirectToStorage;

// Otherwise, it's a semantically normal access. The client should be
// able to figure out the most efficient way to do this access.
Expand Down
52 changes: 0 additions & 52 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,49 +110,6 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
return ConcreteDeclRef(decl, computeSubstitutions(sig, locator));
}

static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
DeclContext *DC) {
// This only matters for stored properties.
if (!member->hasStorage())
return false;

// ... referenced from constructors and destructors.
auto *AFD = dyn_cast<AbstractFunctionDecl>(DC);
if (AFD == nullptr)
return false;

if (!isa<ConstructorDecl>(AFD) && !isa<DestructorDecl>(AFD))
return false;

// ... via a "self.property" reference.
auto *DRE = dyn_cast<DeclRefExpr>(base);
if (DRE == nullptr)
return false;

if (AFD->getImplicitSelfDecl() != cast<DeclRefExpr>(base)->getDecl())
return false;

// Convenience initializers do not require special handling.
// FIXME: This is a language change -- for now, keep the old behavior
#if 0
if (auto *CD = dyn_cast<ConstructorDecl>(AFD))
if (!CD->isDesignatedInit())
return false;
#endif

// Ctor or dtor are for immediate class, not a derived class.
if (!AFD->getParent()->getDeclaredInterfaceType()->isEqual(
member->getDeclContext()->getDeclaredInterfaceType()))
return false;

// If the storage is resilient, we cannot access it directly at all.
if (member->isResilient(DC->getParentModule(),
DC->getResilienceExpansion()))
return false;

return true;
}

ConstraintLocator *Solution::getCalleeLocator(ConstraintLocator *locator,
bool lookThroughApply) const {
auto &cs = getConstraintSystem();
Expand Down Expand Up @@ -184,15 +141,6 @@ Solution::getConstraintLocator(ConstraintLocator *base,
static AccessSemantics
getImplicitMemberReferenceAccessSemantics(Expr *base, VarDecl *member,
DeclContext *DC) {
// Properties that have storage and accessors are frequently accessed through
// accessors. However, in the init and destructor methods for the type
// immediately containing the property, accesses are done direct.
if (shouldAccessStorageDirectly(base, member, DC)) {
// Access this directly instead of going through (e.g.) observing or
// trivial accessors.
return AccessSemantics::DirectToStorage;
}

// Check whether this is a member access on 'self'.
bool isAccessOnSelf = false;
if (auto *baseDRE = dyn_cast<DeclRefExpr>(base->getValueProvidingExpr()))
Expand Down