拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Slang 声明驱动(Claim-Driven)测试方法学:把语言文档逐句拆解为可验证的测试套件

Slang 声明驱动Claim-Driven测试方法学把语言文档逐句拆解为可验证的测试套件【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang本篇技术指南完整讲解 Slang 仓库中docs/generated/tests/_meta/prompts/_claims.md定义的声明驱动测试方法学——如何把一份语言参考文档或设计文档拆解为扁平的声明claim清单再沿文档承诺的测试维度把每条声明映射为具体的.slang测试文件。这套方法是整个 Agentic Test Suite 的骨架conformance/与design/两棵测试树、79 个 bundle、4100 测试文件都以它为准绳。读完本文你将掌握 claim 枚举、维度映射、系统化变体扩展、功能/发射测试配对、bundle README 结构与停止准则的完整工作流并能将其复用到任意文档驱动的测试生成场景。一、为什么是声明驱动Claim-Driven而不是计数驱动Slang 的 Agentic Test Suite 位于docs/generated/tests/由 agent 生成、agent 维护每一条测试都锚定anchor到某条文档声明文档变化时整套套件随之重建。据docs/generated/tests/INDEX.md的统计当前共 79 个 bundle、4112 个.slang测试文件按意图分布为functional1938、negative797、boundary776、expansion299、characterization215、stress84、regression3。这套套件的第一原则写在_claims.md与套件 README 中The campaign is claim-driven, not count-driven.战役是声明驱动的不是计数驱动的。具体含义是一份文档被拆解为一个扁平化的声明列表只有当每条声明都至少被一个测试覆盖且覆盖了文档承诺的各个维度基础用例、边界情形、边界值、主要特性组合、不同类型、有意义的后端或者被登记在未测试声明表中并给出分类理由时bundle 才算完成测试数量是这个过程的产出永远不是目标。不要因为测试数够了就停止也不要为了凑数而加测试。与此配套的是两棵测试树的角色分工见_meta/prompts/_common.md与 README.md测试树锚定文档角色docs/generated/tests/conformance/docs/language-reference/*.md人工编写的权威规范规范一致性测试失败 规范与编译器不一致的信号docs/generated/tests/design/docs/generated/design/*.md从源码反推的设计文档回归覆盖测试失败 已知行为的回归同一处编译器表面允许两棵树重叠覆盖——它们验证的是不同性质规范一致性 vs. 行为回归。当conformance/测试失败而其design/对应测试通过时这本身就是套件想要暴露的规范与编译器漂移信号应据此提交 finding。二、第 1 步枚举文档中的每一条声明这是整个流程的承重步骤load-bearing step。在写任何测试之前先产出文档中每一条规范性、可测试陈述的扁平编号清单。什么是一条声明一条claim声明是文档承诺的、可独立验证的一个断言——一条文法产生式、一行表格、must/shall/is rejected句、一个工作示例、一个明确的例外条款。参见_claims.md§1。风格要求每条声明是一句话尽量沿用文档原话编号按子区文档的小节标题分组。原文给出的例子_claims.mdL31-L390xFFFFFFFF无后缀、十六进制基的类型是uint。 —— 一条声明。前缀产生新值后缀产生旧值。 ——这是两条声明前缀的产出与后缀的产出。它们可以由一个文件测试但它们是两个独立的声明。UINT_MAX 1回绕为0每个已文档化的无符号整数类型上的每个二元算术运算符在溢出时都回绕。 —— 这是一条声明但会沿{int, uint, int64_t, uint64_t}× 每个运算符、-、*、/…倍增——一条声明很多测试。枚举出的清单作为Claims小节检入 bundle README见下文第五节。它是审查者与下一轮战役会话判断bundle 是否完成的依据。声明数才是 bundle 的目标不是测试数。三、第 2 步沿文档承诺的维度把声明映射为测试每条声明最终要么进入## Functional coverage已覆盖要么进入## Untested claims附理由。当每条被枚举的声明都出现在这两张表之一时bundle 即告完成。对每条声明需要遍历以下维度并为文档实际承诺的每一个维度写测试文档没覆盖的维度直接跳过——不要发明声明维度含义示例基础用例Basic case文档字面直说的直线路径测试总是存在边界情形Corner cases文档记载的边界条件空输入、零长度数组、单元素向量、默认初始化值、有歧义但可解析的重载等边界值Boundary values类型或文法点名的数值边界MIN/MAX/0/MIN-1/MAX1/0xFFFFFFFF/NaN/±Inf/ 空字符串 /capacity-1主要特性组合Main feature combinations文档记载的组合作为 struct 成员、泛型内部、extension之后、enum例外条款下、[ForceInline]被调方内部不同类型Different types文档声明适用的每个类型/形状/限定符每个已文档化数值类型int/uint/int64_t/uint64_t/float/double/half、每个形状标量/向量/矩阵、每个限定符const/static/uniform/in/inout/out有意义的后端Meaningful back-ends把声明分类为目标无关或目标相关见下表目标无关 vs 目标相关的后端扇出这是强制性扇出mandatory fan-out详见_common.md§ Exercise every feasible back-end目标无关值/语义在 codegen 之前就已解析词法、预处理、解析、名字查找、重载解析、泛型特化的语义、常量折叠后的值、多数诊断、AST 形状→ 用INTERPRETslangi 字节码解释器和/或COMPARE_COMPUTE -cpu一两条指令即可不需要按目标扇出。目标相关发射出的代码 / legalization / capability 中可观察→ 为声明可观察的每一个可行文本发射目标加一条SIMPLE -target T指令——hlsl、glsl、spirv-asm、metal、wgsl、cuda、cpp——不只是文档点名的目标也不只是 HLSLSPIR-V。这是套件获得按目标回归覆盖的地方单目标测试会悄悄掩盖 Metal/WGSL/CUDA/GLSL 的 codegen bug。无法表达该声明的目标进入## Untested claims理由unsupported-on-target绝不用弱化的 CHECK 硬凑绿色。构造与 legalization 变体深度当文档描述的变换或发射随输入的类型、形状或形式分支时——类型映射/布局表、opcode 或 decoration 列表、按元素类型的数组 stride、按操作的原子、按地址空间的存储类——要为文档枚举的每一行/每个分支实例化一个测试而不是给整张表一个测试。这就是发射与 legalization深度所在单个StructuredBufferintstride 测试无法覆盖布局规则描述的int8/int64/struct/float4[3]stride 分支单个InterlockedAdd也覆盖不了 and/or/xor/min/max/exchange/compare-exchange 各形式。要把文档的表格和 for each … 规则当作需要展开的枚举而不是可以概括的散文。同时保持branch-driven而非 Cartesian——只覆盖文档与目标管线确实区分对待的变体。因此一条声明通常产出多个测试文件声明在## Functional coverage中的行列出它们全部。只有当文档本身没有承诺任何边界、类型、组合或后端特定观察时单条基础用例测试才可接受。跨 bundle 引用当某声明已在兄弟 bundle 中被完整测试时在## Untested claims中以理由out-of-bundle记录并链接到覆盖它的测试。不要注水不要偷工减料。bundle 的规模跟随文档的规模——薄文档产出薄 bundle这是正确的结果富文档产出富 bundle_claims.mdL112-L114。四、系统化变体扩展文档只命名家族而没有枚举成员时设计文档经常泛化地陈述规则——原子内建函数 lower 到对应的目标 op、结构化缓冲布局遵循下列规则、窄整数类型按目标的位宽支持发射——却不列出编译器实际分支的每个成员或单元格。此时可以在文档小节没有逐一列举的情况下实例化单元格但必须同时满足全部四个条件。这不是给对着未覆盖代码写测试开绿灯见_expand.md§ The hard rule而是一种纪律化地阅读权威来源、获取其隐含变体的方式。规则见_claims.md§ Systematic variant expansion变体轴必须是真实的且由权威表面确认——不能靠猜。候选单元格从以下来源枚举语言参考的类型/内建/运算符表权威规范当它命名该家族时也是引用依据或core-module 声明*.meta.slang作为哪些内建重载/运算符真实存在的事实依据。core-module 是编译器源码因此只能用来枚举候选单元格绝不能作为测试的doc_ref。若两个表面都不能确认单元格存在那就是在猜——停止改记一条 doc gap。锚定到命名该家族的文档小节遵循正常的 source-of-truth 层级语言参考优先设计文档兜底。同时在## Doc gaps observed加一行注明文档泛化命名了家族但没有枚举单元格Kind 为missing-example或undocumented-behaviorSuggested addition 形如枚举 atomic-op / stride / width 变体表。表面锚定的扩展与 doc-gap 通道并行运行两者都要做。每个单元格的行为必须通过运行编译器来确定——绝不能假设它能工作。对每个候选单元格编译并分类实际结果干净、形状符合预期的输出→ 保留测试把CHECK钉到你观察到的真实发射文本上干净拒绝/诊断→ 作为负向测试保留锚定到 capability 或类型规则DIAGNOSTIC_TEST精确的E####码abort / crash / 内部错误 / 畸形输出→ 这是finding编译器 bug不是测试。不要写一个用宽松 CHECK 掩盖它的通过测试。假设它能工作是本规则唯一禁止的事WGSL 的double和int8abort 正是因为在单元格上运行并分类、而不是假设全绿才被发现的。剪掉塌缩的单元格——branch-driven不是 Cartesian。表面给出的是候选网格只保留管线确实区别对待的单元格保留表面自身区分的单元格有符号 vs 无符号的Min/Max是不同 opdevicevsthreadgroup原子是不同地址空间无法从规范区分两个单元格时两个都编译并对发射文本做 diff观察输出永远允许读覆盖率不允许。发射相同 ⇒ 保留一个代表其余在声明的Tests单元格中注记 same emission。CHECK 紧度。钉住标识该单元格的 token——具体 opOpAtomicAnd、decorationArrayStride 2或布局 token——要紧而声明不依赖的内容要放开名称/ID/寄存器%{{[0-9]}}、a_{{[0-9]}}以及被测 token 周围那些声明说明符与限定符__device__、__noinline__、inline、static。它们稳定、可钉但不是声明要测的东西。说不出区分 token 的单元格 没有被区分的单元格——折回第 4 步的塌缩步骤。一句话总结候选网格来自权威表面保留/丢弃的决策来自观察到的编译器输出。覆盖率永远不会告诉你该加哪些单元格——只会告诉你哪些 bundle 值得做这件事。五、第 3 步功能测试与发射测试默认配对对任何文档声明在特定目标的发射文本中可观察的声明bundle 默认获得两个测试文件_claims.md§3功能测试functional//TEST:INTERPRET(filecheckCHECK):或//TEST:COMPARE_COMPUTE(filecheck-bufferCHECK):-cpu——通过printf/ 输出缓冲观察运行时值或行为发射测试emission//TEST:SIMPLE(filecheckCHECK):-target hlsl以及/或-target spirv-asm/-target glsl/-target cuda——把同一声明用户可见的发射文本钉住。命名约定topic-sub-area-functional.slang与topic-sub-area-emission.slang。跨目标发射可以放在一个带多条//TEST指令的文件里也可以当发射模式差异大到 CHECK 行会互相冲突时按目标拆文件。仓库中conformance/expressions-operatorsbundle 是教科书式的例子。其prefix-increment-yields-new.slang展示了//META块 注释 INTERPRET指令的标准形态//META: generatedtrue //META: modelclaude-opus-4-7 //META: generated_at2026-06-01T14:00:0000:00 //META: source_commitd25453d7f0b4867db4cb5eabf34fb6cd088cf596 //META: doc_refdocs/language-reference/expressions-operators.md#prefix-operator-expressions //META: doc_section_digest7fc06f74bccd80f5ad67ec31cc96986ffd178b15f5edb80257c79bb75b196d01 //META: purposePrefix x yields the **new** value per the docs explicit bullet list Read → Increment → Write → Yield the new value. //META: intentboundary //META: pipeline_stageruntime //META: warningAuto-generated. May drift from source. Do not edit by hand. // The docs bullet list for the built-in prefix operator says // the expression yields the NEW (post-increment) value. Compared to // the postfix sibling (which yields the OLD value), this is the // distinguishing contract. Verify both the yielded value and the // updated variable. //TEST:INTERPRET(filecheckCHECK): void main() { int x 10; int yielded x; //CHECK: yielded11 x11 printf(yielded%d x%d\n, yielded, x); }注意其中的纪律//META: purpose与 bundle README 覆盖表中的 Claim 单元格逐字一致//META之后的正文注释必须补充验证什么声明 如何验证机制而不是逐字引用文档原文——// The doc says: ...属于反模式因为doc_ref与purpose已经承担了那个职责。六、第 4 步Bundle README 承载声明的权威枚举bundle README 是审查者与下一轮战役会话判断 bundle 是否完成的产物包含三个承载声明的部分_claims.md§4## Claims—— 第 1 步提取的每条声明的扁平编号清单按子区/文档标题分组。这是事实基准枚举这里的每个 claim ID 必须出现在下面两张表之一。## Functional coverage—— 每条至少有一个测试的声明一行。列Claim | Intent | Anchor | Tests。其中 Intent 使用受控词汇functional | boundary | negative | expansion | regressionAnchor 是锚定到文档小节的链接Tests 是 bundle 内的可点击文件名。## Untested claims—— 每条本 bundle 中没有测试的声明一行附理由out-of-bundle/compiler-bug-pending/non-normative/unclassified。Claim 单元格要点名具体的表面而不是文档顶层的概念。审查者应能只读表格就知道每个测试是测什么的而无需打开.slang文件。原文给出的示例行节选自某 bundle 的表格| C7 |WaveActiveSumafter a divergentif/elsereconverges and sums across the originally-divergent threads. | basic, backends | ... | | C8 | Same operator on a divergentswitchwith[unroll]doesnotreconverge. | corner | ... |以观察测试断言什么开头当声明依赖某个诊断码、具体内建或 SPIR-V op 时钉住E####或具体名字。像 vector operators work 这种模糊行是声明分解不足的信号——一行被要求背负了许多不同声明。仓库中conformance/expressions-operators/README.md是真实范例覆盖表逐行列出前缀是恒等x x、前缀-是算术取反、前缀~按位取反、前缀!逻辑取反、前缀产生新值boundary、后缀产生旧值boundary、?:不短路boundary、括号表达式值不变、(StructTy)0兼容性转换等价于{}初始化等每行锚定到docs/language-reference/expressions-operators.md的具体小节## Untested claims则把完整的中缀运算符表out-of-bundle理由手写tests/套件已充分覆盖、运算符重载out-of-bundle理由重载解析语义在 name-resolution bundle、调用/下标表达式out-of-bundle理由由ast-reference/expressions覆盖分类登记。七、第 5 步可复用的测试模式每个 (声明 × 维度) 组合一个.slang文件顶部带//META块引用覆盖该声明的最具体文档锚点。既有模式细节见_common.md函数参数击败常量折叠器function-param to defeat the constant folder用于观察优化 pass 行为或运行时算术的测试。字面量会被常量折叠器提前算掉改为从uniform参数或缓冲区读取输入。重载探针overload-probe用于观察字面量或表达式的类型。如int probe(int) { return 1; } int probe(uint) { return 2; }通过解析到哪个重载断言类型。//TEST:INTERPRET(filecheckCHECK):通过 slangi 解释器 printf观察值正确性。//TEST:COMPARE_COMPUTE(filecheck-bufferCHECK):-cpu观察dispatch 形状行为线程 ID、组 ID、原子、groupshared、wave op——INTERPRET 无法建模执行模型之处。//TEST:SIMPLE(filecheckCHECK):-target backend发射钉扎测试与对应功能测试配对见第五节。//DIAGNOSTIC_TEST:SIMPLE(diagCHECK):用于 is rejected 类声明带 caret 锚定的^^^^注释和E####诊断码。诊断文本必须逐字取自编译器真实输出Suggested annotationscaret 列号要 10//CHECK:前缀占掉 1–9 列且紧跟在出错源码行的下一行。配套的 CHECK 模式卫生规则_common.md中反复强调也是绝大多数 CHECK 失败来源值得在此点出绝不钉编译器生成的 SSA id 或 mangled 名SPIR-V%29、IR%1234、_S3、f_0都随 codegen 变化且 slang-test 反汇编 SPIR-V 时有时用友好名%f_0有时用数字——一律用宽松捕获%{{[A-Za-z0-9_]}}发射文本中的[[...]]是 FileCheck 的变量引用语法Metal/HLSL 属性需转义// CHECK: {{\[\[}}unroll{{\]\]}}用CHECK-DAG处理无序匹配普通CHECK只用于你确实在验证源码文本顺序的场景CHECK-NOT: OpFunction会误中OpFunctionEnd要点名具体 token默认匹配-O0形状若声明依赖优化行为如内联在指令上加-O1只钉声明依赖的 token问自己这个 token 若改变锚定的声明会变假吗——不会就通配或省略。八、第 6 步停止准则一个 bundle 完成的充要条件_claims.md§6## Claims中枚举的每条声明要么在## Functional coverage中至少有一个测试覆盖文档承诺的维度basic / corner / boundary / combinations / types / back-ends——只限文档点名的那些要么在## Untested claims中有一行带分类理由out-of-bundle/compiler-bug-pending/non-normative/unclassified。两个明确的不要不要为已覆盖的声明注水加测试不要因为达到某个固定测试数就提前收工——测试数就是声明清单 × 维度自然给出的结果。另外unclassified行是审查者标记不是已关闭的 bundle——未分类理由意味着工作未完成。战役层面的编排优先级排序、逐文档工作流、跳过清单、覆盖率里程表见_meta/CAMPAIGN.md一份文档被判定为纯散文导言、词汇表或 TODO占位例如被跳过的docs/language-reference/preprocessor.md、expressions-conversions.md或可测试声明不足约 3 条时直接跳过并记录理由而不是硬造 bundle。九、方法学的工程落地从方法论到可执行流水线声明驱动的原则要真正生效需要一整套工程机制把它变成可运行、可审计的流水线9.1 权威性层级Source-of-truth hierarchy当同一行为在多处被描述时语言参考优先于生成的设计文档_common.md§ Source-of-truth hierarchydocs/language-reference/*.md—— 人工编写的语言参考手册描述 Slang 行为应当如何是权威规范只要覆盖所测声明就锚定到这里docs/generated/design/*.md—— LLM 从编译器源码反推生成的架构文档可能把 bug 当作有意行为固化仅当语言参考未覆盖时才锚定这里语言参考是进行中的工作、不完整设计文档兜底路径依然承重编译器源码—— 永不作测试的首要引用。若行为在语言参考与设计文档中同时出现且互相矛盾锚定语言参考并让测试失败——失败本身就是信号编译器只可能匹配其中一方人工 triage 决定是规范错还是编译器错并在 bundle README 中写一行drift-from-sourcedoc-gap同时点名两个引用。9.2 驱动脚本lint 与 verifydocs/generated/tests/_meta/regenerate.py是套件的驱动完整命令表见_meta/regenerate.mdpython3 docs/generated/tests/_meta/regenerate.py list # 列出所有 bundle key python3 docs/generated/tests/_meta/regenerate.py list-stale # 分类 missing / stale / fresh python3 docs/generated/tests/_meta/regenerate.py lint bundle # 结构 lint主要契约 python3 docs/generated/tests/_meta/regenerate.py verify bundle # 运行 slang-test 验证 python3 docs/generated/tests/_meta/regenerate.py digest bundle # 计算 digest python3 docs/generated/tests/_meta/regenerate.py mark-fresh bundle --model id python3 docs/generated/tests/_meta/regenerate.py doc-gaps # 按源文档聚合 doc-gap 行 python3 docs/generated/tests/_meta/regenerate.py findings list|show|file|dup|fixedlint 是主要契约不需要slangc就能跑校验每个.slang有匹配的//META块、//TEST指令至少带一条 CHECK、finding YAML 符合 schema、bundle README 携带必需 front-matter 与章节结构。注意README 带 YAML front-matter会被 Jekyll 的 Liquid 处理正文中裸{{/{%会炸掉整个站点构建——所以 bundle README 里{{1,2},{3,4}}要写成{ {1,2},{3,4} }FileCheck 的{{.*}}要用code#123;#123;.*#125;#125;/code数值实体。verify 运行slang-test报告三个桶passed指令运行且 CHECK 匹配、ignoredrunner 没有该指令请求的后端如无 DXC 时的-target dxil不算失败CI 夜间任务会验证、FAILED指令运行但 CHECK 不匹配或诊断测试 runner 报错。每个 FAILED 都必须修复后才能提交——本地失败还提交到 CI 会浪费夜间运行、把真实编译器 bug 埋进失败噪声里。9.3 编译器 bug 的审计轨迹findings 与 expected-failures写测试时若观察到slangc崩溃SIGSEGV、ICE、文档声明的诊断不触发、codegen 与引用声明矛盾、或旧测试在升级后失败不要自行开 issue、不要试图修复而是写结构化finding位置docs/generated/tests/_meta/findings/id.yamlschema 见_meta/schema/finding.schema.json必填字段idkebab-case与文件名一致、bundle、suspected_kindsigsegv | wrong-diagnostic | wrong-codegen | regression | catalog-drift | doc-claim-overstated、observed_at、evidence精确复现命令 源码路径 观察摘要、expected正确行为的一句话声明 citation_kind 可解析的引用路径campaign 模式下禁止regenerate.py findings file——YAML 留在findings/不进filed/由之后的人工 triage 复查、编辑、去重后再 filed受影响的测试路径加入_meta/expected-failures.txt每条上方以#注释注明 pending finding 路径verify对命中该列表的测试单列expected-fail桶不计入退出码。该列表只用于已 filed 的编译器 bug不是停放 flaky 测试的地方。finding 是证据不是结论。命令命名了临时文件而没给evidence.repro_source内联源码时 lint 会警告——真实 triage 中曾有一次 17 个 finding 有 7 个因此无法重跑其中 2 个还产生了误导性的已修复假象。9.4 文档反馈回路Doc gaps observed## Doc gaps observed是通往文档再生成的反馈通道regenerate.py doc-gaps按source_doc聚合所有 bundle 的 gap 行作为下一版docs/generated/design/*.md生成的输入。Kind 受控词汇包括missing-example文档命名声明但没有最小示例、missing-surface文档命名 IR/AST 内部构造但没有用户级语法、undocumented-behavior编译器行为真实可及但文档沉默、cascading-only-mention、ambiguous-claim、drift-from-source文档描述与编译器实际行为矛盾。每行必须自带Suggested addition写成可直接执行的文档修改指令。当文档声称的表面被编译器拒绝如文档写的-validate-spirv标志实际不存在、Metal 声称支持NonUniformResourceIndex但 core-module 的能力集排除了 Metal时记录 doc-gap 比绕开问题更有价值——下一次文档再生成会消费这一行并修复事实基准。十、真实 bundle 验证方法学在仓库中的落地形态最后用两个已存在的 bundle 展示方法学如何落到真实产物上。conformance/expressions-operators的 Intent 段落明确说明了声明选择策略文档枚举了前缀/后缀/中缀运算符表并给出?:HLSL 风格不短路、括号、强制转换的显式规则。高价值声明优先——前缀 vs 后缀产生旧值 vs 新值是经典 bug 源?:不短路是 Slang 相对 C 家族的特有例外用未选中分支上的副作用钉住。10 个测试文件对应 9 条覆盖声明 3 条分类登记的未测试声明。conformance/basics-execution-divergence-reconvergence则展示了声明的分组编号Preamble 的 C1–C3uniform 路径、两个收敛作用域、mutually convergent 集合、结构化控制流分歧的 C4–C8if/else、无else的if、switch、fall-through、循环、线程组纠缠函数的 C9、wave 纠缠函数的 C10–C11。由于 wave/subgroup 运行时值只有 GPU 可观察覆盖策略是emission-firstSPIR-V 钉OpSelectionMerge/OpBranchConditional/OpSwitch/OpLoopMerge/GroupNonUniform*HLSL 钉WaveActiveMin/MaxGLSL 钉subgroupMin/MaxGPU 值类声明C9/C10/C11 的运行时值全部以gpu-other理由登记在## Untested claims并说明需要的 runner 能力。这与_claims.md§4 引用的 wave-divergence 表格示例一脉相承——声明分解的颗粒度、维度的选择、未测试理由的分类都是同一套方法论在真实 bundle 中的直接体现。结语声明驱动的测试方法学把测试套件质量从不可度量的直觉变成可审计的契约声明的完整枚举是目标测试数是产出覆盖率数据是指导文档驱动扩展的信号永远不是追逐逐行覆盖的目标README.md 中的 load-bearing rule。薄文档产出薄 bundle、富文档产出富 bundle未测试的声明必须带分类理由发现的编译器 bug 走结构化 finding 通道文档的缺陷走 doc-gap 反馈通道回到文档再生成。这套闭环使conformance/树能持续暴露规范 vs 编译器漂移、design/树能持续守住已固化的行为也让套件本身在 nightly 中保持绿而不掩盖真实信号——这正是把一份语言文档变成完整测试包的全部答案。【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门