summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;