October 07, 2013
Hello all,

I recently discovered this issue with std.bigint.BigInt and std.math.abs:
http://d.puremagic.com/issues/show_bug.cgi?id=11188

In short, the following code:

  import std.bigint, std.math, std.typetuple;

  auto foo(T)()
  {
      T n = -3;
      return std.math.abs(n);
  }

  void main()
  {
      foreach (T; TypeTuple!(byte, short, int, long, BigInt))
      {
          assert(foo!T() == 3);             // works
          assert(foo!(shared(T)) == 3);     // fails for BigInt
          assert(foo!(const(T)) == 3);      // fails for BigInt
          assert(foo!(immutable(T)) == 3);  // fails for BigInt
      }
  }

... will fail to compile for the shared, const and immutable variants of BigInt, with the compiler error message being:

/opt/dmd/include/d2/std/math.d(303):        std.math.abs(Num)(Num x) if (is(typeof(Num.init >= 0)) && is(typeof(-Num.init)) && !(is(Num* : const(ifloat*)) || is(Num* : const(idouble*)) || is(Num* : const(ireal*))))
/opt/dmd/include/d2/std/math.d(314):        std.math.abs(Num)(Num z) if (is(Num* : const(cfloat*)) || is(Num* : const(cdouble*)) || is(Num* : const(creal*)))
/opt/dmd/include/d2/std/math.d(322):        std.math.abs(Num)(Num y) if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*)) || is(Num* : const(ireal*)))
bigabs.d(6): Error: template std.math.abs(Num)(Num x) if (is(typeof(Num.init >= 0)) && is(typeof(-Num.init)) && !(is(Num* : const(ifloat*)) || is(Num* : const(idouble*)) || is(Num* : const(ireal*)))) cannot deduce template function from argument types !()(shared(BigInt))

... and similarly for const and immutable.

What I can't see is why there is a failure to deduce the template function.  In fact some checks show that it's the very first of these conditions:

    is(typeof(Num.init >= 0))

... that fails.  This is rather unintuitive.  Doesn't a BigInt -- even an immutable one -- default to 0?

Advice very much appreciated, as I'm feeling stumped.

Thanks & best wishes,

    -- Joe