Skip to content

Commit 83c90b6

Browse files
committed
AST: Turn NominalTypeDecl::getStoredProperties() into a request
This improves on the previous situation: - The request ensures that the backing storage for lazy properties and property wrappers gets synthesized first; previously it was only somewhat guaranteed by callers. - Instead of returning a range this just returns an ArrayRef, which simplifies clients. - Indexing into the ArrayRef is O(1), which addresses some FIXMEs in the SIL optimizer.
1 parent b0e18e8 commit 83c90b6

30 files changed

+201
-145
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//===----------------------------------------------------------------------===//
1717
SWIFT_TYPEID_NAMED(NominalTypeDecl *, NominalTypeDecl)
1818
SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)
19+
SWIFT_TYPEID_NAMED(Decl *, Decl)
1920
SWIFT_TYPEID(Type)
2021
SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo)
2122
SWIFT_TYPEID(PropertyWrapperTypeInfo)

include/swift/AST/Decl.h

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3451,40 +3451,12 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
34513451
/// Retrieve information about this type as a property wrapper.
34523452
PropertyWrapperTypeInfo getPropertyWrapperTypeInfo() const;
34533453

3454-
private:
3455-
/// Predicate used to filter StoredPropertyRange.
3456-
struct ToStoredProperty {
3457-
ToStoredProperty() {}
3458-
Optional<VarDecl *> operator()(Decl *decl) const;
3459-
};
3460-
3461-
public:
3462-
/// A range for iterating the stored member variables of a structure.
3463-
using StoredPropertyRange = OptionalTransformRange<DeclRange,
3464-
ToStoredProperty>;
3465-
34663454
/// Return a collection of the stored member variables of this type.
3467-
StoredPropertyRange getStoredProperties() const;
3455+
ArrayRef<VarDecl *> getStoredProperties() const;
34683456

3469-
private:
3470-
/// Predicate used to filter StoredPropertyRange.
3471-
struct ToStoredPropertyOrMissingMemberPlaceholder {
3472-
Optional<Decl *> operator()(Decl *decl) const;
3473-
};
3474-
3475-
public:
3476-
/// A range for iterating the stored member variables of a structure.
3477-
using StoredPropertyOrMissingMemberPlaceholderRange
3478-
= OptionalTransformRange<DeclRange,
3479-
ToStoredPropertyOrMissingMemberPlaceholder>;
3480-
34813457
/// Return a collection of the stored member variables of this type, along
34823458
/// with placeholders for unimportable stored properties.
3483-
StoredPropertyOrMissingMemberPlaceholderRange
3484-
getStoredPropertiesAndMissingMemberPlaceholders() const {
3485-
return StoredPropertyOrMissingMemberPlaceholderRange(getMembers(),
3486-
ToStoredPropertyOrMissingMemberPlaceholder());
3487-
}
3459+
ArrayRef<Decl *> getStoredPropertiesAndMissingMemberPlaceholders() const;
34883460

34893461
// Implement isa/cast/dyncast/etc.
34903462
static bool classof(const Decl *D) {

include/swift/AST/TypeCheckRequests.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,52 @@ class TypeCheckFunctionBodyUntilRequest :
713713
bool isCached() const { return true; }
714714
};
715715

716+
/// Request to obtain a list of stored properties in a nominal type.
717+
///
718+
/// This will include backing storage for lazy properties and
719+
/// property wrappers, synthesizing them if necessary.
720+
class StoredPropertiesRequest :
721+
public SimpleRequest<StoredPropertiesRequest,
722+
ArrayRef<VarDecl *>(NominalTypeDecl *),
723+
CacheKind::Cached> {
724+
public:
725+
using SimpleRequest::SimpleRequest;
726+
727+
private:
728+
friend SimpleRequest;
729+
730+
// Evaluation.
731+
llvm::Expected<ArrayRef<VarDecl *>>
732+
evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
733+
734+
public:
735+
bool isCached() const { return true; }
736+
};
737+
738+
/// Request to obtain a list of stored properties in a nominal type,
739+
/// together with any missing members corresponding to stored
740+
/// properties that could not be deserialized.
741+
///
742+
/// This will include backing storage for lazy properties and
743+
/// property wrappers, synthesizing them if necessary.
744+
class StoredPropertiesAndMissingMembersRequest :
745+
public SimpleRequest<StoredPropertiesAndMissingMembersRequest,
746+
ArrayRef<Decl *>(NominalTypeDecl *),
747+
CacheKind::Cached> {
748+
public:
749+
using SimpleRequest::SimpleRequest;
750+
751+
private:
752+
friend SimpleRequest;
753+
754+
// Evaluation.
755+
llvm::Expected<ArrayRef<Decl *>>
756+
evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
757+
758+
public:
759+
bool isCached() const { return true; }
760+
};
761+
716762
// Allow AnyValue to compare two Type values, even though Type doesn't
717763
// support ==.
718764
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ SWIFT_TYPEID(IsSetterMutatingRequest)
4141
SWIFT_TYPEID(OpaqueReadOwnershipRequest)
4242
SWIFT_TYPEID(LazyStoragePropertyRequest)
4343
SWIFT_TYPEID(TypeCheckFunctionBodyUntilRequest)
44+
SWIFT_TYPEID(StoredPropertiesRequest)
45+
SWIFT_TYPEID(StoredPropertiesAndMissingMembersRequest)

