Skip to content

[CoroutineAccessors] Synthesize default requirement implementations. #77429

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 11 commits into from
Nov 10, 2024
Merged
7 changes: 3 additions & 4 deletions include/swift/AST/AnyFunctionRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,9 @@ class AnyFunctionRef {
->getReferenceStorageReferent();
if (mapIntoContext)
valueTy = AD->mapTypeIntoContext(valueTy);
YieldTypeFlags flags(
isYieldingDefaultMutatingAccessor(AD->getAccessorKind())
? ParamSpecifier::InOut
: ParamSpecifier::LegacyShared);
YieldTypeFlags flags(isYieldingMutableAccessor(AD->getAccessorKind())
? ParamSpecifier::InOut
: ParamSpecifier::LegacyShared);
buffer.push_back(AnyFunctionType::Yield(valueTy, flags));
return buffer;
}
Expand Down
14 changes: 9 additions & 5 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6046,8 +6046,8 @@ class AbstractStorageDecl : public ValueDecl {

/// Given that CoroutineAccessors is enabled, is _read/_modify required for
/// ABI stability?
bool
requiresCorrespondingUnderscoredCoroutineAccessor(AccessorKind kind) const;
bool requiresCorrespondingUnderscoredCoroutineAccessor(
AccessorKind kind, AccessorDecl const *decl = nullptr) const;

/// Does this storage have any explicit observers (willSet or didSet) attached
/// to it?
Expand Down Expand Up @@ -6104,9 +6104,9 @@ class AbstractStorageDecl : public ValueDecl {

/// Determine how this storage declaration should actually be accessed.
AccessStrategy getAccessStrategy(AccessSemantics semantics,
AccessKind accessKind,
ModuleDecl *module,
ResilienceExpansion expansion) const;
AccessKind accessKind, ModuleDecl *module,
ResilienceExpansion expansion,
bool useOldABI) const;

/// Do we need to use resilient access patterns outside of this
/// property's resilience domain?
Expand Down Expand Up @@ -8441,6 +8441,10 @@ class AccessorDecl final : public FuncDecl {
/// accessed by it.
ArrayRef<VarDecl *> getAccessedProperties() const;

/// Whether this accessor should have a body. Note that this will be true
/// even when it does not have one _yet_.
bool doesAccessorHaveBody() const;

static bool classof(const Decl *D) {
return D->getKind() == DeclKind::Accessor;
}
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/StorageImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ inline bool isYieldingAccessor(AccessorKind kind) {
}
}

inline bool isYieldingDefaultNonmutatingAccessor(AccessorKind kind) {
inline bool isYieldingImmutableAccessor(AccessorKind kind) {
switch (kind) {
case AccessorKind::Read:
case AccessorKind::Read2:
Expand All @@ -114,7 +114,7 @@ inline bool isYieldingDefaultNonmutatingAccessor(AccessorKind kind) {
}
}

inline bool isYieldingDefaultMutatingAccessor(AccessorKind kind) {
inline bool isYieldingMutableAccessor(AccessorKind kind) {
switch (kind) {
case AccessorKind::Modify:
case AccessorKind::Modify2:
Expand Down
59 changes: 37 additions & 22 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2819,7 +2819,8 @@ getDirectWriteAccessStrategy(const AbstractStorageDecl *storage) {
}

static AccessStrategy
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch);
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch,
bool useOldABI);
static AccessStrategy
getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch);

Expand All @@ -2834,7 +2835,7 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
// If the storage isDynamic (and not @objc) use the accessors.
if (storage->shouldUseNativeDynamicDispatch())
return AccessStrategy::getMaterializeToTemporary(
getOpaqueReadAccessStrategy(storage, false),
getOpaqueReadAccessStrategy(storage, false, false),
getOpaqueWriteAccessStrategy(storage, false));
return AccessStrategy::getStorage();
}
Expand Down Expand Up @@ -2872,7 +2873,13 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
}

static AccessStrategy
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch) {
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch,
bool useOldABI) {
if (useOldABI) {
assert(storage->requiresOpaqueRead2Coroutine());
assert(storage->requiresOpaqueReadCoroutine());
return AccessStrategy::getAccessor(AccessorKind::Read, dispatch);
}
if (storage->requiresOpaqueRead2Coroutine())
return AccessStrategy::getAccessor(AccessorKind::Read2, dispatch);
if (storage->requiresOpaqueReadCoroutine())
Expand All @@ -2889,35 +2896,39 @@ getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch)

