---
generated: true
model: claude-opus-4-8
generated_at: 2026-07-02T00:00:00+00:00
source_commit: 8e2a63cbf22c85332796702fd02a875466486a23
watched_paths_digest: 791702e985b41a9050e6b69e409b63ea1f55b1413ef661ac84540de37ab58aa2
source_doc: docs/generated/design/ast-reference/base.md
source_doc_digest: aa845ab462b17892bcb3ed3f8ee0e41dbf4e764758eb37e1bd358370513bd2cd
warning: "Auto-generated. May drift from source. Do not edit by hand."
---

# Tests for ast-reference/base

## Intent

Tests verify the abstract AST root classes described in
[`docs/generated/design/ast-reference/base.md`](../../../design/ast-reference/base.md):
`NodeBase`, `SyntaxNodeBase`, `SyntaxNode`, `Modifier`,
`ModifiableSyntaxNode`, `DeclBase`, `Decl`, `Stmt`, `Expr`, `Val`,
`Type`, `DeclRefBase`.

The doc is fundamentally about internal compiler structure that
`slangc` does not expose. Most claims at this layer are not directly
observable. The bundle therefore exercises only those claims whose
**consequences** show up in user-facing behavior — overload
resolution by expression type, source locations in diagnostics,
multiple modifiers stacking on a declaration, qualified name
resolution through a parent decl, generic substitution at a
decl-ref site, type-as-Val deduplication. Each test is small and
single-purpose; the bundle is intentionally compact (12 tests)
because the surface area of slangc-observable AST-root behaviors is
small. Coverage strategy: one basic-case observation per observable
claim, plus a negative/diagnostic probe for each claim family that
has a natural negative form (`Expr` type mismatch, undeclared
`DeclRefBase`, malformed `Type`, misplaced `Modifier`).

The bulk of the doc's structural claims — `NodeBase`'s
`astNodeType` discriminator, the `ASTBuilder` back-pointer, the
private `Val::m_operands` array, the support-type catalog — are
recorded under `## Untested claims` because they are internal to the
compiler and unobservable through any test directive that does not
link against the C++ AST headers.

Note on anchors: the current `base.md` groups `SyntaxNodeBase` under
the `### SyntaxNode (SyntaxNodeBase)` heading (anchor
`#syntaxnode-syntaxnodebase`) and describes `DeclRefBase` inside the
`### Val (NodeBase)` heading (anchor `#val-nodebase`) rather than under
dedicated headings; the SourceLoc and DeclRefBase tests anchor there
accordingly.

## Functional coverage

| Claim                                                                                                                                                                                                                             | Intent     | Anchor                                                                                                    | Tests                                                                                            |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Every Decl carries a name and a parent ContainerDecl; the same simple name can live in two different parents and be disambiguated via member-access.                                                                              | functional | [#decl-declbase](../../../design/ast-reference/base.md#decl-declbase)                                     | [`decl-name-and-parent.slang`](decl-name-and-parent.slang)                                       |
| Every Expr carries a QualType filled in by the checker; that type is what overload resolution dispatches on.                                                                                                                      | functional | [#expr-syntaxnode](../../../design/ast-reference/base.md#expr-syntaxnode)                                 | [`expr-carries-type-overload.slang`](expr-carries-type-overload.slang)                           |
| The checker fills in an Expr's QualType and then verifies it against the surrounding context; a mismatch is diagnosed at the expression's source location.                                                                        | negative   | [#expr-syntaxnode](../../../design/ast-reference/base.md#expr-syntaxnode)                                 | [`expr-type-mismatch-diagnoses.slang`](expr-type-mismatch-diagnoses.slang)                       |
| A ModifiableSyntaxNode owns a Modifiers list; the modifiers attached to a Decl actually take effect during checking (a [mutating] member function is permitted to assign through `this`).                                         | functional | [#modifiablesyntaxnode-syntaxnode](../../../design/ast-reference/base.md#modifiablesyntaxnode-syntaxnode) | [`modifiable-syntax-node-modifier-effects.slang`](modifiable-syntax-node-modifier-effects.slang) |
| Modifier derives from SyntaxNode and therefore from SyntaxNodeBase, so a Modifier carries its own SourceLoc; a misplaced attribute is diagnosed at the attribute's column, not at the host decl's column.                         | negative   | [#modifier-syntaxnode](../../../design/ast-reference/base.md#modifier-syntaxnode)                         | [`modifier-carries-source-loc.slang`](modifier-carries-source-loc.slang)                         |
| Modifiers form a linked list attached to a ModifiableSyntaxNode; multiple modifiers stack onto a single declaration and all take effect.                                                                                          | functional | [#modifier-syntaxnode](../../../design/ast-reference/base.md#modifier-syntaxnode)                         | [`modifier-list-multiple-on-decl.slang`](modifier-list-multiple-on-decl.slang)                   |
| Stmt derives from ModifiableSyntaxNode, so a statement can carry one or more modifiers (e.g. an unroll attribute on a for-statement).                                                                                             | functional | [#stmt-modifiablesyntaxnode](../../../design/ast-reference/base.md#stmt-modifiablesyntaxnode)             | [`stmt-carries-modifier.slang`](stmt-carries-modifier.slang)                                     |
| Every SyntaxNodeBase carries a SourceLoc; the diagnostic for a check-time error points at the originating syntax node's column.                                                                                                   | negative   | [#syntaxnode-syntaxnodebase](../../../design/ast-reference/base.md#syntaxnode-syntaxnodebase)             | [`syntaxnodebase-source-loc-in-diagnostic.slang`](syntaxnodebase-source-loc-in-diagnostic.slang) |
| Every type the front end works with is a Type-as-Val; an ill-formed type expression at a declaration site cannot resolve to any Type and is diagnosed.                                                                            | negative   | [#type-val](../../../design/ast-reference/base.md#type-val)                                               | [`type-malformed-diagnoses.slang`](type-malformed-diagnoses.slang)                               |
| A DeclRefBase references a declaration possibly with generic substitutions; a single generic function declaration can be referenced at two different substitutions and each reference resolves to the appropriate specialization. | functional | [#val-nodebase](../../../design/ast-reference/base.md#val-nodebase)                                       | [`declref-generic-substitution.slang`](declref-generic-substitution.slang)                       |
| A DeclRefBase resolves a use of a name to a declaration; when no matching declaration exists in any reachable scope, the checker diagnoses the unresolved reference.                                                              | negative   | [#val-nodebase](../../../design/ast-reference/base.md#val-nodebase)                                       | [`declref-undeclared-name.slang`](declref-undeclared-name.slang)                                 |
| Vals (including Types) are deduplicated by the ASTBuilder; two textually identical type expressions denote the same Val, so an overload set keyed on the type resolves identically at each use.                                   | functional | [#val-nodebase](../../../design/ast-reference/base.md#val-nodebase)                                       | [`val-type-dedup-same-overload.slang`](val-type-dedup-same-overload.slang)                       |

## Untested claims

| Claim                                                                                                                                                                                                       | Reason                 | Anchor                                                                                        | Why untested                                                                                                                                                                             |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NodeBase` carries an `astNodeType` discriminator tag set by the `ASTBuilder` at construction.                                                                                                               | internal-source-fact   | [#nodebase](../../../design/ast-reference/base.md#nodebase)                                    | An internal C++ field on every node with no user-observable consequence; `slangc` never surfaces the tag value through any CLI output or diagnostic.                                       |
| `NodeBase` holds a private `_astBuilder` back-pointer to the AST builder that allocated it.                                                                                                                  | internal-source-fact   | [#nodebase](../../../design/ast-reference/base.md#nodebase)                                    | A private field; not reachable through any slangc text output or diagnostic.                                                                                                              |
| The FIDDLE-generated `ASTNodeType` enum gives every subclass a stable integer tag at build time, powering `as<T>()` / `dynamicCast<T>()`.                                                                    | compile-time-toggle    | [#nodebase](../../../design/ast-reference/base.md#nodebase)                                    | A build-system-generated table baked into the binary; not observable at compile-request run time. The dispatch it powers has no CLI surface.                                             |
| `as<T>()` / `dynamicCast<T>()` dispatch on AST nodes uses the FIDDLE tag.                                                                                                                                    | needs-unit-test        | [#nodebase](../../../design/ast-reference/base.md#nodebase)                                    | An internal C++ API. A C++ unit test in `tools/slang-unit-test/` could construct nodes and assert the cast behavior directly; no slangc CLI surface reaches it.                          |
| `Val` uses a generic `m_operands` list rather than per-class fields for deduplication and substitution.                                                                                                      | internal-source-fact   | [#val-nodebase](../../../design/ast-reference/base.md#val-nodebase)                            | An internal storage-layout choice; the dedup *behavior* is covered by `val-type-dedup-same-overload.slang`, but the operand-list representation itself has no observable consequence.     |
| `Type::m_astBuilderForReflection` is kept for the reflection API only and is not used for semantic checking.                                                                                                 | needs-unit-test        | [#type-val](../../../design/ast-reference/base.md#type-val)                                    | Reflection-only field reachable only through the reflection API (`ISession`/`IComponentType`), not through any FileCheck-able slangc text emit; a C++ unit test could inspect it.        |
| `Decl::checkState` tracks which checking phases have completed for a declaration.                                                                                                                            | implementation-detail  | [#decl-declbase](../../../design/ast-reference/base.md#decl-declbase)                          | The phased-check state machine is internal; the doc names no externally-observable consequence of `checkState` (phase sequencing is described in `pipeline/03-semantic-check.md`).       |
| `Decl::inferredCapabilityRequirements` holds a capability set inferred during checking.                                                                                                                      | out-of-bundle          | [#decl-declbase](../../../design/ast-reference/base.md#decl-declbase)                          | Only the resulting capability-mismatch *diagnostic* is observable, and that surface is exercised by the pipeline/03-semantic-check bundle; the inferred-set field itself is not visible.  |
| `Modifier::keywordName` records the keyword/attribute name that introduced the modifier.                                                                                                                     | internal-source-fact   | [#modifier-syntaxnode](../../../design/ast-reference/base.md#modifier-syntaxnode)              | The name appears only inside diagnostic text (already exercised via `modifier-carries-source-loc.slang`); the stored `Name*` field has no independent observable surface.                 |
| `Scope` is a concrete `NodeBase` used as the runtime name-lookup data structure and does not appear in the parsed AST.                                                                                       | internal-source-fact   | [#root-hierarchy](../../../design/ast-reference/base.md#root-hierarchy)                        | A runtime helper structure, not a parsed node; its identity as a `NodeBase` has no slangc CLI surface. The lookup behavior it implements is covered by name-resolution bundles.          |
| `SyntaxClass<T>` is a reflection-style handle to a concrete AST class used by the visitor and `as<T>()` infrastructure.                                                                                       | needs-unit-test        | [#support-types](../../../design/ast-reference/base.md#support-types)                          | An internal C++ helper type; no slangc CLI surface reaches it. A C++ unit test in `tools/slang-unit-test/` could exercise it directly.                                                    |
| The support-type catalog (`DeclRef<T>`, `Modifiers`, `QualType`, `SubstitutionSet`, `LookupResult`/`LookupResultItem`, `NameLoc`, `TypeExp`, `WitnessTable`, `BuiltinOperationKind`) are non-node helpers.   | internal-source-fact   | [#support-types](../../../design/ast-reference/base.md#support-types)                          | These wrap or describe nodes; their effects bleed through into other observables (a `QualType` is what `Expr::type` carries) but the support types themselves are not surface-visible.    |

## Doc gaps observed

| Anchor                                                                     | Kind                  | Gap                                                                                                                                                                                                                                                                                                                        | Suggested addition                                                                                                                                                                    |
| -------------------------------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [#val-nodebase](../../../design/ast-reference/base.md#val-nodebase)         | missing-surface       | `DeclRefBase` is described only inside the `### Val (NodeBase)` heading, with no dedicated heading of its own; a reader looking for a `#declrefbase` anchor (which older bundles cited) finds nothing, and the decl-ref-specific claims are folded into the `Val` prose.                                                      | Promote `DeclRefBase` to its own `### DeclRefBase (Val)` subsection (mirroring `### Type (Val)`), so decl-ref claims have a stable, specific anchor separate from the generic `Val`.   |
| [#decl-declbase](../../../design/ast-reference/base.md#decl-declbase)       | undocumented-behavior | The doc lists `Decl::inferredCapabilityRequirements` and `Decl::checkState` as fields filled in during checking but names no user-facing consequence for either; it points inward to private fields rather than outward to observable behavior (capability-mismatch diagnostics, phase-ordering effects).                    | Add a one-line cross-link from `#decl-declbase` to `../pipeline/03-semantic-check.md` naming the capability-mismatch diagnostic and the phased-check sequencing as the observables.   |
| [#modifier-syntaxnode](../../../design/ast-reference/base.md#modifier-syntaxnode) | undocumented-behavior | The doc lists `Modifier::keywordName: Name*` but does not name a user-facing consequence of the keyword name beyond its appearance in diagnostics; the diagnostic-text dependency is implicit.                                                                                                                        | Add a one-line note that the `keywordName` is what surfaces in "attribute '<name>' is not valid here" style diagnostics, giving the field an observable anchor.                        |
