lang: Fold signed right shifts arithmetically

261f5d9f6b595456047f8816dcd1e0a9dc002d825a6cb6648397aa4d4195984f
The constant folder shifted a negative value’s absolute magnitude
and restored its sign, which rounds odd negative values toward zero
instead of matching an arithmetic right shift.

Shift signed constants through their signed representation and
reconstruct the width-limited result from its bit pattern.

Assisted-by: Codex:gpt-5.6-sol
Alexis Sellier committed ago 1 parent deffec0a
lib/std/lang/resolver.rad +10 -3
6345 6345
            let raw = (0 - left.magnitude) if left.negative else left.magnitude;
6346 6346
            let shamt = right.magnitude % left.bits as u64;
6347 6347
            return ConstValue::Int(constIntFromBits(raw << shamt, left.bits, left.signed));
6348 6348
        },
6349 6349
        case ast::BinaryOp::Shr => {
6350 -
            return ConstValue::Int(ConstInt {
6351 -
                magnitude: left.magnitude >> right.magnitude, bits, signed, negative: left.negative,
6352 -
            });
6350 +
            let shamt = right.magnitude % left.bits as u64;
6351 +
            if left.signed {
6352 +
                let shifted = constIntToSigned(left) >> shamt as i64;
6353 +
                return ConstValue::Int(
6354 +
                    constIntFromBits(shifted as u64, left.bits, true)
6355 +
                );
6356 +
            }
6357 +
            return ConstValue::Int(
6358 +
                constIntFromBits(left.magnitude >> shamt, left.bits, false)
6359 +
            );
6353 6360
        },
6354 6361
        case ast::BinaryOp::Eq  => return ConstValue::Bool(l == r),
6355 6362
        case ast::BinaryOp::Ne  => return ConstValue::Bool(l <> r),
6356 6363
        case ast::BinaryOp::Lt =>
6357 6364
            return ConstValue::Bool(l < r if signed else left.magnitude < right.magnitude),
test/tests/const.i32.shift.right.rad added +12 -0
1 +
//! returns: 0
2 +
//! Folded signed right shifts must round toward negative infinity.
3 +
4 +
constant NEGATIVE: i32 = -7;
5 +
constant SHIFTED: i32 = NEGATIVE >> 1;
6 +
7 +
@default fn main() -> i32 {
8 +
    if SHIFTED == -4 {
9 +
        return 0;
10 +
    }
11 +
    return 1;
12 +
}