Skip to content

Commit da71271

Browse files
committed
[CoroutineAccessors] Synthesize default req impls.
When a protocol which has a read (or modify) requirement is built with the CoroutineAccessors feature, it gains a read2 (or modify2, respectively) requirement. For this to be compatible with binaries built without the feature, a default implementation for these new requirements must be provided. Cause these new accessor requirements to have default implementations by returning `true` from `doesAccessorHaveBody` when the context is a `ProtocolDecl` and the relevant availability check passes.
1 parent 8995602 commit da71271

15 files changed

+518
-111
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6046,8 +6046,8 @@ class AbstractStorageDecl : public ValueDecl {
60466046

60476047
/// Given that CoroutineAccessors is enabled, is _read/_modify required for
60486048
/// ABI stability?
6049-
bool
6050-
requiresCorrespondingUnderscoredCoroutineAccessor(AccessorKind kind) const;
6049+
bool requiresCorrespondingUnderscoredCoroutineAccessor(
6050+
AccessorKind kind, AccessorDecl const *decl = nullptr) const;
60516051

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

61056105
/// Determine how this storage declaration should actually be accessed.
61066106
AccessStrategy getAccessStrategy(AccessSemantics semantics,
6107-
AccessKind accessKind,
6108-
ModuleDecl *module,
6109-
ResilienceExpansion expansion) const;
6107+
AccessKind accessKind, ModuleDecl *module,
6108+
ResilienceExpansion expansion,
6109+
bool useOldABI) const;
61106110

61116111
/// Do we need to use resilient access patterns outside of this
61126112
/// property's resilience domain?

lib/AST/Decl.cpp

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2819,7 +2819,8 @@ getDirectWriteAccessStrategy(const AbstractStorageDecl *storage) {
28192819
}
28202820

28212821
static AccessStrategy
2822-
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch);
2822+
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch,
2823+
bool useOldABI);
28232824
static AccessStrategy
28242825
getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch);
28252826

@@ -2834,7 +2835,7 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
28342835
// If the storage isDynamic (and not @objc) use the accessors.
28352836
if (storage->shouldUseNativeDynamicDispatch())
28362837
return AccessStrategy::getMaterializeToTemporary(
2837-
getOpaqueReadAccessStrategy(storage, false),
2838+
getOpaqueReadAccessStrategy(storage, false, false),
28382839
getOpaqueWriteAccessStrategy(storage, false));
28392840
return AccessStrategy::getStorage();
28402841
}
@@ -2872,7 +2873,13 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
28722873
}
28732874

28742875
static AccessStrategy
2875-
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch) {
2876+
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch,
2877+
bool useOldABI) {
2878+
if (useOldABI) {
2879+
assert(storage->requiresOpaqueRead2Coroutine());
2880+
assert(storage->requiresOpaqueReadCoroutine());
2881+
return AccessStrategy::getAccessor(AccessorKind::Read, dispatch);
2882+
}
28762883
if (storage->requiresOpaqueRead2Coroutine())
28772884
return AccessStrategy::getAccessor(AccessorKind::Read2, dispatch);
28782885
if (storage->requiresOpaqueReadCoroutine())
@@ -2889,35 +2896,39 @@ getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch)
28892896

28902897
static AccessStrategy
28912898
getOpaqueReadWriteAccessStrategy(const AbstractStorageDecl *storage,
2892-
bool dispatch) {
2899+
bool dispatch, bool useOldABI) {
2900+
if (useOldABI) {
2901+
assert(storage->requiresOpaqueModify2Coroutine());
2902+
assert(storage->requiresOpaqueModifyCoroutine());
2903+
return AccessStrategy::getAccessor(AccessorKind::Modify, dispatch);
2904+
}
28932905
if (storage->requiresOpaqueModify2Coroutine())
28942906
return AccessStrategy::getAccessor(AccessorKind::Modify2, dispatch);
28952907
if (storage->requiresOpaqueModifyCoroutine())
28962908
return AccessStrategy::getAccessor(AccessorKind::Modify, dispatch);
28972909
return AccessStrategy::getMaterializeToTemporary(
2898-
getOpaqueReadAccessStrategy(storage, dispatch),
2899-
getOpaqueWriteAccessStrategy(storage, dispatch));
2910+
getOpaqueReadAccessStrategy(storage, dispatch, false),
2911+
getOpaqueWriteAccessStrategy(storage, dispatch));
29002912
}
29012913