static AccessStrategy
getOpaqueReadWriteAccessStrategy(const AbstractStorageDecl *storage,
bool dispatch) {
bool dispatch, bool useOldABI) {
if (useOldABI) {
assert(storage->requiresOpaqueModify2Coroutine());
assert(storage->requiresOpaqueModifyCoroutine());
return AccessStrategy::getAccessor(AccessorKind::Modify, dispatch);
}
if (storage->requiresOpaqueModify2Coroutine())
return AccessStrategy::getAccessor(AccessorKind::Modify2, dispatch);
if (storage->requiresOpaqueModifyCoroutine())
return AccessStrategy::getAccessor(AccessorKind::Modify, dispatch);
return AccessStrategy::getMaterializeToTemporary(
getOpaqueReadAccessStrategy(storage, dispatch),
getOpaqueWriteAccessStrategy(storage, dispatch));
getOpaqueReadAccessStrategy(storage, dispatch, false),
getOpaqueWriteAccessStrategy(storage, dispatch));
}

static AccessStrategy
getOpaqueAccessStrategy(const AbstractStorageDecl *storage,
AccessKind accessKind, bool dispatch) {
AccessKind accessKind, bool dispatch, bool useOldABI) {
switch (accessKind) {
case AccessKind::Read:
return getOpaqueReadAccessStrategy(storage, dispatch);
return getOpaqueReadAccessStrategy(storage, dispatch, useOldABI);
case AccessKind::Write:
assert(!useOldABI);
return getOpaqueWriteAccessStrategy(storage, dispatch);
case AccessKind::ReadWrite:
return getOpaqueReadWriteAccessStrategy(storage, dispatch);
return getOpaqueReadWriteAccessStrategy(storage, dispatch, useOldABI);
}
llvm_unreachable("bad access kind");
}

AccessStrategy
AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
AccessKind accessKind,
ModuleDecl *module,
ResilienceExpansion expansion) const {
AccessStrategy AbstractStorageDecl::getAccessStrategy(
AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module,
ResilienceExpansion expansion, bool useOldABI) const {
switch (semantics) {
case AccessSemantics::DirectToStorage:
assert(hasStorage() || getASTContext().Diags.hadAnyError());
Expand All @@ -2933,10 +2944,12 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
// If the property is defined in a non-final class or a protocol, the
// accessors are dynamically dispatched, and we cannot do direct access.
if (isPolymorphic(this))
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ true);
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ true,
useOldABI);

if (shouldUseNativeDynamicDispatch())
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false);
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false,
useOldABI);

// If the storage is resilient from the given module and resilience
// expansion, we cannot use direct access.
Expand All @@ -2958,7 +2971,8 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
resilient = isResilient();

if (resilient)
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false);
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false,
useOldABI);
}

LLVM_FALLTHROUGH;
Expand Down Expand Up @@ -3050,10 +3064,8 @@ bool AbstractStorageDecl::requiresOpaqueModify2Coroutine() const {
false);
}