include/swift/Basic/CTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,4 @@ SWIFT_TYPEID_TEMPLATE1_NAMED(std::vector, Vector, typename T, T)
3939

4040
// LLVM ADT types.
4141
SWIFT_TYPEID_TEMPLATE1_NAMED(llvm::TinyPtrVector, TinyPtrVector, typename T, T)
42-
42+
SWIFT_TYPEID_TEMPLATE1_NAMED(llvm::ArrayRef, ArrayRef, typename T, T)

include/swift/Basic/SimpleDisplay.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,20 @@ namespace swift {
107107
}
108108
out << "}";
109109
}
110+
111+
template<typename T>
112+
void simple_display(llvm::raw_ostream &out,
113+
const llvm::ArrayRef<T> &array) {
114+
out << "{";
115+
bool first = true;
116+
for (const T &value : array) {
117+
if (first) first = false;
118+
else out << ", ";
119+
120+
simple_display(out, value);
121+
}
122+
out << "}";
123+
}
110124
}
111125

112126
#endif // SWIFT_BASIC_SIMPLE_DISPLAY_H

include/swift/Basic/Statistics.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,6 @@ FRONTEND_STATISTIC(AST, NumPrefixOperators)
138138
/// Number of precedence groups in the AST context.
139139
FRONTEND_STATISTIC(AST, NumPrecedenceGroups)
140140

141-
/// Number of precedence groups in the AST context.
142-
FRONTEND_STATISTIC(AST, NumStoredPropertiesQueries)
143-
144141
/// Number of full function bodies parsed.
145142
FRONTEND_STATISTIC(Parse, NumFunctionsParsed)
146143

include/swift/SIL/Projection.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -317,18 +317,14 @@ class Projection {
317317
llvm_unreachable("Unhandled ProjectionKind in switch.");
318318
}
319319

320-
/// WARNING: This is not a constant time operation because it requests all
321-
/// BaseType's stored properties.
322320
VarDecl *getVarDecl(SILType BaseType) const {
323321
assert(isValid());
324322
assert((getKind() == ProjectionKind::Struct ||
325323
getKind() == ProjectionKind::Class));
326324
assert(BaseType.getNominalOrBoundGenericNominal() &&
327325
"This should only be called with a nominal type");
328326
auto *NDecl = BaseType.getNominalOrBoundGenericNominal();
329-
auto Iter = NDecl->getStoredProperties().begin();
330-
std::advance(Iter, getIndex());
331-
return *Iter;
327+
return NDecl->getStoredProperties()[getIndex()];
332328
}
333329