29022914
static AccessStrategy
29032915
getOpaqueAccessStrategy(const AbstractStorageDecl *storage,
2904-
AccessKind accessKind, bool dispatch) {
2916+
AccessKind accessKind, bool dispatch, bool useOldABI) {
29052917
switch (accessKind) {
29062918
case AccessKind::Read:
2907-
return getOpaqueReadAccessStrategy(storage, dispatch);
2919+
return getOpaqueReadAccessStrategy(storage, dispatch, useOldABI);
29082920
case AccessKind::Write:
2921+
assert(!useOldABI);
29092922
return getOpaqueWriteAccessStrategy(storage, dispatch);
29102923
case AccessKind::ReadWrite:
2911-
return getOpaqueReadWriteAccessStrategy(storage, dispatch);
2924+
return getOpaqueReadWriteAccessStrategy(storage, dispatch, useOldABI);
29122925
}
29132926
llvm_unreachable("bad access kind");
29142927
}
29152928

2916-
AccessStrategy
2917-
AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
2918-
AccessKind accessKind,
2919-
ModuleDecl *module,
2920-
ResilienceExpansion expansion) const {
2929+
AccessStrategy AbstractStorageDecl::getAccessStrategy(
2930+
AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module,
2931+
ResilienceExpansion expansion, bool useOldABI) const {
29212932
switch (semantics) {
29222933
case AccessSemantics::DirectToStorage:
29232934
assert(hasStorage() || getASTContext().Diags.hadAnyError());
@@ -2933,10 +2944,12 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
29332944
// If the property is defined in a non-final class or a protocol, the
29342945
// accessors are dynamically dispatched, and we cannot do direct access.
29352946
if (isPolymorphic(this))
2936-
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ true);
2947+
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ true,
2948+
useOldABI);
29372949

29382950
if (shouldUseNativeDynamicDispatch())
2939-
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false);
2951+
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false,
2952+
useOldABI);
29402953

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

29602973
if (resilient)
2961-
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false);
2974+
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false,
2975+
useOldABI);
29622976
}
29632977

29642978
LLVM_FALLTHROUGH;

lib/AST/TypeCheckRequests.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -883,9 +883,13 @@ SynthesizeAccessorRequest::getCachedResult() const {
883883
auto *storage = std::get<0>(getStorage());
884884
auto kind = std::get<1>(getStorage());
885885
auto *accessor = storage->getAccessor(kind);
886-
if (accessor)
887-
return accessor;
888-
return std::nullopt;
886+
if (!accessor)
887+
return std::nullopt;
888+
889+
if (accessor->doesAccessorHaveBody() && !accessor->hasBody())
890+
return std::nullopt;
891+
892+
return accessor;
889893
}
890894

