Incorrect type inference for ternary operators #326

Open
kg opened this Issue Mar 25, 2012 · 3 comments

Projects

None yet

2 participants

@kg
kg commented Mar 25, 2012

With the following test case:

using System;

class Base {
}

class A : Base {
}

class B : Base {
}

public static class Program {
    public static void Main (string[] args) {
        var flag = true;
        var a = new A();
        var b = new B();
        Console.WriteLine(flag ? a as Base : b as Base);
        Console.WriteLine(!flag ? a as Base : b as Base);
    }
}

The inferred and expected types in the ILAst for the nodes within the ternary operator are wrong. The ternary node generated for it looks like this:

ternaryop:A[exp:object](ldloc:bool(flag), ldloc:A(a), ldloc:B[exp:A](b))

As you can see, the inferred type for the ternary operation is wrong, and the expected type for the second bit (ldloc b) is wrong.

@dgrunwald
Member

This is hard to fix currently - we're using the Cecil typesystem which misses a 'is subtype of' operation.
I think the correct solution for type inference here would be to apply the C# rules (result type is the input type so that the input type is a subtype), and if that fails, use the expected type.

Fixing this bug will have to wait until we port the decompiler to the NRefactory typesystem.

@kg
kg commented Apr 13, 2012

Understandable. Let me know if I can do anything to help.

@dgrunwald
Member

newdecompiler now generates:

Console.WriteLine(flag ? ((object)new A()) : ((object)new B()));

If the target method expects type Base, the operands are still cast to object, and then the whole ternary expression is cast back to Base. Which is not wrong, but also not pretty, so I'm keeping this bug open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment