F# under the covers XII -- Reflector 6.0 decompilation to C#
A new Reflector release (6.0.0.918), and time to see whether it can approximate in C# some compiled F# code that the 5.1.6.0 version balked at.
The generated IEquatable.Compare
method that couldn't be handled before now succeeds -- the section that had problems now resolves to
public sealed override bool Equals(Context obj) | |
{ | |
if (this <= null) | |
{ | |
return (obj <= null); | |
} | |
if (obj <= null) | |
{ | |
return false; | |
} |
and it's not surprising that comparing not-greater-than-null might be an unexpected piece of IL.
However, when there is a problem with decompilation, the new version no longer provides the detail of which instruction it didn't like. So I don't know why this
let (|CSharpConstStub|_|) (fn:Method) = | |
if fn.Name.ToString() @ "get_" then None | |
else match MapToTypes fn.Body.Statements with | |
| [NodeType.Block; NodeType.Block] -> | |
let block1 = fn.Body.Statements.[0] :?> Block | |
let block2 = fn.Body.Statements.[1] :?> Block | |
match (MapToTypes block1.Statements, MapToTypes block2.Statements) with | |
| ( [NodeType.Nop; NodeType.AssignmentStatement; NodeType.Branch], [NodeType.Return]) -> | |
let ass = block1.Statements.[1] :?> AssignmentStatement | |
let branch = block1.Statements.[2] :?> Branch | |
if branch.Target <> block2 || null <> branch.Condition then None | |
elif ass.Source.NodeType <> NodeType.MemberBinding && ass.Source.NodeType <> NodeType.Literal then None | |
else match (block2.Statements.[0], ass.Target) with | |
| ReturnTemp -> Some() | |
| _ -> None | |
| _ -> None | |
| _ -> None |
raises an error report when trying to decompile to C# (or MC++ or VB); or why this
let (|CSharpGetterInterior|_|) (state:(Statement * Statement * Member)) = | |
let (a, b, fn) = state | |
let block = a :?> Block | |
let block2 = b :?> Block | |
match MapToTypes block.Statements with | |
| [NodeType.Nop; NodeType.AssignmentStatement; NodeType.Branch] -> | |
let ass = block.Statements.[1] :?> AssignmentStatement | |
let branch = block.Statements.[2] :?> Branch | |
if (ass.Source.NodeType <> NodeType.MemberBinding || | |
null <> branch.Condition || | |
branch.Target <> block2) then None | |
elif block2.Statements.Count <> 1 then None | |
else match (block2.Statements.[0], ass.Target) with | |
| ReturnTemp -> | |
let n = (ass.Source :?> MemberBinding).BoundMember.Name.ToString() | |
if fn.Name.ToString().ToUpperInvariant() <> ("get_" + n).ToUpperInvariant() then None | |
else Some () | |
| _ -> None | |
| _ -> None |
throws a NullPointerException while trying to report an error when asked to decompile it as C# (I was able to get an error report sent when asking for VB instead).
Dropping back to 5.1.6.0, both show the usual "invalid branching condition", and point to
if branch.Target <> block2 || null <> branch.Condition then None |
(the former condition) and
if (ass.Source.NodeType <> NodeType.MemberBinding || |
respectively, on the path where we are short-circuiting, as in
L_020d: call bool [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericEqualityIntrinsic<class [Microsoft.Cci]Microsoft.FxCop.Sdk.Block>(!!0, !!0) | |
L_0212: ldc.i4.0 | |
L_0213: ceq | |
L_0215: brfalse.s L_0219 | |
L_0217: br.s L_021b | |
L_0219: br.s L_021f | |
L_021b: ldc.i4.1 | |
L_021c: nop | |
L_021d: br.s L_0238 |
where the last line here is the one that the decompilation faults on.
No comments :
Post a Comment