April 20, 2017
https://issues.dlang.org/show_bug.cgi?id=17336

          Issue ID: 17336
           Summary: Implicit type conversion of size_t.init to int causes
                    standard type compatibility test to break
           Product: D
           Version: D2
          Hardware: x86_64
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: hsteoh@quickfur.ath.cx

Code:
------
void main()
{
    struct B {
        B opBinary(string op : "+")(int b) { return this; }
    }
    static if (is(typeof(B.init + size_t.init) : B))
    {
        size_t x = 1;
        B b1, b2;
        b1 = b2 + x; // line 9
    }
}
------

N.B.: This code was reduced from original generic code where B is a template parameter.

The condition `is(typeof(B.init + size_t.init))` is, AFAIK, the standard way to test if some given type B is compatible with certain operations, in this case addition of a size_t.  It would seem, on the surface, that this condition would fail, because B.opBinary requires an int, and size_t does not implicitly convert to int, so the static if block should be skipped by the compiler.

However, here is what the compiler has to say:

------
test.d(9): Error: incompatible types for ((b2) + (x)): 'B' and 'ulong'
------

How did the condition pass?  Well, a little investigation showed that if `size_t.init` is replaced by `size_t.max`, then the condition does, indeed, not pass, and the static if block is not compiled (no compile error).

This appears to indicate that the compiler is, for whatever reason, maybe overzealous VRP, implicitly converting size_t.init (which is 0L) to int(0), thus causing the standard type compatibility check idiom to fail. Using size_t.max instead forces the compiler to retain the type as size_t because size_t.max cannot fit inside an int, thereby achieving the correct behaviour.

Expected behaviour: if size_t is explicitly asked for, as in size_t.init, shouldn't the compiler suppress implicit conversion to a smaller type??!

--