Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expressions breaking code when compiled using VS2015 Update 1

After installing Visual Studio 2015 Update 1 on my machine I saw that some of my unit tests failed. After doing some investigation I was able to reduce the problem to this line of code:

Expression<Func<GameObject, bool>> expression = t => t.X == 0 && t.Y == 0 && t.GameObjectType == GameObjectType.WindMill;

When hovering over the expression variable the results were different in the versions of Visual Studio:

VS 2015: VS 2015

VS 2015 Update 1: VS 2015 Update 1

The logic that was doing the comparison for the enums (somewhere in ServiceStack.OrmLite code) now acted differently which then eventually resulted in the enum not being recognized as an enum, resulting in the failing unit test.

I was able to reproduce the problem using the following code:

class Program
{
    static void Main(string[] args)
    {
        var gameObjects = new List<GameObject> {
            new GameObject { X = 0, Y = 0, GameObjectType = GameObjectType.WindMill },
            new GameObject { X = 0, Y = 1, GameObjectType = GameObjectType.Pipe },
            new GameObject { X = 0, Y = 2, GameObjectType = GameObjectType.Factory }
        };

        var gameObjectsQueryable = gameObjects.AsQueryable();

        Expression<Func<GameObject, bool>> expression = t => t.X == 0 && t.Y == 0 && t.GameObjectType == GameObjectType.WindMill;

        var result = gameObjectsQueryable.Where(expression);

        var resultAsList = result.ToList();

        foreach (var item in resultAsList)
        {
            Console.WriteLine(item);
        }

        //Obtain the t.GameObjectType == GameObjectType.WindMill part
        var binaryExpression = expression.Body as BinaryExpression;
        var right = binaryExpression.Right;
        var binaryExpression2 = right as BinaryExpression;
        var right2 = binaryExpression2.Right;

        if (right2 is UnaryExpression)
        {
            Console.WriteLine("Found UnaryExpression (This happens when the solution is build with VS2015)...");

            var right2Unary = binaryExpression2.Right as UnaryExpression;
            var right2Constant = right2Unary.Operand as ConstantExpression;
            CheckIfConsantIsAsExpected(right2Constant);
        }
        else
        {
            Console.WriteLine("Found ConstantExpression (This happens when the solution is build with VS2015 Update 1)...");

            var right2Constant = binaryExpression2.Right as ConstantExpression;
            CheckIfConsantIsAsExpected(right2Constant);
        }

        Console.ReadKey();
    }

    public static void CheckIfConsantIsAsExpected(ConstantExpression expression)
    {
        if (expression.Value.Equals(GameObjectType.WindMill))
        {
            Console.WriteLine($"The value is the enum we expected :), : {expression.Value}");
        }
        else
        {
            Console.WriteLine($"The value is not the enum we expected :(, : {expression.Value}");
        }
    }
}

public class GameObject
{
    public int X { get; set; }
    public int Y { get; set; }
    public GameObjectType GameObjectType { get; set; }

    public override string ToString()
    {
        return $"{X},{Y}: {GameObjectType}";
    }
}

public enum GameObjectType
{
    WindMill = 100,
    Pipe = 200,
    Factory = 300
}

On VS 2015 it will go into the UnaryExpression path, and in VS 2015 Update 1 it will go into the ConstantExpression path.

If you compile the solution on VS 2015 and then copy the compiled .exe file to a VS 2015 Update 1 system it will run the same as the VS 2015 version (So also the UnaryExpression path). This suggests it is not JIT related but instead build related.

My question would be if this is intended? (Since it could break existing code when simply recompiling the solution)

like image 572
Devedse Avatar asked Dec 05 '15 00:12

Devedse


1 Answers

This appears to be something that was actually broken with the RTM VS2015. If you compile it without the old version of Roslyn it is actually a ConstantExpression.

4.5 compiler: https://dotnetfiddle.net/XpKg10
Roslyn compiler: https://dotnetfiddle.net/zeGVdh

like image 171
Michael Coxon Avatar answered Nov 14 '22 04:11

Michael Coxon