Why are generic and non-generic structs treated differently when building expression that lifts operator == to nullable?

前端 未结 2 610
猫巷女王i
猫巷女王i 2021-01-01 11:14

This looks like a bug in lifting to null of operands on generic structs.

Consider the following dummy struct, that overrides operator==:



        
相关标签:
2条回答
  • 2021-01-01 11:58

    The short answer is: yes, that's a bug. I've put a minimal repro and a short analysis below.

    My apologies. I wrote a lot of that code and so it was likely my bad.

    I have sent a repro off to the Roslyn development, test and program management teams. I doubt this reproduces in Roslyn, but they'll verify that it does not and decide whether this makes the bar for a C# 5 service pack.

    Feel free to enter an issue on connect.microsoft.com as well if you want it tracked there as well.


    Minimal repro:

    using System;
    using System.Linq.Expressions;
    struct S<T>
    {
        public static bool operator ==(S<T> a, S<T> b) { return false; }
        public static bool operator !=(S<T> a, S<T> b) { return false; }
    }
    class Program
    {
        static void Main()
        {
            Expression<Func<S<int>?, S<int>, bool>> x = (a, b) => a == b;
        }
    }
    

    The code that is generated in the minimal repro is equivalent to

    ParameterExpression pa = Expression.Parameter(typeof(S<int>?), "a");
    ParameterExpression pb = Expression.Parameter(typeof(S<int>), "b");
    Expression.Lambda<Func<S<int>?, S<int>, bool>>(
        Expression.Equal(pa, pb, false, infoof(S<int>.op_Equality)
        new ParameterExpression[2] { pa, pb } );
    

    Where infoof is a fake operator that gets a MethodInfo for the given method.

    The correct code would be:

    ParameterExpression pa = Expression.Parameter(typeof(S<int>?), "a");
    ParameterExpression pb = Expression.Parameter(typeof(S<int>), "b");
    Expression.Lambda<Func<S<int>?, S<int>, bool>>(
        Expression.Equal(pa, Expression.Convert(pb, typeof(S<int>?), false, infoof(S<int>.op_Equality)
        new ParameterExpression[2] { pa, pb } );
    

    The Equal method cannot deal with one nullable, one non-nullable operands. It requires that either both are nullable or neither is.

    (Note that the false is correct. This Boolean controls whether the result of a lifted equality is a lifted Boolean; in C# it is not, in VB it is.)

    0 讨论(0)
  • 2021-01-01 12:13

    Yes, this bug is gone in Roslyn (the compiler under development). We'll see about the existing product.

    0 讨论(0)
提交回复
热议问题