---
generated: true
model: claude-opus-4-7
generated_at: 2026-05-20T13:09:57Z
source_commit: 3250005059a2746ebc504a9d3f71ed112f1f2b94
watched_paths_digest: 328973beec1effabd095eb1784b812673fccfa641b71d28f1e7c83a9228ca518
source_doc: docs/generated/design/ast-reference/declarations.md
source_doc_digest: 8ee031cac40aa40c1d361b29c159ef5a472b28baec129349366fe4ffd78eac99
warning: "Auto-generated. May drift from source. Do not edit by hand."
---

# Tests for ast-reference/declarations

## Intent
Tests verify the documented user-observable roles of the concrete
`Decl` / `DeclBase` subclasses enumerated in
[`docs/generated/design/ast-reference/declarations.md`](../../../design/ast-reference/declarations.md):
`VarDecl`, `LetDecl`, `ParamDecl`, `StructDecl`, `ClassDecl`,
`EnumDecl`, `EnumCaseDecl`, `InterfaceDecl`, `InheritanceDecl`,
`ExtensionDecl`, `TypeDefDecl`, `TypeAliasDecl`, `NamespaceDecl`,
`FuncDecl`, `ConstructorDecl`, `SubscriptDecl`, `PropertyDecl` and the
`AccessorDecl` family (`GetterDecl`, `SetterDecl`, `RefAccessorDecl`),
`GenericDecl`, `GenericTypeParamDecl`, `GenericValueParamDecl`,
`GenericTypeConstraintDecl`, `AssocTypeDecl`, `ImportDecl`,
`UsingDecl`, `EmptyDecl`, `DeclGroup`, `LambdaDecl`, and
`RequireCapabilityDecl`.

The doc is fundamentally about the internal AST shape of these
classes; the user-observable surface is much smaller than the catalog
of fields. Each test therefore picks one declaration kind and writes
the smallest piece of Slang that exercises that kind's documented
role, with overload resolution, type-checking, or diagnostic
emission as the observable. Negative diagnostic tests cover the
declaration-level rejections the documented role implies
(`let` immutability, missing interface requirement, wrong
constructor arity, generic constraint violation, undeclared name,
unknown module, bad capability name).

Internal AST shape claims (parent class in the C++ hierarchy,
private field names, FIDDLE tag, ASTBuilder allocation,
synthesized-only classes that have no user spelling) are recorded
under `## Untested claims` because they are unobservable through any
allowed `slang-test` directive.


## Functional coverage
| Claim | Intent | Anchor | Tests |
| --- | --- | --- | --- |
| A PropertyDecl holds GetterDecl/SetterDecl children; reading and writing the property fires the respective accessor. | functional | [#accessordecl-family](../../../design/ast-reference/declarations.md#accessordecl-family) | [`propertydecl-getter-setter.slang`](propertydecl-getter-setter.slang) |
| A RefAccessorDecl is emitted by the HLSL backend as a return-by-reference helper; the ref accessor's body appears in the emitted text. | functional | [#accessordecl-family](../../../design/ast-reference/declarations.md#accessordecl-family) | [`refaccessor-property.slang`](refaccessor-property.slang) |
| A ClassDecl declares a reference-type aggregate; two variables can refer to the same instance and one's mutation is visible through the other. | functional | [#aggtypedecl-structdecl-classdecl-enumdecl](../../../design/ast-reference/declarations.md#aggtypedecl-structdecl-classdecl-enumdecl) | [`classdecl-reference-type.slang`](classdecl-reference-type.slang) |
| A StructDecl can nest another StructDecl as a member; the nested type is reachable through dotted member access. | functional | [#aggtypedecl-structdecl-classdecl-enumdecl](../../../design/ast-reference/declarations.md#aggtypedecl-structdecl-classdecl-enumdecl) | [`structdecl-nested-struct.slang`](structdecl-nested-struct.slang) |
| A StructDecl declares a value-type aggregate; assigning a struct copies it so the original is unchanged. | functional | [#aggtypedecl-structdecl-classdecl-enumdecl](../../../design/ast-reference/declarations.md#aggtypedecl-structdecl-classdecl-enumdecl) | [`structdecl-value-type.slang`](structdecl-value-type.slang) |
| A StructDecl is emitted as a struct type by each text-emit backend; the struct keyword and field names appear in the output. | functional | [#aggtypedecl-structdecl-classdecl-enumdecl](../../../design/ast-reference/declarations.md#aggtypedecl-structdecl-classdecl-enumdecl) | [`structdecl-emit-multitarget.slang`](structdecl-emit-multitarget.slang) |
| An EnumCaseDecl carries the case's tag value; cases compare equal to the integer they were declared with. | functional | [#enumdecl-and-enumcasedecl](../../../design/ast-reference/declarations.md#enumdecl-and-enumcasedecl) | [`enumcasedecl-tag-value.slang`](enumcasedecl-tag-value.slang) |
| An EnumDecl declares a tagged-union enum and each EnumCaseDecl is one named case; case selection picks the appropriate branch. | functional | [#enumdecl-and-enumcasedecl](../../../design/ast-reference/declarations.md#enumdecl-and-enumcasedecl) | [`enumdecl-tagged-union.slang`](enumdecl-tagged-union.slang) |
| An EnumDecl is treated as an AggTypeDecl so enum types can have conformances; an interface-constrained generic accepts an enum value. | functional | [#enumdecl-and-enumcasedecl](../../../design/ast-reference/declarations.md#enumdecl-and-enumcasedecl) | [`enumdecl-conformance.slang`](enumdecl-conformance.slang) |
| An ExtensionDecl attaches new members to an existing type; the added member is callable on values of that type. | functional | [#extensiondecl](../../../design/ast-reference/declarations.md#extensiondecl) | [`extensiondecl-adds-member.slang`](extensiondecl-adds-member.slang) |
| An ExtensionDecl can add interface conformance to an existing type; the type then dispatches through the interface. | functional | [#extensiondecl](../../../design/ast-reference/declarations.md#extensiondecl) | [`extensiondecl-adds-interface-conformance.slang`](extensiondecl-adds-interface-conformance.slang) |
| A GenericDecl wraps an inner decl with a parameter list; the same inner decl specializes differently at distinct type arguments. | functional | [#genericdecl](../../../design/ast-reference/declarations.md#genericdecl) | [`genericdecl-wrapper.slang`](genericdecl-wrapper.slang) |
| A single GenericDecl can be specialized with different value/type substitutions per call site; each specialization is independent. | functional | [#genericdecl](../../../design/ast-reference/declarations.md#genericdecl) | [`genericdecl-different-substitutions.slang`](genericdecl-different-substitutions.slang) |
| Two GenericDecls can compose: a generic struct field of a generic struct specializes when the outer specializes. | functional | [#genericdecl](../../../design/ast-reference/declarations.md#genericdecl) | [`genericdecl-recursive.slang`](genericdecl-recursive.slang) |
| An InheritanceDecl carries a witness table after checking; an interface default method is reachable through the conforming type. | functional | [#inheritancedecl](../../../design/ast-reference/declarations.md#inheritancedecl) | [`inheritancedecl-base-interface-method.slang`](inheritancedecl-base-interface-method.slang) |
| An InterfaceDecl declares an interface and InheritanceDecl ties a conforming type to it; interface-typed dispatch picks the conforming type's implementation. | functional | [#inheritancedecl](../../../design/ast-reference/declarations.md#inheritancedecl) | [`interfacedecl-and-inheritance.slang`](interfacedecl-and-inheritance.slang) |
| A NamespaceDecl introduces a named scope; members are reached with the namespace-qualified name. | functional | [#namespacedecl-moduledecl-filedecl](../../../design/ast-reference/declarations.md#namespacedecl-moduledecl-filedecl) | [`namespacedecl-qualified-lookup.slang`](namespacedecl-qualified-lookup.slang) |
| Multiple textual namespace declarations with the same name in one module are collapsed into one NamespaceDecl during parsing. | functional | [#namespacedecl-moduledecl-filedecl](../../../design/ast-reference/declarations.md#namespacedecl-moduledecl-filedecl) | [`namespacedecl-same-name-collapse.slang`](namespacedecl-same-name-collapse.slang) |
| A ConstructorDecl is a __init declaration; calling the type as a function dispatches to the constructor and initializes the struct. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`constructordecl-init.slang`](constructordecl-init.slang) |
| A ConstructorDecl's signature is part of the type's API; calling the constructor with the wrong arity is diagnosed. | negative | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`constructordecl-wrong-arity-rejected.slang`](constructordecl-wrong-arity-rejected.slang) |
| A DeclGroup wraps multiple declarations parsed as one group (int a, b;); each name is independently visible. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`declgroup-multi-var.slang`](declgroup-multi-var.slang) |
| A FuncDecl declared as a struct member becomes a method; calling the method dispatches through the receiver. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`funcdecl-member-method.slang`](funcdecl-member-method.slang) |
| A FuncDecl is an ordinary function declaration; two FuncDecls with the same name but different parameter types overload independently. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`funcdecl-and-overload.slang`](funcdecl-and-overload.slang) |
| A FuncDecl supports the modern function form `func name(...) -> T`; the arrow-return spelling produces the same callable as the C-style spelling. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`funcdecl-trailing-arrow-return.slang`](funcdecl-trailing-arrow-return.slang) |
| A GenericTypeConstraintDecl is enforced at the call site; specializing with a type that does not satisfy the constraint is diagnosed. | negative | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`generic-constraint-violation-rejected.slang`](generic-constraint-violation-rejected.slang) |
| A GenericTypeConstraintDecl records a constraint (T : I); a satisfying type argument compiles and a non-satisfying one is diagnosed. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`generic-type-constraint.slang`](generic-type-constraint.slang) |
| A GenericTypeParamDecl introduces a type parameter; the inner decl uses the parameter as a type and is specialized when called. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`generic-type-param.slang`](generic-type-param.slang) |
| A GenericValueParamDecl introduces a value parameter on a GenericDecl; the inner decl uses the value as a compile-time integer. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`generic-value-param.slang`](generic-value-param.slang) |
| A LambdaDecl is the closure-struct produced by a lambda expression; the closure is callable through the IFunc-constrained generic helper. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`lambdadecl-closure.slang`](lambdadecl-closure.slang) |
| A LetDecl is a let variable; immutable. Assignment through a let-bound name is rejected. | negative | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`letdecl-immutable.slang`](letdecl-immutable.slang) |
| A ParamDecl is a function parameter; in/out/inout direction qualifiers govern whether the callee's mutation is visible at the caller. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`paramdecl-in-out-inout.slang`](paramdecl-in-out-inout.slang) |
| A RequireCapabilityDecl is a module-level declaration that states a capability requirement; the module compiles when the target capability is met. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`requirecapabilitydecl.slang`](requirecapabilitydecl.slang) |
| A RequireCapabilityDecl with a non-existent capability name is diagnosed; the decl carries through to capability resolution. | negative | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`requirecapabilitydecl-bad-name-rejected.slang`](requirecapabilitydecl-bad-name-rejected.slang) |
| A SubscriptDecl makes the type indexable; a[i] invokes the subscript's get accessor. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`subscriptdecl-get.slang`](subscriptdecl-get.slang) |
| A TypeAliasDecl introduces a modern-syntax alias (typealias Y = X) for an existing type; the alias is interchangeable with the original. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`typealiasdecl.slang`](typealiasdecl.slang) |
| A TypeDefDecl introduces a typedef-style name for an existing type; the alias is usable wherever the original type would be. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`typedefdecl.slang`](typedefdecl.slang) |
| A UsingDecl brings names from another scope into the current one; an unqualified use of the imported name resolves. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`usingdecl-brings-name.slang`](usingdecl-brings-name.slang) |
| A VarDecl is an ordinary mutable variable; its value can be assigned and re-read. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`vardecl-mutable.slang`](vardecl-mutable.slang) |
| A VarDecl with an initExpr (Expr* initializer) populates the variable's storage with the initializer's value. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`structdecl-default-init.slang`](structdecl-default-init.slang) |
| A reference to a name with no matching Decl in scope is diagnosed; no synthetic UnresolvedDecl reaches the user. | negative | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`declref-undeclared-name-rejected.slang`](declref-undeclared-name-rejected.slang) |
| A struct with no user __init still has a synthesized member-init constructor; positional-initializer syntax fills fields in declaration order. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`constructordecl-synthesized-member-init.slang`](constructordecl-synthesized-member-init.slang) |
| An AssocTypeDecl declares an associated type in an interface; the conforming type supplies a concrete typealias and dispatch produces that type's value. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`assoctypedecl-interface.slang`](assoctypedecl-interface.slang) |
| An EmptyDecl is a declaration that exists only to carry modifiers; a bare semicolon at module scope is accepted. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`emptydecl-bare-semicolon.slang`](emptydecl-bare-semicolon.slang) |
| An ImportDecl makes the declarations of another module visible in the current scope; importing glsl makes its names usable. | functional | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`importdecl-glsl.slang`](importdecl-glsl.slang) |
| An ImportDecl that names a module that cannot be found is diagnosed at parse/check time. | negative | [#nodes](../../../design/ast-reference/declarations.md#nodes) | [`importdecl-unknown-module-rejected.slang`](importdecl-unknown-module-rejected.slang) |
| An interface requirement is whatever Decl is written inside the interface body; a conforming type that omits a required member is diagnosed. | negative | [#requirementdecl-style-nodes-inside-interfacedecl](../../../design/ast-reference/declarations.md#requirementdecl-style-nodes-inside-interfacedecl) | [`interfacedecl-missing-requirement-rejected.slang`](interfacedecl-missing-requirement-rejected.slang) |


## Untested claims
| Claim | Reason | Anchor | Why untested |
| --- | --- | --- | --- |
| `AttributeDecl::syntaxClass` is a reflection handle for an attribute class; the attribute's effect is observable through attribute-bearing tests in other bundles, but the attribute-class identity itself is not. | (unclassified) | (unspecified) | Reason and explanation to be refined by the next regeneration. |
| The `## Family hierarchy` mermaid diagram as a graph: abstract intermediates (`ContainerDecl`, `CallableDecl`, `AggTypeDeclBase`, `FunctionDeclBase`, `VarDeclBase`, `SimpleTypeDecl`, `TypeConstraintDecl`, `NamespaceDeclBase`, `GenericTypeParamDeclBase`, `FileReferenceDeclBase`, `IncludeDeclBase`) carry no FIDDLE concrete tag and produce no user spelling of their own. | (unclassified) | [#containerdecl](../../../design/ast-reference/declarations.md#containerdecl) | Reason and explanation to be refined by the next regeneration. |
| `EmptyDecl::layout(...) in;` form: the doc cites GLSL-specific syntax; we exercise the simpler bare-`;` form that the parser also produces an `EmptyDecl` for. | (unclassified) | [#emptydecl](../../../design/ast-reference/declarations.md#emptydecl) | Reason and explanation to be refined by the next regeneration. |
| `FuncAliasDecl` (see doc gap above): no user spelling. | (unclassified) | [#funcaliasdecl](../../../design/ast-reference/declarations.md#funcaliasdecl) | Reason and explanation to be refined by the next regeneration. |
| `GLSLInterfaceBlockDecl`: GLSL-only surface; not exercised here (see doc gap above). | (unclassified) | [#glslinterfaceblockdecl](../../../design/ast-reference/declarations.md#glslinterfaceblockdecl) | Reason and explanation to be refined by the next regeneration. |
| `IncludeDecl` / `ImplementingDecl` / `__include` / `__implementing`: same reason — they reference companion files. | (unclassified) | [#includedecl](../../../design/ast-reference/declarations.md#includedecl) | Reason and explanation to be refined by the next regeneration. |
| `ModuleDeclarationDecl` (the `module M;` opener): structuring a multi-file module requires more than one source file and so is outside the single-file `slang-test` surface this bundle can exercise. | (unclassified) | [#moduledeclarationdecl](../../../design/ast-reference/declarations.md#moduledeclarationdecl) | Reason and explanation to be refined by the next regeneration. |
| `Decl::checkState` / `Decl::inferredCapabilityRequirements`: internal checking-phase fields. Capability gating is the subject of `pipeline/03-semantic-check`'s capability tests; this bundle covers the user-spelling-side `RequireCapabilityDecl` only. | (unclassified) | [#requirecapabilitydecl](../../../design/ast-reference/declarations.md#requirecapabilitydecl) | Reason and explanation to be refined by the next regeneration. |
| The `SyntaxDecl` model of "keyword binding produced by `__syntax`" is the subject of `docs/generated/tests/syntax-reference/keywords-and-builtins/`, which exercises keyword recognition from the surface-syntax side. The AST-shape claim ("the keyword maps to a parse callback") is not a separate user-observable. | (unclassified) | [#syntaxdecl](../../../design/ast-reference/declarations.md#syntaxdecl) | Reason and explanation to be refined by the next regeneration. |
| Synthesized-only concrete classes that have no user-visible spelling: `SynthesizedStructDecl`, `SynthesizedFuncDecl`, `UnresolvedDecl`, `InterfaceDefaultImplDecl`, `ThisTypeDecl`, `ThisTypeConstraintDecl`. Their existence shows up only through the surrounding feature (interface dispatch, tuple types, default-impl resolution) and the surrounding feature is what we test. | (unclassified) | [#synthesizedstructdecl](../../../design/ast-reference/declarations.md#synthesizedstructdecl) | Reason and explanation to be refined by the next regeneration. |
| Field names listed in the `## Nodes` table (e.g. `VarDecl::type: TypeExp`, `VarDecl::initExpr: Expr*`, `GenericDecl::inner: Decl*`, `ExtensionDecl::targetType: TypeExp`, `EnumCaseDecl::tagVal: IntVal*`, `InheritanceDecl::witnessTable: RefPtr<WitnessTable>`, `ConstructorDecl::m_flavor: int`, `LambdaDecl::funcDecl`, `ModuleDecl::module: Module*`). | internal-source-fact | (unspecified) | Implementation detail (C++ class hierarchy, field names, parser-callback names) with no user-observable consequence. |
| The C++ parent class of any concrete `Decl` (e.g. that `LetDecl extends VarDecl`, that `ConstructorDecl` extends `FunctionDeclBase`, that `GenericTypeParamDecl` extends `GenericTypeParamDeclBase`). | internal-source-fact | [#decl](../../../design/ast-reference/declarations.md#decl) | Only the user-observable behavior is testable. |
| The grammar production a parser callback is named (e.g. `parseAggTypeDecl`, `parseRequireCapabilityDecl`, `parseGenericDecl`). | internal-source-fact | [#parseaggtypedecl](../../../design/ast-reference/declarations.md#parseaggtypedecl) | Implementation detail (C++ class hierarchy, field names, parser-callback names) with no user-observable consequence. |


## Doc gaps observed
| Anchor | Kind | Gap | Suggested addition |
| --- | --- | --- | --- |
| [#function-alias-re-export-of-an-existing-callable](../../../design/ast-reference/declarations.md#function-alias-re-export-of-an-existing-callable) | undocumented-behavior | The doc lists `FuncAliasDecl` as "function alias / re-export of an existing callable" with a grammar link to `[func alias]`. In practice `FuncAliasDecl` is synthesized by the checker for forms like forward-mode differentiation rather than spelled in user code; the surface syntax `func aliasedName = original;` is not accepted by `slangc`. | Either the doc's grammar pointer should be removed, or the doc should clarify that `FuncAliasDecl` is checker-synthesized. |
| [#synthesized-by-the-checker-no-user-spelling](../../../design/ast-reference/declarations.md#synthesized-by-the-checker-no-user-spelling) | undocumented-behavior | The doc enumerates `SynthesizedStructDecl`, `SynthesizedFuncDecl`, `InterfaceDefaultImplDecl`, `ThisTypeDecl`, `ThisTypeConstraintDecl`, and `UnresolvedDecl` as concrete classes, but each is internal — there is no user spelling and no externally observable behavior distinct from the surrounding decl. | A one-line note "synthesized by the checker, no user spelling" would let an agent skip them without doubt. |
| [#modern-syntax-parameter-immutable-unless-outinout](../../../design/ast-reference/declarations.md#modern-syntax-parameter-immutable-unless-outinout) | undocumented-behavior | The doc mentions `ModernParamDecl` ("modern-syntax parameter; immutable unless `out`/`inout`") but does not specify which parameter spelling produces `ModernParamDecl` vs. `ParamDecl`. The parameter-direction test here covers the direction half of the claim; the `ModernParamDecl`-vs-`ParamDecl` distinction would need a doc-level pointer to the modern parameter grammar. |  |
| [#enumdecltagtype](../../../design/ast-reference/declarations.md#enumdecltagtype) | undocumented-behavior | The doc says `EnumDecl::tagType` carries the underlying integer type but does not state a user-facing claim about how the tag type affects, e.g., `int(c)` conversion. The tag-value test here uses the default tag type and so does not exercise the alternative. |  |
| [#enumdecl](../../../design/ast-reference/declarations.md#enumdecl) | undocumented-behavior | The doc mentions `EnumDecl` exhaustive matching is part of the AggTypeDecl machinery; the doc does not state whether a `switch` without `default` over an enum is diagnosed. (In our experimentation `switch` lowering in the interpreter is the blocker; a stmt-tests page would be a better home.) The doc could spell this out so a future agent can either anchor a diagnostic test here or defer to `ast-reference/statements`. |  |
| [#capability-does-not-exist](../../../design/ast-reference/declarations.md#capability-does-not-exist) | undocumented-behavior | `RequireCapabilityDecl`'s observable behavior on a Slang unknown-capability name (the C-39 test) emits a "capability does not exist" error; the source-doc text only says "expressed as a decl so it can be exported". | A one-line claim about the diagnostic would make the negative test directly anchorable. |
| [#glsl-style-interface-block-uniformbufferinout](../../../design/ast-reference/declarations.md#glsl-style-interface-block-uniformbufferinout) | undocumented-behavior | The doc lists `GLSLInterfaceBlockDecl` as "GLSL-style interface block (uniform/buffer/in/out)". The user-observable surface is GLSL-only; this bundle does not exercise it because the interpreter cannot model GLSL interface blocks. A pointer from the doc to a GLSL emit-side test would resolve this. |  |