AccessorDecl *AbstractStorageDecl::getSynthesizedAccessor(AccessorKind kind) const {
if (auto *accessor = getAccessor(kind))
return accessor;

AccessorDecl *
AbstractStorageDecl::getSynthesizedAccessor(AccessorKind kind) const {
ASTContext &ctx = getASTContext();
return evaluateOrDefault(ctx.evaluator,
SynthesizeAccessorRequest{const_cast<AbstractStorageDecl *>(this), kind},
Expand Down Expand Up @@ -7112,7 +7124,10 @@ void AbstractStorageDecl::setComputedSetter(AccessorDecl *setter) {
void
AbstractStorageDecl::setSynthesizedAccessor(AccessorKind kind,
AccessorDecl *accessor) {
assert(!getAccessor(kind) && "accessor already exists");
if (auto *current = getAccessor(kind)) {
assert(current == accessor && "different accessor of this kind exists");
return;
}
assert(accessor->getAccessorKind() == kind);

auto accessors = Accessors.getPointer();
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/LifetimeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ static ValueOwnership getLoweredOwnership(AbstractFunctionDecl *afd) {
}
if (auto *ad = dyn_cast<AccessorDecl>(afd)) {
if (ad->getAccessorKind() == AccessorKind::Set ||
isYieldingDefaultMutatingAccessor(ad->getAccessorKind())) {
isYieldingMutableAccessor(ad->getAccessorKind())) {
return ValueOwnership::InOut;
}
}
Expand Down
10 changes: 7 additions & 3 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,9 +883,13 @@ SynthesizeAccessorRequest::getCachedResult() const {
auto *storage = std::get<0>(getStorage());
auto kind = std::get<1>(getStorage());
auto *accessor = storage->getAccessor(kind);
if (accessor)
return accessor;
return std::nullopt;
if (!accessor)
return std::nullopt;

if (accessor->doesAccessorHaveBody() && !accessor->hasBody())
return std::nullopt;

return accessor;
}

void SynthesizeAccessorRequest::cacheResult(AccessorDecl *accessor) const {
Expand Down
4 changes: 2 additions & 2 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2202,15 +2202,15 @@ static void destructureYieldsForCoroutine(TypeConverter &TC,
return;

// 'modify' yields an inout of the target type.
if (isYieldingDefaultMutatingAccessor(accessor->getAccessorKind())) {
if (isYieldingMutableAccessor(accessor->getAccessorKind())) {
auto loweredValueTy =
TC.getLoweredType(origType, canValueType, expansion);
yields.push_back(SILYieldInfo(loweredValueTy.getASTType(),
ParameterConvention::Indirect_Inout));
} else {
// 'read' yields a borrowed value of the target type, destructuring
// tuples as necessary.
assert(isYieldingDefaultNonmutatingAccessor(accessor->getAccessorKind()));
assert(isYieldingImmutableAccessor(accessor->getAccessorKind()));
destructureYieldsForReadAccessor(TC, expansion, origType, canValueType,
yields);
}
Expand Down
11 changes: 5 additions & 6 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1928,12 +1928,11 @@ SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
if (decl->isResilient(M.getSwiftModule(), expansion))
return false;

auto strategy = decl->getAccessStrategy(AccessSemantics::Ordinary,
decl->supportsMutation()
? AccessKind::ReadWrite
: AccessKind::Read,
M.getSwiftModule(),
expansion);
auto strategy = decl->getAccessStrategy(
AccessSemantics::Ordinary,
decl->supportsMutation() ? AccessKind::ReadWrite : AccessKind::Read,
M.getSwiftModule(), expansion,
/*useOldABI=*/false);
switch (strategy.getKind()) {
case AccessStrategy::Storage: {
// Keypaths rely on accessors to handle the special behavior of weak,
Expand Down
15 changes: 7 additions & 8 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3649,8 +3649,8 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM,

auto semantics = AccessSemantics::Ordinary;
auto strategy = property->getAccessStrategy(semantics, AccessKind::Write,
SGM.M.getSwiftModule(),
expansion);
SGM.M.getSwiftModule(), expansion,
/*useOldABI=*/false);

LValueOptions lvOptions;
lv.addMemberComponent(subSGF, loc, property, subs, lvOptions,
Expand Down Expand Up @@ -4211,12 +4211,11 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
return true;
};

auto strategy = storage->getAccessStrategy(AccessSemantics::Ordinary,
storage->supportsMutation()
? AccessKind::ReadWrite
: AccessKind::Read,
M.getSwiftModule(),
expansion);
auto strategy = storage->getAccessStrategy(
AccessSemantics::Ordinary,
storage->supportsMutation() ? AccessKind::ReadWrite : AccessKind::Read,
M.getSwiftModule(), expansion,
/*useOldABI=*/false);

AbstractStorageDecl *externalDecl = nullptr;
SubstitutionMap externalSubs;
Expand Down
Loading