891895
void SynthesizeAccessorRequest::cacheResult(AccessorDecl *accessor) const {

lib/SILGen/SILGen.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,12 +1928,11 @@ SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
19281928
if (decl->isResilient(M.getSwiftModule(), expansion))
19291929
return false;
19301930

1931-
auto strategy = decl->getAccessStrategy(AccessSemantics::Ordinary,
1932-
decl->supportsMutation()
1933-
? AccessKind::ReadWrite
1934-
: AccessKind::Read,
1935-
M.getSwiftModule(),
1936-
expansion);
1931+
auto strategy = decl->getAccessStrategy(
1932+
AccessSemantics::Ordinary,
1933+
decl->supportsMutation() ? AccessKind::ReadWrite : AccessKind::Read,
1934+
M.getSwiftModule(), expansion,
1935+
/*useOldABI=*/false);
19371936
switch (strategy.getKind()) {
19381937
case AccessStrategy::Storage: {
19391938
// Keypaths rely on accessors to handle the special behavior of weak,

lib/SILGen/SILGenExpr.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3649,8 +3649,8 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM,
36493649

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

36553655
LValueOptions lvOptions;
36563656
lv.addMemberComponent(subSGF, loc, property, subs, lvOptions,
@@ -4211,12 +4211,11 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
42114211
return true;
42124212
};
42134213

4214-
auto strategy = storage->getAccessStrategy(AccessSemantics::Ordinary,
4215-
storage->supportsMutation()
4216-
? AccessKind::ReadWrite
4217-
: AccessKind::Read,
4218-
M.getSwiftModule(),
4219-
expansion);
4214+
auto strategy = storage->getAccessStrategy(
4215+
AccessSemantics::Ordinary,
4216+
storage->supportsMutation() ? AccessKind::ReadWrite : AccessKind::Read,
4217+
M.getSwiftModule(), expansion,
4218+
/*useOldABI=*/false);
42204219

42214220
AbstractStorageDecl *externalDecl = nullptr;
42224221
SubstitutionMap externalSubs;

lib/SILGen/SILGenLValue.cpp

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3070,7 +3070,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenBorrowedBaseVisitor
30703070
auto accessSemantics = e->getAccessSemantics();
30713071
AccessStrategy strategy = var->getAccessStrategy(
30723072
accessSemantics, getFormalAccessKind(accessKind),
3073-
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion());
3073+
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
3074+
/*useOldABI=*/false);
30743075

30753076
auto baseFormalType = getBaseFormalType(e->getBase());
30763077
LValue lv = visit(
@@ -3292,9 +3293,9 @@ static LValue emitLValueForNonMemberVarDecl(
32923293
subs = SGF.F.getForwardingSubstitutionMap();
32933294

32943295
auto access = getFormalAccessKind(accessKind);
3295-
auto strategy =
3296-
var->getAccessStrategy(semantics, access, SGF.SGM.M.getSwiftModule(),
3297-
SGF.F.getResilienceExpansion());
3296+
auto strategy = var->getAccessStrategy(
3297+
semantics, access, SGF.SGM.M.getSwiftModule(),
3298+
SGF.F.getResilienceExpansion(), /*useOldABI=*/false);
32983299

32993300
lv.addNonMemberVarComponent(SGF, loc, var, subs, options, accessKind,
33003301
strategy, formalRValueType, actorIso);
@@ -3887,6 +3888,25 @@ static bool isCurrentFunctionAccessor(SILGenFunction &SGF,
38873888
contextAccessorDecl->getAccessorKind() == accessorKind;
38883889
}
38893890

3891+
static bool isSynthesizedDefaultImplementionatThunk(SILGenFunction &SGF) {
3892+
if (!SGF.FunctionDC)
3893+
return false;
3894+
3895+
auto *decl = SGF.FunctionDC->getAsDecl();
3896+
if (!decl)
3897+
return false;
3898+
3899+
auto *dc = decl->getDeclContext();
3900+
if (!dc)
3901+
return false;
3902+
3903+
auto *proto = dyn_cast<ProtocolDecl>(dc);
3904+
if (!proto)
3905+
return false;
3906+
3907+
return true;
3908+
}
3909+
38903910
LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
38913911
SGFAccessKind accessKind,
38923912
LValueOptions options) {
@@ -3908,11 +3928,10 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
39083928
}
39093929

39103930
auto accessSemantics = e->getAccessSemantics();
3911-
AccessStrategy strategy =
3912-
var->getAccessStrategy(accessSemantics,
3913-
getFormalAccessKind(accessKind),
3914-
SGF.SGM.M.getSwiftModule(),
3915-
SGF.F.getResilienceExpansion());
3931+
AccessStrategy strategy = var->getAccessStrategy(
3932+
accessSemantics, getFormalAccessKind(accessKind),
3933+
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
3934+
/*useOldABI=*/isSynthesizedDefaultImplementionatThunk(SGF));
39163935

39173936
bool isOnSelfParameter = isCallToSelfOfCurrentFunction(SGF, e);
39183937

@@ -3931,10 +3950,9 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
39313950
SGF, readAccessor.getAbstractFunctionDecl(), isObjC)) {
39323951
accessSemantics = AccessSemantics::DirectToImplementation;
39333952
strategy = var->getAccessStrategy(
3934-
accessSemantics,
3935-
getFormalAccessKind(accessKind),
3936-
SGF.SGM.M.getSwiftModule(),
3937-
SGF.F.getResilienceExpansion());
3953+
accessSemantics, getFormalAccessKind(accessKind),
3954+
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
3955+
/*useOldABI=*/false);
39383956
}
39393957
}
39403958

@@ -4119,11 +4137,10 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
41194137

41204138

41214139
auto accessSemantics = e->getAccessSemantics();
4122-
auto strategy =
4123-
decl->getAccessStrategy(accessSemantics,
4124-
getFormalAccessKind(accessKind),
4125-
SGF.SGM.M.getSwiftModule(),
4126-
SGF.F.getResilienceExpansion());
4140+
auto strategy = decl->getAccessStrategy(
4141+
accessSemantics, getFormalAccessKind(accessKind),
4142+
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
4143+
/*useOldABI=*/isSynthesizedDefaultImplementionatThunk(SGF));
41274144

41284145
bool isOnSelfParameter = isCallToSelfOfCurrentFunction(SGF, e);
41294146
bool isContextRead = isCurrentFunctionAccessor(SGF, AccessorKind::Read);
@@ -4141,10 +4158,9 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
41414158
SGF, readAccessor.getAbstractFunctionDecl(), isObjC)) {
41424159
accessSemantics = AccessSemantics::DirectToImplementation;
41434160
strategy = decl->getAccessStrategy(
4144-
accessSemantics,
4145-
getFormalAccessKind(accessKind),
4146-
SGF.SGM.M.getSwiftModule(),
4147-
SGF.F.getResilienceExpansion());
4161+
accessSemantics, getFormalAccessKind(accessKind),
4162+
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
4163+
/*useOldABI=*/false);
41484164
}
41494165
}
41504166

