Skip to content

Language reference: Generics#10165

Merged
skiminki-nv merged 12 commits intoshader-slang:masterfrom
skiminki-nv:2026-02-documentation-improvements-generics-2
Mar 2, 2026
Merged

Language reference: Generics#10165
skiminki-nv merged 12 commits intoshader-slang:masterfrom
skiminki-nv:2026-02-documentation-improvements-generics-2

Conversation

@skiminki-nv
Copy link
Copy Markdown
Contributor

@skiminki-nv skiminki-nv commented Feb 23, 2026

Write a page about generics. Include all supported syntactic constructs with a comprehensive set of examples.

Make small fixed in types-struct.md:

  • use simple-type-expr where new types cannot be declared.
  • __subscript parameter list is mandatory

Fix a bunch of TODO links to generics, since the page now exists.

Write a page about generics. Include all supported syntactic
constructs with a comprehensive set of examples.
@skiminki-nv skiminki-nv added the pr: non-breaking PRs without breaking changes label Feb 23, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new Generics reference (generics.md), inserts "Generics" into the language-reference README, replaces placeholder TODO links with concrete generics links across several type docs, and renames some grammar terms and minor example attributes and wording.

Changes

Cohort / File(s) Summary
New generics doc & README
docs/language-reference/generics.md, docs/language-reference/README.md
Adds a comprehensive generics reference and adds "Generics" to the README contents.
Generic link and wording updates
docs/language-reference/types.md, docs/language-reference/types-array.md, docs/language-reference/types-extension.md, docs/language-reference/types-pointer.md
Replaces TODO placeholder links with links to generics.md; updates inline wording/formatting for generic parameter references.
Struct grammar and examples
docs/language-reference/types-struct.md
Replaces type-expr with simple-type-spec in struct grammar, adds optional generic-params-decl for constructors, and inserts [numthreads(1,1,1)] attributes in examples.
Vector/matrix parameter wording
docs/language-reference/types-vector-and-matrix.md
Updates wording to describe N, R, and C as instantiation-time constant integers in [1,4].
Interface wording
docs/language-reference/types-interface.md
Changes "set of member functions" to "set of members."

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through pages, nibbling TODO crumbs,
I linked up generics and taught type packs to hum,
Constructors dotted i's, examples got their hats,
A tidy rabbit scurried in and smoothed the docs' mats,
Cheers for clearer links and well-placed chums!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Language reference: Generics' directly and clearly summarizes the main change: adding comprehensive generics documentation to the language reference.
Description check ✅ Passed The description is directly related to the changeset, explaining the addition of a generics documentation page, fixes in types-struct.md, and updates to TODO links.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@skiminki-nv skiminki-nv marked this pull request as ready for review February 23, 2026 20:02
@skiminki-nv skiminki-nv requested a review from a team as a code owner February 23, 2026 20:02
@skiminki-nv skiminki-nv requested review from bmillsNV and removed request for a team February 23, 2026 20:02
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
docs/language-reference/types-struct.md (1)

535-536: The function-call operator example (line 594) is now inconsistently missing [numthreads(1,1,1)]

Adding the attribute here is correct, but the void main at line 594 in the function-call operator example was left without it, making the two examples inconsistent within the same file.

✂️ Add the missing attribute to the function-call operator example
+[numthreads(1,1,1)]
 void main(uint3 id : SV_DispatchThreadID)
 {
     TestStruct obj = { 42.0f };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/types-struct.md` around lines 535 - 536, The
function-call operator example's entry point is missing the compute shader
attribute—add the attribute [numthreads(1,1,1)] immediately above the function
declaration for void main (the function-call operator example's void main) so it
matches the earlier example; ensure the attribute is placed exactly before the
void main(uint3 id : SV_DispatchThreadID) declaration to keep both examples
consistent.
docs/language-reference/generics.md (1)

113-116: implicit keyword in coercion constraint syntax is undocumented

The BNF at line 115 includes an optional [implicit] in generic-type-constraint-coercion-decl, but neither the Parameters section (lines 120–141) nor the Description section (lines 144–187) explains what implicit changes. The existing example (line 488) doesn't use it either.

Add a brief explanation of the implicit modifier's semantics to the Parameters or Description section, or note that it is reserved/unimplemented if that is the case.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 113 - 116, The BNF shows an
optional 'implicit' modifier in the generic-type-constraint-coercion-decl but
the prose doesn't explain it; update the Parameters or Description section in
generics.md to either (1) add a short sentence explaining the semantics of
'implicit' (e.g., makes the coercion applied automatically by the compiler
without explicit call, and any visibility/overload rules), or (2) if it is not
yet implemented, add a clear note that 'implicit' is reserved/unimplemented and
will be documented when enabled; reference the 'implicit' token and the
nonterminal generic-type-constraint-coercion-decl so reviewers can find the BNF
to align wording with the grammar.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/language-reference/generics.md`:
- Around line 630-640: The declaration int empty[0] = { }; is a dead/misleading
variable in the implicit-binding example: sumElements unconditionally accesses
arr[0] so a 0-length array would be undefined; remove the unused empty
declaration (or alternatively replace it with a guarded call or a comment and a
safe check) so the example only shows elements and sumElements and no misleading
zero-length array usage.
- Around line 3-5: Change the broken link target for the "[functions and member
functions]" link so it uses the bare placeholder `(TODO)` instead of
`(TODO.md)`; locate the occurrence of the link text "functions and member
functions" in the generics documentation and update the link target to remove
the ".md" extension to match other placeholder links.
- Around line 265-270: The promotion rank list in the generics documentation
omits the fundamental scalar type "half" (aka "float16_t"), causing ambiguous
generic parameter inference for half-typed values; update the promotion ranks
sequence to include "half" (float16_t) in the correct position (between
uint64_t/int64_t and float) and ensure the surrounding text still notes that a
fundamental type is promoted to a 1-dimensional vector if necessary and that
other ambiguous cases remain an error.

---

Nitpick comments:
In `@docs/language-reference/generics.md`:
- Around line 113-116: The BNF shows an optional 'implicit' modifier in the
generic-type-constraint-coercion-decl but the prose doesn't explain it; update
the Parameters or Description section in generics.md to either (1) add a short
sentence explaining the semantics of 'implicit' (e.g., makes the coercion
applied automatically by the compiler without explicit call, and any
visibility/overload rules), or (2) if it is not yet implemented, add a clear
note that 'implicit' is reserved/unimplemented and will be documented when
enabled; reference the 'implicit' token and the nonterminal
generic-type-constraint-coercion-decl so reviewers can find the BNF to align
wording with the grammar.

