本体をどこにも持たない宣言を診断で断つ - #200
Conversation
PRレビュー / PR review変更 14 ファイル、コミット 11 件。 / 14 files, 11 commits. 検証の要否 / Verification required以下を走らせ、失敗した試験の名前と失敗の様子を変更前と突き合わせてください。総数だけで判断しないでください。 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ビルドエラーを出す診断を変えた場合は、アナライザーの試験に加えて解全体の検証が要ります。 慎重を要する箇所 / Guarded areas touched
寿命の追跡と危険の追跡は別々の保証です。一方を保っても他方が保たれるとは限りません。 公開APIまたは生成される記述子を変えた場合は、該当部分の互換性、生成の決定性、基準データの検査を走らせてください。 指摘 / Findings
確認できた点 / Confirmed
これは自動の確認で、査読の代わりにはなりません。指摘は判断の材料であって、従う義務はありません。 |
Summary / 概要
本体をどこにも持たない宣言を取り込むと、生成される HLSL に書くものがありません。
externの宣言がその場合で、C# は警告としか言いません。取り込むメソッドと局所関数は本体の無い宣言としてそのまま書き出され、シェーダーコンパイラが利用者の書いていない符号を名指しします。取り込む構築子と入口は生成器を終了させ、そのコンパイル単位の全てのシェーダーの記述子を捨てます。CMPW0127とCMPWD2D0099を足し、宣言の3つの種それぞれの本体を正規化する visit から報告します。宣言には空の本体を与え、書き換えはそこで終わらせません。Linked issue / 関連する課題
Closes #183
Kind / 種別
Behavior change / 挙動の変更
本体の無い宣言を取り込む入力が、シェーダーコンパイラの失敗や生成器の終了ではなく、その宣言を名指しする誤りになります。診断を1件足すので、
CMPWは111件、CMPWD2Dは99件になります。本体を持つ宣言の生成物は変わりません。下の全数の突き合わせがその測定です。公開APIの署名は変わりません。
Verification / 検証
土台は
9cf26d40です。解全体の建て直しは警告0件、誤り0件でした。土台の欄も同じ機械で測った値で、CI の報告ではありません。ComputeWeave.Tests.SourceGeneratorsComputeWeave.D2D1.Tests.SourceGeneratorsComputeWeave.D2D1.Tests.AssemblyLevelAttributesComputeWeave.Tests.InternalsComputeWeave.D2D1.TestsComputeWeave.Tests土台もこの枝も失敗0件です。足した試験は20本で、計算側の生成器へ17本、Direct2D 側へ3本です。増えた分だけ合計が動いています。
CIも通りました。「ビルドとテスト」が回した6つのスイートは、総数が上の表と同じで、いずれも失敗0件です。CIはハードウェアのアダプターを持たない機械なので、判定しない試験の数だけが手元と違います。「デバイス消失のテスト」と「変更範囲の判定と確認」と「文書の検査」も成功しています。
手元で走らせていないのはデバッグレイヤーだけです。バリア、資源の状態、キューの選択、相互運用のいずれにも触れておらず、本体を持つ宣言の生成物も変わらないためです。
Adapter and driver tested / 試したアダプターとドライバー: Intel(R) Iris(R) Xe Graphics, 32.0.101.7085
族を全数で測り、断りの境界も測りました
本体をどこにも持たない宣言を、宣言を読む6つの探索と局所関数の2つを合わせて9形で掃きました。修正の前は9形すべてが欠陥です。
CMPW0046CMPW0127CMPW0046CMPW0127CMPW0046CMPW0127CMPW0046CMPW0127CMPW0046CMPW0127CMPW0046CMPW0127CMPW0127CMPW0127externで書くCMPW0127CMPW0046は断りではなく、HLSL コンパイラが生成された符号に対して失敗したという報告です。修正後はどの形も報告がCMPW0127の1件だけで、異常終了は1件もありません。断るかどうかは、その宣言が生成される HLSL へ書き出されるかどうかと一致します。呼ばれていなくても書き出される宣言は断り、書き出されない宣言は今までどおり触りません。
CMPW0127CMPW0127シェーダー自身のメソッドと局所関数は、呼ばれなくても生成される HLSL に前方宣言と定義の両方が出ます。生成された文字列で確かめました。外の型のメンバーは、シェーダーが届いたときにだけ取り込まれます。上の5形はいずれも試験で固定してあります。
生成物を全数で突き合わせました
解全体を
-p:EmitCompilerGeneratedFiles=trueで建て直し、書き出された file を突き合わせています。比べたのは同じ作業ツリーの2点で、実装を入れた状態と、実装の2つの file だけを土台の内容へ戻した状態です。各回の建ての前に生成物の folder を消しています。-t:Rebuildはそこを消さないので、消さずに歩くと前の建ての file を相手側と突き合わせることになります。動いた2件は Direct2D の記述子で、同じコミットで2回建てても同じ2件が動きます。動くのは埋め込まれた符号の先頭にある検査値だけです。戻した側でも解全体が誤り0件で建ちますので、本体の無い宣言はこの木の中に1件もありません。
変異試験
実装をコミットしてから、実装の2つの file を土台の内容へ戻して測りました。この修正は報告と、空の本体を与えることの2つでできているので、変異も2つに分けています。
報告を外すと、断りを見る14本がすべて名指しで落ちます。空の本体を外すと、修正前に生成器が終了していた4形だけが落ちます。計算側の3本は構築子の2形と入口で、Direct2D 側の1本は構築子です。2つの変異が別の集合を落とすので、どちらの半分も守るものを持っています。
この変異は試験の穴を1つ見つけました。Direct2D 側の行を最初に足したときは、取り込むメソッドと入口の2本でした。空の本体を外す変異で1本も落ちなかったので調べたところ、Direct2D の入口はそもそも終了せず、終了するのは構築子の取り込みでした。構築子の行を足して、この変異が名指しで落とすことを確かめています。
Notes for the reviewer / 査読者への注記
断つ判断
本体は生成される HLSL に書き出すものそのものですから、持たない宣言は書くものがありません。C# が
externを許すので、利用者の側からは正しい C# として届きます。書き出せない以上、通す形はありません。置き場
報告は、宣言の3つの種それぞれの本体を正規化する visit から出します。宣言を読む6つの探索、つまり4つの取り込みと2つの生成器の入口は、いずれもその3箇所のどれかを通ります。
探索の側へ置く形も採れますが、同じ規則を6回書くことになるうえ、それでは足りません。シェーダー自身のメソッドと呼ばれない局所関数は、探索を経ずに書き出されるためです。3つの visit は、書き出される宣言がすべて通る唯一の場所です。
終了させずに空の本体を与える理由
生成器が終了すると、その生成器の出力はコンパイル単位ごと捨てられます。利用者へ届くのは、生成された型が見つからないという無関係な誤りの束で、直すべき宣言はどこにも出てきません。それがこの報告の置き換えようとしている失敗そのものですから、そこで終わらせては意味がありません。報告は誤りなので、空の本体が書き出したものがシェーダーコンパイラへ届くことはありません。
利用者が報告を抑止した場合は届きます。そのとき構築子は既定の値を返すので、C# と違う値を黙って計算します。これは断りのあとに既定の値を返す
CMPW0120と同じ露出で、この木で既に確立された形です。抑止は誤りに対して明示的に行うものなので、そこまでを設計の対象にしていません。本体を正規化する補助は、もともと「常に波括弧の本体を返す」と述べていました。本体を持たない宣言に対してそれが成り立っていなかったので、述べているとおりにしただけです。
この族に入らないもの
実装部を持たない部分メソッドは C# 自身が断ちます。アクセシビリティを持つものは誤りになり、持たないものは消去されて呼び出しが解決しません。どちらも生成器へ届かないことを測ってあります。部分宣言のうち実装部を持つものは、その実装部が読まれるので、この変更の影響を受けません。
利用者が定義した演算子は、本体を持つかどうかに関わらず
CMPW0115が先に断ちます。二項演算子と変換演算子で測りました。宣言の取り込みへ届かないので、この規則の対象になりませんし、報告が2つ出ることもありません。Direct2D の経路
書き換え器は2つの生成器で共有されていますから、報告も両方へ掛かります。識別子は生成器ごとに別なので、記述子は両側に要ります。Direct2D 側の入口は計算側と別の符号を通るので、独立した行を置きました。
前提が崩れたときの退避
枝ごと戻せます。診断を1件外すことになるので、未出荷の記録と README の件数6箇所も一緒に戻ります。前提が崩れる筋は、本体の無い宣言から意味のある HLSL を書き出せるようになる場合ですが、書くものが無いという性質は言語の側の話なので、崩れるとすれば C# の側です。
測っていないこと
利用者の符号がこの形を何箇所含むかは分かりません。この木の中には1件もありませんでした。
extern以外に本体をどこにも持てない宣言があるかは、C# の仕様を全数で当たったわけではありません。掃いたのはexternと部分宣言と演算子の3つです。報告が1件だけであることを固定しているのは計算側だけです。Direct2D 側の補助は識別子を重複除去してから比べるので、同じ原因が2回報告されても通ります。報告を出すのは共有の書き換え器なので、Direct2D 側だけで重複が起きるには、あちらに固有の二重訪問が要ります。それは測っていません。
Checklist / 確認
If this touches a guarded area / 慎重を要する箇所に触れる場合