diff options
| author | Theresa Foley <10618364+tangent-vector@users.noreply.github.com> | 2025-06-09 11:22:51 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-09 18:22:51 +0000 |
| commit | bfae49d853e0f9b6f9de495b13bcd1642ca4a285 (patch) | |
| tree | 2f58e220b049c6deca7b5b2b3471560f6738908b /source/slang/slang-parser.cpp | |
| parent | bfac247ff2489a1f7fb9766674a6ed25a48a493b (diff) | |
Mediate access to ContainerDecl members (#7242)
Most of what this change does is straightforward: take all the places in the code that used to operate directly on `ContainerDecl::members` and related fields, and instead have them call into a smaller set of accessor methods defined on `ContainerDecl`.
The primary motivation for making this change is that in order to implement on-demand loading of members from serialized AST modules, we need a way to identify and intercept the "demand" for those members.
On-demand loading benefits from having all accesses to the members of a `ContainerDecl` be as narrow as possible.
If a part of the code only need a member at a specific index, it should say so.
If it only needs access to members with a specific name, or a given subclass of `Decl`, then it should say so.
A secondary motivation for this change is that there have recently been several changes that added complexity and special cases by introducing code that operated on (and *mutated*) the member list of a container decl in ways that the existing code had never done before.
Any code that mutates the member list of a `ContainerDecl` needs to be sure to not disrupt the invariants that the lookup acceleration structures currently rely on.
One of the recent changes added a declaration-to-index map to the set of acceleration structures (with different validation/invalidation behavior than the others...) while other recent changes would remove or insert declarations in ways that could change the indices of other declarations in the same container.
It is not clear if any of these pieces of code were aware of the others, and the invariants that might be expected or broken along the way.
This change bottlenecks the vast majority of accesses to the members of a `ContainerDecl` through the following operations:
* Getting a `List` of all of the direct member declarations of a container
* Get the number of direct member declarations, and accessing them by index.
* Looking up the list of direct member declarations with a given name.
* Adding a new direct member declaration to the end of the list.
Some other operations are layered on top of those (e.g., getting a list of all the direct member declarations of a given C++ class).
These layered operations are still centralized on the `ContainerDecl`, with the intention that we *can* change them to be non-layered implementations if we ever need to for performance (e.g., by building a lookup structure for finding member declarations by their type).
The exceptional cases of access/mutation on the direct members of a `ContainerDecl` have also been encapsulated, but rather than expose what would risk appearing like general-purpose accessors (e.g., `removeDecl(d)`, `setDecl(index)`, etc.), these operations have been explicitly named after the specific use case that they serve in the codebase today, to discourage others from using them for more kinds of operations we'd rather not support.
These operations have also been given parameter signatures that match their use cases, to make it so that even somebody determined to abuse them would have to invent suitable arguments out of thin air.
In the case of the declaration-to-index mapping, this change eliminates that acceleration structure, in favor or slightly more complicated (and possibly inefficient, yes) code at the use site.
Over time, it would be good to closely scrutinize each of the use cases that requires more complicated interaction with the members of a `ContainerDecl`, to see whether any of them can be reframed in terms of the more basic operations, or if there is some clean abstraction we can introduce to make operations that mutate the member list feel like... hacky.
Diffstat (limited to 'source/slang/slang-parser.cpp')
| -rw-r--r-- | source/slang/slang-parser.cpp | 5 |
1 files changed, 1 insertions, 4 deletions
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) |
