Why does intpromote spew warnings for ~ operator?

H. S. Teoh hsteoh at quickfur.ath.cx
Mon Sep 13 15:38:44 UTC 2021


On Sun, Sep 12, 2021 at 10:14:03AM -0400, Steven Schveighoffer via Digitalmars-d wrote:
[...]
> ```
> onlineapp.d(11): Deprecation: integral promotion not done for `~x`, use
> '-preview=intpromote' switch or `~cast(int)(x)`
> onlineapp.d(11): Deprecation: integral promotion not done for `~x`, use
> '-preview=intpromote' switch or `~cast(int)(x)`
> Number of affected cases: 0
> ```
[...]

The integer promotion situation in D is a mess.  My personal preference
is:

--------
module nopromote;

enum isNarrowInt(T) = is(T : int) || is(T : uint);

/**
 * A wrapper around a built-in narrow int that truncates the result of
 * arithmetic operations to the narrow type, overriding built-in int promotion
 * rules.
 */
struct Np(T)
    if (isNarrowInt!T)
{
    T impl;
    alias impl this;

    /**
     * Truncating binary operator.
     */
    Np opBinary(string op, U)(U u)
        if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y"))))
    {
        return Np(cast(T) mixin("this.impl " ~ op ~ " u"));
    }

    /**
     * Truncating unary operator.
     */
    Np opUnary(string op)()
        if (is(typeof((T x) => mixin(op ~ "cast(int) x"))))
    {
        return Np(cast(T) mixin(op ~ " cast(int) this.impl"));
    }

    /**
     * Infectiousness: any expression containing Np should automatically use Np
     * operator semantics.
     */
    Np opBinaryRight(string op, U)(U u)
        if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y"))))
    {
        return Np(cast(T) mixin("u " ~ op ~ " this.impl"));
    }
}

/**
 * Returns: A lightweight wrapped type that overrides built-in arithmetic
 * operators to always truncate to the given type without promoting to int or
 * uint.
 */
auto np(T)(T t)
    if (isNarrowInt!T)
{
    return Np!T(t);
}

// Test binary ops
@safe unittest
{
    ubyte x = 1;
    ubyte y = 2;
    auto z = x.np + y;
    static assert(is(typeof(z) : ubyte));
    assert(z == 3);

    byte zz = x.np + y;
    assert(zz == 3);

    x = 255;
    z = x.np + y;
    assert(z == 1);
}

@safe unittest
{
    byte x = 123;
    byte y = 5;
    auto z = x.np + y;
    static assert(is(typeof(z) : byte));
    assert(z == byte.min);

    byte zz = x.np + y;
    assert(zz == byte.min);
}

@safe unittest
{
    import std.random;
    short x = cast(short) uniform(0, 10);
    short y = 10;
    auto z = x.np + y;
    static assert(is(typeof(z) : short));
    assert(z == x + 10);

    short s = x.np + y;
    assert(s == x + 10);
}

// Test unary ops
@safe unittest
{
    byte b = 10;
    auto c = -b.np;
    static assert(is(typeof(c) : byte));
    assert(c == -10);

    ubyte ub = 16;
    auto uc = -ub.np;
    static assert(is(typeof(uc) : ubyte));
    assert(uc == 0xF0);
}
--------

;-)


T

-- 
Let's call it an accidental feature. -- Larry Wall


More information about the Digitalmars-d mailing list