@@ -4597,11 +4613,9 @@ LValue SILGenFunction::emitPropertyLValue(SILLocation loc, ManagedValue base,
45974613
auto baseType = base.getType().getASTType();
45984614
auto subMap = baseType->getContextSubstitutionMap(ivar->getDeclContext());
45994615

4600-
AccessStrategy strategy =
4601-
ivar->getAccessStrategy(semantics,
4602-
getFormalAccessKind(accessKind),
4603-
SGM.M.getSwiftModule(),
4604-
F.getResilienceExpansion());
4616+
AccessStrategy strategy = ivar->getAccessStrategy(
4617+
semantics, getFormalAccessKind(accessKind), SGM.M.getSwiftModule(),
4618+
F.getResilienceExpansion(), /*useOldABI=*/false);
46054619

46064620
auto baseAccessKind =
46074621
getBaseAccessKind(SGM, ivar, accessKind, strategy, baseFormalType,
@@ -5316,10 +5330,9 @@ RValue SILGenFunction::emitRValueForStorageLoad(
53165330
SubstitutionMap substitutions,
53175331
AccessSemantics semantics, Type propTy, SGFContext C,
53185332
bool isBaseGuaranteed) {
5319-
AccessStrategy strategy =
5320-
storage->getAccessStrategy(semantics, AccessKind::Read,
5321-
SGM.M.getSwiftModule(),
5322-
F.getResilienceExpansion());
5333+
AccessStrategy strategy = storage->getAccessStrategy(
5334+
semantics, AccessKind::Read, SGM.M.getSwiftModule(),
5335+
F.getResilienceExpansion(), /*useOldABI=*/false);
53235336

53245337
// If we should call an accessor of some kind, do so.
53255338
if (strategy.getKind() != AccessStrategy::Storage) {

lib/SILGen/SILGenPattern.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3316,11 +3316,11 @@ static bool isBorrowableSubject(SILGenFunction &SGF,
33163316
}
33173317

33183318
// Check the access strategy used to read the storage.
3319-
auto strategy = storage->getAccessStrategy(access,
3320-
AccessKind::Read,
3321-
SGF.SGM.SwiftModule,
3322-
SGF.F.getResilienceExpansion());
3323-
3319+
auto strategy =
3320+
storage->getAccessStrategy(access, AccessKind::Read, SGF.SGM.SwiftModule,
3321+
SGF.F.getResilienceExpansion(),
3322+
/*useOldABI=*/false);
3323+
33243324
switch (strategy.getKind()) {
33253325
case AccessStrategy::Kind::Storage:
33263326
// Accessing storage directly benefits from borrowing.

lib/SILGen/SILGenType.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -835,12 +835,16 @@ SILFunction *SILGenModule::emitProtocolWitness(
835835
if (witnessRef.isAlwaysInline())
836836
InlineStrategy = AlwaysInline;
837837

838+
SILFunction *f = M.lookUpFunction(nameBuffer);
839+
if (f)
840+
return f;
841+
838842
SILGenFunctionBuilder builder(*this);
839-
auto *f = builder.createFunction(
843+
f = builder.createFunction(
840844
linkage, nameBuffer, witnessSILFnType, genericEnv,
841-
SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, serializedKind,
842-
IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, ProfileCounter(),
843-
IsThunk, SubclassScope::NotApplicable, InlineStrategy);
845+
SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent,
846+
serializedKind, IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible,
847+
ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineStrategy);
844848

845849
f->setDebugScope(new (M)
846850
SILDebugScope(RegularLocation(witnessRef.getDecl()), f));
@@ -1055,6 +1059,10 @@ class SILGenDefaultWitnessTable
10551059
SILDeclRef witnessRef,
10561060
IsFreeFunctionWitness_t isFree,
10571061
Witness witness) {
1062+
if (!cast<AbstractFunctionDecl>(witnessRef.getDecl())->hasBody()) {
1063+
addMissingDefault();
1064+
return;
1065+
}
10581066
SILFunction *witnessFn = SGM.emitProtocolWitness(
10591067
ProtocolConformanceRef(Proto), SILLinkage::Private, IsNotSerialized,
10601068
requirementRef, witnessRef, isFree, witness);

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4345,7 +4345,8 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
43454345
// direct-to-storage in order for the conversion to be non-ephemeral.
43464346
auto access = asd->getAccessStrategy(
43474347
AccessSemantics::Ordinary, AccessKind::ReadWrite,
4348-
DC->getParentModule(), DC->getResilienceExpansion());
4348+
DC->getParentModule(), DC->getResilienceExpansion(),
4349+
/*useOldABI=*/false);
43494350
return access.getKind() == AccessStrategy::Storage;
43504351
};
43514352

0 commit comments

Comments
 (0)