Skip to content

局所変数や引数に隠されるシェーダーのメンバーの読みと呼び出しを診断で断つ - #263

Merged
routersys merged 9 commits into
mainfrom
dev/ComputeWeave.HiddenShaderMember
Sep 21, 2026
Merged

routersys merged 9 commits into
mainfrom
dev/ComputeWeave.HiddenShaderMember

Conversation

@routersys

Copy link
Copy Markdown
Owner

Summary / 概要

課題 #256 のうち、値が黙って変わる形を直します。生成器はシェーダー自身のメンバーを名前だけで書き出すので、this.amount や Shader.Factor のように限定子を付けて読んだメンバーは、同じ関数に同じ名前の局所変数や引数が在ると生成HLSLではそちらに隠されます。C# ではメンバーを指していた読みが局所変数を指し、シェーダーは C# と違う値を診断なく計算していました。

この読みを、著者の書いた位置を名指す誤りの診断 CMPW0131(Direct2D側は CMPWD2D0104)で断ちます。見るのは、生成HLSLがその関数の中でその読みより前に宣言する局所変数と引数だけです。

Linked issue / 関連する課題

#256 のフィールドの3形を直します。メソッドの呼び出しの3形は、限定子を落とす箇所そのものが #252 で入るので、#252 が入ったあとに同じ報告をその箇所へ足します。この PR では課題を閉じません。

Kind / 種別

  • Bug fix / 不具合修正
  • Analyzer or generator / アナライザーまたはジェネレーター

Behavior change / 挙動の変更

新しい診断が2つ増えます。CMPW0131 と CMPWD2D0104 で、どちらも誤りの重大度です。同梱する文書が述べる診断の件数が、計算側は113から114へ、Direct2D側は102から103へ変わります。計算側の CMPW0130 は #257 が取っている番号で、Direct2D側の CMPWD2D0103 は #257 が #258 と重なった CMPWD2D0102 から取り直す番号として空けています。公開APIは変わりません。

断つのは、限定子を付けて読んだシェーダーのメンバーの名前が、同じ関数の中でその読みより前に宣言された局所変数か引数と同じである形です。これまではどの形も診断なく建ち、装置では局所変数の値を読んでいました。

Verification / 検証

dotnet build tests/ComputeWeave.Tests.SourceGenerators/ComputeWeave.Tests.SourceGenerators.csproj -c Release -p:Platform=x64
dotnet tests/ComputeWeave.Tests.SourceGenerators/bin/x64/Release/net10.0/ComputeWeave.Tests.SourceGenerators.dll
dotnet build tests/ComputeWeave.D2D1.Tests.SourceGenerators/ComputeWeave.D2D1.Tests.SourceGenerators.csproj -c Release -p:Platform=x64
dotnet tests/ComputeWeave.D2D1.Tests.SourceGenerators/bin/x64/Release/net10.0/ComputeWeave.D2D1.Tests.SourceGenerators.dll
pwsh build/verify-readme-counts.ps1
pwsh build/verify-analyzer-releases.ps1
pwsh build/audit-upstream-divergence.ps1

土台は fa7f369e、実装のコミットは 2fb7f200 です。出したときの main は 4e654727(#258 の併合)で、そこまでを枝へ併合してあります。

スイート 変更前 変更後
計算側の生成器 合計616、失敗0 合計626、失敗0
Direct2D側の生成器 合計240、失敗0 合計242、失敗0

増える10件と2件は、足した試験の本数と一致します。実装のコミットだけでも2つの試験プロジェクトが建つことを、そのコミットだけを別の作業ツリーへ取り出して確かめました。件数の検査と出荷の記録の検査は通り、乖離の監査は待ち行列が空であると述べます。

課題の形を測り直しました

課題 #256 で 7508bed3 に通した形と装置の値をそのまま挙げます。限定子を落とす箇所は土台 fa7f369e でも同じで、右の列はこの枝で同じ形を生成器へ通した結果です。

書いた形 土台 この枝
float amount = 3; x = this.amount;(捕捉したフィールドは 10) 建つ。装置の値は 3 CMPW0131
float Factor = 3; x = Shader.Factor;(静的フィールドは 2) 建つ。装置の値は 3 CMPW0131
float Go(float amount) => this.amount + amount; を Go(1)(フィールドは 10) 建つ。装置の値は 2 CMPW0131
float amount = this.amount; 建つ CMPW0131。局所変数は自分の初期化子の中でも見えています
x = this.amount; Hlsl.Modf(2.5f, out float amount); 建つ CMPW0131。引数の中の宣言は本体の先頭へ持ち上げられるので、あとに書いても隠します
if (c) { Hlsl.Modf(2.5f, out float amount); } x = this.amount; 建つ CMPW0131。持ち上げられた宣言は、C# では見えないブロックの外でも隠します
x = this.amount; float amount = 3; 建つ 変わらない。あとで宣言された局所変数は HLSL でも宣言の位置から先しか見えません
float Factor = 3; static float Read() => Shader.Factor; 建つ 変わらない。局所関数は別の関数として書き出されるので、囲む関数の局所変数は届きません
別のブロックの中の float amount = 3; 建つ 変わらない
const float Scale = 2; float Scale = 3; Shader.Scale 建つ 変わらない。定数は自分の名前で書き出されます

Direct2D側は最初の形と、あとで宣言する形の2つを同じ試験で固定しました。判定は共有の書き換え器にあり、Direct2D側の試験はその経路が届いて自分の識別子で答えることを見ています。

解全体を建て直しました

ビルドエラーを出す診断なので、生成器が走る11プロジェクトを -t:Rebuild と -p:EmitCompilerGeneratedFiles=true で建て直し、11プロジェクトとも建ちました。この木にはこの断りに掛かるシェーダーが1つも無いということです。生成された1080件のファイルを土台と突き合わせると1078件が同一で、差が出た2件は Direct2D の記述子の埋め込みバイトコードの中だけです。同じコミットを2回建てても動く既知の2件で、新しい断りは生成物を変えていません。

変異

実装をコミットしてから壊しています。壊す前の木は dd0c7766 です。

変異 計算側 Direct2D側
名前の引き当てから報告しない(修正前の形) 4 1
局所変数の宣言の位置を見ない 1 1
引数の中の宣言が持ち上げられることを見ない 2 0
囲む宣言の局所変数を除かない 1 0
引数を見ない 1 0
this を付けたフィールドの読みの箇所だけ戻す 5 1
型名を付けた静的フィールドの読みの箇所だけ戻す 1 0

落ちるのはどれも足した試験だけで、既存の試験は1件も落ちません。1行目は持ち上げられる宣言を集める側を残しているので、持ち上げの2行を除く4件が落ちます。2行目と4行目は、断たない側の対照(あとで宣言する形と、局所関数の中の形)だけが落ちます。断つ側だけを測ると、位置も囲む関数も見ない実装で全部の行が緑になるので、この2つの対照が要ります。

Adapter and driver tested / 試したアダプターとドライバー: Intel(R) Iris(R) Xe Graphics, 32.0.101.7085(土台の3形の値を読み戻したときのものです。この枝の試験はデバイスを開きません)

Checklist / 確認

  • 一つの論理的な変更にまとまっており、無関係な整理や整形を含まない。
  • 各コミットが単独でビルドできる。
  • 実装の変更と検証テストを別のコミットに分けた。
  • 既定ブランチへ入った、またはリリースタグが指すコミットを書き換えていない。
  • 変更は、その部分で既に確立された実装パターンに従っている。
  • public と protected のAPIに、リポジトリが求めるXMLドキュメントを付けた。
  • 既存のドキュメントコメントを維持した。
  • 暗黙の代替動作や互換性のための繕いを持ち込んでいない。
  • 無関係な依存関係を更新していない。
  • 上流から受け継いだファイルを変更したので、乖離台帳へ行を足し、実装のコミットを引きました。監査の道具は指摘を出しません。

If this touches a guarded area / 慎重を要する箇所に触れる場合

  • 試験が守るべき挙動そのものを動かしており、その挙動を意図的に壊すと落ちることを確認した。
  • 任意の待ち時間、固定の再試行回数、非同期処理の速さへの仮定に依存する試験が無い。
  • ビルドエラーを出す診断なので、生成器の試験に加えて解全体を建て直して検証した。

Notes for the reviewer / 査読者への注記

断つ形をどう決めたか

生成HLSLがその関数の中で読みより前に宣言する名前だけを見ます。引数は常にそうです。局所変数は、読みより前に宣言されたものと、引数の中で宣言されたものです。後者は書き換え器が本体の先頭へ持ち上げるので、書いた位置に関わらず、C# では見えないブロックの中に在っても隠します。意味解析の名前の引き当てはブロックの外の宣言を返さないので、持ち上げられる宣言だけは関数の構文を歩いて集めています。読みより後ろで宣言された局所変数は、HLSL でも C# の名前解決と同じく宣言の位置から先しか見えないので、断ちません。断つと C# として正しく、生成HLSLも正しく建つ形を断つことになります。

局所関数の中の読みでは、囲む関数の局所変数を除きます。局所関数は別の関数として書き出されるので、囲む関数の局所変数はそこに在りません。意味解析が返す名前を、読みの位置を囲む宣言の記号で絞っています。

直した場所と、触っていない場所

報告は両方の書き換え器が派生する型に1つ置き、本文の書き換え器が限定子を落とす2箇所(this を付けたフィールド、型名を付けた静的フィールド)から呼びます。初期化子の書き換え器も型名を落としますが、初期化子には局所変数も引数も無いので呼びません。その旨をその場に書いています。

定数は __Shaders_Shader__Scale のような名前で書き出され、局所関数は __Execute__Read のように改名されるので、どちらも隠されません。試験で固定しています。

断つ以外の道を退けた理由

局所変数のほうを改名して読みを通す形も採れます。採らなかったのは、著者が同じ関数に C# では区別できる2つの名前を書いていて、HLSL ではそれを区別できないという事実を、生成器が黙って解決することになるためです。どちらを指すかを決めるのは著者で、名前を変えれば通ります。

main を併合しています

出す前に main が 4e654727(#258)へ進み、Direct2D側の記述子と未出荷の記録と乖離台帳の末尾が衝突したので、main を枝へ併合しました(7607c7fc)。衝突はどれも main の側を先に置く形で解き、#258 が足した診断の分だけ Direct2D側の件数を103へ数え直しています。併合後の先端で生成器の試験2本は、計算側 626、Direct2D側 249 で失敗0です。

測っていないこと

Direct2D側の装置の値は読み戻していません。書き換え器は共有で、生成HLSLは同じ形になります。この枝の生成器の試験はデバイスを開きません。

@routersys routersys added bug Something isn't working / 不具合が起きている analyzer or generator Analyzer or generator / アナライザーまたはジェネレーター labels Sep 17, 2026
@github-actions

github-actions Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

PRレビュー / PR review

変更 15 ファイル、コミット 9 件。 / 15 files, 9 commits.

検証の要否 / Verification required

以下を走らせ、失敗した試験の名前と失敗の様子を変更前と突き合わせてください。総数だけで判断しないでください。
Run the following and compare the names and failure modes against the same suites before your change. Do not judge by totals alone.

dotnet build ComputeWeave.sln -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests.SourceGenerators/ComputeWeave.Tests.SourceGenerators.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests.Internals/ComputeWeave.Tests.Internals.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests/ComputeWeave.Tests.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests.DeviceLost/ComputeWeave.Tests.DeviceLost.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.D2D1.Tests.SourceGenerators/ComputeWeave.D2D1.Tests.SourceGenerators.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.D2D1.Tests/ComputeWeave.D2D1.Tests.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.D2D1.Tests.AssemblyLevelAttributes/ComputeWeave.D2D1.Tests.AssemblyLevelAttributes.csproj -c Release -p:Platform=x64

ビルドエラーを出す診断を変えた場合は、アナライザーの試験に加えて解全体の検証が要ります。
If a diagnostic that produces build errors changed, verify the complete solution as well.

慎重を要する箇所 / Guarded areas touched

  • 寿命と破棄 / lifetime and disposal
    • src/ComputeWeave.D2D1.SourceGenerators/AnalyzerReleases.Unshipped.md
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxRewriters/HlslSourceRewriter.Diagnostics.cs
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxRewriters/HlslSourceRewriter.cs
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxRewriters/ShaderSourceRewriter.cs
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxRewriters/StaticFieldRewriter.cs
    • ほか 1 件 / 1 more
  • 記述子と診断 / descriptors and diagnostics
    • src/ComputeWeave.D2D1.SourceGenerators/AnalyzerReleases.Unshipped.md
    • src/ComputeWeave.D2D1.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxRewriters/HlslSourceRewriter.Diagnostics.cs
    • src/ComputeWeave.SourceGenerators/AnalyzerReleases.Unshipped.md
    • src/ComputeWeave.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs

寿命の追跡と危険の追跡は別々の保証です。一方を保っても他方が保たれるとは限りません。
Lifetime tracking and hazard tracking are separate guarantees; preserving one does not preserve the other.

公開APIまたは生成される記述子を変えた場合は、該当部分の互換性、生成の決定性、基準データの検査を走らせてください。
For public API or generated descriptor changes, run the compatibility, deterministic-generation or golden-data checks of the affected subsystem.

確認できた点 / Confirmed

  • 概要が書かれています。 / A summary is present.
  • 検証の結果が書かれています。 / Verification results are present.
  • 関連する課題が示されています。 / A linked issue is referenced.
  • 実装と検証テストが別のコミットに分かれています。 / Implementation and tests are in separate commits.

これは自動の確認で、査読の代わりにはなりません。指摘は判断の材料であって、従う義務はありません。
This is an automated check, not a substitute for review. Findings are input to a decision, not obligations.

@routersys

Copy link
Copy Markdown
Owner Author

main(0df349d0、#261 まで)を併合して衝突を解きました。#252 が入ったので、保留していたメソッドの呼び出しの側も足しています(実装 946b6a87、試験 d1189b48、乖離台帳 38cc6ef8)。土台との突き合わせと変異を手元で回しているところで、終わり次第、本文を今の内容へ書き換えます。

@routersys routersys changed the title 局所変数や引数に隠されるシェーダーのメンバーの読みを診断で断つ 局所変数や引数に隠されるシェーダーのメンバーの読みと呼び出しを診断で断つ Sep 20, 2026
@routersys
routersys merged commit e232fd7 into main Sep 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

analyzer or generator Analyzer or generator / アナライザーまたはジェネレーター bug Something isn't working / 不具合が起きている

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant