4

正しくビルドして実行するコンパイラがありますが、PEVerify は特定の時点でそれを検証不能と呼んでいます。問題のエラー、対応するソース コード、および ILDasm の出力を注意深く調べた後、.NET および Mono バージョンを除いて、PEVerify のバグを疑うところまで問題を見つけることができませんでした。同じ場所で同じエラーを報告します。

問題のあるメソッドは次のようになります。

internal static bool InAsyncMethod(Expression value)
{
    INodeWithBody ancestor = value.GetAncestor<BlockExpression>() ?? (INodeWithBody) value.GetAncestor<Method>();
    return ContextAnnotations.IsAsync(ancestor);
}

エラーは次のように報告されます。

[IL]: エラー: [D:\SDL-1.3.0-4423\boo\build\Boo.Lang.Compiler.dll: Boo.Lang.Compiler.TypeSystem.AsyncHelper::InAsyncMethod][オフセット 0x00000011][見つかった参照'Boo.Lang.Compiler.Ast.Node'][expected ref Boo.Lang.Compiler.Ast.INodeWithBody'] スタックに予期しない型があります。

Offsest0x11は式の後半に対応し??ます。ILDasm より:

.method assembly hidebysig static bool  InAsyncMethod(class Boo.Lang.Compiler.Ast.Expression 'value') cil managed
{
  // Code size       29 (0x1d)
  .maxstack  2
  .locals init ([0] class Boo.Lang.Compiler.Ast.INodeWithBody ancestor,
           [1] bool CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  callvirt   instance !!0 Boo.Lang.Compiler.Ast.Node::GetAncestor<class Boo.Lang.Compiler.Ast.BlockExpression>()
  IL_0007:  dup
  IL_0008:  brtrue.s   IL_0011
  IL_000a:  pop
  IL_000b:  ldarg.0
  IL_000c:  callvirt   instance !!0 Boo.Lang.Compiler.Ast.Node::GetAncestor<class Boo.Lang.Compiler.Ast.Method>()
  IL_0011:  stloc.0
  IL_0012:  ldloc.0
  IL_0013:  call       bool Boo.Lang.Compiler.Steps.ContextAnnotations::IsAsync(class Boo.Lang.Compiler.Ast.INodeWithBody)
  IL_0018:  stloc.1
  IL_0019:  br.s       IL_001b
  IL_001b:  ldloc.1
  IL_001c:  ret
} // end of method AsyncHelper::InAsyncMethod

このBoo.Lang.Compiler.Ast.Nodeクラスは、すべての AST ノードの基本クラスです。 BlockExpressionMethodは、それぞれラムダとメソッドのノード クラスであり、どちらもINodeWithBodyインターフェースを実装します。C# (型に問題があるとビルドされない) と IL (メソッド呼び出しの最初の型パラメーターが呼び出し000cの戻り値の型であると記述されている) の両方で、すべてが正しく表示されます。GetAncestor<Method>!!0

Node明らかに type の値を持っているのに、ここで type の値を扱っていると PEVerify が考える原因は何Methodですか? そして、それを修正する方法はありますか?

4

2 に答える 2

3

Node明らかに type の値を持っているのに、ここで type の値を扱っていると PEVerify が考える原因は何Methodですか?

Stephane Delcroix によっても指摘されているようIL_0011に、ブランチのターゲットであるため、 に到達する 2 つのコード パスがあります。必ずしも type の値を持つとは限らないことは明らかMethodです。

GetAncestor<TAncestor>戻りますTAncestorGetAncestor<BlockExpression>の結果 または の結果のいずれかを取得したため、 またはGetAncestor<Method>のいずれBlockExpressionMethodです。どちらも を実装INodeWithBodyしているため、論理的には、コードは問題ありません。

残念ながら、「どちらBlockExpressionMethod」は検証するには多すぎます。これは、実装されていないNode(共通ベース) に単純化されます。ECMA-335 §III.1.8.1.3 を参照してください。INodeWithBody

マージされた型 はU、次のように計算されます (これS := Tは、§III.1.8.1.2.2 で定義された互換性関数であることを思い出してください)。

  1. もしそうS := TならU=S

  2. そうでなければ、もしそうT := SならU=T

  3. それ以外の場合、STが両方ともオブジェクト型の場合、 letはとthenVの最も近い共通のスーパータイプになります。STU=V

  4. そうでない場合、マージは失敗します。

C# コンパイラの動作を確認すると、./ の前に型のローカルにstloc.0/の組み合わせが出力されていることがわかります。の一般的なタイプは thenであるため、これによりすべてが機能します。ldloc.0INodeWithBodydupINodeWithBodyMethodINodeWithBody

于 2017-05-21T11:01:41.237 に答える