In `@docs/language-reference/types-struct.md`:
- Around line 535-536: The function-call operator example's entry point is
missing the compute shader attribute—add the attribute [numthreads(1,1,1)]
immediately above the function declaration for void main (the function-call
operator example's void main) so it matches the earlier example; ensure the
attribute is placed exactly before the void main(uint3 id : SV_DispatchThreadID)
declaration to keep both examples consistent.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between de4c23b and 9f35101.

📒 Files selected for processing (8)
  • docs/language-reference/README.md
  • docs/language-reference/generics.md
  • docs/language-reference/types-array.md
  • docs/language-reference/types-extension.md
  • docs/language-reference/types-pointer.md
  • docs/language-reference/types-struct.md
  • docs/language-reference/types-vector-and-matrix.md
  • docs/language-reference/types.md

Comment on lines +3 to +5
Generics in Slang enable compile-time parameterization of [structures](types-struct.md),
[interfaces](types-interface.md), [type aliases](types.md#alias), [functions and member functions](TODO.md),
[subscript operators](types-struct.md#subscript-op), and
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Broken link pattern: TODO.md should be TODO

[functions and member functions](TODO.md) uses a .md extension on the placeholder, which most Markdown renderers will attempt to resolve as an actual file (TODO.md). Every other unfulfilled link in this doc set uses the bare form (TODO) (e.g., types-struct.md line 50, types-extension.md line 23). Please align:

🔗 Proposed fix
-[functions and member functions](TODO.md),
+[functions and member functions (TODO)](TODO),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Generics in Slang enable compile-time parameterization of [structures](types-struct.md),
[interfaces](types-interface.md), [type aliases](types.md#alias), [functions and member functions](TODO.md),
[subscript operators](types-struct.md#subscript-op), and
Generics in Slang enable compile-time parameterization of [structures](types-struct.md),
[interfaces](types-interface.md), [type aliases](types.md#alias), [functions and member functions (TODO)](TODO),
[subscript operators](types-struct.md#subscript-op), and
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 3 - 5, Change the broken
link target for the "[functions and member functions]" link so it uses the bare
placeholder `(TODO)` instead of `(TODO.md)`; locate the occurrence of the link
text "functions and member functions" in the generics documentation and update
the link target to remove the ".md" extension to match other placeholder links.

Comment on lines +265 to +270
- In case all inferred types are [fundamental scalar types](types-fundamental.md#scalar) or
[vector types](types-vector-and-matrix.md) of the same length, the element type with the highest promotion rank is
used. The promotion ranks from the lowest to the highest are: `int8_t`, `uint8_t`, `int16_t`,
`uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float`, `double`.
- A fundamental type is promoted to a 1-dimensional vector if necessary.
- In all other cases, an ambiguous type parameter is an error.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Slang language float16_t half fundamental scalar type generic type inference

💡 Result:

In Slang (the shader language):

  • half is the built-in 16-bit floating-point scalar type (alongside float and double). Support for half depends on the target backend/platform. [1]
  • On the CUDA target, Slang’s half support relies on NVRTC being able to include NVIDIA’s cuda_fp16.h (Slang auto-enables this when it detects half usage). [3]

In C++ (host code):

  • std::float16_t (often informally “float16”) is a C++23 fixed-width floating type alias provided via <stdfloat> only if the implementation supports it (guarded by __STDCPP_FLOAT16_T__). [4]
  • This is separate from Slang’s half keyword; you typically map host std::float16_t (or another FP16 type) to Slang half at the API/binding level, not by using float16_t inside Slang.

For generics + type inference in Slang:

  • Slang supports generics with constraints (interfaces/traits style), and it supports automatic type deduction at call sites—i.e., you can omit explicit generic type arguments and let the compiler infer them from function arguments (e.g., myGenericMethod(obj) instead of myGenericMethod<MyType>(obj)). [2]
  • Unlike C++ templates, Slang generally requires the operations a generic uses to be justified via interface constraints so the function can be type-checked before specialization. [2]

Sources: Slang scalar types (half) [1], Slang generics and automatic type deduction [2], Slang CUDA half support details [3], C++23 std::float16_t / <stdfloat> [4].


🌐 Web query:

Slang shading language type promotion rank specification

💡 Result:

In Slang (the shader language), the language specification currently does not define a numeric “type promotion rank” table (e.g., like C/C++ “integer promotions” / “usual arithmetic conversions”). The Slang Language Specification (Living Standard, 3 March 2025) explicitly marks “Type Conversions” as incomplete: it says the chapter still needs to (1) define implicit coercion vs. explicit conversion and (2) provide a table of built-in implicit coercions “and their costs.” It only sketches the intended rule structure (identity, subtyping-based coercion with a “distance” cost, otherwise use init overloads marked usable for implicit coercion, with overload resolution selecting the best cost). [1]

So, if you’re looking for an actual promotion-rank specification (e.g., “half < float < double” ranks, integer ranks, etc.), you won’t find it specified yet for Slang in the normative spec. [1]

If what you need is a working reference model today, Slang is designed to be highly compatible with HLSL, and HLSL does specify conversion ranks (integer and floating) used to distinguish promotions vs. other conversions. [2]

Sources
[1] Slang Language Specification (Living Standard, 3 March 2025) — “Type Conversions” chapter is WIP and describes the intended coercion/cost + overload-resolution approach. (raw.githubusercontent.com)
[2] High-Level Shader Language (HLSL) Specification Working Draft — “Conversion Rank” sections (integer and floating ranks). (microsoft.github.io)

Citations:


🏁 Script executed:

# Search for float16_t/half references in the codebase, especially in type-related docs
fd -e md -e txt . docs/ | head -20

# Look for type documentation files
fd -i "type" docs/ --type f

# Search for float16_t or half in documentation
rg -i "float16|float16_t|half" docs/ -A 2 -B 2

Repository: shader-slang/slang

Length of output: 21745


🏁 Script executed:

# Search for float16_t in the broader codebase
rg -i "float16_t|float16|\"half\"" . --type-list | head -20

# Check for type promotion rank or type inference logic
rg "promotion.*rank|type.*promotion" docs/ -i

Repository: shader-slang/slang

Length of output: 753


🏁 Script executed:

# Read the generics.md file around lines 265-270 to get full context
sed -n '245,285p' docs/language-reference/generics.md

Repository: shader-slang/slang

Length of output: 2139


🏁 Script executed:

# Look for any references to HLSL or type conversion specs in generics.md
rg "HLSL|conversion|rank" docs/language-reference/generics.md -i -B 2 -A 2

Repository: shader-slang/slang

Length of output: 2244


🏁 Script executed:

# Check the types-fundamental.md file to see if half/float16_t is documented as fundamental scalar
grep -A 5 -B 5 "half\|float16" docs/language-reference/types-fundamental.md | head -40

Repository: shader-slang/slang

Length of output: 770


Add half (or float16_t) to the type promotion rank list for generic parameter inference.

The promotion rank list omits half/float16_t, which is documented as a fundamental scalar type in Slang. When generic type parameters are ambiguously inferred from multiple scalar or vector arguments, the presence of half-typed values would not be resolved by the stated promotion ranks, causing an inference error. For consistency with other fundamental types, half should be positioned in the promotion rank hierarchy (likely between int64_t/uint64_t and float, or separately among floating-point ranks).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 265 - 270, The promotion
rank list in the generics documentation omits the fundamental scalar type "half"
(aka "float16_t"), causing ambiguous generic parameter inference for half-typed
values; update the promotion ranks sequence to include "half" (float16_t) in the
correct position (between uint64_t/int64_t and float) and ensure the surrounding
text still notes that a fundamental type is promoted to a 1-dimensional vector
if necessary and that other ambiguous cases remain an error.

Comment on lines +173 to +176
Conformance and equivalence requirements may be declared as optional. When optional, expression `ParamType is
ParentType` returns `true` when `ParamType` conforms to or equals `ParentType`. When the expression is used in
an `if` statement using the form `if (ParamType is ParentType) { ... }`, then any variable of type `ParamType` may
be used as type `ParentType` in the "then" branch.
Copy link
Copy Markdown
Contributor

@juliusikkala juliusikkala Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, the optional constraints proposal has not been merged, and the implementation has serious problems limiting its usefulness. I don't currently have the energy/bandwidth to fix this, and I've started doubting that the feature may not be worth the mess it causes in the compiler. To date, I've only had one practical use case for this feature personally. I would be open to removing it from the compiler.

Copy link
Copy Markdown
Contributor Author

@skiminki-nv skiminki-nv Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I wasn't aware of the status. I'm basically doing this work by reading whatever is written in the current user documentation, reverse-engineering the compiler, inspecting existing tests, and doing some experimentation. I'll add a remark with a link to #9367. (BTW, the coercion/conversion conformance constraint also feels like a half-finished feature.)

Another thing that I think should work with optional conformance is something like this:

void test<T>(T something) where optional T : IFace
{
    Optional<IFace> opt = something as IFace;
}

This is for feature parity with optionals and interfaces. I'll probably file a feature request about this soon-ish. (Edit: Decided not to write. Interface-valued optional here is maybe not the best idea in practice.)

What comes to the optional conformance feature itself, let's keep that discussion separate. Maybe I'll post a feature request to decide the its fate. From the language perspective, I think it makes sense. But I can't really say if people would find use for it and whether it's worth fixing the current issues.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed: #10185

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
docs/language-reference/generics.md (2)

267-274: Promotion rank list still missing half (float16_t).

half (16-bit) is a documented Slang fundamental scalar floating-point type, yet the promotion rank sequence at lines 271–272 jumps from uint64_t directly to float. When generic type inference encounters a half-typed argument alongside other scalar types, the documented rules leave the outcome unspecified.

✏️ Proposed fix
 `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float`, `double`.
+  (For `half`/`float16_t`, the rank falls between `uint64_t` and `float`.)

Or inline it directly into the rank sequence:

-  `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float`, `double`.
+  `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `half`, `float`, `double`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 267 - 274, The promotion
rank list is missing the 16-bit floating type `half` (aka `float16_t`), so
update the rank sequence in the generics documentation to include `half` between
`uint64_t` and `float`; edit the promotion ranks paragraph (the list showing
`int8_t`, `uint8_t`, ..., `uint64_t`, `float`, `double`) to insert
`half`/`float16_t` at the correct position so that generic parameter inference
covers 16-bit floats.

3-5: TODO.md broken link still present.

The placeholder [functions and member functions](TODO.md) uses the .md extension, which renderers will attempt to resolve as a real file. All other placeholder links in this doc set use the bare form (TODO).

🔗 Proposed fix
-[functions and member functions](TODO.md),
+[functions and member functions](TODO),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 3 - 5, The link "[functions
and member functions](TODO.md)" is using a `.md` extension causing a broken
resolver; change it to the bare placeholder form "(TODO)" to match other links
in this document (look for the link text "functions and member functions" or the
literal "TODO.md" in this line) so the placeholder behaves consistently with the
rest of the docs.
🧹 Nitpick comments (2)
docs/language-reference/generics.md (2)

150-157: generic-value-param-trad-decl absent from the Description prose.

The Description section lists three kinds of generic parameter declarations but omits the traditional-style value parameter (generic-value-param-trad-decl). A reader relying solely on this section will not know that the let-less form (e.g., <uint N>) is also valid, nor how it relates to the let form. Consider adding it as a bullet (or a parenthetical note inside the existing generic-value-param-decl bullet) and adding a corresponding example.

✏️ Suggested prose addition
 - Generic value parameter declaration *`generic-value-param-decl`*, which adds a value parameter with an optional
-  default value. The value type must be one of `bool`, `int`, `uint`.
+  default value using the modern `let` syntax (e.g., `let N : uint`). The value type must be one of `bool`, `int`, `uint`.
+- Generic value parameter declaration *`generic-value-param-trad-decl`* uses the traditional syntax where the type
+  precedes the identifier (e.g., `uint N`). It is otherwise equivalent to *`generic-value-param-decl`*.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 150 - 157, The Description
currently lists generic-value-param-decl, generic-type-param-decl, and
generic-type-param-pack-decl but omits the traditional value parameter form;
update the prose to include generic-value-param-trad-decl (the let-less form
such as <uint N>) by either adding a fourth bullet or extending the
generic-value-param-decl bullet to mention the
`generic-value-param-trad-decl`/let-less form and how it relates to the `let`
form, and add a short example showing both `<let N: uint = 4>` and the
traditional `<uint N>` usage so readers see the equivalence and syntax
difference.

111-115: implicit modifier in generic-type-constraint-coercion-decl is undocumented.

The grammar defines [**'implicit'**] as an optional qualifier on the coercion constraint, but neither the Parameters section (line 133–135) nor the Description section explains what implicit means or when it should be used. The existing GitHub reference (#10087) covers general coercion-constraint limitations, but the semantics of implicit itself need prose.

✏️ Suggested addition to the Parameters description (lines 133–135)
 - *`generic-type-constraint-coercion-decl`* is a generic parameter conformance clause, requiring the declared parameter
-  to be coercible. This constraint may be used only in [generic structure extensions](types-extension.md#generic-struct).
-  See GitHub issue [`#10087`](https://github.com/shader-slang/slang/issues/10087).
+  to be coercible. The optional `implicit` qualifier requires the conversion to be an implicit (not just explicit)
+  coercion. This constraint may be used only in [generic structure extensions](types-extension.md#generic-struct).
+  See GitHub issue [`#10087`](https://github.com/shader-slang/slang/issues/10087).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 111 - 115, The docs omit a
prose explanation for the optional 'implicit' qualifier on
generic-type-constraint-coercion-decl; update the Parameters and Description
sections for generic-type-constraint-coercion-decl to define what 'implicit'
means (e.g., that the coercion is automatically applied by the compiler where a
subtype is expected without requiring an explicit cast), state its effect on
type-checking and overload resolution, note any limitations/interaction with
existing coercion-constraint rules (referencing the coercion-constraint
limitations in `#10087`), and add a short usage note or example showing when to
use 'implicit' versus an explicit coercion to guide readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/language-reference/generics.md`:
- Line 116: MD028 is triggered by blank lines separating adjacent blockquote
blocks in docs/language-reference/generics.md; remove the empty line between
each adjacent ">" blockquote pair and insert a non-blockquote separator (for
example an HTML comment `<!-- -->`) instead so processors won't merge them into
one block or render a literal blank line, and apply this change at the
occurrences flagged by the linter (the blockquote groups around the MD028 hits).

---

Duplicate comments:
In `@docs/language-reference/generics.md`:
- Around line 267-274: The promotion rank list is missing the 16-bit floating
type `half` (aka `float16_t`), so update the rank sequence in the generics
documentation to include `half` between `uint64_t` and `float`; edit the
promotion ranks paragraph (the list showing `int8_t`, `uint8_t`, ...,
`uint64_t`, `float`, `double`) to insert `half`/`float16_t` at the correct
position so that generic parameter inference covers 16-bit floats.
- Around line 3-5: The link "[functions and member functions](TODO.md)" is using
a `.md` extension causing a broken resolver; change it to the bare placeholder
form "(TODO)" to match other links in this document (look for the link text
"functions and member functions" or the literal "TODO.md" in this line) so the
placeholder behaves consistently with the rest of the docs.

---

Nitpick comments:
In `@docs/language-reference/generics.md`:
- Around line 150-157: The Description currently lists generic-value-param-decl,
generic-type-param-decl, and generic-type-param-pack-decl but omits the
traditional value parameter form; update the prose to include
generic-value-param-trad-decl (the let-less form such as <uint N>) by either
adding a fourth bullet or extending the generic-value-param-decl bullet to
mention the `generic-value-param-trad-decl`/let-less form and how it relates to
the `let` form, and add a short example showing both `<let N: uint = 4>` and the
traditional `<uint N>` usage so readers see the equivalence and syntax
difference.
- Around line 111-115: The docs omit a prose explanation for the optional
'implicit' qualifier on generic-type-constraint-coercion-decl; update the
Parameters and Description sections for generic-type-constraint-coercion-decl to
define what 'implicit' means (e.g., that the coercion is automatically applied
by the compiler where a subtype is expected without requiring an explicit cast),
state its effect on type-checking and overload resolution, note any
limitations/interaction with existing coercion-constraint rules (referencing the
coercion-constraint limitations in `#10087`), and add a short usage note or
example showing when to use 'implicit' versus an explicit coercion to guide
readers.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9f35101 and eaf3d20.

📒 Files selected for processing (1)
  • docs/language-reference/generics.md

@swoods-nv swoods-nv requested review from csyonghe and tangent-vector and removed request for bmillsNV February 24, 2026 22:17
- distinguish between parameters and arguments (= values for the parameters)
- avoid type/subtype and inheritance. Simply use conformance, instead.
- improve text based on feedback from Claude
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
docs/language-reference/generics.md (3)

3-5: ⚠️ Potential issue | 🟡 Minor

[functions and member functions](TODO.md) uses .md on the placeholder link.

All other unresolved links in this doc set use the bare (TODO) form without .md to avoid unintended file resolution.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 3 - 5, Update the
unresolved link for "functions and member functions" to use the bare TODO form
instead of including the .md extension: replace the `(TODO.md)` link target in
the "functions and member functions" entry with `(TODO)` so it matches the other
unresolved links; look for the exact text "functions and member functions" in
the Generics doc and update its link target accordingly.

267-273: ⚠️ Potential issue | 🟡 Minor

Promotion-rank list omits half / float16_t.

half is a fundamental scalar type in Slang; its position in the promotion-rank hierarchy is unspecified, leaving its type inference behavior undefined.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 267 - 273, The
promotion-rank list omits the fundamental 16-bit floating type; update the
promotion order in the generics documentation so that `half` / `float16_t` is
explicitly included (e.g., place `half`/`float16_t` before `float` and after
`uint64_t`), and mention both canonical names (`half` and `float16_t`) so type
inference behavior is defined for that scalar; ensure the promotion paragraph
that lists ranks and the sentence about promoting scalars to 1-D vectors are
kept consistent with the added entry.

115-115: ⚠️ Potential issue | 🟡 Minor

MD028: blank lines between adjacent blockquotes (also at lines 184, 187, 202).

Some renderers will merge consecutive > blocks separated by blank lines into a single block with a literal blank line. Separate them with a <!-- --> comment instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` at line 115, There are blank lines
between adjacent blockquote blocks which some renderers merge; for each adjacent
">" block (the problematic blockquote sequences around the sections noted)
remove the empty line between them and insert an HTML comment marker <!-- -->
instead so the renderer preserves the intended separation; look for the
consecutive blockquote lines starting with ">" and replace the blank line
between them with <!-- --> to fix rendering.
🧹 Nitpick comments (1)
docs/language-reference/generics.md (1)

119-140: Consider varying sentence openings in the Parameters bullet list (lines 123–126).

Four consecutive bullets start with "declares a generic …". While acceptable in reference-doc style, varying the phrasing (e.g., "Introduces a…", "Specifies a…") would satisfy the LanguageTool style warning and marginally improve readability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 119 - 140, The four
consecutive parameter bullets (generic-param-decl, generic-value-param-decl,
generic-value-param-trad-decl, generic-type-param-decl) all begin with
"declares"; change the wording for some bullets to vary sentence openings (e.g.,
use "Introduces a…", "Specifies a…", or "Defines a…") while keeping the same
technical meaning and references (generic-params-decl,
generic-type-param-pack-decl, where-clause, etc.), so the list reads less
repetitive but retains each symbol name and its description.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/language-reference/generics.md`:
- Around line 509-512: Add a short explicit note in the "Type Parameter Packs"
or "Type Checking" section stating that equality and conformance constraints on
pack parameters are applied element-wise (e.g., for a pack declared as "each T",
a constraint like "where T == int" or "where T : SomeTrait" must hold for every
element of the pack). Reference the pack syntax "each T" and examples such as
the function "sumInts<each T>(expand each T terms) where T == int" to clarify
that the constraint applies to each T in the pack.
- Around line 152-153: The docs entry for generic value parameter declaration
(`generic-value-param-decl`) inaccurately restricts allowed value types to
`bool`, `int`, and `uint`; update the prose to list all types accepted by the
compiler's validation (see isValidCompileTimeConstantType() in
slang-check-decl.cpp), including all scalar integer variants
(int8/int16/int32/int64, uint8/uint16/uint32/uint64), pointer-sized integers
(intptr/uintptr), bool, and enum types (and note that fixed-width and
pointer-sized integer aliases are permitted as compile-time constant types).
Ensure the sentence replaces the old three-type list with this comprehensive set
and optionally mention that defaults are allowed and must be compile-time
constants.

---

Duplicate comments:
In `@docs/language-reference/generics.md`:
- Around line 3-5: Update the unresolved link for "functions and member
functions" to use the bare TODO form instead of including the .md extension:
replace the `(TODO.md)` link target in the "functions and member functions"
entry with `(TODO)` so it matches the other unresolved links; look for the exact
text "functions and member functions" in the Generics doc and update its link
target accordingly.
- Around line 267-273: The promotion-rank list omits the fundamental 16-bit
floating type; update the promotion order in the generics documentation so that
`half` / `float16_t` is explicitly included (e.g., place `half`/`float16_t`
before `float` and after `uint64_t`), and mention both canonical names (`half`
and `float16_t`) so type inference behavior is defined for that scalar; ensure
the promotion paragraph that lists ranks and the sentence about promoting
scalars to 1-D vectors are kept consistent with the added entry.
- Line 115: There are blank lines between adjacent blockquote blocks which some
renderers merge; for each adjacent ">" block (the problematic blockquote
sequences around the sections noted) remove the empty line between them and
insert an HTML comment marker <!-- --> instead so the renderer preserves the
intended separation; look for the consecutive blockquote lines starting with ">"
and replace the blank line between them with <!-- --> to fix rendering.

---

Nitpick comments:
In `@docs/language-reference/generics.md`:
- Around line 119-140: The four consecutive parameter bullets
(generic-param-decl, generic-value-param-decl, generic-value-param-trad-decl,
generic-type-param-decl) all begin with "declares"; change the wording for some
bullets to vary sentence openings (e.g., use "Introduces a…", "Specifies a…", or
"Defines a…") while keeping the same technical meaning and references
(generic-params-decl, generic-type-param-pack-decl, where-clause, etc.), so the
list reads less repetitive but retains each symbol name and its description.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between eaf3d20 and abad2ed.

📒 Files selected for processing (2)
  • docs/language-reference/generics.md
  • docs/language-reference/types-interface.md
✅ Files skipped from review due to trivial changes (1)
  • docs/language-reference/types-interface.md

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (5)
docs/language-reference/generics.md (5)

511-514: ⚠️ Potential issue | 🟡 Minor

No explanation that where constraints on a type parameter pack apply element-wise.

Lines 511 and 539 both use where T == int / where T == float on each T packs, but neither the "Type Parameter Packs" section nor "Type Checking" explains that such constraints are checked per element of the pack. Without that note, readers may not understand why the constraint syntax is singular (T == int) rather than each T == int.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 511 - 514, Clarify in the
"Type Parameter Packs" and "Type Checking" sections that a `where` constraint
written against a pack type parameter (e.g., `where T == int` used with `each T`
in the example function `sumInts`) is applied element-wise to every element of
the pack; update the text to state that `where T == int` is equivalent to
requiring each element of `each T` be `int` (and likewise for `where T ==
float`), and add a short sentence referencing the `sumInts(each T)`/`sumHelper`
example to illustrate the element-wise constraint semantics.

3-5: ⚠️ Potential issue | 🟡 Minor

(TODO.md) should be bare (TODO) on the broken placeholder link.

[functions and member functions](TODO.md) differs from every other unfulfilled link in this doc set, which all use the bare (TODO) form. TODO.md will be attempted as a real file resolution by most renderers.

🔗 Proposed fix
-[functions and member functions](TODO.md),
+[functions and member functions (TODO)](TODO),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 3 - 5, Replace the broken
placeholder link "[functions and member functions](TODO.md)" with the bare
"(TODO)" placeholder to match the other unfulfilled links in this document;
locate the text in the Generics section (the line containing "[functions and
member functions](TODO.md)") and change the link target to "(TODO)" so renderers
do not try to resolve a non-existent TODO.md file.

152-153: ⚠️ Potential issue | 🟡 Minor

Incomplete list of allowed generic value parameter types (also repeated in the intro at line 7).

The compiler's isValidCompileTimeConstantType() accepts all scalar integer variants (int8_t/int16_t/int32_t/int64_t, uint8_t/uint16_t/uint32_t/uint64_t), pointer-sized integers (intptr_t/uintptr_t), bool, and enum types. The current text lists only bool, int, uint, which understates the full set and also conflicts with the value-parameter example at line 624 that uses let N : uint (a uint alias).


265-275: ⚠️ Potential issue | 🟡 Minor

half / float16_t is still absent from the type-promotion-rank list.

The fundamental scalar type half (16-bit float) is not placed anywhere in the ranked sequence int8_t … uint64_t, float, double. Any call site mixing half-typed arguments with another scalar or same-length vector would produce an unresolvable inference error, and readers have no guidance on where half sits.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 265 - 275, The
promotion-rank list in the generics doc is missing the 16-bit float type; update
the ranked sequence (the line listing `int8_t, uint8_t, ... uint64_t, float,
double`) to include `half` (aka `float16_t`) at the correct position (i.e.,
between `uint64_t` and `float`) and mention `half`'s alias `float16_t` so
`half`-typed scalars or same-length vectors participate in the promotion rules;
keep the existing note about promoting fundamental types to 1-dimensional
vectors unchanged.

115-115: ⚠️ Potential issue | 🟡 Minor

MD028: blank lines inside blockquotes still unresolved at lines 115, 184, 187, and 202.

Blank lines between adjacent blockquote blocks cause inconsistent rendering across Markdown processors (some merge them; some insert a literal blank). Inserting a <!-- --> comment between the two > blocks is the standard fix.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` at line 115, MD028 indicates blank lines
between adjacent blockquote lines ('>') causing inconsistent rendering; fix each
adjacent '>' block by inserting an HTML comment placeholder <!-- --> between the
two blockquote lines so they remain separate but produce no visible blank line,
ensuring you update each occurrence flagged by MD028 (adjacent '>' blockquote
pairs).
🧹 Nitpick comments (1)
docs/language-reference/generics.md (1)

123-126: Four consecutive bullet items begin with "declares" — consider varying the sentence openers.

The LanguageTool linter flags this as a readability concern. A light rewrite (e.g., using a noun phrase or passive voice for every other entry) removes the repetition.

✏️ Suggested rewrite
-- *`generic-value-param-decl`* declares a generic value parameter.
-- *`generic-value-param-trad-decl`* declares a generic value parameter using traditional syntax.
-- *`generic-type-param-decl`* declares a generic type parameter.
-- *`generic-type-param-pack-decl`* declares a generic type parameter pack.
+- *`generic-value-param-decl`* — generic value parameter declaration.
+- *`generic-value-param-trad-decl`* — generic value parameter declaration (traditional syntax).
+- *`generic-type-param-decl`* — generic type parameter declaration.
+- *`generic-type-param-pack-decl`* — generic type parameter pack declaration.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 123 - 126, The four
consecutive list items all start with "declares", hurting readability; revise
the four entries for generic-value-param-decl, generic-value-param-trad-decl,
generic-type-param-decl, and generic-type-param-pack-decl to vary sentence
openers (e.g., use a noun phrase or passive construction for some items like "A
generic value parameter: ..." or "Used to declare a generic type parameter") so
the lines alternate and remove repetitive "declares" at the start while
preserving the same meanings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@docs/language-reference/generics.md`:
- Around line 511-514: Clarify in the "Type Parameter Packs" and "Type Checking"
sections that a `where` constraint written against a pack type parameter (e.g.,
`where T == int` used with `each T` in the example function `sumInts`) is
applied element-wise to every element of the pack; update the text to state that
`where T == int` is equivalent to requiring each element of `each T` be `int`
(and likewise for `where T == float`), and add a short sentence referencing the
`sumInts(each T)`/`sumHelper` example to illustrate the element-wise constraint
semantics.
- Around line 3-5: Replace the broken placeholder link "[functions and member
functions](TODO.md)" with the bare "(TODO)" placeholder to match the other
unfulfilled links in this document; locate the text in the Generics section (the
line containing "[functions and member functions](TODO.md)") and change the link
target to "(TODO)" so renderers do not try to resolve a non-existent TODO.md
file.
- Around line 265-275: The promotion-rank list in the generics doc is missing
the 16-bit float type; update the ranked sequence (the line listing `int8_t,
uint8_t, ... uint64_t, float, double`) to include `half` (aka `float16_t`) at
the correct position (i.e., between `uint64_t` and `float`) and mention `half`'s
alias `float16_t` so `half`-typed scalars or same-length vectors participate in
the promotion rules; keep the existing note about promoting fundamental types to
1-dimensional vectors unchanged.
- Line 115: MD028 indicates blank lines between adjacent blockquote lines ('>')
causing inconsistent rendering; fix each adjacent '>' block by inserting an HTML
comment placeholder <!-- --> between the two blockquote lines so they remain
separate but produce no visible blank line, ensuring you update each occurrence
flagged by MD028 (adjacent '>' blockquote pairs).

---

Nitpick comments:
In `@docs/language-reference/generics.md`:
- Around line 123-126: The four consecutive list items all start with
"declares", hurting readability; revise the four entries for
generic-value-param-decl, generic-value-param-trad-decl,
generic-type-param-decl, and generic-type-param-pack-decl to vary sentence
openers (e.g., use a noun phrase or passive construction for some items like "A
generic value parameter: ..." or "Used to declare a generic type parameter") so
the lines alternate and remove repetitive "declares" at the start while
preserving the same meanings.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between abad2ed and fb3e8dd.

📒 Files selected for processing (1)
  • docs/language-reference/generics.md

Copy link
Copy Markdown
Collaborator

@csyonghe csyonghe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this looks good. I would prefer "specialization" over "instantiation" as the terminology, because specialization is what is being used in the codebase and in existing docs.

Generics in Slang enable parameterization of [structures](types-struct.md),
[interfaces](types-interface.md), [type aliases](types.md#alias), [functions and member functions](TODO.md),
[subscript operators](types-struct.md#subscript-op), and
[constructors](types-struct.md#constructor). Parameterization is allowed for types and
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Parameterization is allowed for" this is confusing. I guess you mean "A generic parameter can be a type or an integer or bool-typed value."

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More specifically, a generic parameter can only be a proper type. An interface by itself isn't allowed as specialization argument, .e.g. f<IFoo>() is not allowed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also: if a generic argument is an integer or bool value, then the argument itself must be a compile-time or link-time constant. (and need to define compile-time/link-time constant somewhere, including what is considered "constant").

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you mean "A generic parameter can be a type or an integer or bool-typed value."

Right. I'll clarify.

More specifically, a generic parameter can only be a proper type

I'll add a clarification.

also: if a generic argument is an integer or bool value, then the argument itself must be a compile-time or link-time constant.

Makes sense.

and need to define compile-time/link-time constant somewhere, including what is considered "constant"

The constant definition has to wait until the page on compilation stages has been written. I don't want to start the argument what "compile-time" means in this patch. I'll leave a todo.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More specifically, a generic parameter can only be a proper type. An interface by itself isn't allowed as specialization argument, .e.g. f() is not allowed.

This does not seem to be the case. The following compiles just fine, and TBH, I'm not really seeing why it shouldn't compile as long as we consider interface-typed variables as variants where every embedded type conforms to the interface:

uint doSomething<T>()
{
    return sizeof(T);
}

struct TestType
{
    IArithmetic i;
}

interface ITest
{
}

RWStructuredBuffer<uint> outputBuffer;

[numthreads(1,1,1)]
void computeMain(uint3 id : SV_DispatchThreadID)
{
    outputBuffer[0] = doSomething<TestType>();
    outputBuffer[1] = doSomething<int64_t>();
    outputBuffer[2] = doSomething<IArithmetic>();
    outputBuffer[3] = doSomething<ITest>();
}

That said, I'm seeing an ICE for trying to pass an interface-typed object with dynamic dispatching enabled to a generic:

uint functionCallTest<T>(T obj)
{
    return 0;
}

interface ITest
{
}

struct ABC : ITest
{
}

struct DEF : ITest
{
}

ITest createITest(bool type)
{
    if (type)
        return ABC();
    else
        return DEF();
}


RWStructuredBuffer<uint> outputBuffer;

[numthreads(1,1,1)]
void computeMain(uint3 id : SV_DispatchThreadID)
{
    ITest testVariant = createITest(id.x == 1);
    outputBuffer[0] = functionCallTest(testVariant); // this triggers an internal compiler error
}

The above compiles just fine if createITest() only ever creates either ABC or DEF.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #10263.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by cdaf27c

[interfaces](types-interface.md), [type aliases](types.md#alias), [functions and member functions](TODO.md),
[subscript operators](types-struct.md#subscript-op), and
[constructors](types-struct.md#constructor). Parameterization is allowed for types and
`uint`/`int`/`bool`-typed values. In addition, Slang supports [generic structure
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extensions are not restricted to struct types. I would just call it extensions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the generic struct extension (extension<T>) only works on structs and classes, but the latter are not officially supported?

Or what do you have in mind exactly? Can you give an example?

`uint`/`int`/`bool`-typed values. In addition, Slang supports [generic structure
extension](types-extension.md#generic-struct) covered in [type extensions](types-extension.md).

When the generic parameters are bound, a generic type or function is instantiated. An instantiated
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use the word "specialized" more than "instantiated".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What word we should use would be a reasonable question.

I'll copy-paste here what I wrote in Discord:

I'm still pondering on the following terms:

  • "specialization" vs "instantiation". Either could be reasonably used here. Indeed, "specialization" usually means providing all arguments to a generic and making it specific to those arguments; and "instantiation" means creating an instance of a generic. Usually, you'd only ever instantiate a fully specialized generic, although technically, you could instantiate also non-specialized or partially specialized generics, too. (Not sure why we'd want to do that, except as an optimization for things that don't depend on generic parameters.) Anyway, the latest version still uses "instantiation", since C++ overloads "specialization" to also mean providing definitions for specific generic parameters. "Instantiation" avoids this confusion.

The problem I wanted to avoid is that "specialization" means two different things:

  1. Providing all arguments to a generic thing, making it a concrete thing. This is Slang's specialization, and AFAICT, Slang always instantiates specialized generics when used.
  2. Overriding generics for specific parameter combinations, making some parameter combinations special. This is what C++ specialization and partial specialization usually means.

In other words, when I'm writing a C++ template and I'm specializing it, this is what I usually mean:

template <typename T>
constexpr size_t getSizeForSomePurpose()
{
    return sizeof(T);
}

template <>
constexpr size_t getSizeForSomePurpose<std::uint16_t>()
{
    // let's say that we need additional padding for this particular type
    return sizeof(std::uint32_t);
}

and if I want to specialize (1st kind) this template, then I'll provide the template parameters:

int main()
{
    printf("Test: %zu\n", getSizeForSomePurpose<std::uint64_t>());
    printf("Test: %zu\n", getSizeForSomePurpose<std::uint16_t>());

    return 0;
}

But often this is referred to as instantiation in the C++ world.

Slang does not support "specialize (2nd kind)".

Anyway, I think I'll switch the word to specialize and add a note.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instantiation of specializations:

uint doSomething<T>()
{
    return 3;
}

RWStructuredBuffer<uint> outputBuffer;

[numthreads(1,1,1)]
void computeMain(uint3 id : SV_DispatchThreadID)
{
    outputBuffer[0] = doSomething<int32_t>();
    outputBuffer[1] = doSomething<int64_t>();
}

Slang does two instances of doSomething<>() here, even if they're exactly the same. For better code, Slang could instantiate a single doSomething<>, since there's no generic parameter dependency. That is, instantiate without specialization (1st kind).

And the following won't compile:

uint doSomething<T>()
{
    return sizeof(T);
}

// compilation failure:
// specialization of the 2nd kind is not supported
uint doSomething<int16_t>()
{
    return 4;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by cdaf27c

function. Conceptually, partial parameter binding can be done by defining a generic type alias for a generic
object, but this does not instantiate a generic.

Slang does not directly support specialization or partial specialization of generics. However, [generic struct
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused. What do you mean by Slang does not support specialization? Foo<Bar> is a specialization of Foo<>.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slang does not support the programmer defining different implementations for different parameter combinations. (specialization of the 2nd kind).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by cdaf27c

> [#10164](https://github.com/shader-slang/slang/issues/10164) for details.


## Examples
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is probably more helpful to interleave these examples with their descriptions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps. I did consider this, but I had the following considerations:

  1. I didn't want the description text to be littered with examples here, since here I thought we should have a reasonable bunch of them. Interleaving might make the examples overwhelm the text.
  2. Often (most of the time?) programmers don't actually care about the syntactical details at all. Instead, they want to see the coding patterns, that is, learn by example. People tend to care about the details only when they can't find the examples.
  3. This is not a tutorial.

So, I thought that a collection of titled examples might be a better fit here. At any rate, interleaving would be a trivial change for a subsequent patch, if that turns out to be a better fit after all.

Add also more clarifications based on detailed review by Claude.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (4)
docs/language-reference/generics.md (4)

4-4: ⚠️ Potential issue | 🟡 Minor

Inconsistent TODO link pattern: use bare (TODO) instead of (TODO.md).

The link [functions and member functions](TODO.md) uses .md extension, which differs from other placeholder links in this documentation set that use the bare form (TODO). This inconsistency was flagged in previous reviews but remains unaddressed.

🔗 Proposed fix
-[interfaces](types-interface.md), [type aliases](types.md#alias), [functions and member functions](TODO.md),
+[interfaces](types-interface.md), [type aliases](types.md#alias), [functions and member functions](TODO),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` at line 4, Replace the inconsistent
placeholder link "[functions and member functions](TODO.md)" with the bare
"(TODO)" form to match the other links in this file (e.g., those used for
interfaces and type aliases); locate the text in
docs/language-reference/generics.md and update the link target for the
"[functions and member functions]" entry so it uses "(TODO)" instead of
"(TODO.md)".

281-282: ⚠️ Potential issue | 🟡 Minor

Add half to the type promotion rank list.

The promotion rank list omits half (also known as float16_t), which is a fundamental scalar type in Slang. When generic type parameters are inferred from multiple scalar or vector arguments, the absence of half from the promotion ranks means that scenarios involving half-typed values won't be properly resolved by the stated rules.

🔢 Proposed fix
 - If all inferred types are [fundamental scalar types](types-fundamental.md#scalar) or
   [vector types](types-vector-and-matrix.md) of the same length, the element type with the highest promotion rank is
-  used. The promotion ranks from the lowest to the highest are: `int8_t`, `uint8_t`, `int16_t`,
-  `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float`, `double`.
+  used. The promotion ranks from the lowest to the highest are: `int8_t`, `uint8_t`, `int16_t`,
+  `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `half`, `float`, `double`.
   - A fundamental type is promoted to a 1-dimensional vector if necessary.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 281 - 282, The promotion
rank list in the generics docs currently reads "int8_t, uint8_t, int16_t,
uint16_t, int32_t, uint32_t, int64_t, uint64_t, float, double" and omits the
16-bit float type; update that sequence to include `half` (also accept the alias
`float16_t`) placed before `float` so the order becomes ...`uint64_t`, `half`
(or `float16_t`), `float`, `double`, ensuring the generic type-promotion rules
cover half-precision values.

13-13: ⚠️ Potential issue | 🟡 Minor

Inconsistent TODO link pattern: use bare (TODO) instead of (TODO.md).

The link [link-time constants (TODO)](TODO.md) uses .md extension. For consistency with other placeholder links in the documentation, use the bare form (TODO).

🔗 Proposed fix
-bound by providing arguments (explicit binding), by inference (implicit binding), or by a combination of both.
-Value-typed arguments to the generic parameters must be [link-time constants (TODO)](TODO.md).
+bound by providing arguments (explicit binding), by inference (implicit binding), or by a combination of both.
+Value-typed arguments to the generic parameters must be [link-time constants](TODO).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` at line 13, Replace the placeholder link
using the `.md` extension with the bare `(TODO)` form in the sentence
"Value-typed arguments to the generic parameters must be [link-time constants
(TODO)](TODO.md)." — update the bracketed link text so it reads `[link-time
constants (TODO)](TODO)` to match the project's placeholder link pattern.

161-161: ⚠️ Potential issue | 🟡 Minor

Update documentation to list all supported generic value parameter types.

The statement "The value type must be one of bool, int, uint" significantly understates what the compiler actually accepts. According to previous analysis of isValidCompileTimeConstantType() in slang-check-decl.cpp, the compiler accepts all scalar integer types (including int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t), pointer-sized integers (intptr_t, uintptr_t), bool, and enum types.

📝 Proposed fix
-- Generic value parameter declaration *`generic-value-param-decl`* or *`generic-value-param-trad-decl`*, which
-  adds a value parameter with an optional default value. The value type must be one of `bool`, `int`, `uint`.
+- Generic value parameter declaration *`generic-value-param-decl`* or *`generic-value-param-trad-decl`*, which
+  adds a value parameter with an optional default value. The value type must be a scalar integer type
+  (`int8_t`, `int16_t`, `int32_t`, `int64_t`, `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `intptr_t`, `uintptr_t`),
+  `bool`, or an enum type.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` at line 161, The doc line claiming "The
value type must be one of `bool`, `int`, `uint`" is incomplete; update the
sentence to enumerate all supported compile-time constant types by matching the
compiler's isValidCompileTimeConstantType() logic (function
isValidCompileTimeConstantType in slang-check-decl.cpp): list bool, all scalar
signed and unsigned integer widths (e.g., int8_t, int16_t, int32_t, int64_t and
uint8_t, uint16_t, uint32_t, uint64_t), pointer-sized integers (intptr_t,
uintptr_t), and enum types (in addition to generic int/uint aliases), so the
documentation reflects the exact set the compiler accepts.
🧹 Nitpick comments (2)
docs/language-reference/generics.md (2)

240-263: Clarify that constraints on type parameter packs apply element-wise.

The "Type Checking" section describes constraints in general terms but doesn't explicitly state that when a constraint is applied to a type parameter pack (declared with each T), the constraint must hold for every element in the pack. This behavior is demonstrated in the examples at lines 519 (where T == int) and 549 (where T == float), but the documentation doesn't make this explicit.

📝 Suggested addition

Consider adding a note in this section or in the "Type Parameter Packs" section (lines 201-238) that clarifies:

> 📝 **Remark:** When a constraint is applied to a type parameter pack (declared with `each T`),
> the constraint applies element-wise to each type in the pack. For example, `where T == int` on a pack
> parameter requires that every element of the pack must be `int`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` around lines 240 - 263, Add a short
clarifying note to the "Type Checking" section (or the "Type Parameter Packs"
section) stating that constraints applied to a type parameter pack (declared
with each T) are enforced element-wise for every type in the pack; reference the
pack syntax `each T` and the example constraints `where T == int` / `where T ==
float` so readers know the constraint must hold for each element of the pack.

21-21: Fix blank lines inside blockquotes for consistent rendering (MD028).

Blank lines separating consecutive blockquote blocks (at lines 21, 122, 192, 195, and 210) may render inconsistently across Markdown processors. Some will merge the blocks, others will show literal blank lines. The standard fix is to separate adjacent blockquotes with a non-blockquote element like <!-- -->.

✏️ Example fix pattern

For line 21 (between two remark blocks):

 > would provide a definition for a specific combination of arguments. However,
 > [generic structure extension](types-extension.md#generic-struct) can be used to extend generic structures to
 > similar effect.
-
+
+<!-- -->
 > 📝 **Remark 2:** Slang does not currently support using interface-typed variables that require dynamic dispatch as

Apply the same pattern at lines 122, 192, 195, and 210 where blank lines separate blockquotes.

Also applies to: 122-122, 192-192, 195-195, 210-210

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/language-reference/generics.md` at line 21, There are blank lines
separating consecutive blockquote blocks which cause inconsistent Markdown
rendering; for each occurrence replace the empty line between adjacent
blockquotes with a non-blockquote element such as an HTML comment (<!-- -->) so
the blockquotes remain distinct (apply this fix wherever consecutive blockquote
blocks appear).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@docs/language-reference/generics.md`:
- Line 4: Replace the inconsistent placeholder link "[functions and member
functions](TODO.md)" with the bare "(TODO)" form to match the other links in
this file (e.g., those used for interfaces and type aliases); locate the text in
docs/language-reference/generics.md and update the link target for the
"[functions and member functions]" entry so it uses "(TODO)" instead of
"(TODO.md)".
- Around line 281-282: The promotion rank list in the generics docs currently
reads "int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t,
float, double" and omits the 16-bit float type; update that sequence to include
`half` (also accept the alias `float16_t`) placed before `float` so the order
becomes ...`uint64_t`, `half` (or `float16_t`), `float`, `double`, ensuring the
generic type-promotion rules cover half-precision values.
- Line 13: Replace the placeholder link using the `.md` extension with the bare
`(TODO)` form in the sentence "Value-typed arguments to the generic parameters
must be [link-time constants (TODO)](TODO.md)." — update the bracketed link text
so it reads `[link-time constants (TODO)](TODO)` to match the project's
placeholder link pattern.
- Line 161: The doc line claiming "The value type must be one of `bool`, `int`,
`uint`" is incomplete; update the sentence to enumerate all supported
compile-time constant types by matching the compiler's
isValidCompileTimeConstantType() logic (function isValidCompileTimeConstantType
in slang-check-decl.cpp): list bool, all scalar signed and unsigned integer
widths (e.g., int8_t, int16_t, int32_t, int64_t and uint8_t, uint16_t, uint32_t,
uint64_t), pointer-sized integers (intptr_t, uintptr_t), and enum types (in
addition to generic int/uint aliases), so the documentation reflects the exact
set the compiler accepts.

---

Nitpick comments:
In `@docs/language-reference/generics.md`:
- Around line 240-263: Add a short clarifying note to the "Type Checking"
section (or the "Type Parameter Packs" section) stating that constraints applied
to a type parameter pack (declared with each T) are enforced element-wise for
every type in the pack; reference the pack syntax `each T` and the example
constraints `where T == int` / `where T == float` so readers know the constraint
must hold for each element of the pack.
- Line 21: There are blank lines separating consecutive blockquote blocks which
cause inconsistent Markdown rendering; for each occurrence replace the empty
line between adjacent blockquotes with a non-blockquote element such as an HTML
comment (<!-- -->) so the blockquotes remain distinct (apply this fix wherever
consecutive blockquote blocks appear).

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between fb3e8dd and cdaf27c.

📒 Files selected for processing (1)
  • docs/language-reference/generics.md

The allowed value types include boolean, all integer types, and
enumeration types.
[subscript operators](types-struct.md#subscript-op), and
[constructors](types-struct.md#constructor). A generic parameter can be a type, a [Boolean](types-fundamental.md#boolean)
value, an [integer](types-fundamental.md#integer) value, or an [enumeration (TODO)](TODO.md) value.
In addition, Slang supports [generic structure extension](types-extension.md#generic-struct), covered
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just refer to this as generic extensions? Extensions are to extending types, and not specific to structs, especially from the user's standpoint.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you insist.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skiminki-nv skiminki-nv added this pull request to the merge queue Mar 2, 2026
Merged via the queue into shader-slang:master with commit 376eb40 Mar 2, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: non-breaking PRs without breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants