lang: Fold unsigned division as unsigned

a902a880655810bab5d555af66e3037a18203098fe58c72077a39b3aa60f8d68
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 9913dc8b
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 +
}