lang: Fold unsigned division as unsigned

438a079ffb70c1e14c3c6ffd292efa7929f896e128405e15e3f1c77a60e78ffc
Constant division and remainder converted every operand through i64.
Values above the signed maximum therefore produced signed quotients and
remainders.

Evaluate unsigned constant operands from their u64 magnitudes while
retaining the signed path for signed expressions.

Assisted-by: Codex:gpt-5.6-sol
Alexis Sellier committed ago 1 parent ce82565a
lib/std/lang/resolver.rad +16 -4
6338 6338
            return ConstValue::Bool(l >= r if signed else left.magnitude >= right.magnitude),
6339 6339
        case ast::BinaryOp::Add => return ConstValue::Int(constIntFromSigned(l + r, bits, signed)),
6340 6340
        case ast::BinaryOp::Sub => return ConstValue::Int(constIntFromSigned(l - r, bits, signed)),
6341 6341
        case ast::BinaryOp::Mul => return ConstValue::Int(constIntFromSigned(l * r, bits, signed)),
6342 6342
        case ast::BinaryOp::Div => {
6343 -
            if r == 0 {
6343 +
            if signed {
6344 +
                if r == 0 {
6345 +
                    return nil;
6346 +
                }
6347 +
                return ConstValue::Int(constIntFromSigned(l / r, bits, true));
6348 +
            }
6349 +
            if right.magnitude == 0 {
6344 6350
                return nil;
6345 6351
            }
6346 -
            return ConstValue::Int(constIntFromSigned(l / r, bits, signed));
6352 +
            return constInt(left.magnitude / right.magnitude, bits, false, false);
6347 6353
        },
6348 6354
        case ast::BinaryOp::Mod => {
6349 -
            if r == 0 {
6355 +
            if signed {
6356 +
                if r == 0 {
6357 +
                    return nil;
6358 +
                }
6359 +
                return ConstValue::Int(constIntFromSigned(l % r, bits, true));
6360 +
            }
6361 +
            if right.magnitude == 0 {
6350 6362
                return nil;
6351 6363
            }
6352 -
            return ConstValue::Int(constIntFromSigned(l % r, bits, signed));
6364 +
            return constInt(left.magnitude % right.magnitude, bits, false, false);
6353 6365
        },
6354 6366
        case ast::BinaryOp::BitAnd => return ConstValue::Int(constIntFromSigned(l & r, bits, signed)),
6355 6367
        case ast::BinaryOp::BitOr  => return ConstValue::Int(constIntFromSigned(l | r, bits, signed)),
6356 6368
        case ast::BinaryOp::BitXor => return ConstValue::Int(constIntFromSigned(l ^ r, bits, signed)),
6357 6369
        else => return nil,
test/tests/const.u64.divide.rad added +10 -0
1 +
//! returns: 0
2 +
3 +
constant QUOTIENT: u64 = 0xffffffffffffffff / 2;
4 +
5 +
@default fn main() -> i32 {
6 +
    if QUOTIENT == 0x7fffffffffffffff {
7 +
        return 0;
8 +
    }
9 +
    return 1;
10 +
}