我有一个可以正确构建和运行的编译器,但 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]: Error: [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'] Unexpected type on the stack.
偏移量 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
class 是所有 AST 节点的基类。 BlockExpression
和 Method
分别是 lambda 和方法的节点类,它们都实现了 INodeWithBody
界面。一切看起来都是正确的,无论是在 C# 中(如果存在类型问题就不会构建)和 IL 中(它在 000c
处表示 GetAncestor<Method>
调用的返回类型是 !!0
,第一个类型参数在方法调用上。)
是什么导致 PEVerify 认为它正在处理类型为 Node
的值?在这里,当它显然具有 Method
类型的值时?有什么办法可以解决吗?
最佳答案
What is causing PEVerify to think it's dealing with a value of type
Node
here when it clearly has a value of typeMethod
?
正如 Stephane Delcroix 所指出的,有两条代码路径可以到达 IL_0011
。 ,因为它是分支的目标。它显然不一定具有 Method
类型的值.
GetAncestor<TAncestor>
返回 TAncestor
.你有 GetAncestor<BlockExpression>
的结果,或 GetAncestor<Method>
的结果,所以 BlockExpression
或 Method
.两者都实现 INodeWithBody
,所以从逻辑上讲,代码仍然没问题。
不幸的是,“BlockExpression
或 Method
”对于验证来说太多了。这被简化为 Node
(公共(public)基础),不实现INodeWithBody
.请参阅 ECMA-335 §III.1.8.1.3:
The merged type,
U
, shall be computed as follows (recall thatS := T
is the compatibility function defined in §III.1.8.1.2.2):
if
S := T
thenU=S
Otherwise, if
T := S
thenU=T
Otherwise, if
S
andT
are both object types, then letV
be the closest common supertype ofS
andT
thenU=V
.Otherwise, the merge shall fail.
如果您检查 C# 编译器的功能,您会看到它发出一个 stloc.0
/ldloc.0
组合成一个本地类型 INodeWithBody
在 dup
之前.这使得一切正常,因为 INodeWithBody
的常见类型和 Method
然后是INodeWithBody
.
关于c# - 为什么这段代码无法验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44095408/