{"owner":"shader-slang","repo":"slang","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md","CLAUDE.md"],"skills":{"AGENTS.md":"<!--\nSPDX-FileCopyrightText: The Khronos Group, Inc.\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# Repository Guidelines\n\n## Project Structure & Module Organization\n\nSlang is a shading-language compiler and runtime implemented primarily in C++20 and built with\nCMake.\n\nKey directories:\n\n- `source/`: core implementation, including `source/slang/`, `source/core/`,\n  `source/compiler-core/`, and tools like `source/slangc/`.\n- `include/`: public API headers.\n- `prelude/` and `source/standard-modules/`: standard/prelude headers.\n- `tests/`: test suites grouped by feature or target.\n- `tools/`: test infrastructure and developer tools.\n- `docs/`: documentation.\n- `examples/`: runnable samples.\n- `cmake/`: CMake helpers.\n- `external/`: vendored dependencies.\n\n## Repository-Local Skills\n\nThis repository stores local agent skills under `.claude/skills/`. Codex and other non-Claude\nharnesses should still consult those `SKILL.md` files when a user asks for the workflow they\ndescribe.\n\nReview-related skills:\n\n- `slang-review-clarity-workflow`: coordinate the end-to-end clarity review workflow.\n- `slang-review-clarity`: generate high-level clarity and explainability review candidates.\n- `slang-review-fine-grained-clarity`: generate line-by-line name/comment/type/function\n  consistency review candidates.\n- `slang-review-consolidate-candidates`: merge candidate files and resolve duplicates,\n  overlap, and superseded comments.\n- `slang-review-scope-filter`: conservatively filter candidate comments to issues the PR\n  author can reasonably own before posting.\n- `slang-review-resolve-judgment-calls`: resolve uncertain candidates with focused follow-up\n  analysis before posting.\n- `slang-review-post-github`: post filtered candidates as one proper GitHub PR review.\n\n## WSL and Windows Tooling\n\nWhen working in this repository from WSL on Windows, use Windows-native developer tools by\ndefault unless the user explicitly asks for the WSL/Linux version.\n\n- Use `git.exe`, not bare `git`. These worktrees use Windows path conventions; WSL Git can\n  corrupt or misinterpret worktree state, and Windows Git has much better file I/O performance\n  on this checkout.\n- When the `slang-build` skill invokes CMake, use `cmake.exe`, not bare `cmake`, for\n  Windows-hosted configure and build commands. Windows CMake can find Visual Studio 2026 and\n  the Windows toolchains required by the `vs2026` preset.\n- Use `gh.exe` instead of bare `gh` when GitHub CLI commands need to share the same\n  Windows-native Git and credential context.\n- Convert WSL paths before passing them to Windows tools, for example `wslpath -w \"$path\"`.\n  Convert paths printed by Windows tools back before using them in shell commands, for example\n  `wslpath -u \"$win_path\"`.\n- If a required `.exe` tool is unavailable, stop and report it instead of silently falling back\n  to the WSL/Linux tool.\n\n## Build, Test, and Development Commands\n\nSlang build setup is platform-specific, especially under WSL. For compiler builds, use the\n`slang-build` skill from `skills/slang-build` in the `shader-slang/slang-skills` repository\ninstead of following hard-coded commands in this file.\n\nIf the skill is unavailable because skills cannot be installed or network access is limited, use\n`docs/building.md` as the fallback build reference.\n\nExamples:\n\n- `/slang-build build debug`: build the Debug configuration.\n- `/slang-build rebuild debug`: discard the existing build directory and rebuild Debug.\n- `/slang-build configure releasewithdebug`: configure an optimized build with symbols.\n- `/slang-build clean`: rename and remove the existing build directory.\n\nDo not infer WSL build commands from generic Linux instructions. Follow the platform detection,\nhost-tool selection, CMake preset choice, and clean-build steps defined by the skill.\n\nAfter building, run tests from the repository root using the generated `slang-test` binary in\nthe directory for the selected configuration:\n\n- `build/Debug/bin/slang-test`: run the Debug test suite.\n- `build/RelWithDebInfo/bin/slang-test -use-test-server -server-count 8`: run optimized\n  tests with symbols in parallel using test servers.\n- `build/Release/bin/slang-test -use-test-server -server-count 8`: run Release tests in\n  parallel using test servers.\n\nOn Windows-hosted builds, use the `.exe` suffix if that is the generated binary name.\n\n## Include Path Conventions\n\nPrefer direct paths over relative traversal in `#include` directives. The `source/` directory is\non the compiler include path (exposed by the `core` CMake target), so cross-module headers are\nreachable without `../`:\n\n```cpp\n// Preferred in new code\n#include \"core/slang-string.h\"\n#include \"compiler-core/slang-source-loc.h\"\n\n// Existing code still uses the relative form; do not change it purely for style\n#include \"../core/slang-string.h\"\n#include \"../compiler-core/slang-source-loc.h\"\n```\n\nNew files should use direct paths. Existing files need not be converted purely for style, but may\nbe opportunistically updated when the file is already being substantially modified for other\nreasons (e.g., a security fix or feature addition touching many lines).\n\n## Coding Style & Naming Conventions\n\nFormatting:\n\n- Use four-space indentation for C, C++, headers, and Slang files.\n- Run `./extras/formatting.sh` before committing to apply rules from `.clang-format`\n  and `.editorconfig`.\n- Follow Allman braces, a 100-column limit, left-aligned pointers, and final newlines.\n\nConventions:\n\n- Follow `docs/design/coding-conventions.md`.\n- Avoid STL containers, iostreams, RTTI, and exceptions for ordinary errors.\n- Use `UpperCamelCase` for types and `lowerCamelCase` for values.\n- Use `SLANG_`-prefixed `SCREAMING_SNAKE_CASE` for macros.\n- Prefer comments that explain why code exists.\n\nReview conventions (recurring review feedback — following them avoids review round-trips):\n\n- Comment functions in complete sentences: what it does first, then why if non-obvious; include a\n  concrete example for non-trivial logic.\n- Write explanatory comments in a conversational style. Prefer \"Consider this example:\" followed\n  by the relevant user code over abstract labels such as \"Full source shape\", \"AST trace\", or\n  \"IR trace\". After the example, explain what happens step by step in natural prose: which\n  producer creates the AST/IR/value shape, what invariant this code is preserving, and which\n  downstream consumer relies on it. Include enough of the original user code for the example to be\n  understood without reconstructing the surrounding program from memory.\n- Reuse before you write: check shared headers (`slang-ast-type.h`, `slang-ir-util.h`, the `*-util.h`\n  files) for an existing helper (e.g. `isDeclRefTypeOf<T>`) before adding one. When the logic is\n  genuinely new, extract it into a named, documented helper rather than an inline lambda/long block.\n- Keep one source of truth for a mapping or classification, and delete any branch/fallback a refactor\n  makes unreachable.\n- Don't create a second AST/IR/`Val` representation of a value that already has one (it breaks\n  `equals`/dedup); `SLANG_ASSERT` such invariants at the construction site.\n- `SLANG_RELEASE_ASSERT` on out-of-contract input instead of silently returning a default.\n\n## Shell Scripts\n\nScripts under `extras/` (and other repository shell scripts) must run on bash 3.2, the version\nApple ships as `/bin/bash` on macOS. Avoid bash 4+ only features such as `${var,,}`/`${var^^}`\ncase conversion, associative arrays (`declare -A`), `mapfile`/`readarray`, and namerefs\n(`local -n`). Prefer portable equivalents (for example, lowercase with\n`tr '[:upper:]' '[:lower:]'`). Validate with `bash -n script.sh` under the system bash.\n\n## Testing Guidelines\n\nAdd tests near related coverage in `tests/`.\n\nSlang tests:\n\n- Use leading directives such as `//TEST(smoke):SIMPLE:`.\n- Use `//DISABLE_TEST` only with a clear reason.\n- For targeted runs, pass a prefix, for example\n  `build/Debug/bin/slang-test tests/diagnostics/my-test`.\n\nUnit tests live under `tools/slang-unit-test` and typically use `SLANG_UNIT_TEST(name)`.\n\n## Problem-Solving Methodology\n\nFollow the principled path, not the minimal-edit-distance path.\n\n- Fix root causes, not symptoms. A bug surfacing in emit/codegen is usually caused upstream (an IR\n  pass, lowering, type legalization, specialization, or the AST/IR representation). Trace it there.\n- Question every change. If you cannot name a test that fails without a change, it probably should\n  not exist. Ask whether the problem is telling you the direction/representation is flawed.\n- Do not mask. A guard, null-check, or special case that papers over malformed AST/IR/witness-table\n  data is a band-aid hiding a representation bug. Make the representation correct so consumers stay\n  simple.\n- Interrogate the input shape. For any code that handles a particular shape of input (AST node, IR\n  inst, witness, type, ...), always ask: is that shape itself correct and principled, or should the\n  upstream producer be fixed instead? Fix the producer when the shape is wrong; handle it here only\n  when the shape is genuinely valid input. Record the answer in the PR description (Process report).\n- Address conceptually unordered key→value data (witness-table / interface requirement entries) by\n  role/key, never by position/index.\n- Keep a working log throughout the task: the problem and a motivating example, how issues cascade\n  (one fix exposing the next), the fix chosen for each and why it is principled (with a code trace),\n  and rejected alternatives. Distill this log into the PR description; do not commit it.\n\n### Self-Review for Unprincipled Changes\n\nBefore finalizing a non-trivial compiler change, review the diff for signs that the fix is\ncompensating for a bad AST/IR/`Val`/witness representation. Treat the following patterns as\nhigh-risk until you can prove they are the right layer:\n\n- A new custom equivalence relation over `DeclRef`, `Val`, `Type`, `Witness`, or IR shapes, such as\n  recursive helpers named like `are...Equivalent`, `does...Match`, or `try...Match`. First ask why\n  normal `substitute`, `resolve`, `getCanonicalType`, `equals`, or an existing canonical builder\n  does not already make the two values identical.\n- A new helper, fallback, or \"try...\" function that exists only to make one failing test pass. Audit\n  every new helper, even small ones: if it redoes substitution, resolution, AST copy, generic\n  solving, lookup, or lowering, it is probably hiding the actual invariant break.\n- Code that converts checked semantic data back into syntax, such as rebuilding an `Expr` or\n  `TypeExp` from a `Val`, `Type`, `DeclRef`, or witness. The checked semantic field should usually\n  remain the source of truth; reconstructing syntax is a strong signal that a producer or copier is\n  storing the wrong representation.\n- Code that walks arbitrary operand graphs, substitution chains, witness chains, or lookup paths to\n  rediscover context such as generic arguments, requirement keys, canonical paths, or parent\n  declarations. The producer should usually store or construct the canonical form directly.\n- Lowering, emit, specialization, or typeflow logic that patches a malformed AST/IR shape from an\n  earlier phase. These consumers should be simple; if they need target-specific knowledge of a\n  front-end representation accident, trace the producer instead.\n- Hardcoded knowledge of particular `DeclRef` subclasses, builtin magic type names, generic\n  argument indices, witness-table entry order, or nested-vs-flat specialization shape. Such code\n  needs a strong invariant and should usually live at a canonical construction boundary.\n- Guards that silently return a default value for an \"impossible\" shape. Use an assertion when the\n  shape is truly out of contract; otherwise explain why the shape is valid input and add coverage.\n\nStart each review by making a short inventory of every new helper/fallback/special case in the\ndiff. For each entry, record whether it survives, is reverted, or needs a producer-side fix. For\nevery flagged change, write down the input-shape audit before keeping it:\n\n1. What exact shape reaches this code? Include a concrete example and the producing function.\n2. Is that shape canonical and intentionally allowed, or is it an accidental alternative spelling?\n3. If it is accidental, can the producer be fixed so downstream code uses the existing\n   `substitute`/`resolve`/canonicalization path?\n4. What semantic source of truth already exists, and is this code rebuilding syntax or structural\n   shape from it instead of preserving it?\n5. Which test fails if this change is removed, and does that test prove this layer is responsible?\n   Do the revert drill when practical: remove the helper/special case, run the smallest failing\n   test, and use the failure to identify the real producer-consumer break.\n6. Can the special case be replaced by an assertion plus a producer-side fix, or by reusing an\n   existing helper?\n\nDo not keep a flagged change merely because it makes tests pass. If it remains necessary, the\n`Process report` section of the PR description must justify why this input shape is valid and why\nthis layer owns the logic, with a code trace from producer to consumer.\n\n## Commit & Pull Request Guidelines\n\n- Use short, imperative commit subjects, for example `Reject invalid descriptor heap access`.\n- Keep PRs small and based on `master`.\n- PRs require passing workflows, review approval, and a `pr: non-breaking` or\n  `pr: breaking change` label.\n- Human contributors should sign the CLA when prompted.\n- For formatting failures, run installed hooks from `./extras/install-git-hooks.sh` or\n  request the format bot with `/format`.\n\nWrite the PR description in this five-part format:\n\n1. **Motivation** — the problem, with a concrete example / motivating test case.\n2. **Proposed solution** — the approach and why it is principled.\n3. **Change summary** — the files/areas touched and what each does.\n4. **Concepts and vocabulary** — a short glossary between the change summary and the process report.\n   Restate only the codebase-specific or subtle terms the report relies on (e.g. witness, facet,\n   the fixpoint solver, a non-obvious distinction the fix hinges on), as a reminder. Do not explain\n   basic, well-known concepts (interface, associated type) — assume them.\n5. **Process report** — explain every change with a logical reason. For a change addressing a\n   cascading issue, describe the issue (with its motivating test case) and justify the fix with a\n   code trace (the exact functions/insts involved), explaining why it is necessary and principled\n   rather than a workaround. For any change that handles, guards, or special-cases a particular\n   input shape, the report must answer the input-shape check from the methodology — is that shape\n   correct and principled, or should its producer have been fixed instead? — so a reviewer can\n   confirm the fix sits at the right layer.\n\nWrite for a reviewer without the full context in their head. Use the same conversational style\nexpected in code comments: start from a concrete user-code example, include the full relevant\nsnippet rather than just a type or function name, and explain the logical steps in order. Say what\nthe compiler builds, how that representation flows through named functions or IR instructions, and\nwhy the chosen fix preserves the invariant. Avoid terse headings like \"AST trace\"; make the prose\nread like an explanation to a reviewer who is learning the scenario for the first time.\n","CLAUDE.md":"<!--\nSPDX-FileCopyrightText: The Khronos Group, Inc.\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n**Repository**: shader-slang/slang - A shading language for GPU programming\n**Primary Language**: C++ with custom Slang language\n**MCP Tool Available**: `mcp__deepwiki__ask_question` with repoName: \"shader-slang/slang\"\n\nReference other instruction files as well:\n\n- @.github/copilot-instructions.md (shares formatting/testing/debugging info; this CLAUDE.md is the canonical source)\n\nUser-specific instructions for Slang (optional, may not exist):\n\n- @~/.claude/slang-instructions.md\n\n## Build System and Common Commands\n\n### Building the Project\n\nIf you are running in a Windows sandbox, run extras\\win-sandbox-build.bat to produce a build in\ndebug configuration. This script discovers Visual Studio, runs vcvarsall.bat, configures with the\n`vs2022-dev` preset, prefers locally cached dependencies instead of fetching them over the network,\nand defaults to building `slangc`, `slang-test`, and `slangi`. Pass extra target names if you need\nsomething other than that default target set.\n\nOn non-Windows platforms (Linux/macOS), run cmake directly to build:\n\n```bash\n# Configure with default settings (Ninja Multi-Config)\ncmake --preset default\n\n# Configure with visual studio 2022 settings (Preferred on Windows)\n# On Windows, include -DSLANG_IGNORE_ABORT_MSG=ON to suppress\n# modal abort dialogs during unattended/LLM-driven builds.\n# Use -DSLANG_EMBED_CORE_MODULE=OFF to keep core module compilation separate\n# from C++ source compilation. This way errors in *.meta.slang files (e.g.\n# hlsl.meta.slang) do not break the C++ compile — slangc and slang-test still\n# compile successfully, and the module errors are reported by the separate\n# `slang-bootstrap -compile-core-module` step instead.\n# Those errors still fail the build, though: generate_core_module_cache is an\n# ALL target that depends on generate_core_module (source/slang/CMakeLists.txt),\n# generate_core_module runs the bootstrap compile\n# (source/slang-core-module/CMakeLists.txt), and slangc itself takes\n# `REQUIRES generate_core_module_cache`, so even `--target slangc` runs it.\n# What OFF buys you is a clean separation of meta-source errors from C++\n# compilation errors, not a build that ignores meta-source errors.\ncmake.exe --preset vs2022 -DSLANG_IGNORE_ABORT_MSG=ON -DSLANG_EMBED_CORE_MODULE=OFF\n\n# Build Release/Debug binaries.\n# It can take from 5 minutes to 20 minutes depending on the machine.\ncmake --build --preset debug # Debug binary\ncmake --build --preset release # Release binary\n\n# Alternative: use workflow preset (configure + build in one step)\ncmake --workflow --preset debug\n\n# Build specific targets\ncmake --build --preset debug --target slangc\ncmake --build --preset debug --target slang-test\n```\n\n**sccache**: Pass `-DSLANG_USE_SCCACHE=ON` at configure time (or set `SLANG_USE_SCCACHE=1` env var) to use sccache as the compiler launcher for faster rebuilds. This automatically disables precompiled headers due to a known incompatibility. Requires `sccache` in PATH.\n\nWhen building with `cmake --build`, redirect all of outputs to null-device.\nWhen the build failed, then, re-run the same command without the redirections.\nIt is to avoid wasting the token usage of LLM.\n\nExample,\n\n```\n# Print the build logs only when the initial attempt failed.\ncmake --build --preset debug >/dev/null 2>&1 || cmake --build --preset debug\n```\n\n### Formatting\n\n**Run `./extras/formatting.sh` before committing changes.** PRs must conform to the project's coding style. Use `./extras/formatting.sh --check-only` to verify without modifying files.\n\n### Suppressing Unused Variable Warnings\n\nWhen a variable declared in an `if` condition is unused inside the body (the condition exists only for its type-check side-effect), use the **C++17 if-init-statement** pattern instead of `SLANG_UNUSED`:\n\n```cpp\n// Preferred: C++17 if-init pattern\nif (auto foo = as<IRFoo>(inst); foo)\n{\n    // foo not needed in body — the type check is the point\n}\n\n// Avoid: SLANG_UNUSED inside the body\nif (auto foo = as<IRFoo>(inst))\n{\n    SLANG_UNUSED(foo);\n}\n```\n\nFor variables that are set but never read outside an `if` (e.g., a plain local variable), use `SLANG_UNUSED(var)` with a comment explaining why.\n\n### Problem-Solving Methodology\n\nFollow the **principled path**, not the minimal-edit-distance path. The goal is a correct\nrepresentation that is robust by construction, even when that means a larger rework.\n\n- **Fix root causes, not symptoms.** When a bug appears in emit/codegen, the cause is usually\n  upstream (an IR pass, type legalization, specialization, lowering, or the AST/IR representation\n  itself). Trace it there and fix it there.\n- **Question every change.** Before keeping a change, answer: _Why is this change necessary? What\n  test fails without it? Is this the right fix, or is the problem telling me the\n  direction/representation is flawed?_ If you cannot name a test that fails without a change, the\n  change probably should not exist.\n- **Do not mask.** A guard, null-check, or special case that papers over a malformed\n  AST/IR/witness-table is a band-aid that hides a representation bug. A guard that is never hit\n  under correct input is dead code. Prefer making the representation correct so consumers stay\n  simple.\n- **Interrogate the input shape.** Whenever you write or change code that handles a particular\n  shape of input — an AST node, IR inst, witness, type, etc. — always ask: _is that input shape\n  itself correct and principled, or should the upstream producer of it be fixed instead?_ If the\n  shape is wrong or accidental, fix the producer; handle it here only when the shape is genuinely\n  valid input. This is the routine double-check that root-causing was done at the right layer, and\n  its answer is required in the PR description (see the Process report below).\n- **Prefer correct representation over edit distance.** If two surface forms _should_ be\n  equivalent, model them identically. If a consumer reads data by position/index/identity when the\n  data is conceptually an unordered key→value set (e.g. witness-table / interface requirement\n  entries), make the access by role/key, not by position.\n- **Keep a working log/report.** Maintain a scratch markdown document throughout the task that\n  records: the problem and a motivating example, road-blockers encountered, how issues **cascade**\n  (one fix exposing the next), the fix chosen for each and _why it is principled_ (with a concrete\n  code trace), and alternatives that were rejected and why. This log is what you distill into the\n  PR description below. (Keep the log out of the commit — it feeds the PR body, it is not a repo\n  artifact.)\n\n### Self-Review for Unprincipled Changes\n\nBefore finalizing a non-trivial compiler change, review the diff for signs that the fix is\ncompensating for a bad AST/IR/`Val`/witness representation. Treat these patterns as red flags until\nyou can prove they are the right layer:\n\n- **Custom semantic equivalence.** New recursive helpers over `DeclRef`, `Val`, `Type`, `Witness`,\n  or IR shapes (for example `are...Equivalent`, `does...Match`, or `try...Match`) often mean two\n  alternative representations were allowed to survive. First ask why `substitute`, `resolve`,\n  `getCanonicalType`, `equals`, or an existing canonical builder does not already make the values\n  identical.\n- **Unaudited helper growth.** Treat every new helper, fallback, and `try...` function as a review\n  target, not only large or complicated ones. A helper that exists to make one failing test pass,\n  or that reimplements part of substitution, resolution, AST copy, generic solving, lookup, or\n  lowering, is often the place where an unprincipled fix hides.\n- **Semantic-to-syntax reconstruction.** Code that turns checked semantic data (`Val`, `Type`,\n  `DeclRef`, witness, lowered IR value) back into syntax (`Expr`, `TypeExp`, parser-shaped AST) is\n  a strong smell. The checked semantic field should usually be the source of truth; rebuilding\n  surface syntax, as in a helper that recreates an expression from an `IntVal`, usually means the\n  producer/copier/substitution path is preserving the wrong representation.\n- **Context rediscovery by graph walking.** Code that walks arbitrary operand graphs, substitution\n  chains, witness chains, lookup paths, or IR users to recover generic arguments, requirement keys,\n  canonical paths, or parent declarations is usually downstream repair. Prefer storing or building\n  the canonical form at the producer.\n- **Consumer-side patching.** Lowering, emit, specialization, typeflow, and backend code should not\n  patch malformed AST/IR shapes from earlier phases. If these consumers need front-end-specific\n  knowledge of an accidental representation, trace and fix the producer instead.\n- **Hardcoded representation trivia.** Special cases for particular `DeclRef` subclasses, builtin\n  magic type names, generic argument indices, witness-table entry order, or nested-vs-flat\n  specialization shape need a strong invariant and usually belong at a canonical construction\n  boundary.\n- **Silent impossible-shape handling.** A guard that returns a default value for an out-of-contract\n  shape hides bugs. Assert impossible shapes; handle a shape only when you can explain why it is\n  valid input.\n\nBegin the review with a \"suspect helpers\" inventory: list every new helper/fallback/special case,\nwhat existing mechanism it overlaps with, the test that fails without it, and whether it survived,\nwas reverted, or was replaced by a producer-side fix. For every flagged change, run this audit\nbefore keeping it:\n\n1. Name the exact input shape, the producing function, and a concrete source or IR example.\n2. Decide whether that shape is canonical and intentionally allowed, or an accidental alternative\n   spelling that should be eliminated.\n3. If it is accidental, try the producer-side fix first so downstream code can use the normal\n   `substitute`/`resolve`/canonicalization path.\n4. Name the semantic source of truth that already exists. If the change rebuilds syntax or a\n   parallel structural form from that source of truth, justify why the stored representation cannot\n   be fixed instead.\n5. Name the test that fails without the change and explain why that test proves this layer owns the\n   logic. When practical, do the revert drill: remove the helper/special case, run the smallest\n   failing test, and use the failure to trace the real producer-consumer break.\n6. Prefer replacing the special case with an assertion plus a producer fix, or with an existing\n   helper that already encodes the invariant.\n\nDo not keep a flagged change only because it makes tests pass. If it remains necessary, the\n`Process report` section of the PR description must justify why the input shape is valid and why\nthis layer owns the logic, with a code trace from producer to consumer.\n\n### Code Style and Review Conventions\n\nRecurring review feedback distilled into rules — following them avoids review round-trips. (These\ngovern how code reads and is structured; the Problem-Solving Methodology above governs _what_ to\nchange.)\n\n- **Write function comments as complete sentences: what, then why.** State what the function does\n  first; then, if the reason it exists isn't obvious from that description, add a brief summary of\n  why. For non-trivial behavior, include a concrete example. Avoid terse fragment- or bullet-only\n  comments on a function. For instance, `substituteElementOfCompositeType` should read like _\"Return\n  `target` with its element type replaced by `newElementType`, preserving shape: scalar →\n  newElementType, `vector<T,N>` → `vector<newElementType,N>`, `matrix<T,R,C>` → `matrix<newElementType,R,C>`.\"_\n  — not _\"element coerce target\"_.\n\n- **Use conversational examples for code comments and PR explanations.** When explaining a subtle\n  compiler path, prefer \"Consider this example:\" followed by the relevant user code. Do not use\n  abstract labels such as \"Full source shape\", \"AST trace\", or \"IR trace\" as a substitute for\n  explanation. After the code, describe what happens step by step in natural prose: which parser,\n  checker, copier, lowering pass, or IR pass creates the shape; what invariant the local code\n  preserves; and which downstream consumer depends on that invariant. Include enough of the user's\n  original code for the example to make sense on its own.\n\n- **Reuse before you write; then extract non-trivial logic into a named, documented helper.** Before\n  writing a new helper, search for an existing one — what you need is often already provided by a\n  shared header (the AST/IR helpers in `slang-ast-type.h`, `slang-ir-util.h`, and the various\n  `*-util.h` files). For example, to test whether a type is a `DeclRefType` of a particular\n  declaration, use the existing `isDeclRefTypeOf<T>(type)` rather than re-deriving it. When the\n  logic genuinely is new, don't bury a multi-step computation in an inline lambda or a long inline\n  block: give it an intention-revealing name (`coerceOperandsOfBuiltinBinaryExpr`,\n  `substituteElementOfCompositeType`, `unifyBaseType`) and a doc comment, so the caller stays\n  readable and the helper is reusable.\n\n- **Keep one source of truth; delete dead code after a refactor.** Map or classify a given thing in\n  exactly one place — e.g. the operator-name → operation-kind mapping lives only in\n  `getBuiltinOperationKindFromString`, not re-implemented at call sites. When a change makes a\n  branch, fallback, or helper unreachable, remove it rather than leaving it as dead code.\n\n- **One canonical representation per value; assert the invariant.** Don't introduce a second\n  AST/IR/`Val` representation for something that already has one — multiple forms of the same logical\n  value break `equals`/identity checks and deduplication. When an invariant guarantees a\n  representation is never produced for certain inputs (e.g. `+`/`-`/`*` are always a\n  `PolynomialIntVal`, never a `BuiltinOperationIntVal`), `SLANG_ASSERT` it at the construction site\n  so a violation is caught rather than silently producing a divergent form.\n\n- **Fail loudly on out-of-contract input.** When a helper is only valid for a restricted set of\n  inputs, `SLANG_RELEASE_ASSERT` on anything outside that set instead of silently returning a default\n  — e.g. `substituteElementOfCompositeType` asserts its operand is a builtin scalar/vector/matrix.\n\n### PR Workflow\n\n1. **Format your code**: Run `./extras/formatting.sh` before committing\n2. **Label your PR**: Use \"pr: non-breaking\" (default) or \"pr: breaking change\" (for ABI/language breaking changes)\n3. **Include tests**: Add regression tests as `.slang` files under `tests/`\n4. **Write the PR description in this required five-part format:**\n   1. **Motivation** — the problem being solved, with a concrete example / motivating test case.\n   2. **Proposed solution** — the approach, and why it is the principled one.\n   3. **Change summary** — a table or list of the files/areas touched and what each does.\n   4. **Concepts and vocabulary** — a short glossary, placed between the change summary and the\n      process report. Restate only the _codebase-specific or subtle_ terms the report relies on, as\n      a reminder for the reviewer (e.g. witness / `getSub`, facet / `getInheritanceInfo`, the\n      fixpoint solver, or a non-obvious distinction the fix hinges on). Do **not** explain basic,\n      well-known concepts (e.g. interface, associated type) — assume them.\n   5. **Process report** — explain _every_ change with a logical reason. For a change that\n      addresses a **cascading** issue, describe the issue (with its motivating test case) and\n      justify why the fix is correct with a **code trace** (the exact functions/insts involved),\n      not just a description. State explicitly why each change is necessary and principled rather\n      than a workaround. For any change that handles, guards, or special-cases a particular input\n      shape, the report **must** answer the input-shape check from the methodology — _is that shape\n      correct and principled, or should its producer have been fixed instead?_ — so a reviewer can\n      confirm the fix sits at the right layer.\n\n   Write for a reviewer who does not have the full context in their head. Use the same\n   conversational style required for code comments: start from a concrete user-code example, include\n   the full relevant snippet instead of just naming a type or function, and explain the logical\n   steps in order. Say what the compiler builds, how that representation flows through named\n   functions or IR instructions, and why the chosen fix preserves the invariant. Avoid terse labels\n   such as \"AST trace\"; make the prose read like an explanation to a reviewer who is learning the\n   scenario for the first time.\n\n### Testing\n\nslang-test must run from repository root\n\n```bash\n# Run all tests with multiple servers (takes from 10 to 30 minutes)\n./build/Release/bin/slang-test -use-test-server -server-count 8\n\n# Run specific test\n# The test file must be placed under \"tests/\" directory\n./build/Release/bin/slang-test tests/path/to/test.slang\n\n# Run unit tests\n./build/Release/bin/slang-test slang-unit-test-tool/\n```\n\n**Writing Tests Without GPU**:\n\n- Use CPU compute: `//TEST:COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type`\n- Use interpreter: `//TEST:INTERPRET(filecheck=CHECK):`\n- Example test structure in `tests/language-feature/lambda/lambda-0.slang`\n\n**Diagnostic Tests** (see `docs/diagnostics.md` for full details):\n\nUse `//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK):` as the test directive to verify that the compiler emits expected diagnostics. Annotations in comments match against compiler output by message text, severity, or error code. Carets align to columns on the preceding source line:\n\n```slang\n//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK):-target spirv\nint foo = undefined;\n//CHECK: E01234\n//CHECK:  ^^^^^^^^^ error\n```\n\n**SPIRV Validation**:\n\n- Set `SLANG_RUN_SPIRV_VALIDATION=1` when using `slangc -target spirv`\n- Don't use system's `spirv-val` tool (may be outdated)\n\n### Slang Command Line Usage\n\n**IMPORTANT:** Slang uses single dashes for multi-character options (not double dashes like most tools):\n\n- Use `-help` (not `--help`)\n- Use `-target spirv` (not `--target spirv`)\n- Use `-dump-ir` (not `--dump-ir`)\n- Use `-stage compute` (not `--stage compute`)\n\n### AVOID These Debugging Options\n\n**DO NOT USE** these options as they are unmaintained, unreliable or unnecessary:\n\n- slangc with `-dump-ast`, `-dump-intermediate-prefix`, `-dump-intermediates`,\n  `-dump-ir-ids`, `-serial-ir`, and `-dump-repro`.\n- slang-test with `-category` and `-api`\n\n### Repro Tooling\n\n`-load-repro` and `-extract-repro` are specialized repro tools; use them when\nworking on repro handling. Inputs are validated before use.\n\n## Architecture Overview\n\n### Core Components\n\n**Compiler Pipeline**:\n\n- **Lexer** (`source/compiler-core/slang-lexer.cpp`): Tokenizes source code\n- **Preprocessor** (`source/slang/slang-preprocessor.cpp`): Handles #include, macros, conditionals\n- **Parser** (`source/slang/slang-parser.cpp`): Recursive descent parser producing AST\n- **Semantic Checker** (`source/slang/slang-check.cpp`): Type checking, name resolution, validation\n- **IR Generation** (`source/slang/slang-lower-to-ir.cpp`): Converts AST to Slang IR\n- **IR Passes** (`source/slang/slang-ir-*.cpp`): Optimization and lowering passes\n- **Code Emission** (`source/slang/slang-emit-*.cpp`): Target-specific code generation\n\n**Key Directories**:\n\n- `source/core/`: Core utilities (strings, containers, file system, platform abstractions)\n- `source/compiler-core/`: Compiler infrastructure (diagnostics, downstream compilers)\n- `source/slang/`: Main compiler implementation (frontend, IR, backend)\n- `source/slangc/`: Command-line compiler tool\n- `source/slang-core-module/`, `source/slang-glsl-module/`, `source/standard-modules/`: Standard library modules\n- `source/slang-wasm/`: WebAssembly bindings\n- `source/slang-record-replay/`: API call record/replay\n- `source/slang-rt/`: Runtime library\n- `tools/`: Development and testing tools\n- `include/`: Public API headers (`slang.h`)\n- `external/`: Third-party dependencies and submodules\n- `prelude/`: Built-in language definitions and standard library\n- `tests/`: Comprehensive test suite\n- `docs/`: Project documentation (user guide in `docs/user-guide/`)\n- `build/source/slang/fiddle/`: Generated code from FIDDLE macros (created during build)\n\n### Compilation Model\n\n**Key Concepts**:\n\n- **CompileRequest**: Bundles options, input files, and code generation requests\n- **TranslationUnit**: Collection of source files (HLSL: one per file, Slang: all files together)\n- **EntryPoint**: Function name + pipeline stage to compile\n- **Target**: Output format (DXIL, SPIR-V, etc.) + capability profile\n\n**Supported Targets**:\n\n- Direct3D 11/12 (HLSL output)\n- Vulkan (SPIR-V, GLSL output)\n- Metal (MSL output) - experimental\n- WebGPU (WGSL output) - experimental\n- CUDA/OptiX (C++ output)\n- CPU (C++ output, executables, libraries)\n\n## Development Workflow\n\n### Adding New Language Features\n\n1. Update lexer for new tokens (`source/compiler-core/slang-lexer.cpp`)\n2. Extend parser for new syntax (`source/slang/slang-parser.cpp`)\n3. Add semantic analysis (`source/slang/slang-check-*.cpp`)\n4. Implement IR generation (`source/slang/slang-ir-*.cpp`)\n5. Add code generation for each target backend (`source/slang/slang-emit-*.cpp`)\n6. Write comprehensive tests under `tests/`\n\n### Common Development Tasks\n\n- **Adding an IR instruction**: Update the Lua definition files in `source/slang/slang-ir-insts.lua`, then regenerate\n- **Adding a built-in function**: Add to appropriate module in `prelude/`\n- **Adding a new target**: Implement new emitter in `source/slang/slang-emit-*.cpp`\n\n### Capability Atoms Documentation\n\n**`docs/user-guide/a4-02-reference-capability-atoms.md` is auto-generated — never edit it directly.**\n\nIt is produced by `slang-capability-generator` from `source/slang/slang-capabilities.capdef`. To add or update a capability atom's description:\n\n1. Add or update the `///` doc comment immediately before the `def` or `alias` in `slang-capabilities.capdef`:\n   ```\n   /// My description here.\n   alias myatom = ...;\n   ```\n2. Regenerate the doc:\n   ```bash\n   cmake --build --preset debug --target slang-capability-generator\n   mkdir -p build/capgen-out\n   ./build/generators/Debug/bin/slang-capability-generator \\\n       source/slang/slang-capabilities.capdef \\\n       --target-directory build/capgen-out \\\n       --doc docs/user-guide/a4-02-reference-capability-atoms.md\n   ```\n3. Commit the updated `slang-capabilities.capdef` and the regenerated `.md` together.\n\nNote: the `///` comment must be on the **public alias** (e.g. `alias node = _node;`), not on the internal `def _node : stage;` atom, for the description to appear under the public name.\n\n### Modifying Public Headers (`include/`)\n\nAll files under `include/` are public API. Changes must preserve binary (ABI) and source\ncompatibility for callers compiled against older versions of the header.\n\n#### Enums\n\n- **Never insert a new enumerator in the middle of an existing enum.** Insertion shifts all\n  subsequent integer values, silently breaking any caller that stores or compares the value.\n- **Always append** new enumerators immediately before the terminal count/sentinel member\n  (e.g. `CountOf`, `Count`, `NUM_*`), assigning an explicit integer value (the next sequential\n  integer after the preceding enumerator).\n- **Removed enumerators**: rename to `REMOVED_<Name>` and keep the original integer value.\n  Never reuse or reclaim a retired integer.\n\n#### Virtual tables (COM interfaces)\n\nSlang's public interfaces (`ISession`, `IModule`, `IComponentType`, etc.) are COM-style\nvtables declared with `virtual` methods in `include/slang.h`. The vtable layout is fixed by\ndeclaration order. Violating these rules corrupts the vtable and causes silent crashes or\nwrong-method dispatch for any caller compiled against an older header.\n\n- **Never reorder virtual methods** within an interface.\n- **Never change a virtual method's signature** (return type, parameter types, calling\n  convention, or `SLANG_MCALL` decoration).\n- **Never insert a new virtual method** in the middle of an interface — append only, at the\n  end of the interface before the closing brace.\n- **Never remove a virtual method** — replace its body with a stub that returns\n  `SLANG_E_NOT_IMPLEMENTED` and keep the declaration in place.\n- Avoid extending an existing public COM interface in place when clients may implement or\n  query it by UUID. Prefer adding a new derived/versioned interface with its own UUID, while\n  keeping the original interface declaration and UUID supported for existing callers.\n\n### Debugging tools\n\n#### IR Dump (`-dump-ir`)\n\n```bash\n# Dump IR at every pass (use with -target and -o to avoid mixing output)\nslangc -dump-ir -target spirv-asm -o tmp.spv test.slang | python extras/split-ir-dump.py\n\n# Dump IR before/after a specific pass\nslangc -dump-ir-before lowerGenerics -dump-ir-after lowerGenerics -target spirv-asm -o tmp.spv test.slang > pass.dump\n```\n\n- Always combine `-dump-ir` with `-target` (otherwise compilation stops early) and `-o <file>` (otherwise target code mixes with IR on stdout)\n- Use `extras/split-ir-dump.py` to split large dumps into per-pass files. See `extras/split-ir-dump.md` for details.\n- You can insert `dumpIRToString()` in C++ code and write to a file with `File::writeAllText()` for ad-hoc inspection.\n- When debugging, focus on root causes in IR passes (specialization, inlining, type legalization, buffer lowering) rather than band-aid fixes in emit logic. The compiler philosophy is to keep emission simple and do heavy transforms in IR passes.\n\n#### InstTrace\n\nTrace where a problematic IR instruction was created:\n\n```bash\npython3 ./extras/insttrace.py <debugUID> ./build/Debug/bin/slangc tests/my-test.slang -target spirv\n```\n\n#### SPIRV Tools\n\n- `slangc -target spirv-asm` — compile to SPIRV assembly\n- Set `SLANG_RUN_SPIRV_VALIDATION=1` for static validation; use `-skip-spirv-validation` to see SPIRV output even when validation fails\n- `slangc -target spirv-asm -emit-spirv-via-glsl` — generate reference SPIRV via GLSL for comparison\n\n#### Assertion Behavior (`SLANG_ASSERT`)\n\nOn Windows, assertion failures normally open a modal dialog that blocks execution. Set the `SLANG_ASSERT` environment variable to control this:\n\n| Value                 | Behavior                                                                                                                       |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| `system`              | Use the system `assert()`, which shows a modal dialog and allows the developers to attach the debugger                         |\n| `debugbreak`          | When a debugger is already attached, it will hit a debug-break; fall back to `system` behavior when a debugger is not attached |\n| `release-assert-only` | Skip debug-only assertions (`SLANG_ASSERT`, `SLANG_ASSERT_FAILURE`) and continue; `SLANG_RELEASE_ASSERT` still fires           |\n| _(unset)_             | Throws an exception                                                                                                            |\n\nThe behavior on Windows after an exception is thrown is controlled by the CMake option `SLANG_IGNORE_ABORT_MSG`.\nThis option is highly recommended for unattended automation with LLM workflow; it bakes the behavior into all built executables at compile time.\n\n#### RTX Remix Testing\n\nUse the `/repro-remix` skill or see `extras/repro-remix.md`.\n\n### IR System\n\n- Slang uses a custom SSA-based IR (not LLVM)\n- IR instructions defined in `slang-ir-insts.h` (generated from Lua)\n- Extensive IR pass framework for optimization and lowering\n- Target-specific legalization passes before code emission\n\n### Language Server\n\n- Language Server Protocol implementation in `source/slang/slang-language-server.cpp`\n- Supports IntelliSense, completion, diagnostics, formatting\n- Used by VS Code and Visual Studio extensions\n\n### Module System\n\n- Slang supports separate compilation via modules\n- Modules can be compiled to IR and linked at runtime\n- Optional obfuscation for distributed modules\n- Core language features defined as modules in `prelude/`\n\n### Generated files\n\n- The enum values starting with `kIROp_` are defined in a generated file, `build/source/slang/fiddle/slang-ir-insts-enum.h.fiddle`\n- `FIDDLE()` and `FIDDLE(...)` statements in AST node declarations indicate that additional source is generated and included from `build/source/slang/fiddle`, providing static type system and reflection metadata, visitor support, and serialization support.\n\n### Rebuilding after `hlsl.meta.slang` / `core.meta.slang` changes\n\nThe core module source (`hlsl.meta.slang`, `core.meta.slang`, etc.) is embedded into the `slang-bootstrap` binary at compile time. After modifying these files, force CMake to observe the newer timestamp, regenerate the core-module headers through the build graph, then rebuild `slangc` with the preset/configuration you are using:\n\n```bash\ncmake -E touch source/slang/hlsl.meta.slang   # or whichever meta file changed\ncmake --build --preset <preset> --target generate_core_module_headers\ncmake --build --preset <preset> --target slangc\n```\n\nUse the same `<preset>` you use for the build, such as `debug`, `release`, or `releaseWithDebugInfo`. The `generate_core_module_headers` target invokes the correct `slang-bootstrap` binary for that host/configuration, including Windows `.exe` paths and non-Debug output directories.\n\nIf you skip the `cmake -E touch` step the cached bootstrap binary may silently embed the OLD source, and diagnostics from the bootstrap step will not match the current source file — a sure sign the binary is stale.\n\n### HLSL named-constant emission rule\n\n**Never emit HLSL enum / named-constant values as hard-coded integers.** DXC maps named constants (attribute strings, flag identifiers, etc.) at parse time; if we bake in a numeric value and DXC later changes the internal mapping the generated HLSL will silently break.\n\nThe correct pattern:\n\n1. **Define a Slang enum** (or a set of named intrinsic-backed constants) for each group of conceptual values (e.g. `NodeLaunch` mode, Barrier flag sets).\n2. **Store the name, not the integer, in the IR.** Use `IRStringLit` operands (as `NodeLaunchDecoration` does) or a `Ref<T>` / intrinsic-based accessor that preserves the identifier through to emission.\n3. **Provide a mapping function** in the HLSL emitter (`slang-emit-hlsl.cpp` or `slang-emit-c-like.cpp`) that converts the stored enum/string value back to the HLSL source name so that emitted code reads e.g. `[NodeLaunch(\"broadcasting\")]` not `[NodeLaunch(0)]`.\n\nExamples of this pattern already in the codebase:\n- `NodeLaunchDecoration` stores the mode as `IRStringLit(\"broadcasting\")` and the emitter re-emits the string verbatim.\n- Work-graph output record `Get()` returns `Ref<T>` backed by `__intrinsic_asm \".Get\"` so the emitted HLSL says `.Get(i)` (an l-value in HLSL) rather than an integer offset.\n\n#### Pattern: emitting enum values as target named constants\n\nUse this when a Slang enum must be emitted as named constants rather than integers (e.g. `UAV_MEMORY` instead of `1`).\n\n1. **Define the C++ enum in `slang-type-system-shared.h`** (inside `namespace Slang`, plain `enum` not `enum class` so values implicitly convert to `int`). This header is transitively included by both the core-module source and the emitters.\n\n2. **Mirror it as a Slang enum in the appropriate `*.meta.slang` file**, pulling the actual values from C++ via `$(...)` splices so the two definitions stay in sync:\n   ```slang\n   enum MyFlags : uint { FlagA = $(MyFlags::FlagA), FlagB = $(MyFlags::FlagB) }\n   ```\n\n3. **Declare a `__intrinsic_op` converter in the `.meta.slang` file** to represent the enum-to-string conversion in the IR:\n   ```slang\n   __intrinsic_op(getEnumMyFlags)\n   int GetEnumMyFlags(MyFlags f);\n   ```\n   The mnemonic passed to `__intrinsic_op(...)` must exactly match the Lua key in the next step.\n\n4. **Register the new IR op in `slang-ir-insts.lua`** and add a stable ID in `slang-ir-insts-stable-names.lua`.\n\n5. **Emit the named-constant string in the target emitter** (e.g. `tryEmitInstExprImpl` in `slang-emit-hlsl.cpp`): keep the IR operation tied to the symbolic enum or intrinsic value, then map each accepted bit or value to its HLSL named-constant string and write it out with `m_writer->emit(...)`. Do not document or implement examples that recover HLSL source names from raw integer positions.\n\n### Git commit message\n\n- Don't mention Claude on the commit message\n\n### Debugging with slangpy\n\nUse the `/slangpy-debug` skill to build slangpy from source with your local Slang build for compatibility testing.\n\n## Cross-Platform Considerations\n\n**Supported Platforms**:\nWindows (x64/ARM64), Linux (x64/ARM64), macOS (x64/ARM64), WebAssembly\n\n**Platform Abstractions**:\nUse utilities in `source/core/` for file system, process management, platform detection\n\n**Graphics APIs**:\nCode generation supports all major APIs but runtime testing requires appropriate drivers/SDKs\n\n**WSL on Windows**:\nWhen running under WSL environment, try to append `.exe` to the executables to avoid using Linux binaries\n\n- Use `cmake.exe` instead of `cmake`,\n- Use `python.exe` instead of `python`,\n- Use `gh.exe` instead of `gh` and so on.\n\n### Release Process\n\nUse the `/slang-release-process` skill to push a new release. See `.claude/skills/slang-release-process/SKILL.md` for the full workflow.\n\n## Additional Documents\n\n- User-facing documentation: `docs/user-guide/`\n- Language specification: see below\n\n### Formal Specification\n\nClone `https://github.com/shader-slang/spec.git` under `external/` if needed. Specification files are in `external/spec/specification/`, feature proposals in `external/spec/proposals/`.\n"},"files":{"AGENTS.md":"<!--\nSPDX-FileCopyrightText: The Khronos Group, Inc.\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# Repository Guidelines\n\n## Project Structure & Module Organization\n\nSlang is a shading-language compiler and runtime implemented primarily in C++20 and built with\nCMake.\n\nKey directories:\n\n- `source/`: core implementation, including `source/slang/`, `source/core/`,\n  `source/compiler-core/`, and tools like `source/slangc/`.\n- `include/`: public API headers.\n- `prelude/` and `source/standard-modules/`: standard/prelude headers.\n- `tests/`: test suites grouped by feature or target.\n- `tools/`: test infrastructure and developer tools.\n- `docs/`: documentation.\n- `examples/`: runnable samples.\n- `cmake/`: CMake helpers.\n- `external/`: vendored dependencies.\n\n## Repository-Local Skills\n\nThis repository stores local agent skills under `.claude/skills/`. Codex and other non-Claude\nharnesses should still consult those `SKILL.md` files when a user asks for the workflow they\ndescribe.\n\nReview-related skills:\n\n- `slang-review-clarity-workflow`: coordinate the end-to-end clarity review workflow.\n- `slang-review-clarity`: generate high-level clarity and explainability review candidates.\n- `slang-review-fine-grained-clarity`: generate line-by-line name/comment/type/function\n  consistency review candidates.\n- `slang-review-consolidate-candidates`: merge candidate files and resolve duplicates,\n  overlap, and superseded comments.\n- `slang-review-scope-filter`: conservatively filter candidate comments to issues the PR\n  author can reasonably own before posting.\n- `slang-review-resolve-judgment-calls`: resolve uncertain candidates with focused follow-up\n  analysis before posting.\n- `slang-review-post-github`: post filtered candidates as one proper GitHub PR review.\n\n## WSL and Windows Tooling\n\nWhen working in this repository from WSL on Windows, use Windows-native developer tools by\ndefault unless the user explicitly asks for the WSL/Linux version.\n\n- Use `git.exe`, not bare `git`. These worktrees use Windows path conventions; WSL Git can\n  corrupt or misinterpret worktree state, and Windows Git has much better file I/O performance\n  on this checkout.\n- When the `slang-build` skill invokes CMake, use `cmake.exe`, not bare `cmake`, for\n  Windows-hosted configure and build commands. Windows CMake can find Visual Studio 2026 and\n  the Windows toolchains required by the `vs2026` preset.\n- Use `gh.exe` instead of bare `gh` when GitHub CLI commands need to share the same\n  Windows-native Git and credential context.\n- Convert WSL paths before passing them to Windows tools, for example `wslpath -w \"$path\"`.\n  Convert paths printed by Windows tools back before using them in shell commands, for example\n  `wslpath -u \"$win_path\"`.\n- If a required `.exe` tool is unavailable, stop and report it instead of silently falling back\n  to the WSL/Linux tool.\n\n## Build, Test, and Development Commands\n\nSlang build setup is platform-specific, especially under WSL. For compiler builds, use the\n`slang-build` skill from `skills/slang-build` in the `shader-slang/slang-skills` repository\ninstead of following hard-coded commands in this file.\n\nIf the skill is unavailable because skills cannot be installed or network access is limited, use\n`docs/building.md` as the fallback build reference.\n\nExamples:\n\n- `/slang-build build debug`: build the Debug configuration.\n- `/slang-build rebuild debug`: discard the existing build directory and rebuild Debug.\n- `/slang-build configure releasewithdebug`: configure an optimized build with symbols.\n- `/slang-build clean`: rename and remove the existing build directory.\n\nDo not infer WSL build commands from generic Linux instructions. Follow the platform detection,\nhost-tool selection, CMake preset choice, and clean-build steps defined by the skill.\n\nAfter building, run tests from the repository root using the generated `slang-test` binary in\nthe directory for the selected configuration:\n\n- `build/Debug/bin/slang-test`: run the Debug test suite.\n- `build/RelWithDebInfo/bin/slang-test -use-test-server -server-count 8`: run optimized\n  tests with symbols in parallel using test servers.\n- `build/Release/bin/slang-test -use-test-server -server-count 8`: run Release tests in\n  parallel using test servers.\n\nOn Windows-hosted builds, use the `.exe` suffix if that is the generated binary name.\n\n## Include Path Conventions\n\nPrefer direct paths over relative traversal in `#include` directives. The `source/` directory is\non the compiler include path (exposed by the `core` CMake target), so cross-module headers are\nreachable without `../`:\n\n```cpp\n// Preferred in new code\n#include \"core/slang-string.h\"\n#include \"compiler-core/slang-source-loc.h\"\n\n// Existing code still uses the relative form; do not change it purely for style\n#include \"../core/slang-string.h\"\n#include \"../compiler-core/slang-source-loc.h\"\n```\n\nNew files should use direct paths. Existing files need not be converted purely for style, but may\nbe opportunistically updated when the file is already being substantially modified for other\nreasons (e.g., a security fix or feature addition touching many lines).\n\n## Coding Style & Naming Conventions\n\nFormatting:\n\n- Use four-space indentation for C, C++, headers, and Slang files.\n- Run `./extras/formatting.sh` before committing to apply rules from `.clang-format`\n  and `.editorconfig`.\n- Follow Allman braces, a 100-column limit, left-aligned pointers, and final newlines.\n\nConventions:\n\n- Follow `docs/design/coding-conventions.md`.\n- Avoid STL containers, iostreams, RTTI, and exceptions for ordinary errors.\n- Use `UpperCamelCase` for types and `lowerCamelCase` for values.\n- Use `SLANG_`-prefixed `SCREAMING_SNAKE_CASE` for macros.\n- Prefer comments that explain why code exists.\n\nReview conventions (recurring review feedback — following them avoids review round-trips):\n\n- Comment functions in complete sentences: what it does first, then why if non-obvious; include a\n  concrete example for non-trivial logic.\n- Write explanatory comments in a conversational style. Prefer \"Consider this example:\" followed\n  by the relevant user code over abstract labels such as \"Full source shape\", \"AST trace\", or\n  \"IR trace\". After the example, explain what happens step by step in natural prose: which\n  producer creates the AST/IR/value shape, what invariant this code is preserving, and which\n  downstream consumer relies on it. Include enough of the original user code for the example to be\n  understood without reconstructing the surrounding program from memory.\n- Reuse before you write: check shared headers (`slang-ast-type.h`, `slang-ir-util.h`, the `*-util.h`\n  files) for an existing helper (e.g. `isDeclRefTypeOf<T>`) before adding one. When the logic is\n  genuinely new, extract it into a named, documented helper rather than an inline lambda/long block.\n- Keep one source of truth for a mapping or classification, and delete any branch/fallback a refactor\n  makes unreachable.\n- Don't create a second AST/IR/`Val` representation of a value that already has one (it breaks\n  `equals`/dedup); `SLANG_ASSERT` such invariants at the construction site.\n- `SLANG_RELEASE_ASSERT` on out-of-contract input instead of silently returning a default.\n\n## Shell Scripts\n\nScripts under `extras/` (and other repository shell scripts) must run on bash 3.2, the version\nApple ships as `/bin/bash` on macOS. Avoid bash 4+ only features such as `${var,,}`/`${var^^}`\ncase conversion, associative arrays (`declare -A`), `mapfile`/`readarray`, and namerefs\n(`local -n`). Prefer portable equivalents (for example, lowercase with\n`tr '[:upper:]' '[:lower:]'`). Validate with `bash -n script.sh` under the system bash.\n\n## Testing Guidelines\n\nAdd tests near related coverage in `tests/`.\n\nSlang tests:\n\n- Use leading directives such as `//TEST(smoke):SIMPLE:`.\n- Use `//DISABLE_TEST` only with a clear reason.\n- For targeted runs, pass a prefix, for example\n  `build/Debug/bin/slang-test tests/diagnostics/my-test`.\n\nUnit tests live under `tools/slang-unit-test` and typically use `SLANG_UNIT_TEST(name)`.\n\n## Problem-Solving Methodology\n\nFollow the principled path, not the minimal-edit-distance path.\n\n- Fix root causes, not symptoms. A bug surfacing in emit/codegen is usually caused upstream (an IR\n  pass, lowering, type legalization, specialization, or the AST/IR representation). Trace it there.\n- Question every change. If you cannot name a test that fails without a change, it probably should\n  not exist. Ask whether the problem is telling you the direction/representation is flawed.\n- Do not mask. A guard, null-check, or special case that papers over malformed AST/IR/witness-table\n  data is a band-aid hiding a representation bug. Make the representation correct so consumers stay\n  simple.\n- Interrogate the input shape. For any code that handles a particular shape of input (AST node, IR\n  inst, witness, type, ...), always ask: is that shape itself correct and principled, or should the\n  upstream producer be fixed instead? Fix the producer when the shape is wrong; handle it here only\n  when the shape is genuinely valid input. Record the answer in the PR description (Process report).\n- Address conceptually unordered key→value data (witness-table / interface requirement entries) by\n  role/key, never by position/index.\n- Keep a working log throughout the task: the problem and a motivating example, how issues cascade\n  (one fix exposing the next), the fix chosen for each and why it is principled (with a code trace),\n  and rejected alternatives. Distill this log into the PR description; do not commit it.\n\n### Self-Review for Unprincipled Changes\n\nBefore finalizing a non-trivial compiler change, review the diff for signs that the fix is\ncompensating for a bad AST/IR/`Val`/witness representation. Treat the following patterns as\nhigh-risk until you can prove they are the right layer:\n\n- A new custom equivalence relation over `DeclRef`, `Val`, `Type`, `Witness`, or IR shapes, such as\n  recursive helpers named like `are...Equivalent`, `does...Match`, or `try...Match`. First ask why\n  normal `substitute`, `resolve`, `getCanonicalType`, `equals`, or an existing canonical builder\n  does not already make the two values identical.\n- A new helper, fallback, or \"try...\" function that exists only to make one failing test pass. Audit\n  every new helper, even small ones: if it redoes substitution, resolution, AST copy, generic\n  solving, lookup, or lowering, it is probably hiding the actual invariant break.\n- Code that converts checked semantic data back into syntax, such as rebuilding an `Expr` or\n  `TypeExp` from a `Val`, `Type`, `DeclRef`, or witness. The checked semantic field should usually\n  remain the source of truth; reconstructing syntax is a strong signal that a producer or copier is\n  storing the wrong representation.\n- Code that walks arbitrary operand graphs, substitution chains, witness chains, or lookup paths to\n  rediscover context such as generic arguments, requirement keys, canonical paths, or parent\n  declarations. The producer should usually store or construct the canonical form directly.\n- Lowering, emit, specialization, or typeflow logic that patches a malformed AST/IR shape from an\n  earlier phase. These consumers should be simple; if they need target-specific knowledge of a\n  front-end representation accident, trace the producer instead.\n- Hardcoded knowledge of particular `DeclRef` subclasses, builtin magic type names, generic\n  argument indices, witness-table entry order, or nested-vs-flat specialization shape. Such code\n  needs a strong invariant and should usually live at a canonical construction boundary.\n- Guards that silently return a default value for an \"impossible\" shape. Use an assertion when the\n  shape is truly out of contract; otherwise explain why the shape is valid input and add coverage.\n\nStart each review by making a short inventory of every new helper/fallback/special case in the\ndiff. For each entry, record whether it survives, is reverted, or needs a producer-side fix. For\nevery flagged change, write down the input-shape audit before keeping it:\n\n1. What exact shape reaches this code? Include a concrete example and the producing function.\n2. Is that shape canonical and intentionally allowed, or is it an accidental alternative spelling?\n3. If it is accidental, can the producer be fixed so downstream code uses the existing\n   `substitute`/`resolve`/canonicalization path?\n4. What semantic source of truth already exists, and is this code rebuilding syntax or structural\n   shape from it instead of preserving it?\n5. Which test fails if this change is removed, and does that test prove this layer is responsible?\n   Do the revert drill when practical: remove the helper/special case, run the smallest failing\n   test, and use the failure to identify the real producer-consumer break.\n6. Can the special case be replaced by an assertion plus a producer-side fix, or by reusing an\n   existing helper?\n\nDo not keep a flagged change merely because it makes tests pass. If it remains necessary, the\n`Process report` section of the PR description must justify why this input shape is valid and why\nthis layer owns the logic, with a code trace from producer to consumer.\n\n## Commit & Pull Request Guidelines\n\n- Use short, imperative commit subjects, for example `Reject invalid descriptor heap access`.\n- Keep PRs small and based on `master`.\n- PRs require passing workflows, review approval, and a `pr: non-breaking` or\n  `pr: breaking change` label.\n- Human contributors should sign the CLA when prompted.\n- For formatting failures, run installed hooks from `./extras/install-git-hooks.sh` or\n  request the format bot with `/format`.\n\nWrite the PR description in this five-part format:\n\n1. **Motivation** — the problem, with a concrete example / motivating test case.\n2. **Proposed solution** — the approach and why it is principled.\n3. **Change summary** — the files/areas touched and what each does.\n4. **Concepts and vocabulary** — a short glossary between the change summary and the process report.\n   Restate only the codebase-specific or subtle terms the report relies on (e.g. witness, facet,\n   the fixpoint solver, a non-obvious distinction the fix hinges on), as a reminder. Do not explain\n   basic, well-known concepts (interface, associated type) — assume them.\n5. **Process report** — explain every change with a logical reason. For a change addressing a\n   cascading issue, describe the issue (with its motivating test case) and justify the fix with a\n   code trace (the exact functions/insts involved), explaining why it is necessary and principled\n   rather than a workaround. For any change that handles, guards, or special-cases a particular\n   input shape, the report must answer the input-shape check from the methodology — is that shape\n   correct and principled, or should its producer have been fixed instead? — so a reviewer can\n   confirm the fix sits at the right layer.\n\nWrite for a reviewer without the full context in their head. Use the same conversational style\nexpected in code comments: start from a concrete user-code example, include the full relevant\nsnippet rather than just a type or function name, and explain the logical steps in order. Say what\nthe compiler builds, how that representation flows through named functions or IR instructions, and\nwhy the chosen fix preserves the invariant. Avoid terse headings like \"AST trace\"; make the prose\nread like an explanation to a reviewer who is learning the scenario for the first time.\n","CLAUDE.md":"<!--\nSPDX-FileCopyrightText: The Khronos Group, Inc.\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n**Repository**: shader-slang/slang - A shading language for GPU programming\n**Primary Language**: C++ with custom Slang language\n**MCP Tool Available**: `mcp__deepwiki__ask_question` with repoName: \"shader-slang/slang\"\n\nReference other instruction files as well:\n\n- @.github/copilot-instructions.md (shares formatting/testing/debugging info; this CLAUDE.md is the canonical source)\n\nUser-specific instructions for Slang (optional, may not exist):\n\n- @~/.claude/slang-instructions.md\n\n## Build System and Common Commands\n\n### Building the Project\n\nIf you are running in a Windows sandbox, run extras\\win-sandbox-build.bat to produce a build in\ndebug configuration. This script discovers Visual Studio, runs vcvarsall.bat, configures with the\n`vs2022-dev` preset, prefers locally cached dependencies instead of fetching them over the network,\nand defaults to building `slangc`, `slang-test`, and `slangi`. Pass extra target names if you need\nsomething other than that default target set.\n\nOn non-Windows platforms (Linux/macOS), run cmake directly to build:\n\n```bash\n# Configure with default settings (Ninja Multi-Config)\ncmake --preset default\n\n# Configure with visual studio 2022 settings (Preferred on Windows)\n# On Windows, include -DSLANG_IGNORE_ABORT_MSG=ON to suppress\n# modal abort dialogs during unattended/LLM-driven builds.\n# Use -DSLANG_EMBED_CORE_MODULE=OFF to keep core module compilation separate\n# from C++ source compilation. This way errors in *.meta.slang files (e.g.\n# hlsl.meta.slang) do not break the C++ compile — slangc and slang-test still\n# compile successfully, and the module errors are reported by the separate\n# `slang-bootstrap -compile-core-module` step instead.\n# Those errors still fail the build, though: generate_core_module_cache is an\n# ALL target that depends on generate_core_module (source/slang/CMakeLists.txt),\n# generate_core_module runs the bootstrap compile\n# (source/slang-core-module/CMakeLists.txt), and slangc itself takes\n# `REQUIRES generate_core_module_cache`, so even `--target slangc` runs it.\n# What OFF buys you is a clean separation of meta-source errors from C++\n# compilation errors, not a build that ignores meta-source errors.\ncmake.exe --preset vs2022 -DSLANG_IGNORE_ABORT_MSG=ON -DSLANG_EMBED_CORE_MODULE=OFF\n\n# Build Release/Debug binaries.\n# It can take from 5 minutes to 20 minutes depending on the machine.\ncmake --build --preset debug # Debug binary\ncmake --build --preset release # Release binary\n\n# Alternative: use workflow preset (configure + build in one step)\ncmake --workflow --preset debug\n\n# Build specific targets\ncmake --build --preset debug --target slangc\ncmake --build --preset debug --target slang-test\n```\n\n**sccache**: Pass `-DSLANG_USE_SCCACHE=ON` at configure time (or set `SLANG_USE_SCCACHE=1` env var) to use sccache as the compiler launcher for faster rebuilds. This automatically disables precompiled headers due to a known incompatibility. Requires `sccache` in PATH.\n\nWhen building with `cmake --build`, redirect all of outputs to null-device.\nWhen the build failed, then, re-run the same command without the redirections.\nIt is to avoid wasting the token usage of LLM.\n\nExample,\n\n```\n# Print the build logs only when the initial attempt failed.\ncmake --build --preset debug >/dev/null 2>&1 || cmake --build --preset debug\n```\n\n### Formatting\n\n**Run `./extras/formatting.sh` before committing changes.** PRs must conform to the project's coding style. Use `./extras/formatting.sh --check-only` to verify without modifying files.\n\n### Suppressing Unused Variable Warnings\n\nWhen a variable declared in an `if` condition is unused inside the body (the condition exists only for its type-check side-effect), use the **C++17 if-init-statement** pattern instead of `SLANG_UNUSED`:\n\n```cpp\n// Preferred: C++17 if-init pattern\nif (auto foo = as<IRFoo>(inst); foo)\n{\n    // foo not needed in body — the type check is the point\n}\n\n// Avoid: SLANG_UNUSED inside the body\nif (auto foo = as<IRFoo>(inst))\n{\n    SLANG_UNUSED(foo);\n}\n```\n\nFor variables that are set but never read outside an `if` (e.g., a plain local variable), use `SLANG_UNUSED(var)` with a comment explaining why.\n\n### Problem-Solving Methodology\n\nFollow the **principled path**, not the minimal-edit-distance path. The goal is a correct\nrepresentation that is robust by construction, even when that means a larger rework.\n\n- **Fix root causes, not symptoms.** When a bug appears in emit/codegen, the cause is usually\n  upstream (an IR pass, type legalization, specialization, lowering, or the AST/IR representation\n  itself). Trace it there and fix it there.\n- **Question every change.** Before keeping a change, answer: _Why is this change necessary? What\n  test fails without it? Is this the right fix, or is the problem telling me the\n  direction/representation is flawed?_ If you cannot name a test that fails without a change, the\n  change probably should not exist.\n- **Do not mask.** A guard, null-check, or special case that papers over a malformed\n  AST/IR/witness-table is a band-aid that hides a representation bug. A guard that is never hit\n  under correct input is dead code. Prefer making the representation correct so consumers stay\n  simple.\n- **Interrogate the input shape.** Whenever you write or change code that handles a particular\n  shape of input — an AST node, IR inst, witness, type, etc. — always ask: _is that input shape\n  itself correct and principled, or should the upstream producer of it be fixed instead?_ If the\n  shape is wrong or accidental, fix the producer; handle it here only when the shape is genuinely\n  valid input. This is the routine double-check that root-causing was done at the right layer, and\n  its answer is required in the PR description (see the Process report below).\n- **Prefer correct representation over edit distance.** If two surface forms _should_ be\n  equivalent, model them identically. If a consumer reads data by position/index/identity when the\n  data is conceptually an unordered key→value set (e.g. witness-table / interface requirement\n  entries), make the access by role/key, not by position.\n- **Keep a working log/report.** Maintain a scratch markdown document throughout the task that\n  records: the problem and a motivating example, road-blockers encountered, how issues **cascade**\n  (one fix exposing the next), the fix chosen for each and _why it is principled_ (with a concrete\n  code trace), and alternatives that were rejected and why. This log is what you distill into the\n  PR description below. (Keep the log out of the commit — it feeds the PR body, it is not a repo\n  artifact.)\n\n### Self-Review for Unprincipled Changes\n\nBefore finalizing a non-trivial compiler change, review the diff for signs that the fix is\ncompensating for a bad AST/IR/`Val`/witness representation. Treat these patterns as red flags until\nyou can prove they are the right layer:\n\n- **Custom semantic equivalence.** New recursive helpers over `DeclRef`, `Val`, `Type`, `Witness`,\n  or IR shapes (for example `are...Equivalent`, `does...Match`, or `try...Match`) often mean two\n  alternative representations were allowed to survive. First ask why `substitute`, `resolve`,\n  `getCanonicalType`, `equals`, or an existing canonical builder does not already make the values\n  identical.\n- **Unaudited helper growth.** Treat every new helper, fallback, and `try...` function as a review\n  target, not only large or complicated ones. A helper that exists to make one failing test pass,\n  or that reimplements part of substitution, resolution, AST copy, generic solving, lookup, or\n  lowering, is often the place where an unprincipled fix hides.\n- **Semantic-to-syntax reconstruction.** Code that turns checked semantic data (`Val`, `Type`,\n  `DeclRef`, witness, lowered IR value) back into syntax (`Expr`, `TypeExp`, parser-shaped AST) is\n  a strong smell. The checked semantic field should usually be the source of truth; rebuilding\n  surface syntax, as in a helper that recreates an expression from an `IntVal`, usually means the\n  producer/copier/substitution path is preserving the wrong representation.\n- **Context rediscovery by graph walking.** Code that walks arbitrary operand graphs, substitution\n  chains, witness chains, lookup paths, or IR users to recover generic arguments, requirement keys,\n  canonical paths, or parent declarations is usually downstream repair. Prefer storing or building\n  the canonical form at the producer.\n- **Consumer-side patching.** Lowering, emit, specialization, typeflow, and backend code should not\n  patch malformed AST/IR shapes from earlier phases. If these consumers need front-end-specific\n  knowledge of an accidental representation, trace and fix the producer instead.\n- **Hardcoded representation trivia.** Special cases for particular `DeclRef` subclasses, builtin\n  magic type names, generic argument indices, witness-table entry order, or nested-vs-flat\n  specialization shape need a strong invariant and usually belong at a canonical construction\n  boundary.\n- **Silent impossible-shape handling.** A guard that returns a default value for an out-of-contract\n  shape hides bugs. Assert impossible shapes; handle a shape only when you can explain why it is\n  valid input.\n\nBegin the review with a \"suspect helpers\" inventory: list every new helper/fallback/special case,\nwhat existing mechanism it overlaps with, the test that fails without it, and whether it survived,\nwas reverted, or was replaced by a producer-side fix. For every flagged change, run this audit\nbefore keeping it:\n\n1. Name the exact input shape, the producing function, and a concrete source or IR example.\n2. Decide whether that shape is canonical and intentionally allowed, or an accidental alternative\n   spelling that should be eliminated.\n3. If it is accidental, try the producer-side fix first so downstream code can use the normal\n   `substitute`/`resolve`/canonicalization path.\n4. Name the semantic source of truth that already exists. If the change rebuilds syntax or a\n   parallel structural form from that source of truth, justify why the stored representation cannot\n   be fixed instead.\n5. Name the test that fails without the change and explain why that test proves this layer owns the\n   logic. When practical, do the revert drill: remove the helper/special case, run the smallest\n   failing test, and use the failure to trace the real producer-consumer break.\n6. Prefer replacing the special case with an assertion plus a producer fix, or with an existing\n   helper that already encodes the invariant.\n\nDo not keep a flagged change only because it makes tests pass. If it remains necessary, the\n`Process report` section of the PR description must justify why the input shape is valid and why\nthis layer owns the logic, with a code trace from producer to consumer.\n\n### Code Style and Review Conventions\n\nRecurring review feedback distilled into rules — following them avoids review round-trips. (These\ngovern how code reads and is structured; the Problem-Solving Methodology above governs _what_ to\nchange.)\n\n- **Write function comments as complete sentences: what, then why.** State what the function does\n  first; then, if the reason it exists isn't obvious from that description, add a brief summary of\n  why. For non-trivial behavior, include a concrete example. Avoid terse fragment- or bullet-only\n  comments on a function. For instance, `substituteElementOfCompositeType` should read like _\"Return\n  `target` with its element type replaced by `newElementType`, preserving shape: scalar →\n  newElementType, `vector<T,N>` → `vector<newElementType,N>`, `matrix<T,R,C>` → `matrix<newElementType,R,C>`.\"_\n  — not _\"element coerce target\"_.\n\n- **Use conversational examples for code comments and PR explanations.** When explaining a subtle\n  compiler path, prefer \"Consider this example:\" followed by the relevant user code. Do not use\n  abstract labels such as \"Full source shape\", \"AST trace\", or \"IR trace\" as a substitute for\n  explanation. After the code, describe what happens step by step in natural prose: which parser,\n  checker, copier, lowering pass, or IR pass creates the shape; what invariant the local code\n  preserves; and which downstream consumer depends on that invariant. Include enough of the user's\n  original code for the example to make sense on its own.\n\n- **Reuse before you write; then extract non-trivial logic into a named, documented helper.** Before\n  writing a new helper, search for an existing one — what you need is often already provided by a\n  shared header (the AST/IR helpers in `slang-ast-type.h`, `slang-ir-util.h`, and the various\n  `*-util.h` files). For example, to test whether a type is a `DeclRefType` of a particular\n  declaration, use the existing `isDeclRefTypeOf<T>(type)` rather than re-deriving it. When the\n  logic genuinely is new, don't bury a multi-step computation in an inline lambda or a long inline\n  block: give it an intention-revealing name (`coerceOperandsOfBuiltinBinaryExpr`,\n  `substituteElementOfCompositeType`, `unifyBaseType`) and a doc comment, so the caller stays\n  readable and the helper is reusable.\n\n- **Keep one source of truth; delete dead code after a refactor.** Map or classify a given thing in\n  exactly one place — e.g. the operator-name → operation-kind mapping lives only in\n  `getBuiltinOperationKindFromString`, not re-implemented at call sites. When a change makes a\n  branch, fallback, or helper unreachable, remove it rather than leaving it as dead code.\n\n- **One canonical representation per value; assert the invariant.** Don't introduce a second\n  AST/IR/`Val` representation for something that already has one — multiple forms of the same logical\n  value break `equals`/identity checks and deduplication. When an invariant guarantees a\n  representation is never produced for certain inputs (e.g. `+`/`-`/`*` are always a\n  `PolynomialIntVal`, never a `BuiltinOperationIntVal`), `SLANG_ASSERT` it at the construction site\n  so a violation is caught rather than silently producing a divergent form.\n\n- **Fail loudly on out-of-contract input.** When a helper is only valid for a restricted set of\n  inputs, `SLANG_RELEASE_ASSERT` on anything outside that set instead of silently returning a default\n  — e.g. `substituteElementOfCompositeType` asserts its operand is a builtin scalar/vector/matrix.\n\n### PR Workflow\n\n1. **Format your code**: Run `./extras/formatting.sh` before committing\n2. **Label your PR**: Use \"pr: non-breaking\" (default) or \"pr: breaking change\" (for ABI/language breaking changes)\n3. **Include tests**: Add regression tests as `.slang` files under `tests/`\n4. **Write the PR description in this required five-part format:**\n   1. **Motivation** — the problem being solved, with a concrete example / motivating test case.\n   2. **Proposed solution** — the approach, and why it is the principled one.\n   3. **Change summary** — a table or list of the files/areas touched and what each does.\n   4. **Concepts and vocabulary** — a short glossary, placed between the change summary and the\n      process report. Restate only the _codebase-specific or subtle_ terms the report relies on, as\n      a reminder for the reviewer (e.g. witness / `getSub`, facet / `getInheritanceInfo`, the\n      fixpoint solver, or a non-obvious distinction the fix hinges on). Do **not** explain basic,\n      well-known concepts (e.g. interface, associated type) — assume them.\n   5. **Process report** — explain _every_ change with a logical reason. For a change that\n      addresses a **cascading** issue, describe the issue (with its motivating test case) and\n      justify why the fix is correct with a **code trace** (the exact functions/insts involved),\n      not just a description. State explicitly why each change is necessary and principled rather\n      than a workaround. For any change that handles, guards, or special-cases a particular input\n      shape, the report **must** answer the input-shape check from the methodology — _is that shape\n      correct and principled, or should its producer have been fixed instead?_ — so a reviewer can\n      confirm the fix sits at the right layer.\n\n   Write for a reviewer who does not have the full context in their head. Use the same\n   conversational style required for code comments: start from a concrete user-code example, include\n   the full relevant snippet instead of just naming a type or function, and explain the logical\n   steps in order. Say what the compiler builds, how that representation flows through named\n   functions or IR instructions, and why the chosen fix preserves the invariant. Avoid terse labels\n   such as \"AST trace\"; make the prose read like an explanation to a reviewer who is learning the\n   scenario for the first time.\n\n### Testing\n\nslang-test must run from repository root\n\n```bash\n# Run all tests with multiple servers (takes from 10 to 30 minutes)\n./build/Release/bin/slang-test -use-test-server -server-count 8\n\n# Run specific test\n# The test file must be placed under \"tests/\" directory\n./build/Release/bin/slang-test tests/path/to/test.slang\n\n# Run unit tests\n./build/Release/bin/slang-test slang-unit-test-tool/\n```\n\n**Writing Tests Without GPU**:\n\n- Use CPU compute: `//TEST:COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type`\n- Use interpreter: `//TEST:INTERPRET(filecheck=CHECK):`\n- Example test structure in `tests/language-feature/lambda/lambda-0.slang`\n\n**Diagnostic Tests** (see `docs/diagnostics.md` for full details):\n\nUse `//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK):` as the test directive to verify that the compiler emits expected diagnostics. Annotations in comments match against compiler output by message text, severity, or error code. Carets align to columns on the preceding source line:\n\n```slang\n//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK):-target spirv\nint foo = undefined;\n//CHECK: E01234\n//CHECK:  ^^^^^^^^^ error\n```\n\n**SPIRV Validation**:\n\n- Set `SLANG_RUN_SPIRV_VALIDATION=1` when using `slangc -target spirv`\n- Don't use system's `spirv-val` tool (may be outdated)\n\n### Slang Command Line Usage\n\n**IMPORTANT:** Slang uses single dashes for multi-character options (not double dashes like most tools):\n\n- Use `-help` (not `--help`)\n- Use `-target spirv` (not `--target spirv`)\n- Use `-dump-ir` (not `--dump-ir`)\n- Use `-stage compute` (not `--stage compute`)\n\n### AVOID These Debugging Options\n\n**DO NOT USE** these options as they are unmaintained, unreliable or unnecessary:\n\n- slangc with `-dump-ast`, `-dump-intermediate-prefix`, `-dump-intermediates`,\n  `-dump-ir-ids`, `-serial-ir`, and `-dump-repro`.\n- slang-test with `-category` and `-api`\n\n### Repro Tooling\n\n`-load-repro` and `-extract-repro` are specialized repro tools; use them when\nworking on repro handling. Inputs are validated before use.\n\n## Architecture Overview\n\n### Core Components\n\n**Compiler Pipeline**:\n\n- **Lexer** (`source/compiler-core/slang-lexer.cpp`): Tokenizes source code\n- **Preprocessor** (`source/slang/slang-preprocessor.cpp`): Handles #include, macros, conditionals\n- **Parser** (`source/slang/slang-parser.cpp`): Recursive descent parser producing AST\n- **Semantic Checker** (`source/slang/slang-check.cpp`): Type checking, name resolution, validation\n- **IR Generation** (`source/slang/slang-lower-to-ir.cpp`): Converts AST to Slang IR\n- **IR Passes** (`source/slang/slang-ir-*.cpp`): Optimization and lowering passes\n- **Code Emission** (`source/slang/slang-emit-*.cpp`): Target-specific code generation\n\n**Key Directories**:\n\n- `source/core/`: Core utilities (strings, containers, file system, platform abstractions)\n- `source/compiler-core/`: Compiler infrastructure (diagnostics, downstream compilers)\n- `source/slang/`: Main compiler implementation (frontend, IR, backend)\n- `source/slangc/`: Command-line compiler tool\n- `source/slang-core-module/`, `source/slang-glsl-module/`, `source/standard-modules/`: Standard library modules\n- `source/slang-wasm/`: WebAssembly bindings\n- `source/slang-record-replay/`: API call record/replay\n- `source/slang-rt/`: Runtime library\n- `tools/`: Development and testing tools\n- `include/`: Public API headers (`slang.h`)\n- `external/`: Third-party dependencies and submodules\n- `prelude/`: Built-in language definitions and standard library\n- `tests/`: Comprehensive test suite\n- `docs/`: Project documentation (user guide in `docs/user-guide/`)\n- `build/source/slang/fiddle/`: Generated code from FIDDLE macros (created during build)\n\n### Compilation Model\n\n**Key Concepts**:\n\n- **CompileRequest**: Bundles options, input files, and code generation requests\n- **TranslationUnit**: Collection of source files (HLSL: one per file, Slang: all files together)\n- **EntryPoint**: Function name + pipeline stage to compile\n- **Target**: Output format (DXIL, SPIR-V, etc.) + capability profile\n\n**Supported Targets**:\n\n- Direct3D 11/12 (HLSL output)\n- Vulkan (SPIR-V, GLSL output)\n- Metal (MSL output) - experimental\n- WebGPU (WGSL output) - experimental\n- CUDA/OptiX (C++ output)\n- CPU (C++ output, executables, libraries)\n\n## Development Workflow\n\n### Adding New Language Features\n\n1. Update lexer for new tokens (`source/compiler-core/slang-lexer.cpp`)\n2. Extend parser for new syntax (`source/slang/slang-parser.cpp`)\n3. Add semantic analysis (`source/slang/slang-check-*.cpp`)\n4. Implement IR generation (`source/slang/slang-ir-*.cpp`)\n5. Add code generation for each target backend (`source/slang/slang-emit-*.cpp`)\n6. Write comprehensive tests under `tests/`\n\n### Common Development Tasks\n\n- **Adding an IR instruction**: Update the Lua definition files in `source/slang/slang-ir-insts.lua`, then regenerate\n- **Adding a built-in function**: Add to appropriate module in `prelude/`\n- **Adding a new target**: Implement new emitter in `source/slang/slang-emit-*.cpp`\n\n### Capability Atoms Documentation\n\n**`docs/user-guide/a4-02-reference-capability-atoms.md` is auto-generated — never edit it directly.**\n\nIt is produced by `slang-capability-generator` from `source/slang/slang-capabilities.capdef`. To add or update a capability atom's description:\n\n1. Add or update the `///` doc comment immediately before the `def` or `alias` in `slang-capabilities.capdef`:\n   ```\n   /// My description here.\n   alias myatom = ...;\n   ```\n2. Regenerate the doc:\n   ```bash\n   cmake --build --preset debug --target slang-capability-generator\n   mkdir -p build/capgen-out\n   ./build/generators/Debug/bin/slang-capability-generator \\\n       source/slang/slang-capabilities.capdef \\\n       --target-directory build/capgen-out \\\n       --doc docs/user-guide/a4-02-reference-capability-atoms.md\n   ```\n3. Commit the updated `slang-capabilities.capdef` and the regenerated `.md` together.\n\nNote: the `///` comment must be on the **public alias** (e.g. `alias node = _node;`), not on the internal `def _node : stage;` atom, for the description to appear under the public name.\n\n### Modifying Public Headers (`include/`)\n\nAll files under `include/` are public API. Changes must preserve binary (ABI) and source\ncompatibility for callers compiled against older versions of the header.\n\n#### Enums\n\n- **Never insert a new enumerator in the middle of an existing enum.** Insertion shifts all\n  subsequent integer values, silently breaking any caller that stores or compares the value.\n- **Always append** new enumerators immediately before the terminal count/sentinel member\n  (e.g. `CountOf`, `Count`, `NUM_*`), assigning an explicit integer value (the next sequential\n  integer after the preceding enumerator).\n- **Removed enumerators**: rename to `REMOVED_<Name>` and keep the original integer value.\n  Never reuse or reclaim a retired integer.\n\n#### Virtual tables (COM interfaces)\n\nSlang's public interfaces (`ISession`, `IModule`, `IComponentType`, etc.) are COM-style\nvtables declared with `virtual` methods in `include/slang.h`. The vtable layout is fixed by\ndeclaration order. Violating these rules corrupts the vtable and causes silent crashes or\nwrong-method dispatch for any caller compiled against an older header.\n\n- **Never reorder virtual methods** within an interface.\n- **Never change a virtual method's signature** (return type, parameter types, calling\n  convention, or `SLANG_MCALL` decoration).\n- **Never insert a new virtual method** in the middle of an interface — append only, at the\n  end of the interface before the closing brace.\n- **Never remove a virtual method** — replace its body with a stub that returns\n  `SLANG_E_NOT_IMPLEMENTED` and keep the declaration in place.\n- Avoid extending an existing public COM interface in place when clients may implement or\n  query it by UUID. Prefer adding a new derived/versioned interface with its own UUID, while\n  keeping the original interface declaration and UUID supported for existing callers.\n\n### Debugging tools\n\n#### IR Dump (`-dump-ir`)\n\n```bash\n# Dump IR at every pass (use with -target and -o to avoid mixing output)\nslangc -dump-ir -target spirv-asm -o tmp.spv test.slang | python extras/split-ir-dump.py\n\n# Dump IR before/after a specific pass\nslangc -dump-ir-before lowerGenerics -dump-ir-after lowerGenerics -target spirv-asm -o tmp.spv test.slang > pass.dump\n```\n\n- Always combine `-dump-ir` with `-target` (otherwise compilation stops early) and `-o <file>` (otherwise target code mixes with IR on stdout)\n- Use `extras/split-ir-dump.py` to split large dumps into per-pass files. See `extras/split-ir-dump.md` for details.\n- You can insert `dumpIRToString()` in C++ code and write to a file with `File::writeAllText()` for ad-hoc inspection.\n- When debugging, focus on root causes in IR passes (specialization, inlining, type legalization, buffer lowering) rather than band-aid fixes in emit logic. The compiler philosophy is to keep emission simple and do heavy transforms in IR passes.\n\n#### InstTrace\n\nTrace where a problematic IR instruction was created:\n\n```bash\npython3 ./extras/insttrace.py <debugUID> ./build/Debug/bin/slangc tests/my-test.slang -target spirv\n```\n\n#### SPIRV Tools\n\n- `slangc -target spirv-asm` — compile to SPIRV assembly\n- Set `SLANG_RUN_SPIRV_VALIDATION=1` for static validation; use `-skip-spirv-validation` to see SPIRV output even when validation fails\n- `slangc -target spirv-asm -emit-spirv-via-glsl` — generate reference SPIRV via GLSL for comparison\n\n#### Assertion Behavior (`SLANG_ASSERT`)\n\nOn Windows, assertion failures normally open a modal dialog that blocks execution. Set the `SLANG_ASSERT` environment variable to control this:\n\n| Value                 | Behavior                                                                                                                       |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| `system`              | Use the system `assert()`, which shows a modal dialog and allows the developers to attach the debugger                         |\n| `debugbreak`          | When a debugger is already attached, it will hit a debug-break; fall back to `system` behavior when a debugger is not attached |\n| `release-assert-only` | Skip debug-only assertions (`SLANG_ASSERT`, `SLANG_ASSERT_FAILURE`) and continue; `SLANG_RELEASE_ASSERT` still fires           |\n| _(unset)_             | Throws an exception                                                                                                            |\n\nThe behavior on Windows after an exception is thrown is controlled by the CMake option `SLANG_IGNORE_ABORT_MSG`.\nThis option is highly recommended for unattended automation with LLM workflow; it bakes the behavior into all built executables at compile time.\n\n#### RTX Remix Testing\n\nUse the `/repro-remix` skill or see `extras/repro-remix.md`.\n\n### IR System\n\n- Slang uses a custom SSA-based IR (not LLVM)\n- IR instructions defined in `slang-ir-insts.h` (generated from Lua)\n- Extensive IR pass framework for optimization and lowering\n- Target-specific legalization passes before code emission\n\n### Language Server\n\n- Language Server Protocol implementation in `source/slang/slang-language-server.cpp`\n- Supports IntelliSense, completion, diagnostics, formatting\n- Used by VS Code and Visual Studio extensions\n\n### Module System\n\n- Slang supports separate compilation via modules\n- Modules can be compiled to IR and linked at runtime\n- Optional obfuscation for distributed modules\n- Core language features defined as modules in `prelude/`\n\n### Generated files\n\n- The enum values starting with `kIROp_` are defined in a generated file, `build/source/slang/fiddle/slang-ir-insts-enum.h.fiddle`\n- `FIDDLE()` and `FIDDLE(...)` statements in AST node declarations indicate that additional source is generated and included from `build/source/slang/fiddle`, providing static type system and reflection metadata, visitor support, and serialization support.\n\n### Rebuilding after `hlsl.meta.slang` / `core.meta.slang` changes\n\nThe core module source (`hlsl.meta.slang`, `core.meta.slang`, etc.) is embedded into the `slang-bootstrap` binary at compile time. After modifying these files, force CMake to observe the newer timestamp, regenerate the core-module headers through the build graph, then rebuild `slangc` with the preset/configuration you are using:\n\n```bash\ncmake -E touch source/slang/hlsl.meta.slang   # or whichever meta file changed\ncmake --build --preset <preset> --target generate_core_module_headers\ncmake --build --preset <preset> --target slangc\n```\n\nUse the same `<preset>` you use for the build, such as `debug`, `release`, or `releaseWithDebugInfo`. The `generate_core_module_headers` target invokes the correct `slang-bootstrap` binary for that host/configuration, including Windows `.exe` paths and non-Debug output directories.\n\nIf you skip the `cmake -E touch` step the cached bootstrap binary may silently embed the OLD source, and diagnostics from the bootstrap step will not match the current source file — a sure sign the binary is stale.\n\n### HLSL named-constant emission rule\n\n**Never emit HLSL enum / named-constant values as hard-coded integers.** DXC maps named constants (attribute strings, flag identifiers, etc.) at parse time; if we bake in a numeric value and DXC later changes the internal mapping the generated HLSL will silently break.\n\nThe correct pattern:\n\n1. **Define a Slang enum** (or a set of named intrinsic-backed constants) for each group of conceptual values (e.g. `NodeLaunch` mode, Barrier flag sets).\n2. **Store the name, not the integer, in the IR.** Use `IRStringLit` operands (as `NodeLaunchDecoration` does) or a `Ref<T>` / intrinsic-based accessor that preserves the identifier through to emission.\n3. **Provide a mapping function** in the HLSL emitter (`slang-emit-hlsl.cpp` or `slang-emit-c-like.cpp`) that converts the stored enum/string value back to the HLSL source name so that emitted code reads e.g. `[NodeLaunch(\"broadcasting\")]` not `[NodeLaunch(0)]`.\n\nExamples of this pattern already in the codebase:\n- `NodeLaunchDecoration` stores the mode as `IRStringLit(\"broadcasting\")` and the emitter re-emits the string verbatim.\n- Work-graph output record `Get()` returns `Ref<T>` backed by `__intrinsic_asm \".Get\"` so the emitted HLSL says `.Get(i)` (an l-value in HLSL) rather than an integer offset.\n\n#### Pattern: emitting enum values as target named constants\n\nUse this when a Slang enum must be emitted as named constants rather than integers (e.g. `UAV_MEMORY` instead of `1`).\n\n1. **Define the C++ enum in `slang-type-system-shared.h`** (inside `namespace Slang`, plain `enum` not `enum class` so values implicitly convert to `int`). This header is transitively included by both the core-module source and the emitters.\n\n2. **Mirror it as a Slang enum in the appropriate `*.meta.slang` file**, pulling the actual values from C++ via `$(...)` splices so the two definitions stay in sync:\n   ```slang\n   enum MyFlags : uint { FlagA = $(MyFlags::FlagA), FlagB = $(MyFlags::FlagB) }\n   ```\n\n3. **Declare a `__intrinsic_op` converter in the `.meta.slang` file** to represent the enum-to-string conversion in the IR:\n   ```slang\n   __intrinsic_op(getEnumMyFlags)\n   int GetEnumMyFlags(MyFlags f);\n   ```\n   The mnemonic passed to `__intrinsic_op(...)` must exactly match the Lua key in the next step.\n\n4. **Register the new IR op in `slang-ir-insts.lua`** and add a stable ID in `slang-ir-insts-stable-names.lua`.\n\n5. **Emit the named-constant string in the target emitter** (e.g. `tryEmitInstExprImpl` in `slang-emit-hlsl.cpp`): keep the IR operation tied to the symbolic enum or intrinsic value, then map each accepted bit or value to its HLSL named-constant string and write it out with `m_writer->emit(...)`. Do not document or implement examples that recover HLSL source names from raw integer positions.\n\n### Git commit message\n\n- Don't mention Claude on the commit message\n\n### Debugging with slangpy\n\nUse the `/slangpy-debug` skill to build slangpy from source with your local Slang build for compatibility testing.\n\n## Cross-Platform Considerations\n\n**Supported Platforms**:\nWindows (x64/ARM64), Linux (x64/ARM64), macOS (x64/ARM64), WebAssembly\n\n**Platform Abstractions**:\nUse utilities in `source/core/` for file system, process management, platform detection\n\n**Graphics APIs**:\nCode generation supports all major APIs but runtime testing requires appropriate drivers/SDKs\n\n**WSL on Windows**:\nWhen running under WSL environment, try to append `.exe` to the executables to avoid using Linux binaries\n\n- Use `cmake.exe` instead of `cmake`,\n- Use `python.exe` instead of `python`,\n- Use `gh.exe` instead of `gh` and so on.\n\n### Release Process\n\nUse the `/slang-release-process` skill to push a new release. See `.claude/skills/slang-release-process/SKILL.md` for the full workflow.\n\n## Additional Documents\n\n- User-facing documentation: `docs/user-guide/`\n- Language specification: see below\n\n### Formal Specification\n\nClone `https://github.com/shader-slang/spec.git` under `external/` if needed. Specification files are in `external/spec/specification/`, feature proposals in `external/spec/proposals/`.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"<!--\nSPDX-FileCopyrightText: The Khronos Group, Inc.\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# Repository Guidelines\n\n## Project Structure & Module Organization\n\nSlang is a shading-language compiler and runtime implemented primarily in C++20 and built with\nCMake.\n\nKey directories:\n\n- `source/`: core implementation, including `source/slang/`, `source/core/`,\n  `source/compiler-core/`, and tools like `source/slangc/`.\n- `include/`: public API headers.\n- `prelude/` and `source/standard-modules/`: standard/prelude headers.\n- `tests/`: test suites grouped by feature or target.\n- `tools/`: test infrastructure and developer tools.\n- `docs/`: documentation.\n- `examples/`: runnable samples.\n- `cmake/`: CMake helpers.\n- `external/`: vendored dependencies.\n\n## Repository-Local Skills\n\nThis repository stores local agent skills under `.claude/skills/`. Codex and other non-Claude\nharnesses should still consult those `SKILL.md` files when a user asks for the workflow they\ndescribe.\n\nReview-related skills:\n\n- `slang-review-clarity-workflow`: coordinate the end-to-end clarity review workflow.\n- `slang-review-clarity`: generate high-level clarity and explainability review candidates.\n- `slang-review-fine-grained-clarity`: generate line-by-line name/comment/type/function\n  consistency review candidates.\n- `slang-review-consolidate-candidates`: merge candidate files and resolve duplicates,\n  overlap, and superseded comments.\n- `slang-review-scope-filter`: conservatively filter candidate comments to issues the PR\n  author can reasonably own before posting.\n- `slang-review-resolve-judgment-calls`: resolve uncertain candidates with focused follow-up\n  analysis before posting.\n- `slang-review-post-github`: post filtered candidates as one proper GitHub PR review.\n\n## WSL and Windows Tooling\n\nWhen working in this repository from WSL on Windows, use Windows-native developer tools by\ndefault unless the user explicitly asks for the WSL/Linux version.\n\n- Use `git.exe`, not bare `git`. These worktrees use Windows path conventions; WSL Git can\n  corrupt or misinterpret worktree state, and Windows Git has much better file I/O performance\n  on this checkout.\n- When the `slang-build` skill invokes CMake, use `cmake.exe`, not bare `cmake`, for\n  Windows-hosted configure and build commands. Windows CMake can find Visual Studio 2026 and\n  the Windows toolchains required by the `vs2026` preset.\n- Use `gh.exe` instead of bare `gh` when GitHub CLI commands need to share the same\n  Windows-native Git and credential context.\n- Convert WSL paths before passing them to Windows tools, for example `wslpath -w \"$path\"`.\n  Convert paths printed by Windows tools back before using them in shell commands, for example\n  `wslpath -u \"$win_path\"`.\n- If a required `.exe` tool is unavailable, stop and report it instead of silently falling back\n  to the WSL/Linux tool.\n\n## Build, Test, and Development Commands\n\nSlang build setup is platform-specific, especially under WSL. For compiler builds, use the\n`slang-build` skill from `skills/slang-build` in the `shader-slang/slang-skills` repository\ninstead of following hard-coded commands in this file.\n\nIf the skill is unavailable because skills cannot be installed or network access is limited, use\n`docs/building.md` as the fallback build reference.\n\nExamples:\n\n- `/slang-build build debug`: build the Debug configuration.\n- `/slang-build rebuild debug`: discard the existing build directory and rebuild Debug.\n- `/slang-build configure releasewithdebug`: configure an optimized build with symbols.\n- `/slang-build clean`: rename and remove the existing build directory.\n\nDo not infer WSL build commands from generic Linux instructions. Follow the platform detection,\nhost-tool selection, CMake preset choice, and clean-build steps defined by the skill.\n\nAfter building, run tests from the repository root using the generated `slang-test` binary in\nthe directory for the selected configuration:\n\n- `build/Debug/bin/slang-test`: run the Debug test suite.\n- `build/RelWithDebInfo/bin/slang-test -use-test-server -server-count 8`: run optimized\n  tests with symbols in parallel using test servers.\n- `build/Release/bin/slang-test -use-test-server -server-count 8`: run Release tests in\n  parallel using test servers.\n\nOn Windows-hosted builds, use the `.exe` suffix if that is the generated binary name.\n\n## Include Path Conventions\n\nPrefer direct paths over relative traversal in `#include` directives. The `source/` directory is\non the compiler include path (exposed by the `core` CMake target), so cross-module headers are\nreachable without `../`:\n\n```cpp\n// Preferred in new code\n#include \"core/slang-string.h\"\n#include \"compiler-core/slang-source-loc.h\"\n\n// Existing code still uses the relative form; do not change it purely for style\n#include \"../core/slang-string.h\"\n#include \"../compiler-core/slang-source-loc.h\"\n```\n\nNew files should use direct paths. Existing files need not be converted purely for style, but may\nbe opportunistically updated when the file is already being substantially modified for other\nreasons (e.g., a security fix or feature addition touching many lines).\n\n## Coding Style & Naming Conventions\n\nFormatting:\n\n- Use four-space indentation for C, C++, headers, and Slang files.\n- Run `./extras/formatting.sh` before committing to apply rules from `.clang-format`\n  and `.editorconfig`.\n- Follow Allman braces, a 100-column limit, left-aligned pointers, and final newlines.\n\nConventions:\n\n- Follow `docs/design/coding-conventions.md`.\n- Avoid STL containers, iostreams, RTTI, and exceptions for ordinary errors.\n- Use `UpperCamelCase` for types and `lowerCamelCase` for values.\n- Use `SLANG_`-prefixed `SCREAMING_SNAKE_CASE` for macros.\n- Prefer comments that explain why code exists.\n\nReview conventions (recurring review feedback — following them avoids review round-trips):\n\n- Comment functions in complete sentences: what it does first, then why if non-obvious; include a\n  concrete example for non-trivial logic.\n- Write explanatory comments in a conversational style. Prefer \"Consider this example:\" followed\n  by the relevant user code over abstract labels such as \"Full source shape\", \"AST trace\", or\n  \"IR trace\". After the example, explain what happens step by step in natural prose: which\n  producer creates the AST/IR/value shape, what invariant this code is preserving, and which\n  downstream consumer relies on it. Include enough of the original user code for the example to be\n  understood without reconstructing the surrounding program from memory.\n- Reuse before you write: check shared headers (`slang-ast-type.h`, `slang-ir-util.h`, the `*-util.h`\n  files) for an existing helper (e.g. `isDeclRefTypeOf<T>`) before adding one. When the logic is\n  genuinely new, extract it into a named, documented helper rather than an inline lambda/long block.\n- Keep one source of truth for a mapping or classification, and delete any branch/fallback a refactor\n  makes unreachable.\n- Don't create a second AST/IR/`Val` representation of a value that already has one (it breaks\n  `equals`/dedup); `SLANG_ASSERT` such invariants at the construction site.\n- `SLANG_RELEASE_ASSERT` on out-of-contract input instead of silently returning a default.\n\n## Shell Scripts\n\nScripts under `extras/` (and other repository shell scripts) must run on bash 3.2, the version\nApple ships as `/bin/bash` on macOS. Avoid bash 4+ only features such as `${var,,}`/`${var^^}`\ncase conversion, associative arrays (`declare -A`), `mapfile`/`readarray`, and namerefs\n(`local -n`). Prefer portable equivalents (for example, lowercase with\n`tr '[:upper:]' '[:lower:]'`). Validate with `bash -n script.sh` under the system bash.\n\n## Testing Guidelines\n\nAdd tests near related coverage in `tests/`.\n\nSlang tests:\n\n- Use leading directives such as `//TEST(smoke):SIMPLE:`.\n- Use `//DISABLE_TEST` only with a clear reason.\n- For targeted runs, pass a prefix, for example\n  `build/Debug/bin/slang-test tests/diagnostics/my-test`.\n\nUnit tests live under `tools/slang-unit-test` and typically use `SLANG_UNIT_TEST(name)`.\n\n## Problem-Solving Methodology\n\nFollow the principled path, not the minimal-edit-distance path.\n\n- Fix root causes, not symptoms. A bug surfacing in emit/codegen is usually caused upstream (an IR\n  pass, lowering, type legalization, specialization, or the AST/IR representation). Trace it there.\n- Question every change. If you cannot name a test that fails without a change, it probably should\n  not exist. Ask whether the problem is telling you the direction/representation is flawed.\n- Do not mask. A guard, null-check, or special case that papers over malformed AST/IR/witness-table\n  data is a band-aid hiding a representation bug. Make the representation correct so consumers stay\n  simple.\n- Interrogate the input shape. For any code that handles a particular shape of input (AST node, IR\n  inst, witness, type, ...), always ask: is that shape itself correct and principled, or should the\n  upstream producer be fixed instead? Fix the producer when the shape is wrong; handle it here only\n  when the shape is genuinely valid input. Record the answer in the PR description (Process report).\n- Address conceptually unordered key→value data (witness-table / interface requirement entries) by\n  role/key, never by position/index.\n- Keep a working log throughout the task: the problem and a motivating example, how issues cascade\n  (one fix exposing the next), the fix chosen for each and why it is principled (with a code trace),\n  and rejected alternatives. Distill this log into the PR description; do not commit it.\n\n### Self-Review for Unprincipled Changes\n\nBefore finalizing a non-trivial compiler change, review the diff for signs that the fix is\ncompensating for a bad AST/IR/`Val`/witness representation. Treat the following patterns as\nhigh-risk until you can prove they are the right layer:\n\n- A new custom equivalence relation over `DeclRef`, `Val`, `Type`, `Witness`, or IR shapes, such as\n  recursive helpers named like `are...Equivalent`, `does...Match`, or `try...Match`. First ask why\n  normal `substitute`, `resolve`, `getCanonicalType`, `equals`, or an existing canonical builder\n  does not already make the two values identical.\n- A new helper, fallback, or \"try...\" function that exists only to make one failing test pass. Audit\n  every new helper, even small ones: if it redoes substitution, resolution, AST copy, generic\n  solving, lookup, or lowering, it is probably hiding the actual invariant break.\n- Code that converts checked semantic data back into syntax, such as rebuilding an `Expr` or\n  `TypeExp` from a `Val`, `Type`, `DeclRef`, or witness. The checked semantic field should usually\n  remain the source of truth; reconstructing syntax is a strong signal that a producer or copier is\n  storing the wrong representation.\n- Code that walks arbitrary operand graphs, substitution chains, witness chains, or lookup paths to\n  rediscover context such as generic arguments, requirement keys, canonical paths, or parent\n  declarations. The producer should usually store or construct the canonical form directly.\n- Lowering, emit, specialization, or typeflow logic that patches a malformed AST/IR shape from an\n  earlier phase. These consumers should be simple; if they need target-specific knowledge of a\n  front-end representation accident, trace the producer instead.\n- Hardcoded knowledge of particular `DeclRef` subclasses, builtin magic type names, generic\n  argument indices, witness-table entry order, or nested-vs-flat specialization shape. Such code\n  needs a strong invariant and should usually live at a canonical construction boundary.\n- Guards that silently return a default value for an \"impossible\" shape. Use an assertion when the\n  shape is truly out of contract; otherwise explain why the shape is valid input and add coverage.\n\nStart each review by making a short inventory of every new helper/fallback/special case in the\ndiff. For each entry, record whether it survives, is reverted, or needs a producer-side fix. For\nevery flagged change, write down the input-shape audit before keeping it:\n\n1. What exact shape reaches this code? Include a concrete example and the producing function.\n2. Is that shape canonical and intentionally allowed, or is it an accidental alternative spelling?\n3. If it is accidental, can the producer be fixed so downstream code uses the existing\n   `substitute`/`resolve`/canonicalization path?\n4. What semantic source of truth already exists, and is this code rebuilding syntax or structural\n   shape from it instead of preserving it?\n5. Which test fails if this change is removed, and does that test prove this layer is responsible?\n   Do the revert drill when practical: remove the helper/special case, run the smallest failing\n   test, and use the failure to identify the real producer-consumer break.\n6. Can the special case be replaced by an assertion plus a producer-side fix, or by reusing an\n   existing helper?\n\nDo not keep a flagged change merely because it makes tests pass. If it remains necessary, the\n`Process report` section of the PR description must justify why this input shape is valid and why\nthis layer owns the logic, with a code trace from producer to consumer.\n\n## Commit & Pull Request Guidelines\n\n- Use short, imperative commit subjects, for example `Reject invalid descriptor heap access`.\n- Keep PRs small and based on `master`.\n- PRs require passing workflows, review approval, and a `pr: non-breaking` or\n  `pr: breaking change` label.\n- Human contributors should sign the CLA when prompted.\n- For formatting failures, run installed hooks from `./extras/install-git-hooks.sh` or\n  request the format bot with `/format`.\n\nWrite the PR description in this five-part format:\n\n1. **Motivation** — the problem, with a concrete example / motivating test case.\n2. **Proposed solution** — the approach and why it is principled.\n3. **Change summary** — the files/areas touched and what each does.\n4. **Concepts and vocabulary** — a short glossary between the change summary and the process report.\n   Restate only the codebase-specific or subtle terms the report relies on (e.g. witness, facet,\n   the fixpoint solver, a non-obvious distinction the fix hinges on), as a reminder. Do not explain\n   basic, well-known concepts (interface, associated type) — assume them.\n5. **Process report** — explain every change with a logical reason. For a change addressing a\n   cascading issue, describe the issue (with its motivating test case) and justify the fix with a\n   code trace (the exact functions/insts involved), explaining why it is necessary and principled\n   rather than a workaround. For any change that handles, guards, or special-cases a particular\n   input shape, the report must answer the input-shape check from the methodology — is that shape\n   correct and principled, or should its producer have been fixed instead? — so a reviewer can\n   confirm the fix sits at the right layer.\n\nWrite for a reviewer without the full context in their head. Use the same conversational style\nexpected in code comments: start from a concrete user-code example, include the full relevant\nsnippet rather than just a type or function name, and explain the logical steps in order. Say what\nthe compiler builds, how that representation flows through named functions or IR instructions, and\nwhy the chosen fix preserves the invariant. Avoid terse headings like \"AST trace\"; make the prose\nread like an explanation to a reviewer who is learning the scenario for the first time.\n","category":"root","tokens":3883},{"name":"CLAUDE.md","path":"CLAUDE.md","title":"CLAUDE.md","content":"<!--\nSPDX-FileCopyrightText: The Khronos Group, Inc.\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n**Repository**: shader-slang/slang - A shading language for GPU programming\n**Primary Language**: C++ with custom Slang language\n**MCP Tool Available**: `mcp__deepwiki__ask_question` with repoName: \"shader-slang/slang\"\n\nReference other instruction files as well:\n\n- @.github/copilot-instructions.md (shares formatting/testing/debugging info; this CLAUDE.md is the canonical source)\n\nUser-specific instructions for Slang (optional, may not exist):\n\n- @~/.claude/slang-instructions.md\n\n## Build System and Common Commands\n\n### Building the Project\n\nIf you are running in a Windows sandbox, run extras\\win-sandbox-build.bat to produce a build in\ndebug configuration. This script discovers Visual Studio, runs vcvarsall.bat, configures with the\n`vs2022-dev` preset, prefers locally cached dependencies instead of fetching them over the network,\nand defaults to building `slangc`, `slang-test`, and `slangi`. Pass extra target names if you need\nsomething other than that default target set.\n\nOn non-Windows platforms (Linux/macOS), run cmake directly to build:\n\n```bash\n# Configure with default settings (Ninja Multi-Config)\ncmake --preset default\n\n# Configure with visual studio 2022 settings (Preferred on Windows)\n# On Windows, include -DSLANG_IGNORE_ABORT_MSG=ON to suppress\n# modal abort dialogs during unattended/LLM-driven builds.\n# Use -DSLANG_EMBED_CORE_MODULE=OFF to keep core module compilation separate\n# from C++ source compilation. This way errors in *.meta.slang files (e.g.\n# hlsl.meta.slang) do not break the C++ compile — slangc and slang-test still\n# compile successfully, and the module errors are reported by the separate\n# `slang-bootstrap -compile-core-module` step instead.\n# Those errors still fail the build, though: generate_core_module_cache is an\n# ALL target that depends on generate_core_module (source/slang/CMakeLists.txt),\n# generate_core_module runs the bootstrap compile\n# (source/slang-core-module/CMakeLists.txt), and slangc itself takes\n# `REQUIRES generate_core_module_cache`, so even `--target slangc` runs it.\n# What OFF buys you is a clean separation of meta-source errors from C++\n# compilation errors, not a build that ignores meta-source errors.\ncmake.exe --preset vs2022 -DSLANG_IGNORE_ABORT_MSG=ON -DSLANG_EMBED_CORE_MODULE=OFF\n\n# Build Release/Debug binaries.\n# It can take from 5 minutes to 20 minutes depending on the machine.\ncmake --build --preset debug # Debug binary\ncmake --build --preset release # Release binary\n\n# Alternative: use workflow preset (configure + build in one step)\ncmake --workflow --preset debug\n\n# Build specific targets\ncmake --build --preset debug --target slangc\ncmake --build --preset debug --target slang-test\n```\n\n**sccache**: Pass `-DSLANG_USE_SCCACHE=ON` at configure time (or set `SLANG_USE_SCCACHE=1` env var) to use sccache as the compiler launcher for faster rebuilds. This automatically disables precompiled headers due to a known incompatibility. Requires `sccache` in PATH.\n\nWhen building with `cmake --build`, redirect all of outputs to null-device.\nWhen the build failed, then, re-run the same command without the redirections.\nIt is to avoid wasting the token usage of LLM.\n\nExample,\n\n```\n# Print the build logs only when the initial attempt failed.\ncmake --build --preset debug >/dev/null 2>&1 || cmake --build --preset debug\n```\n\n### Formatting\n\n**Run `./extras/formatting.sh` before committing changes.** PRs must conform to the project's coding style. Use `./extras/formatting.sh --check-only` to verify without modifying files.\n\n### Suppressing Unused Variable Warnings\n\nWhen a variable declared in an `if` condition is unused inside the body (the condition exists only for its type-check side-effect), use the **C++17 if-init-statement** pattern instead of `SLANG_UNUSED`:\n\n```cpp\n// Preferred: C++17 if-init pattern\nif (auto foo = as<IRFoo>(inst); foo)\n{\n    // foo not needed in body — the type check is the point\n}\n\n// Avoid: SLANG_UNUSED inside the body\nif (auto foo = as<IRFoo>(inst))\n{\n    SLANG_UNUSED(foo);\n}\n```\n\nFor variables that are set but never read outside an `if` (e.g., a plain local variable), use `SLANG_UNUSED(var)` with a comment explaining why.\n\n### Problem-Solving Methodology\n\nFollow the **principled path**, not the minimal-edit-distance path. The goal is a correct\nrepresentation that is robust by construction, even when that means a larger rework.\n\n- **Fix root causes, not symptoms.** When a bug appears in emit/codegen, the cause is usually\n  upstream (an IR pass, type legalization, specialization, lowering, or the AST/IR representation\n  itself). Trace it there and fix it there.\n- **Question every change.** Before keeping a change, answer: _Why is this change necessary? What\n  test fails without it? Is this the right fix, or is the problem telling me the\n  direction/representation is flawed?_ If you cannot name a test that fails without a change, the\n  change probably should not exist.\n- **Do not mask.** A guard, null-check, or special case that papers over a malformed\n  AST/IR/witness-table is a band-aid that hides a representation bug. A guard that is never hit\n  under correct input is dead code. Prefer making the representation correct so consumers stay\n  simple.\n- **Interrogate the input shape.** Whenever you write or change code that handles a particular\n  shape of input — an AST node, IR inst, witness, type, etc. — always ask: _is that input shape\n  itself correct and principled, or should the upstream producer of it be fixed instead?_ If the\n  shape is wrong or accidental, fix the producer; handle it here only when the shape is genuinely\n  valid input. This is the routine double-check that root-causing was done at the right layer, and\n  its answer is required in the PR description (see the Process report below).\n- **Prefer correct representation over edit distance.** If two surface forms _should_ be\n  equivalent, model them identically. If a consumer reads data by position/index/identity when the\n  data is conceptually an unordered key→value set (e.g. witness-table / interface requirement\n  entries), make the access by role/key, not by position.\n- **Keep a working log/report.** Maintain a scratch markdown document throughout the task that\n  records: the problem and a motivating example, road-blockers encountered, how issues **cascade**\n  (one fix exposing the next), the fix chosen for each and _why it is principled_ (with a concrete\n  code trace), and alternatives that were rejected and why. This log is what you distill into the\n  PR description below. (Keep the log out of the commit — it feeds the PR body, it is not a repo\n  artifact.)\n\n### Self-Review for Unprincipled Changes\n\nBefore finalizing a non-trivial compiler change, review the diff for signs that the fix is\ncompensating for a bad AST/IR/`Val`/witness representation. Treat these patterns as red flags until\nyou can prove they are the right layer:\n\n- **Custom semantic equivalence.** New recursive helpers over `DeclRef`, `Val`, `Type`, `Witness`,\n  or IR shapes (for example `are...Equivalent`, `does...Match`, or `try...Match`) often mean two\n  alternative representations were allowed to survive. First ask why `substitute`, `resolve`,\n  `getCanonicalType`, `equals`, or an existing canonical builder does not already make the values\n  identical.\n- **Unaudited helper growth.** Treat every new helper, fallback, and `try...` function as a review\n  target, not only large or complicated ones. A helper that exists to make one failing test pass,\n  or that reimplements part of substitution, resolution, AST copy, generic solving, lookup, or\n  lowering, is often the place where an unprincipled fix hides.\n- **Semantic-to-syntax reconstruction.** Code that turns checked semantic data (`Val`, `Type`,\n  `DeclRef`, witness, lowered IR value) back into syntax (`Expr`, `TypeExp`, parser-shaped AST) is\n  a strong smell. The checked semantic field should usually be the source of truth; rebuilding\n  surface syntax, as in a helper that recreates an expression from an `IntVal`, usually means the\n  producer/copier/substitution path is preserving the wrong representation.\n- **Context rediscovery by graph walking.** Code that walks arbitrary operand graphs, substitution\n  chains, witness chains, lookup paths, or IR users to recover generic arguments, requirement keys,\n  canonical paths, or parent declarations is usually downstream repair. Prefer storing or building\n  the canonical form at the producer.\n- **Consumer-side patching.** Lowering, emit, specialization, typeflow, and backend code should not\n  patch malformed AST/IR shapes from earlier phases. If these consumers need front-end-specific\n  knowledge of an accidental representation, trace and fix the producer instead.\n- **Hardcoded representation trivia.** Special cases for particular `DeclRef` subclasses, builtin\n  magic type names, generic argument indices, witness-table entry order, or nested-vs-flat\n  specialization shape need a strong invariant and usually belong at a canonical construction\n  boundary.\n- **Silent impossible-shape handling.** A guard that returns a default value for an out-of-contract\n  shape hides bugs. Assert impossible shapes; handle a shape only when you can explain why it is\n  valid input.\n\nBegin the review with a \"suspect helpers\" inventory: list every new helper/fallback/special case,\nwhat existing mechanism it overlaps with, the test that fails without it, and whether it survived,\nwas reverted, or was replaced by a producer-side fix. For every flagged change, run this audit\nbefore keeping it:\n\n1. Name the exact input shape, the producing function, and a concrete source or IR example.\n2. Decide whether that shape is canonical and intentionally allowed, or an accidental alternative\n   spelling that should be eliminated.\n3. If it is accidental, try the producer-side fix first so downstream code can use the normal\n   `substitute`/`resolve`/canonicalization path.\n4. Name the semantic source of truth that already exists. If the change rebuilds syntax or a\n   parallel structural form from that source of truth, justify why the stored representation cannot\n   be fixed instead.\n5. Name the test that fails without the change and explain why that test proves this layer owns the\n   logic. When practical, do the revert drill: remove the helper/special case, run the smallest\n   failing test, and use the failure to trace the real producer-consumer break.\n6. Prefer replacing the special case with an assertion plus a producer fix, or with an existing\n   helper that already encodes the invariant.\n\nDo not keep a flagged change only because it makes tests pass. If it remains necessary, the\n`Process report` section of the PR description must justify why the input shape is valid and why\nthis layer owns the logic, with a code trace from producer to consumer.\n\n### Code Style and Review Conventions\n\nRecurring review feedback distilled into rules — following them avoids review round-trips. (These\ngovern how code reads and is structured; the Problem-Solving Methodology above governs _what_ to\nchange.)\n\n- **Write function comments as complete sentences: what, then why.** State what the function does\n  first; then, if the reason it exists isn't obvious from that description, add a brief summary of\n  why. For non-trivial behavior, include a concrete example. Avoid terse fragment- or bullet-only\n  comments on a function. For instance, `substituteElementOfCompositeType` should read like _\"Return\n  `target` with its element type replaced by `newElementType`, preserving shape: scalar →\n  newElementType, `vector<T,N>` → `vector<newElementType,N>`, `matrix<T,R,C>` → `matrix<newElementType,R,C>`.\"_\n  — not _\"element coerce target\"_.\n\n- **Use conversational examples for code comments and PR explanations.** When explaining a subtle\n  compiler path, prefer \"Consider this example:\" followed by the relevant user code. Do not use\n  abstract labels such as \"Full source shape\", \"AST trace\", or \"IR trace\" as a substitute for\n  explanation. After the code, describe what happens step by step in natural prose: which parser,\n  checker, copier, lowering pass, or IR pass creates the shape; what invariant the local code\n  preserves; and which downstream consumer depends on that invariant. Include enough of the user's\n  original code for the example to make sense on its own.\n\n- **Reuse before you write; then extract non-trivial logic into a named, documented helper.** Before\n  writing a new helper, search for an existing one — what you need is often already provided by a\n  shared header (the AST/IR helpers in `slang-ast-type.h`, `slang-ir-util.h`, and the various\n  `*-util.h` files). For example, to test whether a type is a `DeclRefType` of a particular\n  declaration, use the existing `isDeclRefTypeOf<T>(type)` rather than re-deriving it. When the\n  logic genuinely is new, don't bury a multi-step computation in an inline lambda or a long inline\n  block: give it an intention-revealing name (`coerceOperandsOfBuiltinBinaryExpr`,\n  `substituteElementOfCompositeType`, `unifyBaseType`) and a doc comment, so the caller stays\n  readable and the helper is reusable.\n\n- **Keep one source of truth; delete dead code after a refactor.** Map or classify a given thing in\n  exactly one place — e.g. the operator-name → operation-kind mapping lives only in\n  `getBuiltinOperationKindFromString`, not re-implemented at call sites. When a change makes a\n  branch, fallback, or helper unreachable, remove it rather than leaving it as dead code.\n\n- **One canonical representation per value; assert the invariant.** Don't introduce a second\n  AST/IR/`Val` representation for something that already has one — multiple forms of the same logical\n  value break `equals`/identity checks and deduplication. When an invariant guarantees a\n  representation is never produced for certain inputs (e.g. `+`/`-`/`*` are always a\n  `PolynomialIntVal`, never a `BuiltinOperationIntVal`), `SLANG_ASSERT` it at the construction site\n  so a violation is caught rather than silently producing a divergent form.\n\n- **Fail loudly on out-of-contract input.** When a helper is only valid for a restricted set of\n  inputs, `SLANG_RELEASE_ASSERT` on anything outside that set instead of silently returning a default\n  — e.g. `substituteElementOfCompositeType` asserts its operand is a builtin scalar/vector/matrix.\n\n### PR Workflow\n\n1. **Format your code**: Run `./extras/formatting.sh` before committing\n2. **Label your PR**: Use \"pr: non-breaking\" (default) or \"pr: breaking change\" (for ABI/language breaking changes)\n3. **Include tests**: Add regression tests as `.slang` files under `tests/`\n4. **Write the PR description in this required five-part format:**\n   1. **Motivation** — the problem being solved, with a concrete example / motivating test case.\n   2. **Proposed solution** — the approach, and why it is the principled one.\n   3. **Change summary** — a table or list of the files/areas touched and what each does.\n   4. **Concepts and vocabulary** — a short glossary, placed between the change summary and the\n      process report. Restate only the _codebase-specific or subtle_ terms the report relies on, as\n      a reminder for the reviewer (e.g. witness / `getSub`, facet / `getInheritanceInfo`, the\n      fixpoint solver, or a non-obvious distinction the fix hinges on). Do **not** explain basic,\n      well-known concepts (e.g. interface, associated type) — assume them.\n   5. **Process report** — explain _every_ change with a logical reason. For a change that\n      addresses a **cascading** issue, describe the issue (with its motivating test case) and\n      justify why the fix is correct with a **code trace** (the exact functions/insts involved),\n      not just a description. State explicitly why each change is necessary and principled rather\n      than a workaround. For any change that handles, guards, or special-cases a particular input\n      shape, the report **must** answer the input-shape check from the methodology — _is that shape\n      correct and principled, or should its producer have been fixed instead?_ — so a reviewer can\n      confirm the fix sits at the right layer.\n\n   Write for a reviewer who does not have the full context in their head. Use the same\n   conversational style required for code comments: start from a concrete user-code example, include\n   the full relevant snippet instead of just naming a type or function, and explain the logical\n   steps in order. Say what the compiler builds, how that representation flows through named\n   functions or IR instructions, and why the chosen fix preserves the invariant. Avoid terse labels\n   such as \"AST trace\"; make the prose read like an explanation to a reviewer who is learning the\n   scenario for the first time.\n\n### Testing\n\nslang-test must run from repository root\n\n```bash\n# Run all tests with multiple servers (takes from 10 to 30 minutes)\n./build/Release/bin/slang-test -use-test-server -server-count 8\n\n# Run specific test\n# The test file must be placed under \"tests/\" directory\n./build/Release/bin/slang-test tests/path/to/test.slang\n\n# Run unit tests\n./build/Release/bin/slang-test slang-unit-test-tool/\n```\n\n**Writing Tests Without GPU**:\n\n- Use CPU compute: `//TEST:COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type`\n- Use interpreter: `//TEST:INTERPRET(filecheck=CHECK):`\n- Example test structure in `tests/language-feature/lambda/lambda-0.slang`\n\n**Diagnostic Tests** (see `docs/diagnostics.md` for full details):\n\nUse `//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK):` as the test directive to verify that the compiler emits expected diagnostics. Annotations in comments match against compiler output by message text, severity, or error code. Carets align to columns on the preceding source line:\n\n```slang\n//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK):-target spirv\nint foo = undefined;\n//CHECK: E01234\n//CHECK:  ^^^^^^^^^ error\n```\n\n**SPIRV Validation**:\n\n- Set `SLANG_RUN_SPIRV_VALIDATION=1` when using `slangc -target spirv`\n- Don't use system's `spirv-val` tool (may be outdated)\n\n### Slang Command Line Usage\n\n**IMPORTANT:** Slang uses single dashes for multi-character options (not double dashes like most tools):\n\n- Use `-help` (not `--help`)\n- Use `-target spirv` (not `--target spirv`)\n- Use `-dump-ir` (not `--dump-ir`)\n- Use `-stage compute` (not `--stage compute`)\n\n### AVOID These Debugging Options\n\n**DO NOT USE** these options as they are unmaintained, unreliable or unnecessary:\n\n- slangc with `-dump-ast`, `-dump-intermediate-prefix`, `-dump-intermediates`,\n  `-dump-ir-ids`, `-serial-ir`, and `-dump-repro`.\n- slang-test with `-category` and `-api`\n\n### Repro Tooling\n\n`-load-repro` and `-extract-repro` are specialized repro tools; use them when\nworking on repro handling. Inputs are validated before use.\n\n## Architecture Overview\n\n### Core Components\n\n**Compiler Pipeline**:\n\n- **Lexer** (`source/compiler-core/slang-lexer.cpp`): Tokenizes source code\n- **Preprocessor** (`source/slang/slang-preprocessor.cpp`): Handles #include, macros, conditionals\n- **Parser** (`source/slang/slang-parser.cpp`): Recursive descent parser producing AST\n- **Semantic Checker** (`source/slang/slang-check.cpp`): Type checking, name resolution, validation\n- **IR Generation** (`source/slang/slang-lower-to-ir.cpp`): Converts AST to Slang IR\n- **IR Passes** (`source/slang/slang-ir-*.cpp`): Optimization and lowering passes\n- **Code Emission** (`source/slang/slang-emit-*.cpp`): Target-specific code generation\n\n**Key Directories**:\n\n- `source/core/`: Core utilities (strings, containers, file system, platform abstractions)\n- `source/compiler-core/`: Compiler infrastructure (diagnostics, downstream compilers)\n- `source/slang/`: Main compiler implementation (frontend, IR, backend)\n- `source/slangc/`: Command-line compiler tool\n- `source/slang-core-module/`, `source/slang-glsl-module/`, `source/standard-modules/`: Standard library modules\n- `source/slang-wasm/`: WebAssembly bindings\n- `source/slang-record-replay/`: API call record/replay\n- `source/slang-rt/`: Runtime library\n- `tools/`: Development and testing tools\n- `include/`: Public API headers (`slang.h`)\n- `external/`: Third-party dependencies and submodules\n- `prelude/`: Built-in language definitions and standard library\n- `tests/`: Comprehensive test suite\n- `docs/`: Project documentation (user guide in `docs/user-guide/`)\n- `build/source/slang/fiddle/`: Generated code from FIDDLE macros (created during build)\n\n### Compilation Model\n\n**Key Concepts**:\n\n- **CompileRequest**: Bundles options, input files, and code generation requests\n- **TranslationUnit**: Collection of source files (HLSL: one per file, Slang: all files together)\n- **EntryPoint**: Function name + pipeline stage to compile\n- **Target**: Output format (DXIL, SPIR-V, etc.) + capability profile\n\n**Supported Targets**:\n\n- Direct3D 11/12 (HLSL output)\n- Vulkan (SPIR-V, GLSL output)\n- Metal (MSL output) - experimental\n- WebGPU (WGSL output) - experimental\n- CUDA/OptiX (C++ output)\n- CPU (C++ output, executables, libraries)\n\n## Development Workflow\n\n### Adding New Language Features\n\n1. Update lexer for new tokens (`source/compiler-core/slang-lexer.cpp`)\n2. Extend parser for new syntax (`source/slang/slang-parser.cpp`)\n3. Add semantic analysis (`source/slang/slang-check-*.cpp`)\n4. Implement IR generation (`source/slang/slang-ir-*.cpp`)\n5. Add code generation for each target backend (`source/slang/slang-emit-*.cpp`)\n6. Write comprehensive tests under `tests/`\n\n### Common Development Tasks\n\n- **Adding an IR instruction**: Update the Lua definition files in `source/slang/slang-ir-insts.lua`, then regenerate\n- **Adding a built-in function**: Add to appropriate module in `prelude/`\n- **Adding a new target**: Implement new emitter in `source/slang/slang-emit-*.cpp`\n\n### Capability Atoms Documentation\n\n**`docs/user-guide/a4-02-reference-capability-atoms.md` is auto-generated — never edit it directly.**\n\nIt is produced by `slang-capability-generator` from `source/slang/slang-capabilities.capdef`. To add or update a capability atom's description:\n\n1. Add or update the `///` doc comment immediately before the `def` or `alias` in `slang-capabilities.capdef`:\n   ```\n   /// My description here.\n   alias myatom = ...;\n   ```\n2. Regenerate the doc:\n   ```bash\n   cmake --build --preset debug --target slang-capability-generator\n   mkdir -p build/capgen-out\n   ./build/generators/Debug/bin/slang-capability-generator \\\n       source/slang/slang-capabilities.capdef \\\n       --target-directory build/capgen-out \\\n       --doc docs/user-guide/a4-02-reference-capability-atoms.md\n   ```\n3. Commit the updated `slang-capabilities.capdef` and the regenerated `.md` together.\n\nNote: the `///` comment must be on the **public alias** (e.g. `alias node = _node;`), not on the internal `def _node : stage;` atom, for the description to appear under the public name.\n\n### Modifying Public Headers (`include/`)\n\nAll files under `include/` are public API. Changes must preserve binary (ABI) and source\ncompatibility for callers compiled against older versions of the header.\n\n#### Enums\n\n- **Never insert a new enumerator in the middle of an existing enum.** Insertion shifts all\n  subsequent integer values, silently breaking any caller that stores or compares the value.\n- **Always append** new enumerators immediately before the terminal count/sentinel member\n  (e.g. `CountOf`, `Count`, `NUM_*`), assigning an explicit integer value (the next sequential\n  integer after the preceding enumerator).\n- **Removed enumerators**: rename to `REMOVED_<Name>` and keep the original integer value.\n  Never reuse or reclaim a retired integer.\n\n#### Virtual tables (COM interfaces)\n\nSlang's public interfaces (`ISession`, `IModule`, `IComponentType`, etc.) are COM-style\nvtables declared with `virtual` methods in `include/slang.h`. The vtable layout is fixed by\ndeclaration order. Violating these rules corrupts the vtable and causes silent crashes or\nwrong-method dispatch for any caller compiled against an older header.\n\n- **Never reorder virtual methods** within an interface.\n- **Never change a virtual method's signature** (return type, parameter types, calling\n  convention, or `SLANG_MCALL` decoration).\n- **Never insert a new virtual method** in the middle of an interface — append only, at the\n  end of the interface before the closing brace.\n- **Never remove a virtual method** — replace its body with a stub that returns\n  `SLANG_E_NOT_IMPLEMENTED` and keep the declaration in place.\n- Avoid extending an existing public COM interface in place when clients may implement or\n  query it by UUID. Prefer adding a new derived/versioned interface with its own UUID, while\n  keeping the original interface declaration and UUID supported for existing callers.\n\n### Debugging tools\n\n#### IR Dump (`-dump-ir`)\n\n```bash\n# Dump IR at every pass (use with -target and -o to avoid mixing output)\nslangc -dump-ir -target spirv-asm -o tmp.spv test.slang | python extras/split-ir-dump.py\n\n# Dump IR before/after a specific pass\nslangc -dump-ir-before lowerGenerics -dump-ir-after lowerGenerics -target spirv-asm -o tmp.spv test.slang > pass.dump\n```\n\n- Always combine `-dump-ir` with `-target` (otherwise compilation stops early) and `-o <file>` (otherwise target code mixes with IR on stdout)\n- Use `extras/split-ir-dump.py` to split large dumps into per-pass files. See `extras/split-ir-dump.md` for details.\n- You can insert `dumpIRToString()` in C++ code and write to a file with `File::writeAllText()` for ad-hoc inspection.\n- When debugging, focus on root causes in IR passes (specialization, inlining, type legalization, buffer lowering) rather than band-aid fixes in emit logic. The compiler philosophy is to keep emission simple and do heavy transforms in IR passes.\n\n#### InstTrace\n\nTrace where a problematic IR instruction was created:\n\n```bash\npython3 ./extras/insttrace.py <debugUID> ./build/Debug/bin/slangc tests/my-test.slang -target spirv\n```\n\n#### SPIRV Tools\n\n- `slangc -target spirv-asm` — compile to SPIRV assembly\n- Set `SLANG_RUN_SPIRV_VALIDATION=1` for static validation; use `-skip-spirv-validation` to see SPIRV output even when validation fails\n- `slangc -target spirv-asm -emit-spirv-via-glsl` — generate reference SPIRV via GLSL for comparison\n\n#### Assertion Behavior (`SLANG_ASSERT`)\n\nOn Windows, assertion failures normally open a modal dialog that blocks execution. Set the `SLANG_ASSERT` environment variable to control this:\n\n| Value                 | Behavior                                                                                                                       |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| `system`              | Use the system `assert()`, which shows a modal dialog and allows the developers to attach the debugger                         |\n| `debugbreak`          | When a debugger is already attached, it will hit a debug-break; fall back to `system` behavior when a debugger is not attached |\n| `release-assert-only` | Skip debug-only assertions (`SLANG_ASSERT`, `SLANG_ASSERT_FAILURE`) and continue; `SLANG_RELEASE_ASSERT` still fires           |\n| _(unset)_             | Throws an exception                                                                                                            |\n\nThe behavior on Windows after an exception is thrown is controlled by the CMake option `SLANG_IGNORE_ABORT_MSG`.\nThis option is highly recommended for unattended automation with LLM workflow; it bakes the behavior into all built executables at compile time.\n\n#### RTX Remix Testing\n\nUse the `/repro-remix` skill or see `extras/repro-remix.md`.\n\n### IR System\n\n- Slang uses a custom SSA-based IR (not LLVM)\n- IR instructions defined in `slang-ir-insts.h` (generated from Lua)\n- Extensive IR pass framework for optimization and lowering\n- Target-specific legalization passes before code emission\n\n### Language Server\n\n- Language Server Protocol implementation in `source/slang/slang-language-server.cpp`\n- Supports IntelliSense, completion, diagnostics, formatting\n- Used by VS Code and Visual Studio extensions\n\n### Module System\n\n- Slang supports separate compilation via modules\n- Modules can be compiled to IR and linked at runtime\n- Optional obfuscation for distributed modules\n- Core language features defined as modules in `prelude/`\n\n### Generated files\n\n- The enum values starting with `kIROp_` are defined in a generated file, `build/source/slang/fiddle/slang-ir-insts-enum.h.fiddle`\n- `FIDDLE()` and `FIDDLE(...)` statements in AST node declarations indicate that additional source is generated and included from `build/source/slang/fiddle`, providing static type system and reflection metadata, visitor support, and serialization support.\n\n### Rebuilding after `hlsl.meta.slang` / `core.meta.slang` changes\n\nThe core module source (`hlsl.meta.slang`, `core.meta.slang`, etc.) is embedded into the `slang-bootstrap` binary at compile time. After modifying these files, force CMake to observe the newer timestamp, regenerate the core-module headers through the build graph, then rebuild `slangc` with the preset/configuration you are using:\n\n```bash\ncmake -E touch source/slang/hlsl.meta.slang   # or whichever meta file changed\ncmake --build --preset <preset> --target generate_core_module_headers\ncmake --build --preset <preset> --target slangc\n```\n\nUse the same `<preset>` you use for the build, such as `debug`, `release`, or `releaseWithDebugInfo`. The `generate_core_module_headers` target invokes the correct `slang-bootstrap` binary for that host/configuration, including Windows `.exe` paths and non-Debug output directories.\n\nIf you skip the `cmake -E touch` step the cached bootstrap binary may silently embed the OLD source, and diagnostics from the bootstrap step will not match the current source file — a sure sign the binary is stale.\n\n### HLSL named-constant emission rule\n\n**Never emit HLSL enum / named-constant values as hard-coded integers.** DXC maps named constants (attribute strings, flag identifiers, etc.) at parse time; if we bake in a numeric value and DXC later changes the internal mapping the generated HLSL will silently break.\n\nThe correct pattern:\n\n1. **Define a Slang enum** (or a set of named intrinsic-backed constants) for each group of conceptual values (e.g. `NodeLaunch` mode, Barrier flag sets).\n2. **Store the name, not the integer, in the IR.** Use `IRStringLit` operands (as `NodeLaunchDecoration` does) or a `Ref<T>` / intrinsic-based accessor that preserves the identifier through to emission.\n3. **Provide a mapping function** in the HLSL emitter (`slang-emit-hlsl.cpp` or `slang-emit-c-like.cpp`) that converts the stored enum/string value back to the HLSL source name so that emitted code reads e.g. `[NodeLaunch(\"broadcasting\")]` not `[NodeLaunch(0)]`.\n\nExamples of this pattern already in the codebase:\n- `NodeLaunchDecoration` stores the mode as `IRStringLit(\"broadcasting\")` and the emitter re-emits the string verbatim.\n- Work-graph output record `Get()` returns `Ref<T>` backed by `__intrinsic_asm \".Get\"` so the emitted HLSL says `.Get(i)` (an l-value in HLSL) rather than an integer offset.\n\n#### Pattern: emitting enum values as target named constants\n\nUse this when a Slang enum must be emitted as named constants rather than integers (e.g. `UAV_MEMORY` instead of `1`).\n\n1. **Define the C++ enum in `slang-type-system-shared.h`** (inside `namespace Slang`, plain `enum` not `enum class` so values implicitly convert to `int`). This header is transitively included by both the core-module source and the emitters.\n\n2. **Mirror it as a Slang enum in the appropriate `*.meta.slang` file**, pulling the actual values from C++ via `$(...)` splices so the two definitions stay in sync:\n   ```slang\n   enum MyFlags : uint { FlagA = $(MyFlags::FlagA), FlagB = $(MyFlags::FlagB) }\n   ```\n\n3. **Declare a `__intrinsic_op` converter in the `.meta.slang` file** to represent the enum-to-string conversion in the IR:\n   ```slang\n   __intrinsic_op(getEnumMyFlags)\n   int GetEnumMyFlags(MyFlags f);\n   ```\n   The mnemonic passed to `__intrinsic_op(...)` must exactly match the Lua key in the next step.\n\n4. **Register the new IR op in `slang-ir-insts.lua`** and add a stable ID in `slang-ir-insts-stable-names.lua`.\n\n5. **Emit the named-constant string in the target emitter** (e.g. `tryEmitInstExprImpl` in `slang-emit-hlsl.cpp`): keep the IR operation tied to the symbolic enum or intrinsic value, then map each accepted bit or value to its HLSL named-constant string and write it out with `m_writer->emit(...)`. Do not document or implement examples that recover HLSL source names from raw integer positions.\n\n### Git commit message\n\n- Don't mention Claude on the commit message\n\n### Debugging with slangpy\n\nUse the `/slangpy-debug` skill to build slangpy from source with your local Slang build for compatibility testing.\n\n## Cross-Platform Considerations\n\n**Supported Platforms**:\nWindows (x64/ARM64), Linux (x64/ARM64), macOS (x64/ARM64), WebAssembly\n\n**Platform Abstractions**:\nUse utilities in `source/core/` for file system, process management, platform detection\n\n**Graphics APIs**:\nCode generation supports all major APIs but runtime testing requires appropriate drivers/SDKs\n\n**WSL on Windows**:\nWhen running under WSL environment, try to append `.exe` to the executables to avoid using Linux binaries\n\n- Use `cmake.exe` instead of `cmake`,\n- Use `python.exe` instead of `python`,\n- Use `gh.exe` instead of `gh` and so on.\n\n### Release Process\n\nUse the `/slang-release-process` skill to push a new release. See `.claude/skills/slang-release-process/SKILL.md` for the full workflow.\n\n## Additional Documents\n\n- User-facing documentation: `docs/user-guide/`\n- Language specification: see below\n\n### Formal Specification\n\nClone `https://github.com/shader-slang/spec.git` under `external/` if needed. Specification files are in `external/spec/specification/`, feature proposals in `external/spec/proposals/`.\n","category":"root","tokens":8560}]}