我有一个可以正确构建和运行的编译器,但PEVerify在某个时刻称其无法验证。仔细查看错误,相应的源代码和相关点的ILDasm输出后,我找不到问题,我怀疑PEVerify中存在错误,除了.NET和Mono版本在同一个地方报告相同的错误。
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] [offset 0x00000011] [found ref'Boo.Lang.Compiler.Ast.Node'] [expected ref Boo.Lang.Compiler.Ast.INodeWithBody']堆栈上的意外类型。
Offsest 0x11
对应于??
表达式的后半部分。来自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节点的基类。 BlockExpression
和Method
分别是lambdas和方法的节点类,它们都实现了INodeWithBody
接口。一切看起来都是正确的,无论是在C#中(如果存在类型问题都不会构建)和IL中(000c
处的GetAncestor<Method>
调用的返回类型为{{1}) },方法调用的第一个类型参数。)
当PEVerify显然具有!!0
类型的值时,是什么导致PEVerify认为它处理类型为Node
的值?有没有办法解决它?
答案 0 :(得分:3)
当PEVerify明显具有
Node
类型的值时,是什么导致PEVerify认为它正在处理Method
类型的值?
正如Stephane Delcroix所指出的那样,有两条代码路径可以达到IL_0011
,因为它是分支的目标。它显然不一定具有Method
类型的值。
GetAncestor<TAncestor>
返回TAncestor
。您有GetAncestor<BlockExpression>
的结果或GetAncestor<Method>
的结果,因此BlockExpression
或Method
。两者都实现了INodeWithBody
,所以从逻辑上讲,代码仍然很好。
不幸的是,“BlockExpression
或Method
”对验证来说太过分了。这简化为Node
(公共基础),不实现INodeWithBody
。见ECMA-335§III.1.8.1.3:
合并类型
U
应按如下方式计算(回想S := T
是§III.1.8.1.2.2中定义的兼容性函数):
如果
S := T
,则U=S
否则,如果
T := S
则U=T
否则,如果
S
和T
都是对象类型,那么让V
成为S
和T
最接近的常见超类型U=V
。- 醇>
否则,合并将失败。
如果您检查C#编译器的功能,您会看到它在stloc.0
之前将ldloc.0
/ INodeWithBody
组合发送到dup
类型的本地组合中。这使得一切正常,因为INodeWithBody
和Method
的常见类型是INodeWithBody
。
答案 1 :(得分:1)
由于0x11
的{{1}}的第一部分或右部分正在分支到??
,因此不清楚0x08
是否失败。
我倾向于思考GetAncestor<>
会返回Node
而??
的左侧部分缺少明确的演员。