334330
EnumElementDecl *getEnumElementDecl(SILType BaseType) const {

include/swift/SIL/SILInstruction.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4824,11 +4824,10 @@ class StructInst final : public InstructionBaseWithTrailingOperands<
48244824

48254825
StructDecl *S = getStructDecl();
48264826

4827-
NominalTypeDecl::StoredPropertyRange Range = S->getStoredProperties();
4828-
unsigned Index = 0;
4829-
for (auto I = Range.begin(), E = Range.end(); I != E; ++I, ++Index)
4830-
if (V == *I)
4831-
return &getAllOperands()[Index];
4827+
auto Props = S->getStoredProperties();
4828+
for (unsigned I = 0, E = Props.size(); I < E; ++I)
4829+
if (V == Props[I])
4830+
return &getAllOperands()[I];
48324831

48334832
// Did not find a matching VarDecl, return nullptr.
48344833
return nullptr;

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,16 +1172,13 @@ FuncDecl *ASTContext::getArrayReserveCapacityDecl() const {
11721172

11731173
StructDecl *IntDecl = IntType->getDecl();
11741174
auto StoredProperties = IntDecl->getStoredProperties();
1175-
auto FieldIter = StoredProperties.begin();
1176-
if (FieldIter == StoredProperties.end())
1175+
if (StoredProperties.size() != 1)
11771176
return nullptr;
1178-
VarDecl *field = *FieldIter;
1177+
VarDecl *field = StoredProperties[0];
11791178
if (field->hasClangNode())
11801179
return nullptr;
11811180
if (!field->getInterfaceType()->is<BuiltinIntegerType>())
11821181
return nullptr;
1183-
if (std::next(FieldIter) != StoredProperties.end())
1184-
return nullptr;
11851182

11861183
if (!FnDecl->getResultInterfaceType()->isVoid())
11871184
return nullptr;

lib/AST/Decl.cpp

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "swift/Basic/Range.h"
5353
#include "swift/Basic/StringExtras.h"
5454
#include "swift/Basic/Statistic.h"
55+
#include "swift/Basic/TypeID.h"
5556
#include "swift/Demangling/ManglingMacros.h"
5657

5758
#include "clang/Basic/CharInfo.h"
@@ -1029,31 +1030,6 @@ ImportDecl::findBestImportKind(ArrayRef<ValueDecl *> Decls) {
10291030
return FirstKind;
10301031
}
10311032

1032-
Optional<VarDecl *>
1033-
NominalTypeDecl::ToStoredProperty::operator()(Decl *decl) const {
1034-
if (auto var = dyn_cast<VarDecl>(decl)) {
1035-
if (!var->isStatic() && var->hasStorage())
1036-
return var;
1037-
}
1038-
1039-
return None;
1040-
}
1041-
1042-
Optional<Decl *>
1043-
NominalTypeDecl::ToStoredPropertyOrMissingMemberPlaceholder
1044-
::operator()(Decl *decl) const {
1045-
if (auto var = dyn_cast<VarDecl>(decl)) {
1046-
if (!var->isStatic() && var->hasStorage())
1047-
return var;
1048-
}
1049-
if (auto missing = dyn_cast<MissingMemberDecl>(decl)) {
1050-
if (missing->getNumberOfFieldOffsetVectorEntries() > 0)
1051-
return missing;
1052-
}
1053-
1054-
return None;
1055-
}
1056-
10571033
void NominalTypeDecl::setConformanceLoader(LazyMemberLoader *lazyLoader,
10581034
uint64_t contextData) {
10591035
assert(!Bits.NominalTypeDecl.HasLazyConformances &&
@@ -3460,22 +3436,23 @@ void NominalTypeDecl::addExtension(ExtensionDecl *extension) {
34603436
addedExtension(extension);
34613437
}
34623438

3463-
auto NominalTypeDecl::getStoredProperties() const
3464-
-> StoredPropertyRange {
3465-
// This should be called at most once per SIL instruction that accesses a
3466-
// VarDecl.
3467-
//
3468-
// FIXME: Once VarDecl itself caches its field index, it should be called at
3469-
// most once per finalized VarDecl.
3470-
if (getASTContext().Stats)
3471-
getASTContext().Stats->getFrontendCounters().NumStoredPropertiesQueries++;
3472-
3473-
// Clang-imported classes never have stored properties.
3474-
if (hasClangNode() && isa<ClassDecl>(this))
3475-
return StoredPropertyRange(DeclRange(nullptr, nullptr),
3476-
ToStoredProperty());
3439+
ArrayRef<VarDecl *> NominalTypeDecl::getStoredProperties() const {
3440+
auto &ctx = getASTContext();
3441+
auto mutableThis = const_cast<NominalTypeDecl *>(this);
3442+
return evaluateOrDefault(
3443+
ctx.evaluator,
3444+
StoredPropertiesRequest{mutableThis},
3445+
{});
3446+
}
34773447

3478-
return StoredPropertyRange(getMembers(), ToStoredProperty());
3448+
ArrayRef<Decl *>
3449+
NominalTypeDecl::getStoredPropertiesAndMissingMemberPlaceholders() const {
3450+
auto &ctx = getASTContext();
3451+
auto mutableThis = const_cast<NominalTypeDecl *>(this);
3452+
return evaluateOrDefault(
3453+
ctx.evaluator,
3454+
StoredPropertiesAndMissingMembersRequest{mutableThis},
3455+
{});
34793456
}
34803457

34813458
bool NominalTypeDecl::isOptionalDecl() const {
@@ -5435,14 +5412,13 @@ bool VarDecl::isSelfParameter() const {
54355412
/// a declared property that is either `lazy` or has an attached
54365413
/// property wrapper.
54375414
static bool isBackingStorageForDeclaredProperty(const VarDecl *var) {
5438-
if (var->getOriginalWrappedProperty())
5415+
if (var->isLazyStorageProperty())
54395416
return true;
54405417

5441-
auto name = var->getName();
5442-
if (name.empty())
5443-
return false;
5418+
if (var->getOriginalWrappedProperty())
5419+
return true;
54445420

5445-
return name.str().startswith("$__lazy_storage_$_");
5421+
return false;
54465422
}
54475423

54485424
/// Whether the given variable is a delcared property that has separate backing storage.

lib/AST/TypeCheckRequests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12-
#include "swift/AST/TypeCheckRequests.h"
1312
#include "swift/AST/ASTContext.h"
1413
#include "swift/AST/Decl.h"
1514
#include "swift/AST/DiagnosticsCommon.h"
1615
#include "swift/AST/Module.h"
1716
#include "swift/AST/PropertyWrappers.h"
17+
#include "swift/AST/TypeCheckRequests.h"
1818
#include "swift/AST/TypeLoc.h"
1919
#include "swift/AST/TypeRepr.h"
2020
#include "swift/AST/Types.h"

lib/IRGen/GenMeta.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,7 +1251,7 @@ namespace {
12511251
auto properties = getType()->getStoredProperties();
12521252

12531253
// uint32_t NumFields;
1254-
B.addInt32(std::distance(properties.begin(), properties.end()));
1254+
B.addInt32(properties.size());
12551255

12561256
// uint32_t FieldOffsetVectorOffset;
12571257
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
@@ -1640,7 +1640,7 @@ namespace {
16401640
B.addInt32(numImmediateMembers);
16411641

16421642
// uint32_t NumFields;
1643-
B.addInt32(std::distance(properties.begin(), properties.end()));
1643+
B.addInt32(properties.size());
16441644

16451645
// uint32_t FieldOffsetVectorOffset;
16461646
B.addInt32(getFieldVectorOffset() / IGM.getPointerSize());

lib/IRGen/GenReflection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
555555
B.addInt16(fieldRecordSize);
556556

557557
auto properties = NTD->getStoredProperties();
558-
B.addInt32(std::distance(properties.begin(), properties.end()));
558+
B.addInt32(properties.size());
559559
for (auto property : properties)
560560
addFieldDecl(property, property->getInterfaceType(),
561561
NTD->getGenericSignature());

lib/IRGen/GenStruct.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -944,14 +944,12 @@ const TypeInfo *TypeConverter::convertStructType(TypeBase *key, CanType type,
944944

945945
} else if (isa<clang::EnumDecl>(clangDecl)) {
946946
// Fall back to Swift lowering for the enum's representation as a struct.
947-
assert(std::distance(D->getStoredProperties().begin(),
948-
D->getStoredProperties().end()) == 1 &&
947+
assert(D->getStoredProperties().size() == 1 &&
949948
"Struct representation of a Clang enum should wrap one value");
950949
} else if (clangDecl->hasAttr<clang::SwiftNewtypeAttr>()) {
951950
// Fall back to Swift lowering for the underlying type's
952951
// representation as a struct member.
953-
assert(std::distance(D->getStoredProperties().begin(),
954-
D->getStoredProperties().end()) == 1 &&
952+
assert(D->getStoredProperties().size() == 1 &&
955953
"Struct representation of a swift_newtype should wrap one value");
956954
} else {
957955
llvm_unreachable("Swift struct represents unexpected imported type");

lib/IRGen/GenType.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,9 +2304,8 @@ SILType irgen::getSingletonAggregateFieldType(IRGenModule &IGM, SILType t,
23042304
// If there's only one stored property, we have the layout of its field.
23052305
auto allFields = structDecl->getStoredProperties();
23062306

2307-
auto field = allFields.begin();
2308-
if (!allFields.empty() && std::next(field) == allFields.end()) {
2309-
auto fieldTy = t.getFieldType(*field, IGM.getSILModule());
2307+
if (allFields.size() == 1) {
2308+
auto fieldTy = t.getFieldType(allFields[0], IGM.getSILModule());
23102309
if (!IGM.isTypeABIAccessible(fieldTy))
23112310
return SILType();
23122311
return fieldTy;

lib/SIL/MemAccessUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ const ValueDecl *AccessedStorage::getDecl() const {
127127

128128
case Class: {
129129
auto *decl = getObject()->getType().getNominalOrBoundGenericNominal();
130-
return *std::next(decl->getStoredProperties().begin(), getPropertyIndex());
130+
return decl->getStoredProperties()[getPropertyIndex()];
131131
}
132132
case Argument:
133133
return getArgument()->getDecl();

0 commit comments

Comments
 (0)