Skip to content

Commit bcb01ce

Browse files
authored
Merge pull request #66482 from DougGregor/requestify-has-storage
Requestify `AbstractStorageDecl::hasStorage()`.
2 parents 4e2f3b1 + 5457290 commit bcb01ce

21 files changed

+341
-83
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5293,10 +5293,10 @@ class AbstractStorageDecl : public ValueDecl {
52935293

52945294
/// Overwrite the registered implementation-info. This should be
52955295
/// used carefully.
5296-
void setImplInfo(StorageImplInfo implInfo) {
5297-
LazySemanticInfo.ImplInfoComputed = 1;
5298-
ImplInfo = implInfo;
5299-
}
5296+
void setImplInfo(StorageImplInfo implInfo);
5297+
5298+
/// Cache the implementation-info, for use by the request-evaluator.
5299+
void cacheImplInfo(StorageImplInfo implInfo);
53005300

53015301
ReadImplKind getReadImpl() const {
53025302
return getImplInfo().getReadImpl();
@@ -5311,9 +5311,7 @@ class AbstractStorageDecl : public ValueDecl {
53115311

53125312
/// Return true if this is a VarDecl that has storage associated with
53135313
/// it.
5314-
bool hasStorage() const {
5315-
return getImplInfo().hasStorage();
5316-
}
5314+
bool hasStorage() const;
53175315

53185316
/// Return true if this storage has the basic accessors/capability
53195317
/// to be mutated. This is generally constant after the accessors are

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7181,6 +7181,13 @@ ERROR(invalid_macro_role_for_macro_syntax,none,
71817181
(unsigned))
71827182
ERROR(macro_cannot_introduce_names,none,
71837183
"'%0' macros are not allowed to introduce names", (StringRef))
7184+
ERROR(macro_accessor_missing_from_expansion,none,
7185+
"expansion of macro %0 did not produce a %select{non-|}1observing "
7186+
"accessor",
7187+
(DeclName, bool))
7188+
ERROR(macro_init_accessor_not_documented,none,
7189+
"expansion of macro %0 produced an unexpected 'init' accessor",
7190+
(DeclName))
71847191

71857192
ERROR(macro_resolve_circular_reference, none,
71867193
"circular reference resolving %select{freestanding|attached}0 macro %1",

include/swift/AST/Evaluator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,12 @@ class Evaluator {
316316
cache.insert<Request>(request, std::move(output));
317317
}
318318

319+
template<typename Request,
320+
typename std::enable_if<!Request::hasExternalCache>::type* = nullptr>
321+
bool hasCachedResult(const Request &request) {
322+
return cache.find_as(request) != cache.end<Request>();
323+
}
324+
319325
/// Do not introduce new callers of this function.
320326
template<typename Request,
321327
typename std::enable_if<!Request::hasExternalCache>::type* = nullptr>

include/swift/AST/NameLookup.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,13 @@ void forEachPotentialResolvedMacro(
556556
llvm::function_ref<void(MacroDecl *, const MacroRoleAttr *)> body
557557
);
558558

559+
/// For each macro with the given role that might be attached to the given
560+
/// declaration, call the body.
561+
void forEachPotentialAttachedMacro(
562+
Decl *decl, MacroRole role,
563+
llvm::function_ref<void(MacroDecl *macro, const MacroRoleAttr *)> body
564+
);
565+
559566
} // end namespace namelookup
560567

561568
/// Describes an inherited nominal entry.

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,26 @@ class InitAccessorPropertiesRequest :
16861686
ArrayRef<VarDecl *>
16871687
evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
16881688

1689+
// Evaluation.
1690+
bool evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const;
1691+
1692+
public:
1693+
bool isCached() const { return true; }
1694+
};
1695+
1696+
class HasStorageRequest :
1697+
public SimpleRequest<HasStorageRequest,
1698+
bool(AbstractStorageDecl *),
1699+
RequestFlags::Cached> {
1700+
public:
1701+
using SimpleRequest::SimpleRequest;
1702+
1703+
private:
1704+
friend SimpleRequest;
1705+
1706+
// Evaluation.
1707+
bool evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const;
1708+
16891709
public:
16901710
bool isCached() const { return true; }
16911711
};

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ SWIFT_REQUEST(TypeChecker, SelfAccessKindRequest, SelfAccessKind(FuncDecl *),
302302
SWIFT_REQUEST(TypeChecker, StorageImplInfoRequest,
303303
StorageImplInfo(AbstractStorageDecl *), SeparatelyCached,
304304
NoLocationInfo)
305+
SWIFT_REQUEST(TypeChecker, HasStorageRequest,
306+
bool(AbstractStorageDecl *), Cached,
307+
NoLocationInfo)
305308
SWIFT_REQUEST(TypeChecker, StoredPropertiesAndMissingMembersRequest,
306309
ArrayRef<Decl *>(NominalTypeDecl *), Cached, NoLocationInfo)
307310
SWIFT_REQUEST(TypeChecker, StoredPropertiesRequest,

lib/AST/Decl.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2525,7 +2525,7 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
25252525
ResilienceExpansion expansion) const {
25262526
switch (semantics) {
25272527
case AccessSemantics::DirectToStorage:
2528-
assert(hasStorage());
2528+
assert(hasStorage() || getASTContext().Diags.hadAnyError());
25292529
return AccessStrategy::getStorage();
25302530

25312531
case AccessSemantics::DistributedThunk:
@@ -6393,13 +6393,40 @@ bool ProtocolDecl::hasCircularInheritedProtocols() const {
63936393
ctx.evaluator, HasCircularInheritedProtocolsRequest{mutableThis}, true);
63946394
}
63956395

6396+
bool AbstractStorageDecl::hasStorage() const {
6397+
ASTContext &ctx = getASTContext();
6398+
return evaluateOrDefault(ctx.evaluator,
6399+
HasStorageRequest{const_cast<AbstractStorageDecl *>(this)},
6400+
false);
6401+
}
6402+
63966403
StorageImplInfo AbstractStorageDecl::getImplInfo() const {
63976404
ASTContext &ctx = getASTContext();
63986405
return evaluateOrDefault(ctx.evaluator,
63996406
StorageImplInfoRequest{const_cast<AbstractStorageDecl *>(this)},
64006407
StorageImplInfo::getSimpleStored(StorageIsMutable));
64016408
}
64026409

6410+
void AbstractStorageDecl::cacheImplInfo(StorageImplInfo implInfo) {
6411+
LazySemanticInfo.ImplInfoComputed = 1;
6412+
ImplInfo = implInfo;
6413+
}
6414+
6415+
void AbstractStorageDecl::setImplInfo(StorageImplInfo implInfo) {
6416+
cacheImplInfo(implInfo);
6417+
6418+
if (isImplicit()) {
6419+
auto &evaluator = getASTContext().evaluator;
6420+
HasStorageRequest request{this};
6421+
if (!evaluator.hasCachedResult(request))
6422+
evaluator.cacheOutput(request, implInfo.hasStorage());
6423+
else {
6424+
assert(
6425+
evaluateOrDefault(evaluator, request, false) == implInfo.hasStorage());
6426+
}
6427+
}
6428+
}
6429+
64036430
bool AbstractStorageDecl::hasPrivateAccessor() const {
64046431
for (auto accessor : getAllAccessors()) {
64056432
if (hasPrivateOrFilePrivateFormalAccess(accessor))

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1627,7 +1627,7 @@ void namelookup::forEachPotentialResolvedMacro(
16271627

16281628
/// For each macro with the given role that might be attached to the given
16291629
/// declaration, call the body.
1630-
static void forEachPotentialAttachedMacro(
1630+
void namelookup::forEachPotentialAttachedMacro(
16311631
Decl *decl, MacroRole role,
16321632
llvm::function_ref<void(MacroDecl *macro, const MacroRoleAttr *)> body
16331633
) {

lib/AST/TypeCheckRequests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ StorageImplInfoRequest::getCachedResult() const {
687687

688688
void StorageImplInfoRequest::cacheResult(StorageImplInfo value) const {
689689
auto *storage = std::get<0>(getStorage());
690-
storage->setImplInfo(value);
690+
storage->cacheImplInfo(value);
691691
}
692692

693693
//----------------------------------------------------------------------------//

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "swift/AST/NameLookupRequests.h"
3535
#include "swift/AST/PrettyStackTrace.h"
3636
#include "swift/AST/SourceFile.h"
37+
#include "swift/AST/TypeCheckRequests.h"
3738
#include "swift/AST/Types.h"
3839
#include "swift/Basic/Defer.h"
3940
#include "swift/Basic/Platform.h"
@@ -5056,6 +5057,7 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
50565057
out->setIsObjC(var->isObjC());
50575058
out->setIsDynamic(var->isDynamic());
50585059
out->copyFormalAccessFrom(var);
5060+
out->getASTContext().evaluator.cacheOutput(HasStorageRequest{out}, false);
50595061
out->setAccessors(SourceLoc(),
50605062
makeBaseClassMemberAccessors(newContext, out, var),
50615063
SourceLoc());

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ void ClangImporter::Implementation::makeComputed(AbstractStorageDecl *storage,
126126
AccessorDecl *getter,
127127
AccessorDecl *setter) {
128128
assert(getter);
129+
storage->getASTContext().evaluator.cacheOutput(HasStorageRequest{storage}, false);
129130
if (setter) {
130131
storage->setImplInfo(StorageImplInfo::getMutableComputed());
131132
storage->setAccessors(SourceLoc(), {getter, setter}, SourceLoc());

lib/Sema/DerivedConformanceEquatableHashable.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,10 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) {
886886
SourceLoc(), C.Id_hashValue, parentDC);
887887
hashValueDecl->setInterfaceType(intType);
888888
hashValueDecl->setSynthesized();
889+
hashValueDecl->setImplicit();
890+
hashValueDecl->setImplInfo(StorageImplInfo::getImmutableComputed());
891+
hashValueDecl->copyFormalAccessFrom(derived.Nominal,
892+
/*sourceIsParentContext*/ true);
889893

890894
ParameterList *params = ParameterList::createEmpty(C);
891895

@@ -904,12 +908,7 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) {
904908
/*sourceIsParentContext*/ true);
905909

906910
// Finish creating the property.
907-
hashValueDecl->setImplicit();
908-
hashValueDecl->setInterfaceType(intType);
909-
hashValueDecl->setImplInfo(StorageImplInfo::getImmutableComputed());
910911
hashValueDecl->setAccessors(SourceLoc(), {getterDecl}, SourceLoc());
911-
hashValueDecl->copyFormalAccessFrom(derived.Nominal,
912-
/*sourceIsParentContext*/ true);
913912

914913
// The derived hashValue of an actor must be nonisolated.
915914
if (!addNonIsolatedToSynthesized(derived.Nominal, hashValueDecl) &&

lib/Sema/TypeCheckMacros.cpp

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,50 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo,
12401240
return macroSourceFile;
12411241
}
12421242

1243+
bool swift::accessorMacroOnlyIntroducesObservers(
1244+
MacroDecl *macro,
1245+
const MacroRoleAttr *attr
1246+
) {
1247+
// Will this macro introduce observers?
1248+
bool foundObserver = false;
1249+
for (auto name : attr->getNames()) {
1250+
if (name.getKind() == MacroIntroducedDeclNameKind::Named &&
1251+
(name.getName().getBaseName().userFacingName() == "willSet" ||
1252+
name.getName().getBaseName().userFacingName() == "didSet")) {
1253+
foundObserver = true;
1254+
} else {
1255+
// Introduces something other than an observer.
1256+
return false;
1257+
}
1258+
}
1259+
1260+
if (foundObserver)
1261+
return true;
1262+
1263+
// WORKAROUND: Older versions of the Observation library make
1264+
// `ObservationIgnored` an accessor macro that implies that it makes a
1265+
// stored property computed. Override that, because we know it produces
1266+
// nothing.
1267+
if (macro->getName().getBaseName().userFacingName() == "ObservationIgnored") {
1268+
return true;
1269+
}
1270+
1271+
return false;
1272+
}
1273+
1274+
bool swift::accessorMacroIntroducesInitAccessor(
1275+
MacroDecl *macro, const MacroRoleAttr *attr
1276+
) {
1277+
for (auto name : attr->getNames()) {
1278+
if (name.getKind() == MacroIntroducedDeclNameKind::Named &&
1279+
(name.getName().getBaseName().getKind() ==
1280+
DeclBaseName::Kind::Constructor))
1281+
return true;
1282+
}
1283+
1284+
return false;
1285+
}
1286+
12431287
Optional<unsigned> swift::expandAccessors(
12441288
AbstractStorageDecl *storage, CustomAttr *attr, MacroDecl *macro
12451289
) {
@@ -1251,30 +1295,54 @@ Optional<unsigned> swift::expandAccessors(
12511295
return None;
12521296

12531297
PrettyStackTraceDecl debugStack(
1254-
"type checking expanded declaration macro", storage);
1298+
"type checking expanded accessor macro", storage);
12551299

12561300
// Trigger parsing of the sequence of accessor declarations. This has the
12571301
// side effect of registering those accessor declarations with the storage
12581302
// declaration, so there is nothing further to do.
1303+
bool foundNonObservingAccessor = false;
1304+
bool foundInitAccessor = false;
12591305
for (auto decl : macroSourceFile->getTopLevelItems()) {
12601306
auto accessor = dyn_cast_or_null<AccessorDecl>(decl.dyn_cast<Decl *>());
12611307
if (!accessor)
12621308
continue;
12631309

1264-
if (accessor->isObservingAccessor())
1265-
continue;
1310+
if (accessor->isInitAccessor())
1311+
foundInitAccessor = true;
12661312

1313+
if (!accessor->isObservingAccessor())
1314+
foundNonObservingAccessor = true;
1315+
}
1316+
1317+
auto roleAttr = macro->getMacroRoleAttr(MacroRole::Accessor);
1318+
bool expectedNonObservingAccessor =
1319+
!accessorMacroOnlyIntroducesObservers(macro, roleAttr);
1320+
if (foundNonObservingAccessor) {
12671321
// If any non-observing accessor was added, mark the initializer as
12681322
// subsumed.
12691323
if (auto var = dyn_cast<VarDecl>(storage)) {
12701324
if (auto binding = var->getParentPatternBinding()) {
12711325
unsigned index = binding->getPatternEntryIndexForVarDecl(var);
12721326
binding->setInitializerSubsumed(index);
1273-
break;
12741327
}
12751328
}
12761329
}
12771330

1331+
// Make sure we got non-observing accessors exactly where we expected to.
1332+
if (foundNonObservingAccessor != expectedNonObservingAccessor) {
1333+
storage->diagnose(
1334+
diag::macro_accessor_missing_from_expansion, macro->getName(),
1335+
!expectedNonObservingAccessor);
1336+
}
1337+
1338+
// 'init' accessors must be documented in the macro role attribute.
1339+
if (foundInitAccessor &&
1340+
!accessorMacroIntroducesInitAccessor(macro, roleAttr)) {
1341+
storage->diagnose(
1342+
diag::macro_init_accessor_not_documented, macro->getName());
1343+
// FIXME: Add the appropriate "names: named(init)".
1344+
}
1345+
12781346
return macroSourceFile->getBufferID();
12791347
}
12801348

lib/Sema/TypeCheckMacros.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ Optional<unsigned> expandPeers(CustomAttr *attr, MacroDecl *macro, Decl *decl);
7777
Optional<unsigned> expandConformances(CustomAttr *attr, MacroDecl *macro,
7878
NominalTypeDecl *nominal);
7979

80+
/// Determine whether an accessor macro with the given attribute only
81+
/// introduces observers like willSet and didSet.
82+
bool accessorMacroOnlyIntroducesObservers(
83+
MacroDecl *macro, const MacroRoleAttr *attr);
84+
85+
/// Determine whether an accessor macro (defined with the given role attribute)
86+
/// introduces an init accessor.
87+
bool accessorMacroIntroducesInitAccessor(
88+
MacroDecl *macro, const MacroRoleAttr *attr);
89+
8090
} // end namespace swift
8191

8292
#endif /* SWIFT_SEMA_TYPECHECKMACROS_H */

0 commit comments

Comments
 (0)