summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheresa Foley <10618364+tangent-vector@users.noreply.github.com>2025-06-09 11:22:51 -0700
committerGitHub <noreply@github.com>2025-06-09 18:22:51 +0000
commitbfae49d853e0f9b6f9de495b13bcd1642ca4a285 (patch)
tree2f58e220b049c6deca7b5b2b3471560f6738908b
parentbfac247ff2489a1f7fb9766674a6ed25a48a493b (diff)
Mediate access to ContainerDecl members (#7242)
Most of what this change does is straightforward: take all the places in the code that used to operate directly on `ContainerDecl::members` and related fields, and instead have them call into a smaller set of accessor methods defined on `ContainerDecl`. The primary motivation for making this change is that in order to implement on-demand loading of members from serialized AST modules, we need a way to identify and intercept the "demand" for those members. On-demand loading benefits from having all accesses to the members of a `ContainerDecl` be as narrow as possible. If a part of the code only need a member at a specific index, it should say so. If it only needs access to members with a specific name, or a given subclass of `Decl`, then it should say so. A secondary motivation for this change is that there have recently been several changes that added complexity and special cases by introducing code that operated on (and *mutated*) the member list of a container decl in ways that the existing code had never done before. Any code that mutates the member list of a `ContainerDecl` needs to be sure to not disrupt the invariants that the lookup acceleration structures currently rely on. One of the recent changes added a declaration-to-index map to the set of acceleration structures (with different validation/invalidation behavior than the others...) while other recent changes would remove or insert declarations in ways that could change the indices of other declarations in the same container. It is not clear if any of these pieces of code were aware of the others, and the invariants that might be expected or broken along the way. This change bottlenecks the vast majority of accesses to the members of a `ContainerDecl` through the following operations: * Getting a `List` of all of the direct member declarations of a container * Get the number of direct member declarations, and accessing them by index. * Looking up the list of direct member declarations with a given name. * Adding a new direct member declaration to the end of the list. Some other operations are layered on top of those (e.g., getting a list of all the direct member declarations of a given C++ class). These layered operations are still centralized on the `ContainerDecl`, with the intention that we *can* change them to be non-layered implementations if we ever need to for performance (e.g., by building a lookup structure for finding member declarations by their type). The exceptional cases of access/mutation on the direct members of a `ContainerDecl` have also been encapsulated, but rather than expose what would risk appearing like general-purpose accessors (e.g., `removeDecl(d)`, `setDecl(index)`, etc.), these operations have been explicitly named after the specific use case that they serve in the codebase today, to discourage others from using them for more kinds of operations we'd rather not support. These operations have also been given parameter signatures that match their use cases, to make it so that even somebody determined to abuse them would have to invent suitable arguments out of thin air. In the case of the declaration-to-index mapping, this change eliminates that acceleration structure, in favor or slightly more complicated (and possibly inefficient, yes) code at the use site. Over time, it would be good to closely scrutinize each of the use cases that requires more complicated interaction with the members of a `ContainerDecl`, to see whether any of them can be reframed in terms of the more basic operations, or if there is some clean abstraction we can introduce to make operations that mutate the member list feel like... hacky.
-rw-r--r--source/slang/slang-ast-base.h11
-rw-r--r--source/slang/slang-ast-decl-ref.cpp4
-rw-r--r--source/slang/slang-ast-decl.cpp238
-rw-r--r--source/slang/slang-ast-decl.h296
-rw-r--r--source/slang/slang-ast-dump.cpp28
-rw-r--r--source/slang/slang-ast-iterator.h2
-rw-r--r--source/slang/slang-ast-support-types.h6
-rw-r--r--source/slang/slang-ast-synthesis.h5
-rw-r--r--source/slang/slang-ast-type.cpp8
-rw-r--r--source/slang/slang-ast-val.cpp16
-rw-r--r--source/slang/slang-check-constraint.cpp2
-rw-r--r--source/slang/slang-check-conversion.cpp2
-rw-r--r--source/slang/slang-check-decl.cpp743
-rw-r--r--source/slang/slang-check-expr.cpp48
-rw-r--r--source/slang/slang-check-modifier.cpp45
-rw-r--r--source/slang/slang-check-overload.cpp8
-rw-r--r--source/slang/slang-check-shader.cpp4
-rw-r--r--source/slang/slang-check-stmt.cpp5
-rw-r--r--source/slang/slang-check-type.cpp59
-rw-r--r--source/slang/slang-compiler.cpp2
-rw-r--r--source/slang/slang-doc-ast.cpp4
-rw-r--r--source/slang/slang-doc-markdown-writer.cpp158
-rw-r--r--source/slang/slang-language-server-ast-lookup.cpp2
-rw-r--r--source/slang/slang-language-server-document-symbols.cpp2
-rw-r--r--source/slang/slang-language-server.cpp33
-rw-r--r--source/slang/slang-lookup.cpp18
-rw-r--r--source/slang/slang-lower-to-ir.cpp59
-rw-r--r--source/slang/slang-parser.cpp5
-rw-r--r--source/slang/slang-reflection-api.cpp6
-rw-r--r--source/slang/slang-serialize-ast.cpp8
-rw-r--r--source/slang/slang-syntax.cpp28
-rw-r--r--source/slang/slang-syntax.h29
-rw-r--r--source/slang/slang-type-layout.cpp4
-rw-r--r--source/slang/slang.cpp20
34 files changed, 1176 insertions, 732 deletions
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h
index b4b0a3453..5b77f9d53 100644
--- a/source/slang/slang-ast-base.h
+++ b/source/slang/slang-ast-base.h
@@ -759,8 +759,15 @@ public:
DeclCheckStateExt checkState = DeclCheckState::Unchecked;
- // The next declaration defined in the same container with the same name
- Decl* nextInContainerWithSameName = nullptr;
+ /// The previous declaration defined in the same `ContainerDecl`
+ /// that has the same name as this declaration.
+ ///
+ /// Note: it is not recommended to ever access this member directly;
+ /// instead, code should use the `ContainerDecl::getPrevDeclWithSameName()`
+ /// method, which ensures that the `_prevInContainerWithSameName` fields
+ /// have been properly set for all declarations in that container.
+ ///
+ Decl* _prevInContainerWithSameName = nullptr;
bool isChecked(DeclCheckState state) const { return checkState >= state; }
void setCheckState(DeclCheckState state)
diff --git a/source/slang/slang-ast-decl-ref.cpp b/source/slang/slang-ast-decl-ref.cpp
index 89fa52b09..76d0324c6 100644
--- a/source/slang/slang-ast-decl-ref.cpp
+++ b/source/slang/slang-ast-decl-ref.cpp
@@ -255,7 +255,7 @@ void GenericAppDeclRef::_toTextOverride(StringBuilder& out)
{
auto genericDecl = as<GenericDecl>(getGenericDeclRef()->getDecl());
Index paramCount = 0;
- for (auto member : genericDecl->members)
+ for (auto member : genericDecl->getDirectMemberDecls())
if (as<GenericTypeParamDeclBase>(member) || as<GenericValueParamDecl>(member))
paramCount++;
getGenericDeclRef()->toText(out);
@@ -381,7 +381,7 @@ void DeclRefBase::toText(StringBuilder& out)
if (auto genericAppDeclRef = substSet.findGenericAppDeclRef(genericDecl))
{
Index paramCount = 0;
- for (auto member : genericDecl->members)
+ for (auto member : genericDecl->getDirectMemberDecls())
if (as<GenericTypeParamDeclBase>(member) ||
as<GenericValueParamDecl>(member))
paramCount++;
diff --git a/source/slang/slang-ast-decl.cpp b/source/slang/slang-ast-decl.cpp
index 4c5d32f71..5152f0901 100644
--- a/source/slang/slang-ast-decl.cpp
+++ b/source/slang/slang-ast-decl.cpp
@@ -49,76 +49,218 @@ bool isInterfaceRequirement(Decl* decl)
return false;
}
-void ContainerDecl::buildMemberDictionary()
+//
+// ContainerDecl
+//
+
+List<Decl*> const& ContainerDecl::getDirectMemberDecls()
+{
+ return _directMemberDecls.decls;
+}
+
+Count ContainerDecl::getDirectMemberDeclCount()
+{
+ return _directMemberDecls.decls.getCount();
+}
+
+Decl* ContainerDecl::getDirectMemberDecl(Index index)
+{
+ return _directMemberDecls.decls[index];
+}
+
+Decl* ContainerDecl::getFirstDirectMemberDecl()
+{
+ if (getDirectMemberDeclCount() == 0)
+ return nullptr;
+ return getDirectMemberDecl(0);
+}
+
+DeclsOfNameList ContainerDecl::getDirectMemberDeclsOfName(Name* name)
+{
+ return DeclsOfNameList(findLastDirectMemberDeclOfName(name));
+}
+
+Decl* ContainerDecl::findLastDirectMemberDeclOfName(Name* name)
+{
+ _ensureLookupAcceleratorsAreValid();
+ if (auto found = _directMemberDecls.accelerators.mapNameToLastDeclOfThatName.tryGetValue(name))
+ return *found;
+ return nullptr;
+}
+
+Decl* ContainerDecl::getPrevDirectMemberDeclWithSameName(Decl* decl)
+{
+ SLANG_ASSERT(decl);
+ SLANG_ASSERT(decl->parentDecl == this);
+
+ _ensureLookupAcceleratorsAreValid();
+ return decl->_prevInContainerWithSameName;
+}
+
+void ContainerDecl::addDirectMemberDecl(Decl* decl)
+{
+ if (!decl)
+ return;
+
+ decl->parentDecl = this;
+ _directMemberDecls.decls.add(decl);
+}
+
+List<Decl*> const& ContainerDecl::getTransparentDirectMemberDecls()
+{
+ _ensureLookupAcceleratorsAreValid();
+ return _directMemberDecls.accelerators.filteredListOfTransparentDecls;
+}
+
+bool ContainerDecl::_areLookupAcceleratorsValid()
+{
+ return _directMemberDecls.accelerators.declCountWhenLastUpdated ==
+ _directMemberDecls.decls.getCount();
+}
+
+void ContainerDecl::_invalidateLookupAccelerators()
+{
+ _directMemberDecls.accelerators.declCountWhenLastUpdated = -1;
+}
+
+void ContainerDecl::_ensureLookupAcceleratorsAreValid()
{
- // Don't rebuild if already built
- if (isMemberDictionaryValid())
+ if (_areLookupAcceleratorsValid())
return;
- // If it's < 0 it means that the dictionaries are entirely invalid
- if (dictionaryLastCount < 0)
+ // If the `declCountWhenLastUpdated` is less than zero, it means that
+ // the accelerators are entirely invalidated, and must be rebuilt
+ // from scratch.
+ //
+ if (_directMemberDecls.accelerators.declCountWhenLastUpdated < 0)
{
- dictionaryLastCount = 0;
- memberDictionary.clear();
- transparentMembers.clear();
+ _directMemberDecls.accelerators.declCountWhenLastUpdated = 0;
+ _directMemberDecls.accelerators.mapNameToLastDeclOfThatName.clear();
+ _directMemberDecls.accelerators.filteredListOfTransparentDecls.clear();
}
// are we a generic?
GenericDecl* genericDecl = as<GenericDecl>(this);
- const Index membersCount = members.getCount();
+ Count memberCount = _directMemberDecls.decls.getCount();
+ Count memberCountWhenLastUpdated = _directMemberDecls.accelerators.declCountWhenLastUpdated;
- SLANG_ASSERT(dictionaryLastCount >= 0 && dictionaryLastCount <= membersCount);
+ SLANG_ASSERT(memberCountWhenLastUpdated >= 0 && memberCountWhenLastUpdated <= memberCount);
- for (Index i = dictionaryLastCount; i < membersCount; ++i)
+ for (Index i = memberCountWhenLastUpdated; i < memberCount; ++i)
{
- Decl* m = members[i];
-
- auto name = m->getName();
-
- // Add any transparent members to a separate list for lookup
- if (m->hasModifier<TransparentModifier>())
+ Decl* memberDecl = _directMemberDecls.decls[i];
+
+ // Transparent member declarations will go into a separate list,
+ // so that they can be conveniently queried later for lookup
+ // operations.
+ //
+ // TODO: Rather than track these using a separate table, we
+ // could design a scheme where transparent members are put into
+ // the same lookup dictionary as everything else, just under
+ // a pseudo-name that identifies transparent members.
+ //
+ if (memberDecl->hasModifier<TransparentModifier>())
{
- TransparentMemberInfo info;
- info.decl = m;
- transparentMembers.add(info);
+ _directMemberDecls.accelerators.filteredListOfTransparentDecls.add(memberDecl);
}
- // Ignore members with no name
- if (!name)
+ // Members that don't have a name don't go into the lookup dictionary.
+ //
+ auto memberName = memberDecl->getName();
+ if (!memberName)
continue;
- // Ignore the "inner" member of a generic declaration
- if (genericDecl && m == genericDecl->inner)
+ // As a special case, we ignore the `inner` member of a
+ // `GenericDecl`, since it will always have the same name
+ // as the outer generic, and should not be found by lookup.
+ //
+ // TODO: We really ought to change up our entire encoding
+ // of generic declarations in the AST.
+ //
+ if (genericDecl && memberDecl == genericDecl->inner)
continue;
- m->nextInContainerWithSameName = nullptr;
+ // It is possible that we have encountered previous declarations
+ // that have the same name as `memberDecl`, and in that
+ // case we want to wire them up into a singly-linked list.
+ //
+ // This list makes it easy for a lookup operation to find, e.g.,
+ // all of the overloaded functions with a given name.
+ //
+ Decl* prevMemberWithSameName = nullptr;
+ _directMemberDecls.accelerators.mapNameToLastDeclOfThatName.tryGetValue(
+ memberName,
+ prevMemberWithSameName);
+ memberDecl->_prevInContainerWithSameName = prevMemberWithSameName;
+
+ // Whether or not there was a previous declaration with this
+ // name, the current `memberDecl` is the last member declaration
+ // with that name encountered so far, and it is what we will
+ // store in the lookup dictionary.
+ //
+ _directMemberDecls.accelerators.mapNameToLastDeclOfThatName[memberName] = memberDecl;
+ }
- Decl* next = nullptr;
- if (memberDictionary.tryGetValue(name, next))
- m->nextInContainerWithSameName = next;
+ _directMemberDecls.accelerators.declCountWhenLastUpdated = memberCount;
+ SLANG_ASSERT(_areLookupAcceleratorsValid());
+}
- memberDictionary[name] = m;
- }
+void ContainerDecl::
+ _invalidateLookupAcceleratorsBecauseUnscopedEnumAttributeWillBeTurnedIntoTransparentModifier(
+ UnscopedEnumAttribute* unscopedEnumAttr,
+ TransparentModifier* transparentModifier)
+{
+ SLANG_ASSERT(unscopedEnumAttr);
+ SLANG_ASSERT(transparentModifier);
+
+ SLANG_UNUSED(unscopedEnumAttr);
+ SLANG_UNUSED(transparentModifier);
- dictionaryLastCount = membersCount;
- SLANG_ASSERT(isMemberDictionaryValid());
+ _invalidateLookupAccelerators();
}
-Index ContainerDecl::getDeclIndex(Decl* decl)
+void ContainerDecl::
+ _removeDirectMemberConstructorDeclBecauseSynthesizedAnotherDefaultConstructorInstead(
+ ConstructorDecl* decl)
{
- if (Index* ptr = mapDeclMemberToIndex.tryGetValue(decl))
- {
- return *ptr;
- }
- Index res = members.findFirstIndex([&](Decl* d) { return d == decl; });
- if (res >= Index(0))
- {
- mapDeclMemberToIndex[decl] = res;
- }
- return res;
+ SLANG_ASSERT(decl);
+
+ _invalidateLookupAccelerators();
+ _directMemberDecls.decls.remove(decl);
+}
+
+void ContainerDecl::
+ _replaceDirectMemberBitFieldVariableDeclAtIndexWithPropertyDeclThatWasSynthesizedForIt(
+ Index index,
+ VarDecl* oldDecl,
+ PropertyDecl* newDecl)
+{
+ SLANG_ASSERT(oldDecl);
+ SLANG_ASSERT(newDecl);
+ SLANG_ASSERT(index >= 0 && index < getDirectMemberDeclCount());
+ SLANG_ASSERT(getDirectMemberDecl(index) == oldDecl);
+
+ SLANG_UNUSED(oldDecl);
+ _invalidateLookupAccelerators();
+ _directMemberDecls.decls[index] = newDecl;
}
+void ContainerDecl::_insertDirectMemberDeclAtIndexForBitfieldPropertyBackingMember(
+ Index index,
+ VarDecl* backingVarDecl)
+{
+ SLANG_ASSERT(backingVarDecl);
+ SLANG_ASSERT(index >= 0 && index <= getDirectMemberDeclCount());
+
+ _invalidateLookupAccelerators();
+ _directMemberDecls.decls.insert(index, backingVarDecl);
+}
+
+//
+//
+//
+
bool isLocalVar(const Decl* decl)
{
const auto varDecl = as<VarDecl>(decl);
@@ -137,14 +279,12 @@ bool isLocalVar(const Decl* decl)
ThisTypeDecl* InterfaceDecl::getThisTypeDecl()
{
- for (auto member : members)
+ auto thisTypeDecl = findFirstDirectMemberDeclOfType<ThisTypeDecl>();
+ if (!thisTypeDecl)
{
- if (auto thisTypeDeclCandidate = as<ThisTypeDecl>(member))
- {
- return thisTypeDeclCandidate;
- }
+ SLANG_UNEXPECTED("InterfaceDecl does not have a ThisType decl.");
}
- SLANG_UNREACHABLE("InterfaceDecl does not have a ThisType decl.");
+ return thisTypeDecl;
}
InterfaceDecl* ThisTypeConstraintDecl::getInterfaceDecl()
diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h
index e281081a7..3410806dc 100644
--- a/source/slang/slang-ast-decl.h
+++ b/source/slang/slang-ast-decl.h
@@ -25,84 +25,280 @@ class UnresolvedDecl : public Decl
FIDDLE(...)
};
+/// Holds the direct member declarations of a `ContainerDecl`.
+///
+/// This type is used to encapsulate the logic the creating
+/// and maintaing the acceleration structures used for member
+/// lookup.
+///
+struct ContainerDeclDirectMemberDecls
+{
+public:
+ List<Decl*> const& getDecls() const { return decls; }
+
+ List<Decl*>& _refDecls() { return decls; }
+
+private:
+ friend class ContainerDecl;
+ friend struct ASTDumpContext;
+
+ List<Decl*> decls;
+
+ struct
+ {
+ Count declCountWhenLastUpdated = 0;
+
+ Dictionary<Name*, Decl*> mapNameToLastDeclOfThatName;
+ List<Decl*> filteredListOfTransparentDecls;
+ } accelerators;
+};
+
+/// A conceptual list of declarations of the same name, in the same container.
+struct DeclsOfNameList
+{
+public:
+ DeclsOfNameList() {}
+
+ explicit DeclsOfNameList(Decl* decl)
+ : _lastDecl(decl)
+ {
+ }
+
+ struct Iterator
+ {
+ public:
+ Iterator() {}
+ Iterator(Decl* decl)
+ : _decl(decl)
+ {
+ }
+
+ Decl* operator*() const { return _decl; }
+
+ Iterator& operator++()
+ {
+ SLANG_ASSERT(_decl);
+ _decl = _decl->_prevInContainerWithSameName;
+ return *this;
+ }
+
+ bool operator!=(const Iterator& other) const { return _decl != other._decl; }
+
+ private:
+ Decl* _decl = nullptr;
+ };
+
+ Iterator begin() const { return _lastDecl; }
+ Iterator end() const { return nullptr; }
+
+private:
+ Decl* _lastDecl = nullptr;
+};
+
// A "container" decl is a parent to other declarations
FIDDLE(abstract)
class ContainerDecl : public Decl
{
FIDDLE(...)
- FIDDLE() List<Decl*> members;
SourceLoc closingSourceLoc;
// The associated scope owned by this decl.
Scope* ownedScope = nullptr;
- template<typename T>
- FilteredMemberList<T> getMembersOfType()
- {
- return FilteredMemberList<T>(members);
- }
-
- void buildMemberDictionary();
+ /// Get all of the direct member declarations inside this container decl.
+ ///
+ List<Decl*> const& getDirectMemberDecls();
- bool isMemberDictionaryValid() const { return dictionaryLastCount == members.getCount(); }
+ /// Get the number of direct member declarations inside this container decl.
+ ///
+ Count getDirectMemberDeclCount();
- void invalidateMemberDictionary()
- {
- dictionaryLastCount = -1;
- mapDeclMemberToIndex.clear();
- }
+ /// Get the direct member declaration of this container decl at the given `index`.
+ ///
+ Decl* getDirectMemberDecl(Index index);
- Dictionary<Name*, Decl*>& getMemberDictionary()
- {
- buildMemberDictionary();
- return memberDictionary;
- }
+ /// Get the first direct member declaration inside of this container decl, if any.
+ ///
+ /// If the container has no direct member declarations, returns null.
+ ///
+ Decl* getFirstDirectMemberDecl();
- List<TransparentMemberInfo>& getTransparentMembers()
+ /// Get all of the direct member declarations inside of this container decl
+ /// that are instances of the specified AST node type `T`.
+ ///
+ template<typename T>
+ FilteredMemberList<T> getDirectMemberDeclsOfType()
{
- buildMemberDictionary();
- return transparentMembers;
+ return FilteredMemberList<T>(getDirectMemberDecls());
}
- void addMember(Decl* member)
+ /// Find the first direct member declaration of this container decl that
+ /// is an instance of the specified AST node type `T`.
+ ///
+ /// If there are no direct member declrations of type `T`, then returns null.
+ /// Otherwise, returns the first matching member, in declaration order.
+ ///
+ template<typename T>
+ T* findFirstDirectMemberDeclOfType()
{
- if (member)
+ auto count = getDirectMemberDeclCount();
+ for (Index i = 0; i < count; ++i)
{
- member->parentDecl = this;
- auto index = members.getCount();
- members.add(member);
- mapDeclMemberToIndex[member] = index;
+ auto decl = getDirectMemberDecl(i);
+ if (auto found = as<T>(decl))
+ return found;
}
+ return nullptr;
}
- static void setParent(ContainerDecl* parent, Decl* child)
+ /// Find all direct member declarations of this container decl that have the given name.
+ ///
+ DeclsOfNameList getDirectMemberDeclsOfName(Name* name);
+
+ /// Find the last direct member declaration of this container decl that has the given name.
+ ///
+ Decl* findLastDirectMemberDeclOfName(Name* name);
+
+ /// Get the previous direct member declaration that has the same name as `decl`.
+ ///
+ Decl* getPrevDirectMemberDeclWithSameName(Decl* decl);
+
+ /// Append the given `decl` to the direct member declarations of this container decl.
+ ///
+ void addDirectMemberDecl(Decl* decl);
+
+ /// Get the subset of direct member declarations that are "transparent."
+ ///
+ /// Transparent members will themselves be considered when performing
+ /// looking on the parent. E.g., if `a` has a transparent member `b`,
+ /// then a lookup like `a.x` will also consider `a.b.x` as a possible
+ /// result.
+ ///
+ List<Decl*> const& getTransparentDirectMemberDecls();
+
+ // Note: Just an alias for `getDirectMemberDecls()`,
+ // but left in place because of just how many call sites were
+ // already using this name.
+ //
+ List<Decl*> const& getMembers() { return getDirectMemberDecls(); }
+
+ // Note: Just an alias for `getDirectMemberDeclsOfType()`,
+ // but left in place because of just how many call sites were
+ // already using this name.
+ //
+ template<typename T>
+ FilteredMemberList<T> getMembersOfType()
{
- if (child)
- child->parentDecl = parent;
- if (parent)
- parent->addMember(child);
+ return getDirectMemberDeclsOfType<T>();
}
- Index getDeclIndex(Decl* d);
+ // Note: Just an alias for `addDirectMemberDecl()`,
+ // but left in place because of just how many call sites were
+ // already using this name.
+ //
+ void addMember(Decl* member) { addDirectMemberDecl(member); }
+
+ //
+ // NOTE: The operations after this point are *not* considered part of
+ // the public API of `ContainerDecl`, and new code should not be
+ // written that uses them.
+ //
+ // They are being left in place because the existing code that uses
+ // them would be difficult or impossible to refactor to use the public
+ // API, but such parts of the codebase should *not* be considered as
+ // examples of how to interact with the Slang AST.
+ //
+
+ /// Invalidate the acceleration structures used for declaration lookup,
+ /// because the code is about to replace `unscopedEnumAttr` with `transparentModifier`
+ /// as part of semantic checking of an `EnumDecl` nested under this `ContainerDecl`.
+ ///
+ /// Cannot be expressed in terms of the rest of the public API because the
+ /// existing assumption has been that any needed `TransparentModifier`s would
+ /// be manifestly obvious just from the syntax being parsed, so that they would
+ /// already be in place on parsed ASTs. the `UnscopedEnumAttribute` is a `TransparentModifier`
+ /// in all but name, but the two don't share a common base class such that code
+ /// could check for them together.
+ ///
+ /// TODO: In the long run, the obvious fix is to eliminate `UnscopedEnumAttribute`,
+ /// becuase it only exists to enable legacy code to be expressed in Slang, rather than
+ /// representing anything we want/intend to support long-term.
+ ///
+ /// TODO: In the even *longer* run, we should eliminate `TransparentModifier` as well,
+ /// because it only exists to support legacy `cbuffer` declarations and similar syntax,
+ /// and those should be deprecated over time.
+ ///
+ void _invalidateLookupAcceleratorsBecauseUnscopedEnumAttributeWillBeTurnedIntoTransparentModifier(
+ UnscopedEnumAttribute* unscopedEnumAttr,
+ TransparentModifier* transparentModifier);
+
+ /// Remove a constructor declaration from the direct member declarations of this container.
+ ///
+ /// This operation is seemingly used when a default constructor declaration has been synthesized
+ /// for a type, but that type already contained a default constructor of its own.
+ ///
+ /// TODO: Somebody should investigate why this operation is even needed; it seems like an
+ /// indication that we are doing something Deeply Wrong in the way that default constructors are
+ /// being handled and synthesized (on top of the things that we know are Wrong By Design).
+ ///
+ void _removeDirectMemberConstructorDeclBecauseSynthesizedAnotherDefaultConstructorInstead(
+ ConstructorDecl* decl);
+
+ /// Replace the given `oldVarDecl` with the given `newPropertyDecl` in the direct member
+ /// declarations of this container decl, because the variable declaration had a bit-field
+ /// specification on it, and the property was synthesized to stand in for that variable
+ /// by providing a getter/settter pair.
+ ///
+ /// This operation cannot be expressed in terms of the rest of the public API, because there
+ /// is currently no other example of parsing a declaration as one AST node class, and
+ /// then determining as part of semantic checking that it should *actually* be represented
+ /// as a different class of declaration entirely.
+ ///
+ /// TODO: In the long run we would either eliminate support for C-style bit-field specifications
+ /// on what would otherwise be an ordinary member variable declaration. Some other syntax, or
+ /// a type-based solution, should be introduced to server the same use cases, without requiring
+ /// us to parse something as a variable that is semantically *not* a variable in almost any
+ /// of the ways that count.
+ ///
+ void _replaceDirectMemberBitFieldVariableDeclAtIndexWithPropertyDeclThatWasSynthesizedForIt(
+ Index index,
+ VarDecl* oldVarDecl,
+ PropertyDecl* newPropertyDecl);
+
+ /// Insert `backingVarDecl` into this container declaration at `index`, to handle the case
+ /// where the backing variable has been synthesized to store the bits of one or more bitfield
+ /// properties.
+ ///
+ /// This operation cannot be expressed in terms of the rest of the public API because the usual
+ /// assumption is that member declarations may be added to a declaration but that, once added,
+ /// their indices in the member list are consistent and stable.
+ ///
+ /// The reason the code that calls this operation can't just add `backingVarDecl` to the end of
+ /// the declaration is that there is an underlying assumption made by users that any
+ /// non-bitfield members before/after a bitfield declaration will have their storage laid out
+ /// before/after the storage for that bitfield.
+ ///
+ /// TODO: A simple cleanup would be to *not* guarantee the order of storage layout for bitfield
+ /// members relative to other member variables, but the real long-term fix is to have an
+ /// alternative means for users to define bitfields that does not inherit the C-like syntax, and
+ /// that can make the storage that is introduced clear at parse time, so that the relevant
+ /// declaration(s) can already be in the correct order.
+ ///
+ void _insertDirectMemberDeclAtIndexForBitfieldPropertyBackingMember(
+ Index index,
+ VarDecl* backingVarDecl);
+
+ // TODO: The following should be a private member, but currently
+ // we have auto-generated code for things like dumping and serialization
+ // that expect to have access to it.
+ //
+ FIDDLE() ContainerDeclDirectMemberDecls _directMemberDecls;
private:
- // Denotes how much of Members has been placed into the dictionary/transparentMembers.
- // If this value equals the Members.getCount(), the dictionary is completely full and valid.
- // If it's >= 0, then the Members after dictionaryLastCount are all that need to be added.
- // If it < 0 it means that the dictionary/transparentMembers is invalid and needs to be
- // recreated.
- Index dictionaryLastCount = 0;
-
- // Dictionary for looking up members by name.
- // This is built on demand before performing lookup.
- Dictionary<Name*, Decl*> memberDictionary;
-
- Dictionary<Decl*, Index> mapDeclMemberToIndex;
-
- // A list of transparent members, to be used in lookup
- // Note: this is only valid if `memberDictionaryIsValid` is true
- List<TransparentMemberInfo> transparentMembers;
+ bool _areLookupAcceleratorsValid();
+ void _invalidateLookupAccelerators();
+ void _ensureLookupAcceleratorsAreValid();
};
// Base class for all variable declarations
diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp
index 7f6f7796c..b07714bf9 100644
--- a/source/slang/slang-ast-dump.cpp
+++ b/source/slang/slang-ast-dump.cpp
@@ -555,8 +555,6 @@ struct ASTDumpContext
}
void dump(const ExpandedSpecializationArg& arg) { dump(arg.witness); }
- void dump(const TransparentMemberInfo& memInfo) { dump(memInfo.decl); }
-
void dumpRemaining()
{
// Have to keep checking count, as dumping objects can add objects
@@ -570,6 +568,32 @@ struct ASTDumpContext
}
}
+ void dump(ContainerDeclDirectMemberDecls const& decls)
+ {
+ m_writer->emit(" { \n");
+ m_writer->indent();
+ bool first = true;
+ for (auto decl : decls.getDecls())
+ {
+ if (!first)
+ {
+ m_writer->emit(",\n");
+ }
+ first = false;
+
+ if (decl)
+ {
+ dump(decl);
+ }
+ else
+ {
+ m_writer->emit("null");
+ }
+ }
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+
void dump(ContainerDecl* decl)
{
if (auto moduleDecl = dynamicCast<ModuleDecl>(decl))
diff --git a/source/slang/slang-ast-iterator.h b/source/slang/slang-ast-iterator.h
index 18a46b303..4c866fc5a 100644
--- a/source/slang/slang-ast-iterator.h
+++ b/source/slang/slang-ast-iterator.h
@@ -532,7 +532,7 @@ void ASTIterator<CallbackFunc, FilterFunc>::visitDecl(DeclBase* decl)
}
if (auto container = as<ContainerDecl>(decl))
{
- for (auto member : container->members)
+ for (auto member : container->getDirectMemberDecls())
{
visitDecl(member);
}
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 19e3f33c8..d05f24e56 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -1096,12 +1096,6 @@ FIDDLE() namespace Slang
MemberFilterStyle m_filterStyle;
};
- struct TransparentMemberInfo
- {
- // The declaration of the transparent member
- Decl* decl = nullptr;
- };
-
template<typename T>
struct FilteredMemberRefList
{
diff --git a/source/slang/slang-ast-synthesis.h b/source/slang/slang-ast-synthesis.h
index bdfd90aeb..7613a6fae 100644
--- a/source/slang/slang-ast-synthesis.h
+++ b/source/slang/slang-ast-synthesis.h
@@ -71,7 +71,10 @@ public:
ASTEmitScope scope = getCurrentScope();
auto scopeDecl = m_builder->create<ScopeDecl>();
auto newScope = m_builder->create<Scope>();
- ContainerDecl::setParent(scope.m_parent, scopeDecl);
+
+ if (scope.m_parent)
+ scope.m_parent->addDirectMemberDecl(scopeDecl);
+
newScope->parent = scope.m_scope;
newScope->containerDecl = scopeDecl;
scope.m_scope = newScope;
diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp
index 7cfc6a67a..5056e5407 100644
--- a/source/slang/slang-ast-type.cpp
+++ b/source/slang/slang-ast-type.cpp
@@ -863,13 +863,7 @@ DeclRef<ThisTypeDecl> ExtractExistentialType::getThisTypeDeclRef()
SubtypeWitness* openedWitness = getSubtypeWitness();
- ThisTypeDecl* thisTypeDecl = nullptr;
- for (auto member : interfaceDecl->members)
- if (as<ThisTypeDecl>(member))
- {
- thisTypeDecl = as<ThisTypeDecl>(member);
- break;
- }
+ ThisTypeDecl* thisTypeDecl = interfaceDecl->getThisTypeDecl();
SLANG_ASSERT(thisTypeDecl);
DeclRef<ThisTypeDecl> specialiedInterfaceDeclRef =
diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp
index 92e170515..40daae3a6 100644
--- a/source/slang/slang-ast-val.cpp
+++ b/source/slang/slang-ast-val.cpp
@@ -213,7 +213,7 @@ Val* maybeSubstituteGenericParam(Val* paramVal, Decl* paramDecl, SubstitutionSet
Count argCount = args.getCount();
Count argIndex = 0;
- for (auto m : outerGeneric->members)
+ for (auto m : outerGeneric->getDirectMemberDecls())
{
// If we have run out of arguments, then we can stop
// iterating over the parameters, because `this`
@@ -541,17 +541,15 @@ Val* DeclaredSubtypeWitness::_substituteImplOverride(
bool found = false;
Index index = 0;
- for (auto m : genericDecl->members)
+ for (auto constraintParam :
+ genericDecl->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto constraintParam = as<GenericTypeConstraintDecl>(m))
+ if (constraintParam == getDeclRef().getDecl())
{
- if (constraintParam == getDeclRef().getDecl())
- {
- found = true;
- break;
- }
- index++;
+ found = true;
+ break;
}
+ index++;
}
if (found)
{
diff --git a/source/slang/slang-check-constraint.cpp b/source/slang/slang-check-constraint.cpp
index 6259e2fb8..3020554c8 100644
--- a/source/slang/slang-check-constraint.cpp
+++ b/source/slang/slang-check-constraint.cpp
@@ -541,7 +541,7 @@ DeclRef<Decl> SemanticsVisitor::trySolveConstraintSystem(
// should have been filled with the resolved types and values for the
// generic parameters. We can now verify if they are complete and consolidate
// them into final argument list.
- for (auto member : genericDeclRef.getDecl()->members)
+ for (auto member : genericDeclRef.getDecl()->getDirectMemberDecls())
{
if (auto typeParam = as<GenericTypeParamDeclBase>(member))
{
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index 41355597f..506abc1be 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -1886,7 +1886,7 @@ bool SemanticsVisitor::tryCoerceLambdaToFuncType(
// If it does, we can't convert it to a function type.
auto operatorName = getName("()");
- for (auto member : lambdaStruct.getDecl()->members)
+ for (auto member : lambdaStruct.getDecl()->getDirectMemberDecls())
{
if (auto field = as<VarDecl>(member))
{
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index aa84a057f..b56c3cb07 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -61,7 +61,7 @@ static void validateDynInterfaceUsage(
return;
// validate members inside `dyn interface`
- for (auto m : decl->members)
+ for (auto m : decl->getDirectMemberDecls())
{
if (isAssociatedTypeDecl(m))
{
@@ -154,20 +154,16 @@ static void validateDynInterfaceUseWithInheritanceDecl(
{
// Ensure if we inherit from a `dyn interface` that the parent does not have: opaque
// types, unsized types, non-copyable types
- for (auto m : aggTypeDeclParent->members)
+ for (auto varDecl : aggTypeDeclParent->getDirectMemberDeclsOfType<VarDecl>())
{
- auto varDecl = as<VarDecl>(m);
- if (!varDecl)
- continue;
-
visitor->ensureDecl(varDecl, DeclCheckState::ReadyForLookup);
if (isNonCopyableType(varDecl->getType()))
{
sink->diagnose(
- m,
+ varDecl,
Diagnostics::cannotHaveNonCopyableMemberWhenInheritingDynInterface,
- m,
+ varDecl,
interfaceDecl);
}
@@ -176,15 +172,15 @@ static void validateDynInterfaceUseWithInheritanceDecl(
bool isOpaque = varTypeTags & (int)TypeTag::Opaque;
if (isUnsized)
sink->diagnose(
- m,
+ varDecl,
Diagnostics::cannotHaveUnsizedMemberWhenInheritingDynInterface,
- m,
+ varDecl,
interfaceDecl);
if (isOpaque)
sink->diagnose(
- m,
+ varDecl,
Diagnostics::cannotHaveOpaqueMemberWhenInheritingDynInterface,
- m,
+ varDecl,
interfaceDecl);
}
}
@@ -567,9 +563,9 @@ private:
bool isMemberInitCtor,
Index& paramIndex);
- void synthesizeCtorBodyForMember(
+ void synthesizeCtorBodyForMemberVar(
ConstructorDecl* ctor,
- Decl* member,
+ VarDeclBase* member,
ThisExpr* thisExpr,
Dictionary<Decl*, Expr*>& cachedDeclToCheckedVar,
SeqStmt* seqStmtChild,
@@ -927,7 +923,7 @@ struct SemanticsDeclReferenceVisitor : public SemanticsDeclVisitorBase,
void visitContainerDecl(ContainerDecl* decl)
{
- for (auto m : decl->members)
+ for (auto m : decl->getDirectMemberDecls())
{
dispatchIfNotNull(m);
}
@@ -1545,10 +1541,9 @@ void SemanticsVisitor::ensureAllDeclsRec(Decl* decl, DeclCheckState state)
// takes place, invalidating the iterator and likely a crash.
//
// Accessing the members via index side steps the issue.
- const auto& members = containerDecl->members;
- for (Index i = 0; i < members.getCount(); ++i)
+ for (Index i = 0; i < containerDecl->getDirectMemberDeclCount(); ++i)
{
- Decl* childDecl = members[i];
+ Decl* childDecl = containerDecl->getDirectMemberDecl(i);
// As an exception, if any of the child is a `ScopeDecl`,
// then that indicates that it represents a scope for local
@@ -1710,39 +1705,49 @@ void SemanticsDeclModifiersVisitor::visitStructDecl(StructDecl* structDecl)
// Replace any bitfield member with a property, do this here before
// name lookup to avoid the original var decl being referenced
- for (auto& m : structDecl->members)
+ //
+ auto directMemberDeclCount = structDecl->getDirectMemberDeclCount();
+ for (Index i = 0; i < directMemberDeclCount; ++i)
{
- const auto bfm = m->findModifier<BitFieldModifier>();
- if (!bfm)
+ auto varDecl = as<VarDecl>(structDecl->getDirectMemberDecl(i));
+ if (!varDecl)
continue;
- auto property = m_astBuilder->create<PropertyDecl>();
- property->modifiers = m->modifiers;
- property->type = as<VarDecl>(m)->type;
- property->loc = m->loc;
- property->nameAndLoc = m->getNameAndLoc();
- property->parentDecl = structDecl;
- property->ownedScope = m_astBuilder->create<Scope>();
- property->ownedScope->containerDecl = property;
- property->ownedScope->parent = getScope(structDecl);
- m = property;
-
- const auto get = m_astBuilder->create<GetterDecl>();
- get->ownedScope = m_astBuilder->create<Scope>();
- get->ownedScope->containerDecl = get;
- get->ownedScope->parent = getScope(property);
- property->addMember(get);
-
- const auto set = m_astBuilder->create<SetterDecl>();
- addModifier(set, m_astBuilder->create<MutatingAttribute>());
- set->ownedScope = m_astBuilder->create<Scope>();
- set->ownedScope->containerDecl = set;
- set->ownedScope->parent = getScope(property);
- property->addMember(set);
+ const auto bitFieldModifier = varDecl->findModifier<BitFieldModifier>();
+ if (!bitFieldModifier)
+ continue;
- structDecl->invalidateMemberDictionary();
+ auto propertyDecl = m_astBuilder->create<PropertyDecl>();
+ propertyDecl->modifiers = varDecl->modifiers;
+ propertyDecl->type = varDecl->type;
+ propertyDecl->loc = varDecl->loc;
+ propertyDecl->nameAndLoc = varDecl->getNameAndLoc();
+ propertyDecl->parentDecl = structDecl;
+ propertyDecl->ownedScope = m_astBuilder->create<Scope>();
+ propertyDecl->ownedScope->containerDecl = propertyDecl;
+ propertyDecl->ownedScope->parent = getScope(structDecl);
+
+ auto propertyDeclScope = getScope(propertyDecl);
+
+ const auto getAccessorDecl = m_astBuilder->create<GetterDecl>();
+ getAccessorDecl->ownedScope = m_astBuilder->create<Scope>();
+ getAccessorDecl->ownedScope->containerDecl = getAccessorDecl;
+ getAccessorDecl->ownedScope->parent = propertyDeclScope;
+ propertyDecl->addMember(getAccessorDecl);
+
+ const auto setAccessorDecl = m_astBuilder->create<SetterDecl>();
+ addModifier(setAccessorDecl, m_astBuilder->create<MutatingAttribute>());
+ setAccessorDecl->ownedScope = m_astBuilder->create<Scope>();
+ setAccessorDecl->ownedScope->containerDecl = setAccessorDecl;
+ setAccessorDecl->ownedScope->parent = propertyDeclScope;
+ propertyDecl->addMember(setAccessorDecl);
+
+ structDecl
+ ->_replaceDirectMemberBitFieldVariableDeclAtIndexWithPropertyDeclThatWasSynthesizedForIt(
+ i,
+ varDecl,
+ propertyDecl);
}
- structDecl->buildMemberDictionary();
}
void SemanticsDeclHeaderVisitor::checkDerivativeMemberAttributeParent(
@@ -2368,7 +2373,7 @@ static inline bool _isDefaultCtor(ConstructorDecl* ctor)
// 1. default ctor must have no parameters
// 2. default ctor can have parameters, but all parameters have init expr (Because we won't
// differentiate this case from 2.)
- if (ctor->members.getCount() == 0 || allParamHaveInitExpr(ctor))
+ if (ctor->getDirectMemberDeclCount() == 0 || allParamHaveInitExpr(ctor))
{
return true;
}
@@ -2750,21 +2755,48 @@ void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl)
bool isUnknownSize = (((int)varTypeTags & unsizedMask) != 0);
if (isUnknownSize)
{
- // Unsized decl must appear as the last member of the struct.
- for (auto memberIdx = parentDecl->members.getCount() - 1; memberIdx >= 0; memberIdx--)
+ // If an unsized variable declaration appears as a member of
+ // an aggregate type (such as a `struct`), then it must be
+ // the *last* non-`static` variable declaration in that type.
+ //
+ // We validate that here by iterating over the members in
+ // reverse order, until we either run into the unsized variable
+ // declaration in question (in which case things are fine),
+ // or we encounter some *other* non-`static` variable declaration,
+ // in which case the unsized declaration is invalid.
+ //
+ for (auto memberIdx = parentDecl->getDirectMemberDeclCount() - 1; memberIdx >= 0;
+ memberIdx--)
{
- if (parentDecl->members[memberIdx] == varDecl)
- {
- break;
- }
- if (auto memberVarDecl = as<VarDeclBase>(parentDecl->members[memberIdx]))
- {
- if (!memberVarDecl->hasModifier<HLSLStaticModifier>())
- {
- getSink()->diagnose(varDecl, Diagnostics::unsizedMemberMustAppearLast);
- }
+ auto memberDecl = parentDecl->getDirectMemberDecl(memberIdx);
+
+ // If we run into the unsized variable declaration before
+ // hitting anything else, the declaration is in a valid
+ // location.
+ //
+ if (memberDecl == varDecl)
break;
- }
+
+ // If we run into another declaration, but it isn't a
+ // variable, then it doesn't impact validity.
+ //
+ auto memberVarDecl = as<VarDeclBase>(memberDecl);
+ if (!memberVarDecl)
+ continue;
+
+ // If we run into another variable declaration, but
+ // it is a `static` variable, then it doesn't
+ // impact the validity of the unsized declaration.
+ //
+ if (memberVarDecl->hasModifier<HLSLStaticModifier>())
+ continue;
+
+ // At this point we've run into a non-`static` variable declaration
+ // that comes *after* the unsized variable declaration, which
+ // means the unsized variable declaration is invalid.
+ //
+ getSink()->diagnose(varDecl, Diagnostics::unsizedMemberMustAppearLast);
+ break;
}
}
}
@@ -2873,11 +2905,10 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
RefPtr<WitnessTable> witnessTable)
{
ASTSynthesizer synth(m_astBuilder, getNamePool());
- Decl* existingDecl = nullptr;
+
AggTypeDecl* aggTypeDecl = nullptr;
- if (context->parentDecl->getMemberDictionary().tryGetValue(
- requirementDeclRef.getName(),
- existingDecl))
+ if (auto existingDecl =
+ context->parentDecl->findLastDirectMemberDeclOfName(requirementDeclRef.getName()))
{
// Remove the `ToBeSynthesizedModifier`.
if (as<ToBeSynthesizedModifier>(existingDecl->modifiers.first))
@@ -2942,10 +2973,10 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
if (!aggTypeDecl)
{
aggTypeDecl = m_astBuilder->create<StructDecl>();
- context->parentDecl->addMember(aggTypeDecl);
aggTypeDecl->nameAndLoc.name = requirementDeclRef.getName();
aggTypeDecl->loc = context->parentDecl->nameAndLoc.loc;
- context->parentDecl->invalidateMemberDictionary();
+
+ context->parentDecl->addDirectMemberDecl(aggTypeDecl);
synth.pushScopeForContainer(aggTypeDecl);
}
@@ -3000,12 +3031,11 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
diffField->nameAndLoc = member->nameAndLoc;
diffField->type.type = diffMemberType;
diffField->checkState = DeclCheckState::SignatureChecked;
- aggTypeDecl->addMember(diffField);
auto visibility = getDeclVisibility(member);
addVisibilityModifier(diffField, visibility);
- aggTypeDecl->invalidateMemberDictionary();
+ aggTypeDecl->addDirectMemberDecl(diffField);
// Inject a `DerivativeMember` modifier on the differential field to point to itself.
{
@@ -3059,25 +3089,17 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
}
// The `Differential` type of a `Differential` type is always itself.
- bool hasDifferentialTypeDef = false;
- for (auto member : aggTypeDecl->members)
- {
- if (auto name = member->getName())
- {
- if (name->text == "Differential")
- {
- hasDifferentialTypeDef = true;
- break;
- }
- }
- }
+ auto differentialName = getName("Differential");
+ bool hasDifferentialTypeDef =
+ aggTypeDecl->findLastDirectMemberDeclOfName(differentialName) != nullptr;
if (!hasDifferentialTypeDef)
{
auto assocTypeDef = m_astBuilder->create<TypeDefDecl>();
- assocTypeDef->nameAndLoc.name = getName("Differential");
+ assocTypeDef->nameAndLoc.name = differentialName;
assocTypeDef->type.type = satisfyingType;
- aggTypeDecl->addMember(assocTypeDef);
assocTypeDef->setCheckState(DeclCheckState::DefinitionChecked);
+
+ aggTypeDecl->addDirectMemberDecl(assocTypeDef);
}
// Go through all members and collect their differential types.
@@ -3261,10 +3283,9 @@ void SemanticsDeclHeaderVisitor::visitGenericDecl(GenericDecl* genericDecl)
// Accessing the members via index side steps the issue.
int parameterIndex = 0;
- const auto& members = genericDecl->members;
- for (Index i = 0; i < members.getCount(); ++i)
+ for (Index i = 0; i < genericDecl->getDirectMemberDeclCount(); ++i)
{
- Decl* m = members[i];
+ Decl* m = genericDecl->getDirectMemberDecl(i);
if (auto typeParam = as<GenericTypeParamDeclBase>(m))
{
@@ -3492,7 +3513,7 @@ static void _registerBuiltinDeclsRec(Session* session, Decl* decl)
}
if (auto containerDecl = as<ContainerDecl>(decl))
{
- for (auto childDecl : containerDecl->members)
+ for (auto childDecl : containerDecl->getDirectMemberDecls())
{
if (as<ScopeDecl>(childDecl))
continue;
@@ -3539,7 +3560,7 @@ void discoverExtensionDecls(List<ExtensionDecl*>& decls, Decl* parent)
decls.add(extDecl);
if (auto containerDecl = as<ContainerDecl>(parent))
{
- for (auto child : containerDecl->members)
+ for (auto child : containerDecl->getDirectMemberDecls())
{
discoverExtensionDecls(decls, child);
}
@@ -3570,20 +3591,19 @@ void SemanticsDeclVisitorBase::checkModule(ModuleDecl* moduleDecl)
_registerBuiltinDeclsRec(getSession(), moduleDecl);
}
- if (moduleDecl->members.getCount() > 0)
+ if (auto firstDeclInModule = moduleDecl->getFirstDirectMemberDecl())
{
- auto firstMember = moduleDecl->members[0];
- if (as<ImplementingDecl>(firstMember))
+ if (as<ImplementingDecl>(firstDeclInModule))
{
if (!getShared()->isInLanguageServer())
{
// A primary module file can't start with an "implementing" declaration.
getSink()->diagnose(
- firstMember,
+ firstDeclInModule,
Diagnostics::primaryModuleFileCannotStartWithImplementingDecl);
}
}
- else if (!as<ModuleDeclarationDecl>(firstMember))
+ else if (!as<ModuleDeclarationDecl>(firstDeclInModule))
{
// A primary module file must start with a `module` declaration.
// TODO: this warning is disabled for now to free users from massive change for now.
@@ -3613,9 +3633,9 @@ void SemanticsDeclVisitorBase::checkModule(ModuleDecl* moduleDecl)
// files are parsed.
auto visitIncludeDecls = [&](ContainerDecl* fileDecl)
{
- for (Index i = 0; i < fileDecl->members.getCount(); i++)
+ for (Index i = 0; i < fileDecl->getDirectMemberDeclCount(); i++)
{
- auto decl = fileDecl->members[i];
+ auto decl = fileDecl->getDirectMemberDecl(i);
if (auto includeDecl = as<IncludeDecl>(decl))
{
ensureDecl(includeDecl, DeclCheckState::DefinitionChecked);
@@ -3631,9 +3651,9 @@ void SemanticsDeclVisitorBase::checkModule(ModuleDecl* moduleDecl)
}
};
visitIncludeDecls(moduleDecl);
- for (Index i = 0; i < moduleDecl->members.getCount(); i++)
+ for (Index i = 0; i < moduleDecl->getDirectMemberDeclCount(); i++)
{
- if (auto fileDecl = as<FileDecl>(moduleDecl->members[i]))
+ if (auto fileDecl = as<FileDecl>(moduleDecl->getDirectMemberDecl(i)))
visitIncludeDecls(fileDecl);
}
@@ -4101,8 +4121,8 @@ bool SemanticsVisitor::doesGenericSignatureMatchRequirement(
// satisfying value to have the same number of members for it to be an
// exact match.
//
- auto memberCount = requiredGenericDeclRef.getDecl()->members.getCount();
- if (satisfyingGenericDeclRef.getDecl()->members.getCount() != memberCount)
+ auto memberCount = requiredGenericDeclRef.getDecl()->getDirectMemberDeclCount();
+ if (satisfyingGenericDeclRef.getDecl()->getDirectMemberDeclCount() != memberCount)
return false;
// We then want to check that pairwise members match, in order.
@@ -4595,7 +4615,7 @@ GenericDecl* SemanticsVisitor::synthesizeGenericSignatureForRequirementWitness(
// that reference those parametesr as arguments for the call expresison
// that makes up the body.
//
- for (auto member : requiredMemberDeclRef.getDecl()->members)
+ for (auto member : requiredMemberDeclRef.getDecl()->getDirectMemberDecls())
{
if (auto typeParamDeclBase = as<GenericTypeParamDeclBase>(member))
{
@@ -4670,25 +4690,24 @@ GenericDecl* SemanticsVisitor::synthesizeGenericSignatureForRequirementWitness(
// from the original requirement decl. For example, we can simply apply declref substituion on
// the original type constraint `U:IDerived` to get `UImpl : IDerived`.
//
- for (auto member : requiredMemberDeclRef.getDecl()->members)
+ for (auto constraintDecl :
+ requiredMemberDeclRef.getDecl()->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto constraintDecl = as<GenericTypeConstraintDecl>(member))
- {
- auto synConstraintDecl = m_astBuilder->create<GenericTypeConstraintDecl>();
- synConstraintDecl->nameAndLoc = constraintDecl->getNameAndLoc();
- synConstraintDecl->parentDecl = synGenericDecl;
+ auto synConstraintDecl = m_astBuilder->create<GenericTypeConstraintDecl>();
+ synConstraintDecl->nameAndLoc = constraintDecl->getNameAndLoc();
+ synConstraintDecl->parentDecl = synGenericDecl;
- // For generic constraint Sub : Sup, we need to substitute them with
- // synthesized generic parameters.
- //
- synConstraintDecl->sub = TypeExp((Type*)constraintDecl->sub.type->substitute(
- m_astBuilder,
- SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
- synConstraintDecl->sup = TypeExp((Type*)constraintDecl->sup.type->substitute(
- m_astBuilder,
- SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
- synGenericDecl->members.add(synConstraintDecl);
- }
+ // For generic constraint Sub : Sup, we need to substitute them with
+ // synthesized generic parameters.
+ //
+ synConstraintDecl->sub = TypeExp((Type*)constraintDecl->sub.type->substitute(
+ m_astBuilder,
+ SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
+ synConstraintDecl->sup = TypeExp((Type*)constraintDecl->sup.type->substitute(
+ m_astBuilder,
+ SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
+
+ synGenericDecl->addDirectMemberDecl(synConstraintDecl);
}
// Override generic pointer to point to the original generic container.
@@ -5182,7 +5201,7 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness(
{
auto genericAppExpr = m_astBuilder->create<GenericAppExpr>();
genericAppExpr->functionExpr = synBase;
- for (auto member : genericDeclRef->members)
+ for (auto member : genericDeclRef->getDirectMemberDecls())
{
if (auto typeParamDecl = as<GenericTypeParamDeclBase>(member))
{
@@ -5421,48 +5440,44 @@ bool SemanticsVisitor::trySynthesizeConstructorRequirementWitness(
SemanticsDeclBodyVisitor bodyVisitor(withParentFunc(ctorDecl));
bodyVisitor.maybeRegisterDifferentiableType(m_astBuilder, context->conformingType);
- for (auto member : context->parentDecl->members)
+ if (auto varDecl = context->parentDecl->findFirstDirectMemberDeclOfType<VarDeclBase>())
{
- if (auto varDecl = as<VarDeclBase>(member))
- {
- auto varExpr = m_astBuilder->create<VarExpr>();
- varExpr->scope = ctorDecl->ownedScope;
- varExpr->name = varDecl->getName();
- auto checkedVarExpr = CheckTerm(varExpr);
- if (!checkedVarExpr)
- return false;
- if (as<ErrorType>(checkedVarExpr->type.type))
- return false;
- auto assign = m_astBuilder->create<AssignExpr>();
- assign->left = checkedVarExpr;
- auto temp = m_astBuilder->create<InvokeExpr>();
- auto lookupResult = lookUpMember(
- m_astBuilder,
- this,
- ctorName,
- varDecl->type.type,
- ctorDecl->ownedScope,
- LookupMask::Function,
- LookupOptions::IgnoreBaseInterfaces);
- temp->functionExpr = createLookupResultExpr(
- ctorName,
- lookupResult,
- nullptr,
- context->parentDecl->loc,
- nullptr);
- temp->arguments.addRange(synArgs);
- auto resolvedVar = ResolveInvoke(temp);
- if (!resolvedVar)
- return false;
- assign->right = resolvedVar;
- assign->type = m_astBuilder->getVoidType();
- bodyVisitor.maybeRegisterDifferentiableType(m_astBuilder, varDecl->type.type);
+ auto varExpr = m_astBuilder->create<VarExpr>();
+ varExpr->scope = ctorDecl->ownedScope;
+ varExpr->name = varDecl->getName();
+ auto checkedVarExpr = CheckTerm(varExpr);
+ if (!checkedVarExpr)
+ return false;
+ if (as<ErrorType>(checkedVarExpr->type.type))
+ return false;
+ auto assign = m_astBuilder->create<AssignExpr>();
+ assign->left = checkedVarExpr;
+ auto temp = m_astBuilder->create<InvokeExpr>();
+ auto lookupResult = lookUpMember(
+ m_astBuilder,
+ this,
+ ctorName,
+ varDecl->type.type,
+ ctorDecl->ownedScope,
+ LookupMask::Function,
+ LookupOptions::IgnoreBaseInterfaces);
+ temp->functionExpr = createLookupResultExpr(
+ ctorName,
+ lookupResult,
+ nullptr,
+ context->parentDecl->loc,
+ nullptr);
+ temp->arguments.addRange(synArgs);
+ auto resolvedVar = ResolveInvoke(temp);
+ if (!resolvedVar)
+ return false;
+ assign->right = resolvedVar;
+ assign->type = m_astBuilder->getVoidType();
+ bodyVisitor.maybeRegisterDifferentiableType(m_astBuilder, varDecl->type.type);
- auto stmt = m_astBuilder->create<ExpressionStmt>();
- stmt->expression = assign;
- seqStmt->stmts.add(stmt);
- break;
- }
+ auto stmt = m_astBuilder->create<ExpressionStmt>();
+ stmt->expression = assign;
+ seqStmt->stmts.add(stmt);
}
}
else if (synArgs.getCount())
@@ -6656,8 +6671,9 @@ bool SemanticsVisitor::trySynthesizeEnumTypeMethodRequirementWitness(
synFunc->nameAndLoc.loc = synFunc->loc;
// synFunc already has its parent set
SLANG_ASSERT(context->parentDecl == synFunc->parentDecl);
- context->parentDecl->addMember(synFunc);
- context->parentDecl->invalidateMemberDictionary();
+
+ context->parentDecl->addDirectMemberDecl(synFunc);
+
addModifier(synFunc, intrinsicOpModifier);
witnessTable->add(
funcDeclRef.getDecl(),
@@ -6751,15 +6767,12 @@ bool SemanticsVisitor::trySynthesizeDifferentialMethodRequirementWitness(
auto varStmt = synth.emitVarDeclStmt(synFunc->returnType.type, getName("result"));
auto resultVarExpr = synth.emitVarExpr(varStmt, synFunc->returnType.type);
- for (auto member : context->parentDecl->members)
+ for (auto varMember : context->parentDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- auto derivativeAttr = member->findModifier<DerivativeMemberAttribute>();
+ auto derivativeAttr = varMember->findModifier<DerivativeMemberAttribute>();
if (!derivativeAttr)
continue;
- auto varMember = as<VarDeclBase>(member);
- if (!varMember)
- continue;
ensureDecl(varMember, DeclCheckState::ReadyForReference);
auto memberType = varMember->getType();
auto diffMemberType = tryGetDifferentialType(m_astBuilder, memberType);
@@ -6841,8 +6854,9 @@ bool SemanticsVisitor::trySynthesizeDifferentialMethodRequirementWitness(
Decl* witnessDecl = synGeneric ? (Decl*)synGeneric : synFunc;
SLANG_ASSERT(context->parentDecl == witnessDecl->parentDecl);
- context->parentDecl->addMember(witnessDecl);
- context->parentDecl->invalidateMemberDictionary();
+
+ context->parentDecl->addDirectMemberDecl(witnessDecl);
+
addModifier(synFunc, m_astBuilder->create<SynthesizedModifier>());
// If `This` is nested inside a generic, we need to form a complete declref type to the
@@ -8230,13 +8244,11 @@ void SemanticsDeclBasesVisitor::visitEnumDecl(EnumDecl* decl)
if (auto enumTypeTypeInterfaceDecl =
as<InterfaceDecl>(enumTypeTypeDeclRefType->getDeclRef().getDecl()))
{
- for (auto memberDecl : enumTypeTypeInterfaceDecl->members)
+ if (auto foundMemberDecl =
+ enumTypeTypeInterfaceDecl->findLastDirectMemberDeclOfName(
+ tagAssociatedTypeName))
{
- if (memberDecl->getName() == tagAssociatedTypeName)
- {
- tagAssociatedTypeDecl = memberDecl;
- break;
- }
+ tagAssociatedTypeDecl = foundMemberDecl;
}
}
}
@@ -8469,7 +8481,7 @@ void SemanticsVisitor::getGenericParams(
List<Decl*>& outParams,
List<GenericTypeConstraintDecl*>& outConstraints)
{
- for (auto dd : decl->members)
+ for (auto dd : decl->getDirectMemberDecls())
{
if (dd == decl->inner)
continue;
@@ -8772,7 +8784,7 @@ List<Val*> getDefaultSubstitutionArgs(
if (astBuilder->m_cachedGenericDefaultArgs.tryGetValue(genericDecl, args))
return args;
- for (auto mm : genericDecl->members)
+ for (auto mm : genericDecl->getDirectMemberDecls())
{
if (auto genericTypeParamDecl = as<GenericTypeParamDecl>(mm))
{
@@ -8801,35 +8813,33 @@ List<Val*> getDefaultSubstitutionArgs(
bool shouldCache = true;
// create default substitution arguments for constraints
- for (auto mm : genericDecl->members)
+ for (auto genericTypeConstraintDecl :
+ genericDecl->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto genericTypeConstraintDecl = as<GenericTypeConstraintDecl>(mm))
+ if (semantics)
+ semantics->ensureDecl(genericTypeConstraintDecl, DeclCheckState::ReadyForReference);
+ auto constraintDeclRef =
+ astBuilder->getDirectDeclRef<GenericTypeConstraintDecl>(genericTypeConstraintDecl);
+ auto supType = getSup(astBuilder, constraintDeclRef);
+ if (!supType)
{
- if (semantics)
- semantics->ensureDecl(genericTypeConstraintDecl, DeclCheckState::ReadyForReference);
- auto constraintDeclRef =
- astBuilder->getDirectDeclRef<GenericTypeConstraintDecl>(genericTypeConstraintDecl);
- auto supType = getSup(astBuilder, constraintDeclRef);
- if (!supType)
- {
- args.add(astBuilder->getErrorType());
- shouldCache = false;
- continue;
- }
- auto witness = astBuilder->getDeclaredSubtypeWitness(
- getSub(astBuilder, constraintDeclRef),
- getSup(astBuilder, constraintDeclRef),
- constraintDeclRef);
- // TODO: this is an ugly hack to prevent crashing.
- // In early stages of compilation witness->sub and witness->sup may not be checked yet.
- // When semanticVisitor is present we have used that to ensure the type is checked.
- // However due to how the code is written we cannot guarantee semanticVisitor is always
- // available here, and if we can't get the checked sup/sub type this subst is incomplete
- // and should not be cached.
- if (!witness->getSub())
- shouldCache = false;
- args.add(witness);
+ args.add(astBuilder->getErrorType());
+ shouldCache = false;
+ continue;
}
+ auto witness = astBuilder->getDeclaredSubtypeWitness(
+ getSub(astBuilder, constraintDeclRef),
+ getSup(astBuilder, constraintDeclRef),
+ constraintDeclRef);
+ // TODO: this is an ugly hack to prevent crashing.
+ // In early stages of compilation witness->sub and witness->sup may not be checked yet.
+ // When semanticVisitor is present we have used that to ensure the type is checked.
+ // However due to how the code is written we cannot guarantee semanticVisitor is always
+ // available here, and if we can't get the checked sup/sub type this subst is incomplete
+ // and should not be cached.
+ if (!witness->getSub())
+ shouldCache = false;
+ args.add(witness);
}
if (shouldCache)
@@ -9219,9 +9229,9 @@ void SemanticsVisitor::checkForRedeclaration(Decl* decl)
// We will now look for other declarations with
// the same name in the same parent/container.
//
- parentDecl->buildMemberDictionary();
- for (auto oldDecl = newDecl->nextInContainerWithSameName; oldDecl;
- oldDecl = oldDecl->nextInContainerWithSameName)
+
+ for (auto oldDecl = parentDecl->getPrevDirectMemberDeclWithSameName(newDecl); oldDecl;
+ oldDecl = parentDecl->getPrevDirectMemberDeclWithSameName(oldDecl))
{
// For each matching declaration, we will check
// whether the redeclaration should be allowed,
@@ -9497,20 +9507,20 @@ AssignExpr* SemanticsDeclBodyVisitor::createMemberAssignmentExpr(
Expr* SemanticsDeclBodyVisitor::createCtorParamExpr(ConstructorDecl* ctor, Index paramIndex)
{
- if (paramIndex < ctor->members.getCount())
- {
- if (auto param = as<ParamDecl>(ctor->members[paramIndex]))
- {
- auto paramType = param->getType();
- auto paramExpr = m_astBuilder->create<VarExpr>();
- paramExpr->scope = ctor->ownedScope;
- paramExpr->declRef = param;
- paramExpr->type = paramType;
- paramExpr->loc = param->loc;
- return paramExpr;
- }
- }
- return nullptr;
+ if (paramIndex >= ctor->getDirectMemberDeclCount())
+ return nullptr;
+
+ auto param = as<ParamDecl>(ctor->getDirectMemberDecl(paramIndex));
+ if (!param)
+ return nullptr;
+
+ auto paramType = param->getType();
+ auto paramExpr = m_astBuilder->create<VarExpr>();
+ paramExpr->scope = ctor->ownedScope;
+ paramExpr->declRef = param;
+ paramExpr->type = paramType;
+ paramExpr->loc = param->loc;
+ return paramExpr;
}
void SemanticsDeclBodyVisitor::synthesizeCtorBodyForBases(
@@ -9581,27 +9591,24 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBodyForBases(
}
}
-void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMember(
+void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMemberVar(
ConstructorDecl* ctor,
- Decl* member,
+ VarDeclBase* varDeclBase,
ThisExpr* thisExpr,
Dictionary<Decl*, Expr*>& cachedDeclToCheckedVar,
SeqStmt* seqStmtChild,
bool isMemberInitCtor,
Index& paramIndex)
{
- auto varDeclBase = as<VarDeclBase>(member);
-
// Static variables are initialized at start of runtime, not inside a constructor
// Once thing to notice is that if a member variable doesn't have name, it must be synthesized
// instead of defined by user, we should not put it into the constructor because it's not a real
// member.
- if (!varDeclBase || varDeclBase->hasModifier<HLSLStaticModifier>() ||
- varDeclBase->getName() == nullptr)
+ if (varDeclBase->hasModifier<HLSLStaticModifier>() || varDeclBase->getName() == nullptr)
return;
Expr* initExpr = nullptr;
- auto structDecl = as<StructDecl>(member->parentDecl);
+ auto structDecl = as<StructDecl>(varDeclBase->parentDecl);
bool useParamList = isMemberInitCtor;
useParamList = isMemberInitCtor && structDecl->m_membersVisibleInCtor.contains(varDeclBase);
@@ -9630,21 +9637,21 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMember(
}
}
- auto assign = createMemberAssignmentExpr(thisExpr, ctor->ownedScope, member, initExpr);
+ auto assign = createMemberAssignmentExpr(thisExpr, ctor->ownedScope, varDeclBase, initExpr);
if (!assign)
return;
auto stmt = m_astBuilder->create<ExpressionStmt>();
stmt->expression = assign;
- stmt->loc = member->loc;
+ stmt->loc = varDeclBase->loc;
Expr* checkedMemberVarExpr;
- if (cachedDeclToCheckedVar.containsKey(member))
- checkedMemberVarExpr = cachedDeclToCheckedVar[member];
+ if (cachedDeclToCheckedVar.containsKey(varDeclBase))
+ checkedMemberVarExpr = cachedDeclToCheckedVar[varDeclBase];
else
{
checkedMemberVarExpr = CheckTerm(assign->left);
- cachedDeclToCheckedVar.add({member, checkedMemberVarExpr});
+ cachedDeclToCheckedVar.add({varDeclBase, checkedMemberVarExpr});
}
seqStmtChild->stmts.add(stmt);
@@ -9667,29 +9674,25 @@ void SemanticsDeclBodyVisitor::maybeInsertDefaultInitExpr(StructDecl* structDecl
thisExpr->scope = ctor->ownedScope;
thisExpr->type = ctor->returnType.type;
auto seqStmtChild = m_astBuilder->create<SeqStmt>();
- seqStmtChild->stmts.reserve(structDecl->members.getCount());
- for (auto& member : structDecl->members)
+ for (auto varDeclBase : structDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- if (auto varDeclBase = as<VarDeclBase>(member))
- {
- if (varDeclBase->hasModifier<HLSLStaticModifier>() ||
- varDeclBase->getName() == nullptr || varDeclBase->initExpr == nullptr)
- continue;
+ if (varDeclBase->hasModifier<HLSLStaticModifier>() ||
+ varDeclBase->getName() == nullptr || varDeclBase->initExpr == nullptr)
+ continue;
- auto assign = createMemberAssignmentExpr(
- thisExpr,
- ctor->ownedScope,
- member,
- varDeclBase->initExpr);
- if (!assign)
- continue;
+ auto assign = createMemberAssignmentExpr(
+ thisExpr,
+ ctor->ownedScope,
+ varDeclBase,
+ varDeclBase->initExpr);
+ if (!assign)
+ continue;
- auto stmt = m_astBuilder->create<ExpressionStmt>();
- stmt->expression = assign;
- stmt->loc = member->loc;
- seqStmtChild->stmts.add(stmt);
- }
+ auto stmt = m_astBuilder->create<ExpressionStmt>();
+ stmt->expression = assign;
+ stmt->loc = varDeclBase->loc;
+ seqStmtChild->stmts.add(stmt);
}
if (seqStmtChild->stmts.getCount() != 0)
{
@@ -9709,8 +9712,6 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBody(
{
auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor);
auto seqStmtChild = m_astBuilder->create<SeqStmt>();
- seqStmtChild->stmts.reserve(
- inheritanceDefaultCtorList.getCount() + structDecl->members.getCount());
ThisExpr* thisExpr = m_astBuilder->create<ThisExpr>();
thisExpr->scope = ctor->ownedScope;
@@ -9737,11 +9738,11 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBody(
ioParamIndex);
// Then synthesize the initialization of the other members.
- for (auto& m : structDecl->members)
+ for (auto directMemberVarDecl : structDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- synthesizeCtorBodyForMember(
+ synthesizeCtorBodyForMemberVar(
ctor,
- m,
+ directMemberVarDecl,
thisExpr,
cachedDeclToCheckedVar,
seqStmtChild,
@@ -9792,12 +9793,9 @@ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl)
DeclRefType::create(m_astBuilder, structDecl),
m_astBuilder->getDefaultInitializableType(),
IsSubTypeOptions::None);
- for (auto m : structDecl->members)
+ for (auto varDeclBase : structDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- auto varDeclBase = as<VarDeclBase>(m);
- if (!varDeclBase)
- continue;
- ensureDecl(m->getDefaultDeclRef(), DeclCheckState::DefaultConstructorReadyForUse);
+ ensureDecl(varDeclBase->getDefaultDeclRef(), DeclCheckState::DefaultConstructorReadyForUse);
if (!isDefaultInitializableType || varDeclBase->initExpr)
continue;
varDeclBase->initExpr = constructDefaultInitExprForType(this, varDeclBase);
@@ -9811,9 +9809,9 @@ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl)
auto seqStmt = as<SeqStmt>(as<BlockStmt>(structDeclInfo.defaultCtor->body)->body);
if (seqStmt && seqStmt->stmts.getCount() == 0)
{
- structDecl->members.remove(structDeclInfo.defaultCtor);
- structDecl->invalidateMemberDictionary();
- structDecl->buildMemberDictionary();
+ structDecl
+ ->_removeDirectMemberConstructorDeclBecauseSynthesizedAnotherDefaultConstructorInstead(
+ structDeclInfo.defaultCtor);
}
}
}
@@ -10225,12 +10223,22 @@ error:;
void SemanticsDeclBasesVisitor::_validateExtensionDeclMembers(ExtensionDecl* decl)
{
- for (auto m : decl->members)
+ for (auto ctor : decl->getDirectMemberDeclsOfType<ConstructorDecl>())
{
- auto ctor = as<ConstructorDecl>(m);
- if (!ctor || !ctor->body || ctor->members.getCount() != 0)
+ // Note(tfoley): AFAICT, the logic here is enforcing that an
+ // `extension` declaration cannot introduce a default constructor,
+ // unless it introduces that default constructor without a body.
+ //
+ // If the constructor declaration is without a body, we allow it
+ // here, and if it has a non-zero number of direct member declarations
+ // (which this code is assuming will be equivalent to just the
+ // parameter declarations), we also allow it.
+ //
+ // The underlying rationale
+
+ if (!ctor->body || ctor->getDirectMemberDeclCount() != 0)
continue;
- getSink()->diagnose(m->loc, Diagnostics::invalidMemberTypeInExtension, m->astNodeType);
+ getSink()->diagnose(ctor, Diagnostics::invalidMemberTypeInExtension, ctor->astNodeType);
}
}
@@ -10861,18 +10869,22 @@ String getSimpleModuleName(Name* name)
return String(slice.head(dotPos));
}
-ModuleDeclarationDecl* findExistingModuleDeclarationDecl(ModuleDecl* decl)
+ModuleDeclarationDecl* findExistingModuleDeclarationDecl(ModuleDecl* moduleDecl)
{
- if (decl->members.getCount() == 0)
+ auto firstMemberOfModule = moduleDecl->getFirstDirectMemberDecl();
+ if (!firstMemberOfModule)
return nullptr;
- if (auto rs = as<ModuleDeclarationDecl>(decl->members[0]))
- return rs;
- for (auto fileDecl : decl->getMembersOfType<FileDecl>())
+
+ if (auto found = as<ModuleDeclarationDecl>(firstMemberOfModule))
+ return found;
+
+ for (auto fileDecl : moduleDecl->getMembersOfType<FileDecl>())
{
- if (fileDecl->members.getCount() == 0)
+ auto firstMemberOfFile = fileDecl->getFirstDirectMemberDecl();
+ if (!firstMemberOfFile)
continue;
- if (auto rs = as<ModuleDeclarationDecl>(fileDecl->members[0]))
- return rs;
+ if (auto found = as<ModuleDeclarationDecl>(firstMemberOfFile))
+ return found;
}
return nullptr;
}
@@ -10902,11 +10914,11 @@ void SemanticsDeclHeaderVisitor::visitIncludeDecl(IncludeDecl* decl)
if (!isNew)
return;
- if (fileDecl->members.getCount() == 0)
+ auto firstDeclInFile = fileDecl->getFirstDirectMemberDecl();
+ if (!firstDeclInFile)
return;
- auto firstMember = fileDecl->members[0];
- if (auto moduleDeclaration = as<ModuleDeclarationDecl>(firstMember))
+ if (auto moduleDeclaration = as<ModuleDeclarationDecl>(firstDeclInFile))
{
// We are trying to include a file that defines a module, the user could mean "import"
// instead.
@@ -10920,25 +10932,25 @@ void SemanticsDeclHeaderVisitor::visitIncludeDecl(IncludeDecl* decl)
importFileDeclIntoScope(moduleDecl->ownedScope, fileDecl);
- if (auto implementing = as<ImplementingDecl>(firstMember))
+ if (auto implementing = as<ImplementingDecl>(firstDeclInFile))
{
// The file we are including must be implementing the current module.
auto moduleName = getSimpleModuleName(implementing->moduleNameAndLoc.name);
auto expectedModuleName = moduleDecl->getName();
bool shouldSkipDiagnostic = false;
- if (moduleDecl->members.getCount())
+ if (auto firstDeclInModule = moduleDecl->getFirstDirectMemberDecl())
{
- if (auto moduleDeclarationDecl = as<ModuleDeclarationDecl>(moduleDecl->members[0]))
+ if (auto moduleDeclarationDecl = as<ModuleDeclarationDecl>(firstDeclInModule))
{
expectedModuleName = moduleDeclarationDecl->getName();
}
else if (getShared()->isInLanguageServer())
{
- auto moduleDeclarationDecls = findExistingModuleDeclarationDecl(moduleDecl);
- if (moduleDeclarationDecls)
+ auto existingModuleDeclarationDecl = findExistingModuleDeclarationDecl(moduleDecl);
+ if (existingModuleDeclarationDecl)
{
- expectedModuleName = moduleDeclarationDecls->getName();
+ expectedModuleName = existingModuleDeclarationDecl->getName();
}
else
{
@@ -11020,17 +11032,18 @@ void SemanticsDeclScopeWiringVisitor::visitImplementingDecl(ImplementingDecl* de
if (!isNew)
return;
- if (!fileDecl || fileDecl->members.getCount() == 0)
- {
+ if (!fileDecl)
+ return;
+
+ auto firstDeclInFile = fileDecl->getFirstDirectMemberDecl();
+ if (!firstDeclInFile)
return;
- }
- auto firstMember = fileDecl->members[0];
- if (as<ModuleDeclarationDecl>(firstMember))
+ if (as<ModuleDeclarationDecl>(firstDeclInFile))
{
// We are trying to implement a file that defines a module, this is expected.
}
- else if (as<ImplementingDecl>(firstMember))
+ else if (as<ImplementingDecl>(firstDeclInFile))
{
getSink()->diagnose(
decl->moduleNameAndLoc.loc,
@@ -11118,11 +11131,10 @@ void SemanticsDeclScopeWiringVisitor::visitNamespaceDecl(NamespaceDecl* decl)
for (auto scope = parentScope; scope; scope = scope->nextSibling)
{
auto container = scope->containerDecl;
- auto nsDeclPtr = container->getMemberDictionary().tryGetValue(decl->getName());
- if (!nsDeclPtr)
+ auto nsDecl = container->findLastDirectMemberDeclOfName(decl->getName());
+ if (!nsDecl)
continue;
- auto nsDecl = *nsDeclPtr;
- for (auto ns = nsDecl; ns; ns = ns->nextInContainerWithSameName)
+ for (auto ns = nsDecl; ns; ns = container->getPrevDirectMemberDeclWithSameName(ns))
{
if (ns == decl)
continue;
@@ -11281,7 +11293,7 @@ void SharedSemanticsContext::registerCandidateExtension(
}
bool hasInheritanceMember = false;
bool hasImplicitCastMember = false;
- for (auto member : extDecl->members)
+ for (auto member : extDecl->getDirectMemberDecls())
{
if (as<InheritanceDecl>(member))
{
@@ -11829,6 +11841,95 @@ ContainerDecl* findDeclsLowestCommonAncestor(Decl*& a, Decl*& b)
return a->parentDecl;
}
+static int _compareDeclsInCommonParentByOrderOfDeclaration(
+ ContainerDecl* commonParent,
+ Decl* lhs,
+ Decl* rhs)
+{
+ if (lhs == rhs)
+ return 0;
+
+ SLANG_ASSERT(commonParent);
+ SLANG_ASSERT(lhs);
+ SLANG_ASSERT(rhs);
+ SLANG_ASSERT(lhs->parentDecl == commonParent);
+ SLANG_ASSERT(rhs->parentDecl == commonParent);
+
+ // Without doing some kind of caching on `commonParent` (which
+ // would bloat the storage of every `ContainerDecl` just to
+ // support this one use case), the worst-cast complexity of
+ // this operation is always going to be linear in the number
+ // of declarations in `commonParent`.
+ //
+ // In an attempt to optimize for the common case, we will assume
+ // that one or the other of the declarations is near the beginning
+ // or end of the sequence of children.
+ //
+ Count childCount = commonParent->getDirectMemberDeclCount();
+ Index loIndex = 0;
+ Index hiIndex = childCount - 1;
+ for (;;)
+ {
+ SLANG_ASSERT(loIndex < hiIndex);
+
+ auto loDecl = commonParent->getDirectMemberDecl(loIndex);
+ auto hiDecl = commonParent->getDirectMemberDecl(hiIndex);
+
+ // TODO(tfoley): There is a frustratingly subtle issue lurking
+ // in the Slang codebase, where operations (notably including
+ // the reflection API's `getTypeParameterConstraintType()`)
+ // assume that the a generic with N type parameters will have
+ // N constraints, with one constraint per type parameter,
+ // in a matching order.
+ //
+ // This assumption is fundamentally *not* guaranteed by the
+ // Slang compiler, but it has worked often enough in practice
+ // that code has ended up depending on this behavior.
+ //
+ // The long/short is that the ordering of the comparisons here
+ // (which cases return `-1` vs. `1`) is important for not
+ // breaking at least one Slang test, and may also have consequences
+ // for other code.
+ //
+ // We need to audit all of the code that is looking up constraints
+ // on generic declarations and trying to associate constraints
+ // with specific parameters and... well, in the ideal case *stop*
+ // them from doing so, because it isn't always a reasonable way
+ // to do things (e.g., there are constraints that would be missed
+ // if code only pays attention to constraints that have one of
+ // the generic parameters on their left-hand-side). Given that
+ // we probably can't fully deprecate things like the reflection
+ // API operations that rely on this assumption, we should instead
+ // author an as-correct-as-possible version of things that, given
+ // the index of a generic (type) parameter, collects all of the
+ // (conformance) constraints with that parameter on the left-hand-side
+ // and forms a conjunction of the interfaces on the right-hand-side.
+ //
+ // (Alternatively we could separate the storage of the original
+ // parameters/constraints as they were declared, vs. the canonicalized
+ // constraints, and only have the reflection API access the former)
+
+ if (loDecl == lhs)
+ return 1;
+ if (loDecl == rhs)
+ return -1;
+
+ if (hiDecl == lhs)
+ return -1;
+ if (hiDecl == rhs)
+ return 1;
+
+ loIndex++;
+ hiIndex--;
+
+ if (loIndex >= hiIndex)
+ {
+ SLANG_UNEXPECTED("failed to find lhs or rhs in common parent");
+ UNREACHABLE_RETURN(0);
+ }
+ }
+}
+
int compareDecls(Decl& lhs, Decl& rhs)
{
int res = compareThreeWays(lhs.astNodeType, rhs.astNodeType);
@@ -11836,9 +11937,36 @@ int compareDecls(Decl& lhs, Decl& rhs)
return res;
Decl* lLCAChild = &lhs;
Decl* rLCAChild = &rhs;
+
+ // TODO(tfoley): This logic implements rules that provide very
+ // little stability of generated mangled names, in cases where
+ // declarations might ever get reordered.
+ //
+ // A more flexible solution would favor comparing declarations
+ // by name whenever possible, along the lines of:
+ //
+ // * For each declaration identify it's deepest ancestor that
+ // has a meaningful stable name (anything like a module,
+ // namespace, type, function, etc. and not anything like
+ // a parameter, local declaration, etc.)
+ //
+ // * Compare those deepest ancestors by name lexicographically,
+ // from the root down. If the module names differ, that's
+ // enough to go by. If they are in the same moduel but in
+ // different types, then use that. If one path is a prefix
+ // of the other, then that establishes an ordering.
+ //
+ // * Only if the above wasn't enough to disambiguate things would
+ // we fall back to anthing based on order of declaration, and
+ // even *then* we would probably want to have some safety rails
+ // in place to identify what kinds of declarations are forcing
+ // us down that path, and ensuring that they are kinds of
+ // declarations we explicitly need/want to support here (e.g.,
+ // generic parameters).
+ //
if (ContainerDecl* lca = findDeclsLowestCommonAncestor(lLCAChild, rLCAChild))
{
- res = compareThreeWays(lca->getDeclIndex(lLCAChild), lca->getDeclIndex(rLCAChild));
+ res = _compareDeclsInCommonParentByOrderOfDeclaration(lca, lLCAChild, rLCAChild);
}
else
{
@@ -12078,7 +12206,7 @@ void checkDerivativeAttributeImpl(
auto appExpr = ctx.getASTBuilder()->create<GenericAppExpr>();
Index count = 0;
- for (auto member : genericDecl->members)
+ for (auto member : genericDecl->getDirectMemberDecls())
{
if (as<GenericTypeParamDecl>(member) || as<GenericValueParamDecl>(member) ||
as<GenericTypePackParamDecl>(member))
@@ -13131,7 +13259,8 @@ bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* struct
ConstructorDecl* ctor = createCtor(structDecl, ctorVisibility);
ctor->addFlavor(ConstructorDecl::ConstructorFlavor::SynthesizedMemberInit);
- ctor->members.reserve(resultMembers.getCount());
+ List<Decl*> ctorParamsBuiltInReverseOrder;
+ ctorParamsBuiltInReverseOrder.reserve(resultMembers.getCount());
// 2. Add the parameter list
bool stopProcessingDefaultValues = false;
@@ -13163,7 +13292,7 @@ bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* struct
ctorParam->nameAndLoc = NameLoc(paramName, ctor->loc);
ctorParam->loc = ctor->loc;
- ctor->members.add(ctorParam);
+ ctorParamsBuiltInReverseOrder.add(ctorParam);
// We need to ensure member is `no_diff` if it cannot be differentiated, `ctor`
// modifiers do not matter in this case since member-wise ctor is always differentiable
@@ -13175,7 +13304,11 @@ bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* struct
addModifier(ctorParam, noDiffMod);
}
}
- ctor->members.reverse();
+ ctorParamsBuiltInReverseOrder.reverse();
+ for (auto ctorParam : ctorParamsBuiltInReverseOrder)
+ {
+ ctor->addDirectMemberDecl(ctorParam);
+ }
return true;
}
@@ -13247,20 +13380,22 @@ void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl)
}
const auto backingMemberIndex = groupInfo[0].memberIndex;
- structDecl->members.insert(backingMemberIndex, backingMember);
- structDecl->invalidateMemberDictionary();
+
+ structDecl->_insertDirectMemberDeclAtIndexForBitfieldPropertyBackingMember(
+ backingMemberIndex,
+ backingMember);
+
++memberIndex;
}
- structDecl->buildMemberDictionary();
// Reset everything
backingWidth = 0;
totalWidth = 0;
groupInfo.clear();
};
- for (; memberIndex < structDecl->members.getCount(); ++memberIndex)
+ for (; memberIndex < structDecl->getDirectMemberDeclCount(); ++memberIndex)
{
- const auto& m = structDecl->members[memberIndex];
+ const auto& m = structDecl->getDirectMemberDecl(memberIndex);
// We can trivially skip any non-property decls
const auto v = as<PropertyDecl>(m);
@@ -13737,7 +13872,7 @@ static inline void _dispatchCapabilitiesVisitorOfFunctionDecl(
{
visitor->setParentFuncOfVisitor(funcDecl);
- for (auto member : funcDecl->members)
+ for (auto member : funcDecl->getDirectMemberDecls())
{
visitor->ensureDecl(member, DeclCheckState::CapabilityChecked);
_propagateRequirement(
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index f4c8cd847..a530eb8f0 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -455,21 +455,24 @@ DeclRefExpr* SemanticsVisitor::ConstructDeclRefExpr(
// Another exception is if we are accessing a property
// that provides a [nonmutating] setter.
- if (!expr->type.isLeftValue && as<PropertyDecl>(declRef.getDecl()))
+ if (!expr->type.isLeftValue)
{
- bool isLValue = false;
- for (auto member : as<ContainerDecl>(declRef.getDecl())->members)
+ if (auto propertyDecl = as<PropertyDecl>(declRef.getDecl()))
{
- if (as<SetterDecl>(member) || as<RefAccessorDecl>(member))
+ bool isLValue = false;
+ for (auto member : propertyDecl->getDirectMemberDeclsOfType<AccessorDecl>())
{
- if (member->findModifier<NonmutatingAttribute>())
+ if (as<SetterDecl>(member) || as<RefAccessorDecl>(member))
{
- isLValue = true;
+ if (member->findModifier<NonmutatingAttribute>())
+ {
+ isLValue = true;
+ }
+ break;
}
- break;
}
+ expr->type.isLeftValue = isLValue;
}
- expr->type.isLeftValue = isLValue;
}
}
else
@@ -479,7 +482,7 @@ DeclRefExpr* SemanticsVisitor::ConstructDeclRefExpr(
if (auto propertyDecl = as<PropertyDecl>(declRef.getDecl()))
{
bool isLValue = false;
- for (auto member : propertyDecl->members)
+ for (auto member : propertyDecl->getDirectMemberDeclsOfType<AccessorDecl>())
{
if (as<SetterDecl>(member) || as<RefAccessorDecl>(member))
{
@@ -681,12 +684,11 @@ Expr* SemanticsVisitor::maybeUseSynthesizedDeclForLookupResult(
createDefaultSubstitutionsIfNeeded(m_astBuilder, this, makeDeclRef(structDecl));
typeDef->type.type = DeclRefType::create(m_astBuilder, synthDeclRef);
- structDecl->members.add(typeDef);
+ structDecl->addDirectMemberDecl(typeDef);
synthesizedDecl->nameAndLoc.name = item.declRef.getName();
synthesizedDecl->loc = parent->loc;
- parent->addMember(synthesizedDecl);
- parent->invalidateMemberDictionary();
+ parent->addDirectMemberDecl(synthesizedDecl);
// Mark the newly synthesized decl as `ToBeSynthesized` so future checking can
// differentiate it from user-provided definitions, and proceed to fill in its
@@ -711,8 +713,7 @@ Expr* SemanticsVisitor::maybeUseSynthesizedDeclForLookupResult(
synthesizedDecl = parent;
- parent->addMember(typeDef);
- parent->invalidateMemberDictionary();
+ parent->addDirectMemberDecl(typeDef);
markSelfDifferentialMembersOfType(parent, subType);
}
@@ -1293,17 +1294,14 @@ bool SemanticsVisitor::canStructBeUsedAsSelfDifferentialType(AggTypeDecl* aggTyp
// and their differential types are the same as the original types.
//
bool canBeUsed = true;
- for (auto member : aggTypeDecl->members)
+ for (auto varDecl : aggTypeDecl->getDirectMemberDeclsOfType<VarDecl>())
{
- if (auto varDecl = as<VarDecl>(member))
+ // Try to get the differential type of the member.
+ Type* diffType = tryGetDifferentialType(getASTBuilder(), varDecl->getType());
+ if (!diffType || !diffType->equals(varDecl->getType()))
{
- // Try to get the differential type of the member.
- Type* diffType = tryGetDifferentialType(getASTBuilder(), varDecl->getType());
- if (!diffType || !diffType->equals(varDecl->getType()))
- {
- canBeUsed = false;
- break;
- }
+ canBeUsed = false;
+ break;
}
}
return canBeUsed;
@@ -4290,7 +4288,7 @@ Expr* SemanticsExprVisitor::visitLambdaExpr(LambdaExpr* lambdaExpr)
{
nameBuilder << getText(m_parentFunc->getName());
nameBuilder << "_";
- nameBuilder << m_parentFunc->members.getCount();
+ nameBuilder << m_parentFunc->getDirectMemberDeclCount();
}
auto name = getName(nameBuilder.getBuffer());
lambdaStructDecl->nameAndLoc.name = name;
@@ -4315,7 +4313,7 @@ Expr* SemanticsExprVisitor::visitLambdaExpr(LambdaExpr* lambdaExpr)
synthesizer.popScope();
funcDecl->body = lambdaExpr->bodyStmt;
- for (auto param : lambdaExpr->paramScopeDecl->members)
+ for (auto param : lambdaExpr->paramScopeDecl->getDirectMemberDecls())
{
funcDecl->addMember(param);
}
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index e5249ac88..1d38fa802 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -273,20 +273,17 @@ AttributeDecl* SemanticsVisitor::lookUpAttributeDecl(Name* attributeName, Scope*
//
// TODO: This step should skip `static` fields.
//
- for (auto member : structDecl->members)
+ for (auto varMember : structDecl->getDirectMemberDeclsOfType<VarDecl>())
{
- if (auto varMember = as<VarDecl>(member))
- {
- ensureDecl(varMember, DeclCheckState::CanUseTypeOfValueDecl);
+ ensureDecl(varMember, DeclCheckState::CanUseTypeOfValueDecl);
- ParamDecl* paramDecl = m_astBuilder->create<ParamDecl>();
- paramDecl->nameAndLoc = member->nameAndLoc;
- paramDecl->type = varMember->type;
- paramDecl->loc = member->loc;
- paramDecl->setCheckState(DeclCheckState::DefinitionChecked);
+ ParamDecl* paramDecl = m_astBuilder->create<ParamDecl>();
+ paramDecl->nameAndLoc = varMember->nameAndLoc;
+ paramDecl->type = varMember->type;
+ paramDecl->loc = varMember->loc;
+ paramDecl->setCheckState(DeclCheckState::DefinitionChecked);
- attrDecl->addMember(paramDecl);
- }
+ attrDecl->addMember(paramDecl);
}
// We need to end by putting the new attribute declaration
@@ -298,8 +295,6 @@ AttributeDecl* SemanticsVisitor::lookUpAttributeDecl(Name* attributeName, Scope*
//
parentDecl->addMember(attrDecl);
- SLANG_ASSERT(!parentDecl->isMemberDictionaryValid());
-
// Finally, we perform any required semantic checks on
// the newly constructed attribute decl.
//
@@ -1660,11 +1655,17 @@ Modifier* SemanticsVisitor::checkModifier(
auto checkedAttr = checkAttribute(hlslUncheckedAttribute, syntaxNode);
- if (as<UnscopedEnumAttribute>(checkedAttr))
+ if (auto unscopedEnumAttr = as<UnscopedEnumAttribute>(checkedAttr))
{
- if (auto parentDecl = as<ContainerDecl>(getParentDecl(as<Decl>(syntaxNode))))
- parentDecl->invalidateMemberDictionary();
- return getASTBuilder()->create<TransparentModifier>();
+ auto transparentModifier = getASTBuilder()->create<TransparentModifier>();
+ if (auto parentDecl = getParentDecl(as<Decl>(syntaxNode)))
+ {
+ parentDecl
+ ->_invalidateLookupAcceleratorsBecauseUnscopedEnumAttributeWillBeTurnedIntoTransparentModifier(
+ unscopedEnumAttr,
+ transparentModifier);
+ }
+ return transparentModifier;
}
return checkedAttr;
}
@@ -1940,7 +1941,7 @@ Modifier* SemanticsVisitor::checkModifier(
// specialization constant with this ID.
Int specConstId = cintVal->getValue();
- for (auto member : decl->parentDecl->members)
+ for (auto member : decl->parentDecl->getDirectMemberDecls())
{
auto constantId = member->findModifier<VkConstantIdAttribute>();
if (constantId)
@@ -2215,14 +2216,8 @@ void SemanticsVisitor::checkRayPayloadStructFields(StructDecl* structDecl)
const HashSet<String> validStages("anyhit", "closesthit", "miss", "caller");
// Check each field in the struct
- for (auto member : structDecl->members)
+ for (auto fieldVarDecl : structDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- auto fieldVarDecl = as<VarDeclBase>(member);
- if (!fieldVarDecl)
- {
- continue;
- }
-
auto readModifier = fieldVarDecl->findModifier<RayPayloadReadSemantic>();
auto writeModifier = fieldVarDecl->findModifier<RayPayloadWriteSemantic>();
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp
index f13f9a99e..8fbdceabb 100644
--- a/source/slang/slang-check-overload.cpp
+++ b/source/slang/slang-check-overload.cpp
@@ -71,7 +71,7 @@ SemanticsVisitor::ParamCounts SemanticsVisitor::CountParameters(
SemanticsVisitor::ParamCounts SemanticsVisitor::CountParameters(DeclRef<GenericDecl> genericRef)
{
ParamCounts counts = {0, 0};
- for (auto m : genericRef.getDecl()->members)
+ for (auto m : genericRef.getDecl()->getDirectMemberDecls())
{
if (auto typeParam = as<GenericTypeParamDecl>(m))
{
@@ -1169,9 +1169,9 @@ Expr* SemanticsVisitor::CompleteOverloadCandidate(
if (auto subscriptDeclRef = candidate.item.declRef.as<SubscriptDecl>())
{
const auto& decl = subscriptDeclRef.getDecl();
- for (auto member : decl->members)
+ for (auto accessorDecl : decl->getDirectMemberDeclsOfType<AccessorDecl>())
{
- if (as<SetterDecl>(member) || as<RefAccessorDecl>(member))
+ if (as<SetterDecl>(accessorDecl) || as<RefAccessorDecl>(accessorDecl))
{
// If the subscript decl has a setter,
// then the call is an l-value if base is l-value.
@@ -1186,7 +1186,7 @@ Expr* SemanticsVisitor::CompleteOverloadCandidate(
// Otherwise, if the accessor is [nonmutating], we can
// also consider the result of the subscript call as l-value
// regardless of the base.
- if (member->findModifier<NonmutatingAttribute>())
+ if (accessorDecl->findModifier<NonmutatingAttribute>())
{
callExpr->type.isLeftValue = true;
break;
diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp
index a57e01a88..e6744071b 100644
--- a/source/slang/slang-check-shader.cpp
+++ b/source/slang/slang-check-shader.cpp
@@ -156,7 +156,7 @@ void EntryPoint::_collectGenericSpecializationParamsRec(Decl* decl)
if (!genericDecl)
return;
- for (auto m : genericDecl->members)
+ for (auto m : genericDecl->getDirectMemberDecls())
{
if (auto genericTypeParam = as<GenericTypeParamDecl>(m))
{
@@ -774,7 +774,7 @@ void Module::_collectShaderParams()
for (Index i = 0; i < workList.getCount(); i++)
{
auto moduleDecl = workList[i];
- for (auto globalDecl : moduleDecl->members)
+ for (auto globalDecl : moduleDecl->getDirectMemberDecls())
{
if (auto globalVar = as<VarDecl>(globalDecl))
{
diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp
index 9d1899462..faf25b716 100644
--- a/source/slang/slang-check-stmt.cpp
+++ b/source/slang/slang-check-stmt.cpp
@@ -76,10 +76,9 @@ void SemanticsStmtVisitor::visitBlockStmt(BlockStmt* stmt)
// Make sure to fully check all nested agg type decls first.
if (stmt->scopeDecl)
{
- for (auto decl : stmt->scopeDecl->members)
+ for (auto aggDecl : stmt->scopeDecl->getDirectMemberDeclsOfType<AggTypeDeclBase>())
{
- if (as<AggTypeDeclBase>(decl))
- ensureAllDeclsRec(decl, DeclCheckState::DefinitionChecked);
+ ensureAllDeclsRec(aggDecl, DeclCheckState::DefinitionChecked);
}
// Consider this code:
diff --git a/source/slang/slang-check-type.cpp b/source/slang/slang-check-type.cpp
index b5f5240a5..bdf9c829a 100644
--- a/source/slang/slang-check-type.cpp
+++ b/source/slang/slang-check-type.cpp
@@ -294,7 +294,7 @@ bool SemanticsVisitor::CoerceToProperTypeImpl(
ensureDecl(genericDeclRef, DeclCheckState::CanSpecializeGeneric);
List<Val*> args;
List<Val*> witnessArgs;
- for (Decl* member : genericDeclRef.getDecl()->members)
+ for (Decl* member : genericDeclRef.getDecl()->getDirectMemberDecls())
{
if (auto typeParam = as<GenericTypeParamDecl>(member))
{
@@ -333,43 +333,36 @@ bool SemanticsVisitor::CoerceToProperTypeImpl(
}
}
- for (Decl* member : genericDeclRef.getDecl()->members)
+ for (auto constraintParam :
+ genericDeclRef.getDecl()->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto constraintParam = as<GenericTypeConstraintDecl>(member))
+ auto genericParam = as<DeclRefType>(constraintParam->sub.type)->getDeclRef();
+ if (!genericParam)
+ return false;
+ auto genericTypeParamDecl = as<GenericTypeParamDecl>(genericParam.getDecl());
+ if (!genericTypeParamDecl)
{
- auto genericParam = as<DeclRefType>(constraintParam->sub.type)->getDeclRef();
- if (!genericParam)
- return false;
- auto genericTypeParamDecl = as<GenericTypeParamDecl>(genericParam.getDecl());
- if (!genericTypeParamDecl)
- {
- diagSink->diagnose(typeExp.exp, Diagnostics::genericTypeNeedsArgs, typeExp);
- return false;
- }
- auto defaultType = CheckProperType(genericTypeParamDecl->initType);
- if (!defaultType)
- {
- diagSink->diagnose(typeExp.exp, Diagnostics::genericTypeNeedsArgs, typeExp);
- return false;
- }
- auto witness =
- tryGetSubtypeWitness(defaultType, CheckProperType(constraintParam->sup));
- if (!witness)
- {
- // diagnose
- getSink()->diagnose(
- genericTypeParamDecl->initType.exp,
- Diagnostics::typeArgumentDoesNotConformToInterface,
- defaultType,
- constraintParam->sup);
- return false;
- }
- witnessArgs.add(witness);
+ diagSink->diagnose(typeExp.exp, Diagnostics::genericTypeNeedsArgs, typeExp);
+ return false;
+ }
+ auto defaultType = CheckProperType(genericTypeParamDecl->initType);
+ if (!defaultType)
+ {
+ diagSink->diagnose(typeExp.exp, Diagnostics::genericTypeNeedsArgs, typeExp);
+ return false;
}
- else
+ auto witness = tryGetSubtypeWitness(defaultType, CheckProperType(constraintParam->sup));
+ if (!witness)
{
- // ignore non-parameter members
+ // diagnose
+ getSink()->diagnose(
+ genericTypeParamDecl->initType.exp,
+ Diagnostics::typeArgumentDoesNotConformToInterface,
+ defaultType,
+ constraintParam->sup);
+ return false;
}
+ witnessArgs.add(witness);
}
// Combine args and witnessArgs
args.addRange(witnessArgs);
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 4e114eb78..8cb50c1e9 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -2942,7 +2942,7 @@ void Module::_discoverEntryPointsImpl(
DiagnosticSink* sink,
const List<RefPtr<TargetRequest>>& targets)
{
- for (auto globalDecl : containerDecl->members)
+ for (auto globalDecl : containerDecl->getDirectMemberDecls())
{
auto maybeFuncDecl = globalDecl;
if (auto genericDecl = as<GenericDecl>(maybeFuncDecl))
diff --git a/source/slang/slang-doc-ast.cpp b/source/slang/slang-doc-ast.cpp
index 7e83d5d59..e6259167b 100644
--- a/source/slang/slang-doc-ast.cpp
+++ b/source/slang/slang-doc-ast.cpp
@@ -76,7 +76,7 @@ static void _addDeclRec(Decl* decl, List<Decl*>& outDecls)
{
// Add the container - which could be a class, struct, enum, namespace, extension, generic
// etc. Now add what the container contains
- for (Decl* childDecl : containerDecl->members)
+ for (Decl* childDecl : containerDecl->getDirectMemberDecls())
{
_addDeclRec(childDecl, outDecls);
}
@@ -85,7 +85,7 @@ static void _addDeclRec(Decl* decl, List<Decl*>& outDecls)
/* static */ void ASTMarkupUtil::findDecls(ModuleDecl* moduleDecl, List<Decl*>& outDecls)
{
- for (Decl* decl : moduleDecl->members)
+ for (Decl* decl : moduleDecl->getDirectMemberDecls())
{
_addDeclRec(decl, outDecls);
}
diff --git a/source/slang/slang-doc-markdown-writer.cpp b/source/slang/slang-doc-markdown-writer.cpp
index f9d615ddb..2a9a83361 100644
--- a/source/slang/slang-doc-markdown-writer.cpp
+++ b/source/slang/slang-doc-markdown-writer.cpp
@@ -17,12 +17,9 @@ namespace Slang
template<typename T>
static void _getDecls(ContainerDecl* containerDecl, List<T*>& out)
{
- for (Decl* decl : containerDecl->members)
+ for (auto decl : containerDecl->getDirectMemberDeclsOfType<T>())
{
- if (T* declAsType = as<T>(decl))
- {
- out.add(declAsType);
- }
+ out.add(decl);
}
}
@@ -32,7 +29,7 @@ static void _getDeclsOfType(
ContainerDecl* containerDecl,
List<Decl*>& out)
{
- for (Decl* decl : containerDecl->members)
+ for (Decl* decl : containerDecl->getDirectMemberDecls())
{
if (as<T>(decl))
{
@@ -385,24 +382,21 @@ DocMarkdownWriter::NameAndText DocMarkdownWriter::_getNameAndText(
else if (auto typeParam = as<GenericTypeParamDeclBase>(decl))
{
bool isFirst = true;
- for (auto member : decl->parentDecl->members)
+ for (auto constraint : decl->parentDecl->getDirectMemberDeclsOfType<TypeConstraintDecl>())
{
- if (auto constraint = as<TypeConstraintDecl>(member))
+ if (isDeclRefTypeOf<Decl>(getSub(m_astBuilder, constraint)).getDecl() == typeParam)
{
- if (isDeclRefTypeOf<Decl>(getSub(m_astBuilder, constraint)).getDecl() == typeParam)
+ if (isFirst)
{
- if (isFirst)
- {
- sb << ": ";
- isFirst = false;
- }
- else
- {
- sb << ", ";
- }
- sb << constraint->getSup().type->toString();
- break;
+ sb << ": ";
+ isFirst = false;
+ }
+ else
+ {
+ sb << ", ";
}
+ sb << constraint->getSup().type->toString();
+ break;
}
}
if (auto genericTypeParam = as<GenericTypeParamDecl>(decl))
@@ -634,20 +628,24 @@ void DocMarkdownWriter::writeProperty(const ASTMarkup::Entry& entry, PropertyDec
propertyDecl->type->toText(typeSB);
out << translateToHTMLWithLinks(propertyDecl, typeSB.produceString());
out << "\n{\n";
- for (auto member : propertyDecl->members)
+ for (auto accessor : propertyDecl->getDirectMemberDeclsOfType<AccessorDecl>())
{
- if (as<GetterDecl>(member))
+ if (as<GetterDecl>(accessor))
{
out << " get;\n";
}
- else if (as<SetterDecl>(member))
+ else if (as<SetterDecl>(accessor))
{
out << " set;\n";
}
- else if (as<RefAccessorDecl>(member))
+ else if (as<RefAccessorDecl>(accessor))
{
out << " ref;\n";
}
+ else
+ {
+ SLANG_UNEXPECTED("unhandled accessor type");
+ }
}
out << "}\n</pre>\n\n";
@@ -792,7 +790,7 @@ void DocMarkdownWriter::writeExtensionConditions(
if (auto targetTypeParentGenericDecl =
as<GenericDecl>(targetTypeDeclRef.getDecl()->parentDecl))
{
- for (auto member : targetTypeParentGenericDecl->members)
+ for (auto member : targetTypeParentGenericDecl->getDirectMemberDecls())
{
if (auto typeParamDecl = as<GenericTypeParamDeclBase>(member))
{
@@ -827,20 +825,19 @@ void DocMarkdownWriter::writeExtensionConditions(
// `T`.
// Find constraints on the originalParamDecl.
- for (auto member : genericParamDecl->parentDecl->members)
+ for (auto typeConstraint :
+ genericParamDecl->parentDecl
+ ->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto typeConstraint = as<GenericTypeConstraintDecl>(member))
+ if (isDeclRefTypeOf<Decl>(typeConstraint->sub.type).getDecl() ==
+ genericParamDecl)
{
- if (isDeclRefTypeOf<Decl>(typeConstraint->sub.type).getDecl() ==
- genericParamDecl)
+ if (typeConstraint->isEqualityConstraint)
{
- if (typeConstraint->isEqualityConstraint)
- {
- isEqualityConstraint = true;
- }
- constraintVal = typeConstraint->getSup().type;
- break;
+ isEqualityConstraint = true;
}
+ constraintVal = typeConstraint->getSup().type;
+ break;
}
}
}
@@ -982,22 +979,20 @@ void DocMarkdownWriter::writeSignature(CallableDecl* callableDecl)
if (auto genericParent = as<GenericDecl>(parentDecl->parentDecl))
{
- for (auto member : genericParent->members)
+ for (auto typeConstraint :
+ genericParent->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto typeConstraint = as<GenericTypeConstraintDecl>(member))
- {
- out << toSlice("\n <span class='code_keyword'>where</span> ");
- out << translateToHTMLWithLinks(
- parentDecl,
- getSub(m_astBuilder, typeConstraint)->toString());
- if (typeConstraint->isEqualityConstraint)
- out << " == ";
- else
- out << toSlice(" : ");
- out << translateToHTMLWithLinks(
- parentDecl,
- getSup(m_astBuilder, typeConstraint)->toString());
- }
+ out << toSlice("\n <span class='code_keyword'>where</span> ");
+ out << translateToHTMLWithLinks(
+ parentDecl,
+ getSub(m_astBuilder, typeConstraint)->toString());
+ if (typeConstraint->isEqualityConstraint)
+ out << " == ";
+ else
+ out << toSlice(" : ");
+ out << translateToHTMLWithLinks(
+ parentDecl,
+ getSup(m_astBuilder, typeConstraint)->toString());
}
}
parentDecl = getParentDecl(parentDecl);
@@ -1238,29 +1233,6 @@ void DocMarkdownWriter::_maybeAppendRequirements(
out << toSlice("\n");
}
-static Decl* _getSameNameDecl(ContainerDecl* parentDecl, Decl* decl)
-{
- Decl* result = nullptr;
- parentDecl->getMemberDictionary().tryGetValue(decl->getName(), result);
- return result;
-}
-
-static bool _isFirstOverridden(Decl* decl)
-{
- decl = _getSameNameDecl(as<ContainerDecl>(getParentDecl(decl)), decl);
-
- ContainerDecl* parentDecl = decl->parentDecl;
-
- Name* declName = decl->getName();
- if (declName)
- {
- Decl** firstDeclPtr = parentDecl->getMemberDictionary().tryGetValue(declName);
- return (firstDeclPtr && *firstDeclPtr == decl) || (firstDeclPtr == nullptr);
- }
-
- return false;
-}
-
void ParsedDescription::write(DocMarkdownWriter* writer, Decl* decl, StringBuilder& out)
{
for (auto span : spans)
@@ -1550,12 +1522,10 @@ void DocMarkdownWriter::writeCallableOverridable(
{
for (auto& entry : page->entries)
{
- Decl* sameNameDecl = _getSameNameDecl(
- as<ContainerDecl>(getParentDecl((Decl*)entry->m_node)),
- callableDecl);
+ auto entryDecl = (Decl*)entry->m_node;
+ auto parentDecl = getParentDecl(entryDecl);
- for (Decl* curDecl = sameNameDecl; curDecl;
- curDecl = curDecl->nextInContainerWithSameName)
+ for (auto curDecl : parentDecl->getDirectMemberDeclsOfName(entryDecl->getName()))
{
CallableDecl* sig = nullptr;
if (GenericDecl* genericDecl = as<GenericDecl>(curDecl))
@@ -1643,7 +1613,7 @@ void DocMarkdownWriter::writeCallableOverridable(
// associated with this callable.
if (genericDecl)
{
- for (Decl* decl : genericDecl->members)
+ for (Decl* decl : genericDecl->getDirectMemberDecls())
{
if (as<GenericTypeParamDeclBase>(decl) || as<GenericValueParamDecl>(decl))
{
@@ -1893,15 +1863,13 @@ void DocMarkdownWriter::writeAggType(
baseTypes = _getAsStringList(inheritanceDecls);
for (auto entry : page->entries)
{
- for (auto member : as<ContainerDecl>(entry->m_node)->members)
+ for (auto inheritanceDecl :
+ as<ContainerDecl>(entry->m_node)->getDirectMemberDeclsOfType<InheritanceDecl>())
{
- if (auto inheritanceDecl = as<InheritanceDecl>(member))
+ if (auto extDecl = as<ExtensionDecl>(entry->m_node))
{
- if (auto extDecl = as<ExtensionDecl>(entry->m_node))
- {
- conditionalConformanceExts.add(extDecl);
- conditionalBaseTypes.add(inheritanceDecl->base->toString());
- }
+ conditionalConformanceExts.add(extDecl);
+ conditionalBaseTypes.add(inheritanceDecl->base->toString());
}
}
}
@@ -2016,11 +1984,8 @@ void DocMarkdownWriter::writeAggType(
out << "## Conditional Conformances\n\n";
for (auto ext : conditionalConformanceExts)
{
- for (auto member : ext->members)
+ for (auto inheritanceDecl : ext->getDirectMemberDeclsOfType<InheritanceDecl>())
{
- auto inheritanceDecl = as<InheritanceDecl>(member);
- if (!inheritanceDecl)
- continue;
out << "### Conformance to ";
out << escapeMarkdownText(inheritanceDecl->base.type->toString());
out << "\n";
@@ -2362,7 +2327,7 @@ void DeclDocumentation::writeGenericParameters(
// The parameters, in order
List<Decl*> params;
- for (Decl* member : genericDecl->members)
+ for (Decl* member : genericDecl->getDirectMemberDecls())
{
if (as<GenericTypeParamDeclBase>(member) || as<GenericValueParamDecl>(member))
{
@@ -2449,12 +2414,9 @@ void DocMarkdownWriter::createPage(ASTMarkup::Entry& entry, Decl* decl)
return;
}
- if (CallableDecl* callableDecl = as<CallableDecl>(decl))
+ if (as<CallableDecl>(decl))
{
- if (_isFirstOverridden(callableDecl))
- {
- ensureDeclPageCreated(entry);
- }
+ ensureDeclPageCreated(entry);
}
else if (as<EnumDecl>(decl))
{
@@ -2538,7 +2500,7 @@ DocumentPage* DocMarkdownWriter::findPageForToken(
continue;
if (auto genericParent = as<GenericDecl>(containerDecl->parentDecl))
{
- for (auto member : genericParent->members)
+ for (auto member : genericParent->getDirectMemberDecls())
{
if (getText(member->getName()) == token)
{
@@ -2551,7 +2513,7 @@ DocumentPage* DocMarkdownWriter::findPageForToken(
}
}
}
- for (auto member : containerDecl->members)
+ for (auto member : containerDecl->getDirectMemberDecls())
{
if (as<ParamDecl>(member) || as<EnumCaseDecl>(member))
{
diff --git a/source/slang/slang-language-server-ast-lookup.cpp b/source/slang/slang-language-server-ast-lookup.cpp
index 53a9f81b9..6c5935992 100644
--- a/source/slang/slang-language-server-ast-lookup.cpp
+++ b/source/slang/slang-language-server-ast-lookup.cpp
@@ -835,7 +835,7 @@ bool _findAstNodeImpl(ASTLookupContext& context, SyntaxNode* node)
}
if (shouldInspectChildren)
{
- for (auto member : container->members)
+ for (auto member : container->getDirectMemberDecls())
{
if (_findAstNodeImpl(context, member))
return true;
diff --git a/source/slang/slang-language-server-document-symbols.cpp b/source/slang/slang-language-server-document-symbols.cpp
index e8a041ca8..d5335a3ef 100644
--- a/source/slang/slang-language-server-document-symbols.cpp
+++ b/source/slang/slang-language-server-document-symbols.cpp
@@ -139,7 +139,7 @@ static void _getDocumentSymbolsImpl(
if (!context.processedDecls.add(parent))
return;
auto srcManager = context.linkage->getSourceManager();
- for (auto child : containerDecl->members)
+ for (auto child : containerDecl->getDirectMemberDecls())
{
if (auto genericDecl = as<GenericDecl>(child))
{
diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp
index 1813fa953..59a9854f0 100644
--- a/source/slang/slang-language-server.cpp
+++ b/source/slang/slang-language-server.cpp
@@ -526,21 +526,24 @@ void appendDefinitionLocation(StringBuilder& sb, Workspace* workspace, const Hum
HumaneSourceLoc getModuleLoc(SourceManager* manager, ContainerDecl* moduleDecl)
{
- if (moduleDecl)
- {
- if (moduleDecl->members.getCount() && moduleDecl->members[0])
- {
- auto loc = moduleDecl->members[0]->loc;
- if (loc.isValid())
- {
- auto location = manager->getHumaneLoc(loc, SourceLocType::Actual);
- location.line = 1;
- location.column = 1;
- return location;
- }
- }
- }
- return HumaneSourceLoc();
+ if (!moduleDecl)
+ return HumaneSourceLoc();
+
+ if (moduleDecl->getDirectMemberDeclCount() == 0)
+ return HumaneSourceLoc();
+
+ auto firstDecl = moduleDecl->getDirectMemberDecl(0);
+ if (!firstDecl)
+ return HumaneSourceLoc();
+
+ auto loc = firstDecl->loc;
+ if (!loc.isValid())
+ return HumaneSourceLoc();
+
+ auto location = manager->getHumaneLoc(loc, SourceLocType::Actual);
+ location.line = 1;
+ location.column = 1;
+ return location;
}
SlangResult LanguageServer::hover(
diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp
index a2284eaa8..d03d763b8 100644
--- a/source/slang/slang-lookup.cpp
+++ b/source/slang/slang-lookup.cpp
@@ -189,7 +189,7 @@ static void _lookUpDirectAndTransparentMembers(
{
// If we are looking up for completion suggestions,
// return all the members that are available.
- for (auto member : containerDecl->members)
+ for (auto member : containerDecl->getDirectMemberDecls())
{
if (!request.shouldConsiderAllLocalNames() && _isUncheckedLocalVar(member))
continue;
@@ -204,15 +204,13 @@ static void _lookUpDirectAndTransparentMembers(
}
else
{
- // Look up the declarations with the chosen name in the container.
- Decl* firstDecl = nullptr;
- containerDecl->getMemberDictionary().tryGetValue(name, firstDecl);
-
- // Now iterate over those declarations (if any) and see if
- // we find any that meet our filtering criteria.
+ // Iterate over the declarations with the chosen name in the container
+ // (if any), and see if we find any that meet our filtering criteria.
+ //
// For example, we might be filtering so that we only consider
// type declarations.
- for (auto m = firstDecl; m; m = m->nextInContainerWithSameName)
+ //
+ for (auto m : containerDecl->getDirectMemberDeclsOfName(name))
{
// Skip this declaration if we are checking and this hasn't been
// checked yet. Because we traverse block statements in order, if
@@ -247,12 +245,12 @@ static void _lookUpDirectAndTransparentMembers(
if (((int)request.options & (int)LookupOptions::IgnoreTransparentMembers) != 0)
return;
- for (auto transparentInfo : containerDecl->getTransparentMembers())
+ for (auto transparentMemberDecl : containerDecl->getTransparentDirectMemberDecls())
{
// The reference to the transparent member should use the same
// path as we used in referring to its parent.
DeclRef<Decl> transparentMemberDeclRef =
- astBuilder->getMemberDeclRef(parentDeclRef, transparentInfo.decl);
+ astBuilder->getMemberDeclRef(parentDeclRef, transparentMemberDecl);
if (transparentMemberDeclRef.getDecl() == request.declToExclude)
continue;
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index bc00eb531..5400ab166 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -3857,7 +3857,7 @@ struct ExprLoweringContext
auto genDecl = genSubst->getGenericDecl();
Index argCounter = 0;
- for (auto memberDecl : genDecl->members)
+ for (auto memberDecl : genDecl->getDirectMemberDecls())
{
if (auto typeParamDecl = as<GenericTypeParamDecl>(memberDecl))
{
@@ -3868,12 +3868,10 @@ struct ExprLoweringContext
_lowerSubstitutionArg(subContext, genSubst, valParamDecl, argCounter++);
}
}
- for (auto memberDecl : genDecl->members)
+ for (auto constraintDecl :
+ genDecl->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto constraintDecl = as<GenericTypeConstraintDecl>(memberDecl))
- {
- _lowerSubstitutionArg(subContext, genSubst, constraintDecl, argCounter++);
- }
+ _lowerSubstitutionArg(subContext, genSubst, constraintDecl, argCounter++);
}
}
// TODO: also need to handle this-type substitution here?
@@ -8115,7 +8113,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
LoweredValInfo visitExtensionDecl(ExtensionDecl* decl)
{
- for (auto& member : decl->members)
+ for (auto& member : decl->getDirectMemberDecls())
ensureDecl(context, member);
return LoweredValInfo();
}
@@ -9210,17 +9208,18 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// First, compute the number of requirement entries that will be included in this
// interface type.
UInt operandCount = 0;
- for (auto requirementDecl : decl->members)
+ for (auto requirementDecl : decl->getDirectMemberDecls())
{
if (as<GenericDecl>(requirementDecl))
requirementDecl = getInner(requirementDecl);
if (as<SubscriptDecl>(requirementDecl) || as<PropertyDecl>(requirementDecl))
{
- for (auto accessorDecl : as<ContainerDecl>(requirementDecl)->members)
+ for (auto accessorDecl :
+ as<ContainerDecl>(requirementDecl)->getDirectMemberDeclsOfType<AccessorDecl>())
{
- if (as<AccessorDecl>(accessorDecl))
- operandCount++;
+ SLANG_UNUSED(accessorDecl);
+ operandCount++;
}
}
if (!shouldDeclBeTreatedAsInterfaceRequirement(requirementDecl))
@@ -9359,7 +9358,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
context->setValue(requirementDeclRef.getDecl(), LoweredValInfo::simple(entry));
}
};
- for (auto requirementDecl : decl->members)
+ for (auto requirementDecl : decl->getDirectMemberDecls())
{
auto requirementKey = getInterfaceRequirementKey(requirementDecl);
if (!requirementKey)
@@ -9373,19 +9372,15 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
if (as<PropertyDecl>(requirementDecl) || as<SubscriptDecl>(requirementDecl))
{
- for (auto member : as<ContainerDecl>(requirementDecl)->members)
+ for (auto accessorDecl : as<ContainerDecl>(requirementDecl)
+ ->getDirectMemberDeclsOfType<AccessorDecl>())
{
- if (auto accessorDecl = as<AccessorDecl>(member))
+ auto accessorKey = getInterfaceRequirementKey(accessorDecl);
+ if (accessorKey)
{
- auto accessorKey = getInterfaceRequirementKey(accessorDecl);
- if (accessorKey)
- {
- auto accessorDeclRef = createDefaultSpecializedDeclRef(
- subContext,
- nullptr,
- accessorDecl);
- addEntry(accessorKey, accessorDeclRef);
- }
+ auto accessorDeclRef =
+ createDefaultSpecializedDeclRef(subContext, nullptr, accessorDecl);
+ addEntry(accessorKey, accessorDeclRef);
}
}
}
@@ -9914,7 +9909,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
//
// First we start with type and value parameters,
// in the order they were declared.
- for (auto member : genericDecl->members)
+ for (auto member : genericDecl->getDirectMemberDecls())
{
if (auto typeParamDecl = as<GenericTypeParamDeclBase>(member))
{
@@ -9937,12 +9932,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
}
// Then we emit constraint parameters, again in
// declaration order.
- for (auto member : genericDecl->members)
+ for (auto constraintDecl :
+ genericDecl->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto constraintDecl = as<GenericTypeConstraintDecl>(member))
- {
- emitGenericConstraintDecl(subContext, constraintDecl);
- }
+ emitGenericConstraintDecl(subContext, constraintDecl);
}
return irGeneric;
@@ -11934,21 +11927,21 @@ static void ensureAllDeclsRec(IRGenContext* context, Decl* decl)
//
if (auto containerDecl = as<AggTypeDeclBase>(decl))
{
- for (auto memberDecl : containerDecl->members)
+ for (auto memberDecl : containerDecl->getDirectMemberDecls())
{
ensureAllDeclsRec(context, memberDecl);
}
}
else if (auto namespaceDecl = as<NamespaceDecl>(decl))
{
- for (auto memberDecl : namespaceDecl->members)
+ for (auto memberDecl : namespaceDecl->getDirectMemberDecls())
{
ensureAllDeclsRec(context, memberDecl);
}
}
else if (auto fileDecl = as<FileDecl>(decl))
{
- for (auto memberDecl : fileDecl->members)
+ for (auto memberDecl : fileDecl->getDirectMemberDecls())
{
ensureAllDeclsRec(context, memberDecl);
}
@@ -12025,7 +12018,7 @@ RefPtr<IRModule> generateIRForTranslationUnit(
//
// Next, ensure that all other global declarations have
// been emitted.
- for (auto decl : translationUnit->getModuleDecl()->members)
+ for (auto decl : translationUnit->getModuleDecl()->getDirectMemberDecls())
{
ensureAllDeclsRec(context, decl);
}
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 431cf6669..49e0704bc 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -3785,9 +3785,6 @@ static NodeBase* parseNamespaceDecl(Parser* parser, void* /*userData*/)
// function `foo` has been defined), and direct member
// lookup will only give us the first.
//
- Decl* firstDecl = nullptr;
- parentDecl->getMemberDictionary().tryGetValue(nameAndLoc.name, firstDecl);
- //
// We will search through the declarations of the name
// and find the first that is a namespace (if any).
//
@@ -3797,7 +3794,7 @@ static NodeBase* parseNamespaceDecl(Parser* parser, void* /*userData*/)
// as possible in the parser, and we'd rather be
// as permissive as possible right now.
//
- for (Decl* d = firstDecl; d; d = d->nextInContainerWithSameName)
+ for (auto d : parentDecl->getDirectMemberDeclsOfName(nameAndLoc.name))
{
namespaceDecl = as<NamespaceDecl>(d);
if (namespaceDecl)
diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp
index 258266da5..c7349b5d3 100644
--- a/source/slang/slang-reflection-api.cpp
+++ b/source/slang/slang-reflection-api.cpp
@@ -3600,7 +3600,7 @@ SLANG_API unsigned int spReflectionDecl_getChildrenCount(SlangReflectionDecl* pa
Decl* decl = (Decl*)parentDecl;
if (as<ContainerDecl>(decl))
{
- return (unsigned int)as<ContainerDecl>(decl)->members.getCount();
+ return (unsigned int)as<ContainerDecl>(decl)->getDirectMemberDeclCount();
}
return 0;
@@ -3613,8 +3613,8 @@ SLANG_API SlangReflectionDecl* spReflectionDecl_getChild(
Decl* decl = (Decl*)parentDecl;
if (auto containerDecl = as<ContainerDecl>(decl))
{
- if (containerDecl->members.getCount() > index)
- return (SlangReflectionDecl*)containerDecl->members[index];
+ if (containerDecl->getDirectMemberDeclCount() > index)
+ return (SlangReflectionDecl*)containerDecl->getDirectMemberDecl(index);
}
return nullptr;
diff --git a/source/slang/slang-serialize-ast.cpp b/source/slang/slang-serialize-ast.cpp
index 9fa338449..c5e54b835 100644
--- a/source/slang/slang-serialize-ast.cpp
+++ b/source/slang/slang-serialize-ast.cpp
@@ -10,6 +10,7 @@
namespace Slang
{
+
// TODO(tfoley): have the parser export this, or a utility function
// for initializing a `SyntaxDecl` in the common case.
//
@@ -434,6 +435,11 @@ void serialize(ASTSerializer const& serializer, NameLoc& value)
serialize(serializer, value.loc);
}
+void serialize(ASTSerializer const& serializer, ContainerDeclDirectMemberDecls& value)
+{
+ serialize(serializer, value._refDecls());
+}
+
#if 0 // FIDDLE TEMPLATE:
%for _,T in ipairs(Slang.NodeBase.subclasses) do
void _serializeASTNodeContents(ASTSerializer const& serializer, $T* value)
@@ -594,7 +600,7 @@ private:
void _assignGenericParameterIndices(GenericDecl* genericDecl)
{
int parameterCounter = 0;
- for (auto m : genericDecl->members)
+ for (auto m : genericDecl->getDirectMemberDecls())
{
if (auto typeParam = as<GenericTypeParamDeclBase>(m))
{
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
index e45311abc..55ed224cb 100644
--- a/source/slang/slang-syntax.cpp
+++ b/source/slang/slang-syntax.cpp
@@ -1093,44 +1093,44 @@ ModuleDecl* getModuleDecl(Scope* scope)
return nullptr;
}
-Decl* getParentDecl(Decl* decl)
+ContainerDecl* getParentDecl(Decl* decl)
{
- decl = decl->parentDecl;
- while (as<GenericDecl>(decl))
- decl = decl->parentDecl;
- return decl;
+ auto parentDecl = decl->parentDecl;
+ while (auto genericDecl = as<GenericDecl>(parentDecl))
+ parentDecl = genericDecl->parentDecl;
+ return parentDecl;
}
-Decl* getParentAggTypeDecl(Decl* decl)
+AggTypeDecl* getParentAggTypeDecl(Decl* decl)
{
decl = decl->parentDecl;
while (decl)
{
- if (as<AggTypeDecl>(decl))
- return decl;
+ if (auto found = as<AggTypeDecl>(decl))
+ return found;
decl = decl->parentDecl;
}
return nullptr;
}
-Decl* getParentAggTypeDeclBase(Decl* decl)
+AggTypeDeclBase* getParentAggTypeDeclBase(Decl* decl)
{
decl = decl->parentDecl;
while (decl)
{
- if (as<AggTypeDeclBase>(decl))
- return decl;
+ if (auto found = as<AggTypeDeclBase>(decl))
+ return found;
decl = decl->parentDecl;
}
return nullptr;
}
-Decl* getParentFunc(Decl* decl)
+FunctionDeclBase* getParentFunc(Decl* decl)
{
while (decl)
{
- if (as<FunctionDeclBase>(decl))
- return decl;
+ if (auto found = as<FunctionDeclBase>(decl))
+ return found;
decl = decl->parentDecl;
}
return nullptr;
diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h
index 97f829b59..1b5fc005d 100644
--- a/source/slang/slang-syntax.h
+++ b/source/slang/slang-syntax.h
@@ -61,7 +61,7 @@ inline FilteredMemberRefList<Decl> getGenericMembers(
{
return FilteredMemberRefList<Decl>(
astBuilder,
- genericInnerDecl.getParent().getDecl()->members,
+ genericInnerDecl.getParent().getDecl()->getDirectMemberDecls(),
genericInnerDecl,
filterStyle);
}
@@ -73,7 +73,7 @@ inline FilteredMemberRefList<Decl> getMembers(
{
return FilteredMemberRefList<Decl>(
astBuilder,
- declRef.getDecl()->members,
+ declRef.getDecl()->getDirectMemberDecls(),
declRef,
filterStyle);
}
@@ -84,7 +84,22 @@ inline FilteredMemberRefList<T> getMembersOfType(
DeclRef<ContainerDecl> declRef,
MemberFilterStyle filterStyle = MemberFilterStyle::All)
{
- return FilteredMemberRefList<T>(astBuilder, declRef.getDecl()->members, declRef, filterStyle);
+ // TODO: This should in principle be using:
+ //
+ // declRef.getDecl()->getDirectMemberDeclsOfType<T>()
+ //
+ // instead of:
+ //
+ // declRef.getDecl()->getDirectMemberDecls()
+ //
+ // and then the `FilteredMemberRefList` would only be responsible for
+ // filtering, plus associated each `T*` in the list with a `DeclRef<T>`.
+ //
+ return FilteredMemberRefList<T>(
+ astBuilder,
+ declRef.getDecl()->getDirectMemberDecls(),
+ declRef,
+ filterStyle);
}
void _foreachDirectOrExtensionMemberOfType(
@@ -373,10 +388,10 @@ ModuleDecl* getModuleDecl(Scope* scope);
Module* getModule(Decl* decl);
/// Get the parent decl, skipping any generic decls in between.
-Decl* getParentDecl(Decl* decl);
-Decl* getParentAggTypeDecl(Decl* decl);
-Decl* getParentAggTypeDeclBase(Decl* decl);
-Decl* getParentFunc(Decl* decl);
+ContainerDecl* getParentDecl(Decl* decl);
+AggTypeDecl* getParentAggTypeDecl(Decl* decl);
+AggTypeDeclBase* getParentAggTypeDeclBase(Decl* decl);
+FunctionDeclBase* getParentFunc(Decl* decl);
} // namespace Slang
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index b2171823b..61a453f37 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -5761,7 +5761,7 @@ void TypeLayoutContext::buildExternTypeMap()
if (auto scopeDecl = as<ScopeDecl>(decl))
{
- for (auto member : scopeDecl->members)
+ for (auto member : scopeDecl->getDirectMemberDecls())
{
go(go, member);
}
@@ -5771,7 +5771,7 @@ void TypeLayoutContext::buildExternTypeMap()
for (const auto& m : linkage->loadedModulesList)
{
const auto& ast = m->getModuleDecl();
- for (auto member : ast->members)
+ for (auto member : ast->getDirectMemberDecls())
{
processDecl(processDecl, member);
}
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index d66e86b2d..daebddeae 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -2994,17 +2994,14 @@ static void collectExportedConstantInContainer(
ASTBuilder* builder,
ContainerDecl* containerDecl)
{
- for (auto m : containerDecl->members)
+ for (auto varMember : containerDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- auto varMember = as<VarDeclBase>(m);
- if (!varMember)
- continue;
if (!varMember->val)
continue;
bool isExported = false;
bool isConst = false;
bool isExtern = false;
- for (auto modifier : m->modifiers)
+ for (auto modifier : varMember->modifiers)
{
if (as<HLSLExportModifier>(modifier))
isExported = true;
@@ -3018,14 +3015,14 @@ static void collectExportedConstantInContainer(
}
if (isExported && isConst)
{
- auto mangledName = getMangledName(builder, m);
+ auto mangledName = getMangledName(builder, varMember);
if (isExtern && dict.containsKey(mangledName))
continue;
dict[mangledName] = varMember->val;
}
}
- for (auto member : containerDecl->members)
+ for (auto member : containerDecl->getDirectMemberDecls())
{
if (as<NamespaceDecl>(member) || as<FileDecl>(member))
{
@@ -5262,7 +5259,7 @@ void Module::_processFindDeclsExportSymbolsRec(Decl* decl)
// If it's a container process it's children
if (auto containerDecl = as<ContainerDecl>(decl))
{
- for (auto child : containerDecl->members)
+ for (auto child : containerDecl->getDirectMemberDecls())
{
_processFindDeclsExportSymbolsRec(child);
}
@@ -6809,12 +6806,9 @@ SlangResult Linkage::loadSerializedModuleContents(
module->_discoverEntryPoints(sink, targets);
// Hook up fileDecl's scope to module's scope.
- for (auto globalDecl : moduleDecl->members)
+ for (auto fileDecl : moduleDecl->getDirectMemberDeclsOfType<FileDecl>())
{
- if (auto fileDecl = as<FileDecl>(globalDecl))
- {
- addSiblingScopeForContainerDecl(m_astBuilder, moduleDecl->ownedScope, fileDecl);
- }
+ addSiblingScopeForContainerDecl(m_astBuilder, moduleDecl->ownedScope, fileDecl);
}
return SLANG_OK;