diff --git a/BUILDING_FROM_SOURCE.md b/BUILDING_FROM_SOURCE.md index bb1e70733c..4182939e77 100644 --- a/BUILDING_FROM_SOURCE.md +++ b/BUILDING_FROM_SOURCE.md @@ -109,7 +109,7 @@ Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specifi For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal developtment you should be fine without it. -### libcxb libraries +### libxcb libraries You may see an error like this during builds: diff --git a/compiler/builtins/README.md b/compiler/builtins/README.md index ceaf3007e3..2ab95cd260 100644 --- a/compiler/builtins/README.md +++ b/compiler/builtins/README.md @@ -60,7 +60,7 @@ Its one thing to actually write these functions, its _another_ thing to let the ## Specifying how we pass args to the function ### builtins/mono/src/borrow.rs -After we have all of this, we need to specify if the arguments we're passing are owned, borrowed or irrelevant. Towards the bottom of this file, add a new case for you builtin and specify each arg. Be sure to read the comment, as it explains this in more detail. +After we have all of this, we need to specify if the arguments we're passing are owned, borrowed or irrelevant. Towards the bottom of this file, add a new case for your builtin and specify each arg. Be sure to read the comment, as it explains this in more detail. ## Testing it ### solve/tests/solve_expr.rs @@ -87,7 +87,7 @@ In this directory, there are a couple files like `gen_num.rs`, `gen_str.rs`, etc fn atan() { assert_evals_to!("Num.atan 10", 1.4711276743037347, f64); } - ``` +``` But replace `Num.atan`, the return value, and the return type with your new builtin. # Mistakes that are easy to make!! diff --git a/compiler/builtins/bitcode/src/dec.zig b/compiler/builtins/bitcode/src/dec.zig index 2f0dcb6abe..b9eba9c0cc 100644 --- a/compiler/builtins/bitcode/src/dec.zig +++ b/compiler/builtins/bitcode/src/dec.zig @@ -310,9 +310,7 @@ pub const RocDec = extern struct { // (n / 0) is an error if (denominator_i128 == 0) { - // The compiler frontend does the `denominator == 0` check for us, - // therefore this case is unreachable from roc user code - unreachable; + @panic("TODO runtime exception for dividing by 0!"); } // If they're both negative, or if neither is negative, the final answer diff --git a/compiler/builtins/bitcode/src/num.zig b/compiler/builtins/bitcode/src/num.zig index 41d93df976..54bcf8ff5a 100644 --- a/compiler/builtins/bitcode/src/num.zig +++ b/compiler/builtins/bitcode/src/num.zig @@ -102,7 +102,7 @@ pub fn exportRound(comptime T: type, comptime name: []const u8) void { pub fn exportDivCeil(comptime T: type, comptime name: []const u8) void { comptime var f = struct { fn func(a: T, b: T) callconv(.C) T { - return math.divCeil(T, a, b) catch unreachable; + return math.divCeil(T, a, b) catch @panic("TODO runtime exception for dividing by 0!"); } }.func; @export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong }); diff --git a/compiler/builtins/docs/Num.roc b/compiler/builtins/docs/Num.roc index 2f45e22600..2e4b78708f 100644 --- a/compiler/builtins/docs/Num.roc +++ b/compiler/builtins/docs/Num.roc @@ -81,8 +81,6 @@ interface Num minI64, minU64, minI128, - modInt, - modFloat, mul, mulChecked, mulWrap, diff --git a/compiler/builtins/roc/Num.roc b/compiler/builtins/roc/Num.roc index 1cbba15026..1d1102d8fe 100644 --- a/compiler/builtins/roc/Num.roc +++ b/compiler/builtins/roc/Num.roc @@ -67,6 +67,7 @@ interface Num isNegative, rem, div, + divChecked, sqrt, log, round, @@ -93,7 +94,9 @@ interface Num bytesToU16, bytesToU32, divCeil, + divCeilChecked, divFloor, + divFloorChecked, toStr, isMultipleOf, minI8, @@ -238,10 +241,13 @@ atan : Float a -> Float a sqrt : Float a -> Result (Float a) [ SqrtOfNegative ]* log : Float a -> Result (Float a) [ LogNeedsPositive ]* -div : Float a, Float a -> Result (Float a) [ DivByZero ]* +div : Float a, Float a -> Float a +divChecked : Float a, Float a -> Result (Float a) [ DivByZero ]* -divCeil: Int a, Int a -> Result (Int a) [ DivByZero ]* -divFloor: Int a, Int a -> Result (Int a) [ DivByZero ]* +divCeil : Int a, Int a -> Int a +divCeilChecked : Int a, Int a -> Result (Int a) [ DivByZero ]* +divFloor : Int a, Int a -> Int a +divFloorChecked : Int a, Int a -> Result (Int a) [ DivByZero ]* # mod : Float a, Float a -> Result (Float a) [ DivByZero ]* rem : Int a, Int a -> Result (Int a) [ DivByZero ]* diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 8659f19d12..5a8be89856 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -316,17 +316,31 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - // divInt : Int a, Int a -> Result (Int a) [ DivByZero ]* + // divInt : Int a, Int a -> Int a add_top_level_function_type!( Symbol::NUM_DIV_INT, vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))) + ); + + // divIntChecked : Int a, Int a -> Result (Int a) [ DivByZero ]* + add_top_level_function_type!( + Symbol::NUM_DIV_INT_CHECKED, + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), ); - // divCeil: Int a, Int a -> Result (Int a) [ DivByZero ]* + // divCeil : Int a, Int a -> Int a add_top_level_function_type!( Symbol::NUM_DIV_CEIL, vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))) + ); + + //divCeilChecked : Int a, Int a -> Result (Int a) [ DivByZero ]* + add_top_level_function_type!( + Symbol::NUM_DIV_CEIL_CHECKED, + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), ); @@ -659,6 +673,13 @@ pub fn types() -> MutMap { add_top_level_function_type!( Symbol::NUM_DIV_FLOAT, vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))) + ); + + // divChecked : Float a, Float a -> Result (Float a) [ DivByZero ]* + add_top_level_function_type!( + Symbol::NUM_DIV_FLOAT_CHECKED, + vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], Box::new(result_type(float_type(flex(TVAR1)), div_by_zero.clone())), ); diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 19a2896dc6..57de898cf5 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -196,8 +196,11 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option NUM_COS => num_cos, NUM_TAN => num_tan, NUM_DIV_FLOAT => num_div_float, + NUM_DIV_FLOAT_CHECKED => num_div_float_checked, NUM_DIV_INT => num_div_int, + NUM_DIV_INT_CHECKED => num_div_int_checked, NUM_DIV_CEIL => num_div_ceil, + NUM_DIV_CEIL_CHECKED => num_div_ceil_checked, NUM_ABS => num_abs, NUM_NEG => num_neg, NUM_REM => num_rem, @@ -4183,8 +4186,13 @@ fn num_abs(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -/// Num.div : Float, Float -> Result Float [ DivByZero ]* +/// Num.div : Float, Float -> Float fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def { + num_binop(symbol, var_store, LowLevel::NumDivUnchecked) +} + +/// Num.divChecked : Float, Float -> Result Float [ DivByZero ]* +fn num_div_float_checked(symbol: Symbol, var_store: &mut VarStore) -> Def { let bool_var = var_store.fresh(); let num_var = var_store.fresh(); let unbound_zero_var = var_store.fresh(); @@ -4249,8 +4257,13 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -/// Num.div : Int a , Int a -> Result (Int a) [ DivByZero ]* +/// Num.div : Int a, Int a -> Int a fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def { + num_binop(symbol, var_store, LowLevel::NumDivUnchecked) +} + +/// Num.divChecked : Int a , Int a -> Result (Int a) [ DivByZero ]* +fn num_div_int_checked(symbol: Symbol, var_store: &mut VarStore) -> Def { let bool_var = var_store.fresh(); let num_var = var_store.fresh(); let unbound_zero_var = var_store.fresh(); @@ -4320,8 +4333,13 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -/// Num.divCeil : Int a , Int a -> Result (Int a) [ DivByZero ]* +/// Num.divCeil : Int a, Int a -> Int a fn num_div_ceil(symbol: Symbol, var_store: &mut VarStore) -> Def { + num_binop(symbol, var_store, LowLevel::NumDivCeilUnchecked) +} + +/// Num.divCeilChecked : Int a , Int a -> Result (Int a) [ DivByZero ]* +fn num_div_ceil_checked(symbol: Symbol, var_store: &mut VarStore) -> Def { let bool_var = var_store.fresh(); let num_var = var_store.fresh(); let unbound_zero_var = var_store.fresh(); diff --git a/compiler/load_internal/src/file.rs b/compiler/load_internal/src/file.rs index 380099174a..28f5e9c2e8 100644 --- a/compiler/load_internal/src/file.rs +++ b/compiler/load_internal/src/file.rs @@ -3598,17 +3598,14 @@ fn run_solve<'a>( let (solved_subs, exposed_vars_by_symbol, problems) = { if module_id.is_builtin() { match cached_subs.lock().remove(&module_id) { - None => { - // this should never happen - run_solve_solve( - imported_builtins, - exposed_for_module, - constraints, - constraint, - var_store, - module, - ) - } + None => run_solve_solve( + imported_builtins, + exposed_for_module, + constraints, + constraint, + var_store, + module, + ), Some((subs, exposed_vars_by_symbol)) => { (Solved(subs), exposed_vars_by_symbol.to_vec(), vec![]) } diff --git a/compiler/load_internal/tests/test_load.rs b/compiler/load_internal/tests/test_load.rs index f78802553c..8f0223d483 100644 --- a/compiler/load_internal/tests/test_load.rs +++ b/compiler/load_internal/tests/test_load.rs @@ -426,12 +426,12 @@ mod test_load { loaded_module, hashmap! { "floatTest" => "Float *", - "divisionFn" => "Float a, Float a -> Result (Float a) [ DivByZero ]*", - "divisionTest" => "Result (Float *) [ DivByZero ]*", + "divisionFn" => "Float a, Float a -> Float a", + "divisionTest" => "Float *", "intTest" => "I64", "x" => "Float *", "constantNum" => "Num *", - "divDep1ByDep2" => "Result (Float *) [ DivByZero ]*", + "divDep1ByDep2" => "Float *", "fromDep2" => "Float *", }, ); diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index c0d39f41b3..b15f8e682f 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -290,8 +290,10 @@ impl LowLevelWrapperType { Symbol::NUM_LT => CanBeReplacedBy(NumLt), Symbol::NUM_LTE => CanBeReplacedBy(NumLte), Symbol::NUM_COMPARE => CanBeReplacedBy(NumCompare), - Symbol::NUM_DIV_FLOAT => WrapperIsRequired, - Symbol::NUM_DIV_CEIL => WrapperIsRequired, + Symbol::NUM_DIV_FLOAT => CanBeReplacedBy(NumDivUnchecked), + Symbol::NUM_DIV_FLOAT_CHECKED => WrapperIsRequired, + Symbol::NUM_DIV_CEIL => CanBeReplacedBy(NumDivCeilUnchecked), + Symbol::NUM_DIV_CEIL_CHECKED => WrapperIsRequired, Symbol::NUM_REM => WrapperIsRequired, Symbol::NUM_IS_MULTIPLE_OF => CanBeReplacedBy(NumIsMultipleOf), Symbol::NUM_ABS => CanBeReplacedBy(NumAbs), diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index c66fa0f090..cadd3ea782 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -945,118 +945,126 @@ define_builtins! { 36 NUM_IS_POSITIVE: "isPositive" 37 NUM_IS_NEGATIVE: "isNegative" 38 NUM_REM: "rem" - 39 NUM_DIV_FLOAT: "div" - 40 NUM_DIV_INT: "divFloor" - 41 NUM_MOD_INT: "modInt" - 42 NUM_MOD_FLOAT: "modFloat" - 43 NUM_SQRT: "sqrt" - 44 NUM_LOG: "log" - 45 NUM_ROUND: "round" - 46 NUM_COMPARE: "compare" - 47 NUM_POW: "pow" - 48 NUM_CEILING: "ceiling" - 49 NUM_POW_INT: "powInt" - 50 NUM_FLOOR: "floor" - 51 NUM_ADD_WRAP: "addWrap" - 52 NUM_ADD_CHECKED: "addChecked" - 53 NUM_ADD_SATURATED: "addSaturated" - 54 NUM_ATAN: "atan" - 55 NUM_ACOS: "acos" - 56 NUM_ASIN: "asin" - 57 NUM_AT_SIGNED128: "@Signed128" - 58 NUM_SIGNED128: "Signed128" - 59 NUM_AT_SIGNED64: "@Signed64" - 60 NUM_SIGNED64: "Signed64" - 61 NUM_AT_SIGNED32: "@Signed32" - 62 NUM_SIGNED32: "Signed32" - 63 NUM_AT_SIGNED16: "@Signed16" - 64 NUM_SIGNED16: "Signed16" - 65 NUM_AT_SIGNED8: "@Signed8" - 66 NUM_SIGNED8: "Signed8" - 67 NUM_AT_UNSIGNED128: "@Unsigned128" - 68 NUM_UNSIGNED128: "Unsigned128" - 69 NUM_AT_UNSIGNED64: "@Unsigned64" - 70 NUM_UNSIGNED64: "Unsigned64" - 71 NUM_AT_UNSIGNED32: "@Unsigned32" - 72 NUM_UNSIGNED32: "Unsigned32" - 73 NUM_AT_UNSIGNED16: "@Unsigned16" - 74 NUM_UNSIGNED16: "Unsigned16" - 75 NUM_AT_UNSIGNED8: "@Unsigned8" - 76 NUM_UNSIGNED8: "Unsigned8" - 77 NUM_AT_BINARY64: "@Binary64" - 78 NUM_BINARY64: "Binary64" - 79 NUM_AT_BINARY32: "@Binary32" - 80 NUM_BINARY32: "Binary32" - 81 NUM_BITWISE_AND: "bitwiseAnd" - 82 NUM_BITWISE_XOR: "bitwiseXor" - 83 NUM_BITWISE_OR: "bitwiseOr" - 84 NUM_SHIFT_LEFT: "shiftLeftBy" - 85 NUM_SHIFT_RIGHT: "shiftRightBy" - 86 NUM_SHIFT_RIGHT_ZERO_FILL: "shiftRightZfBy" - 87 NUM_SUB_WRAP: "subWrap" - 88 NUM_SUB_CHECKED: "subChecked" - 89 NUM_SUB_SATURATED: "subSaturated" - 90 NUM_MUL_WRAP: "mulWrap" - 91 NUM_MUL_CHECKED: "mulChecked" - 92 NUM_INT: "Int" - 93 NUM_FLOAT: "Float" - 94 NUM_AT_NATURAL: "@Natural" - 95 NUM_NATURAL: "Natural" - 96 NUM_NAT: "Nat" - 97 NUM_INT_CAST: "intCast" - 98 NUM_IS_MULTIPLE_OF: "isMultipleOf" - 99 NUM_AT_DECIMAL: "@Decimal" - 100 NUM_DECIMAL: "Decimal" - 101 NUM_DEC: "Dec" // the Num.Dectype alias - 102 NUM_BYTES_TO_U16: "bytesToU16" - 103 NUM_BYTES_TO_U32: "bytesToU32" - 104 NUM_CAST_TO_NAT: "#castToNat" - 105 NUM_DIV_CEIL: "divCeil" - 106 NUM_TO_STR: "toStr" - 107 NUM_MIN_I8: "minI8" - 108 NUM_MAX_I8: "maxI8" - 109 NUM_MIN_U8: "minU8" - 110 NUM_MAX_U8: "maxU8" - 111 NUM_MIN_I16: "minI16" - 112 NUM_MAX_I16: "maxI16" - 113 NUM_MIN_U16: "minU16" - 114 NUM_MAX_U16: "maxU16" - 115 NUM_MIN_I32: "minI32" - 116 NUM_MAX_I32: "maxI32" - 117 NUM_MIN_U32: "minU32" - 118 NUM_MAX_U32: "maxU32" - 119 NUM_MIN_I64: "minI64" - 120 NUM_MAX_I64: "maxI64" - 121 NUM_MIN_U64: "minU64" - 122 NUM_MAX_U64: "maxU64" - 123 NUM_MIN_I128: "minI128" - 124 NUM_MAX_I128: "maxI128" - 125 NUM_TO_I8: "toI8" - 126 NUM_TO_I8_CHECKED: "toI8Checked" - 127 NUM_TO_I16: "toI16" - 128 NUM_TO_I16_CHECKED: "toI16Checked" - 129 NUM_TO_I32: "toI32" - 130 NUM_TO_I32_CHECKED: "toI32Checked" - 131 NUM_TO_I64: "toI64" - 132 NUM_TO_I64_CHECKED: "toI64Checked" - 133 NUM_TO_I128: "toI128" - 134 NUM_TO_I128_CHECKED: "toI128Checked" - 135 NUM_TO_U8: "toU8" - 136 NUM_TO_U8_CHECKED: "toU8Checked" - 137 NUM_TO_U16: "toU16" - 138 NUM_TO_U16_CHECKED: "toU16Checked" - 139 NUM_TO_U32: "toU32" - 140 NUM_TO_U32_CHECKED: "toU32Checked" - 141 NUM_TO_U64: "toU64" - 142 NUM_TO_U64_CHECKED: "toU64Checked" - 143 NUM_TO_U128: "toU128" - 144 NUM_TO_U128_CHECKED: "toU128Checked" - 145 NUM_TO_NAT: "toNat" - 146 NUM_TO_NAT_CHECKED: "toNatChecked" - 147 NUM_TO_F32: "toF32" - 148 NUM_TO_F32_CHECKED: "toF32Checked" - 149 NUM_TO_F64: "toF64" - 150 NUM_TO_F64_CHECKED: "toF64Checked" + 39 NUM_REM_CHECKED: "remChecked" + 40 NUM_DIV_FLOAT: "div" + 41 NUM_DIV_FLOAT_CHECKED: "divChecked" + 42 NUM_DIV_INT: "divFloor" + 43 NUM_DIV_INT_CHECKED: "divFloorChecked" + 44 NUM_MOD_INT: "modInt" + 45 NUM_MOD_INT_CHECKED: "modIntChecked" + 46 NUM_MOD_FLOAT: "modFloat" + 47 NUM_MOD_FLOAT_CHECKED: "modFloatChecked" + 48 NUM_SQRT: "sqrt" + 49 NUM_SQRT_CHECKED: "sqrtChecked" + 50 NUM_LOG: "log" + 51 NUM_LOG_CHECKED: "logChecked" + 52 NUM_ROUND: "round" + 53 NUM_COMPARE: "compare" + 54 NUM_POW: "pow" + 55 NUM_CEILING: "ceiling" + 56 NUM_POW_INT: "powInt" + 57 NUM_FLOOR: "floor" + 58 NUM_ADD_WRAP: "addWrap" + 59 NUM_ADD_CHECKED: "addChecked" + 60 NUM_ADD_SATURATED: "addSaturated" + 61 NUM_ATAN: "atan" + 62 NUM_ACOS: "acos" + 63 NUM_ASIN: "asin" + 64 NUM_AT_SIGNED128: "@Signed128" + 65 NUM_SIGNED128: "Signed128" + 66 NUM_AT_SIGNED64: "@Signed64" + 67 NUM_SIGNED64: "Signed64" + 68 NUM_AT_SIGNED32: "@Signed32" + 69 NUM_SIGNED32: "Signed32" + 70 NUM_AT_SIGNED16: "@Signed16" + 71 NUM_SIGNED16: "Signed16" + 72 NUM_AT_SIGNED8: "@Signed8" + 73 NUM_SIGNED8: "Signed8" + 74 NUM_AT_UNSIGNED128: "@Unsigned128" + 75 NUM_UNSIGNED128: "Unsigned128" + 76 NUM_AT_UNSIGNED64: "@Unsigned64" + 77 NUM_UNSIGNED64: "Unsigned64" + 78 NUM_AT_UNSIGNED32: "@Unsigned32" + 79 NUM_UNSIGNED32: "Unsigned32" + 80 NUM_AT_UNSIGNED16: "@Unsigned16" + 81 NUM_UNSIGNED16: "Unsigned16" + 82 NUM_AT_UNSIGNED8: "@Unsigned8" + 83 NUM_UNSIGNED8: "Unsigned8" + 84 NUM_AT_BINARY64: "@Binary64" + 85 NUM_BINARY64: "Binary64" + 86 NUM_AT_BINARY32: "@Binary32" + 87 NUM_BINARY32: "Binary32" + 88 NUM_BITWISE_AND: "bitwiseAnd" + 89 NUM_BITWISE_XOR: "bitwiseXor" + 90 NUM_BITWISE_OR: "bitwiseOr" + 91 NUM_SHIFT_LEFT: "shiftLeftBy" + 92 NUM_SHIFT_RIGHT: "shiftRightBy" + 93 NUM_SHIFT_RIGHT_ZERO_FILL: "shiftRightZfBy" + 94 NUM_SUB_WRAP: "subWrap" + 95 NUM_SUB_CHECKED: "subChecked" + 96 NUM_SUB_SATURATED: "subSaturated" + 97 NUM_MUL_WRAP: "mulWrap" + 98 NUM_MUL_CHECKED: "mulChecked" + 99 NUM_INT: "Int" + 100 NUM_FLOAT: "Float" + 101 NUM_AT_NATURAL: "@Natural" + 102 NUM_NATURAL: "Natural" + 103 NUM_NAT: "Nat" + 104 NUM_INT_CAST: "intCast" + 105 NUM_IS_MULTIPLE_OF: "isMultipleOf" + 106 NUM_AT_DECIMAL: "@Decimal" + 107 NUM_DECIMAL: "Decimal" + 108 NUM_DEC: "Dec" // the Num.Dectype alias + 109 NUM_BYTES_TO_U16: "bytesToU16" + 110 NUM_BYTES_TO_U32: "bytesToU32" + 111 NUM_CAST_TO_NAT: "#castToNat" + 112 NUM_DIV_CEIL: "divCeil" + 113 NUM_DIV_CEIL_CHECKED: "divCeilChecked" + 114 NUM_TO_STR: "toStr" + 115 NUM_MIN_I8: "minI8" + 116 NUM_MAX_I8: "maxI8" + 117 NUM_MIN_U8: "minU8" + 118 NUM_MAX_U8: "maxU8" + 119 NUM_MIN_I16: "minI16" + 120 NUM_MAX_I16: "maxI16" + 121 NUM_MIN_U16: "minU16" + 122 NUM_MAX_U16: "maxU16" + 123 NUM_MIN_I32: "minI32" + 124 NUM_MAX_I32: "maxI32" + 125 NUM_MIN_U32: "minU32" + 126 NUM_MAX_U32: "maxU32" + 127 NUM_MIN_I64: "minI64" + 128 NUM_MAX_I64: "maxI64" + 129 NUM_MIN_U64: "minU64" + 130 NUM_MAX_U64: "maxU64" + 131 NUM_MIN_I128: "minI128" + 132 NUM_MAX_I128: "maxI128" + 133 NUM_TO_I8: "toI8" + 134 NUM_TO_I8_CHECKED: "toI8Checked" + 135 NUM_TO_I16: "toI16" + 136 NUM_TO_I16_CHECKED: "toI16Checked" + 137 NUM_TO_I32: "toI32" + 138 NUM_TO_I32_CHECKED: "toI32Checked" + 139 NUM_TO_I64: "toI64" + 140 NUM_TO_I64_CHECKED: "toI64Checked" + 141 NUM_TO_I128: "toI128" + 142 NUM_TO_I128_CHECKED: "toI128Checked" + 143 NUM_TO_U8: "toU8" + 144 NUM_TO_U8_CHECKED: "toU8Checked" + 145 NUM_TO_U16: "toU16" + 146 NUM_TO_U16_CHECKED: "toU16Checked" + 147 NUM_TO_U32: "toU32" + 148 NUM_TO_U32_CHECKED: "toU32Checked" + 149 NUM_TO_U64: "toU64" + 150 NUM_TO_U64_CHECKED: "toU64Checked" + 151 NUM_TO_U128: "toU128" + 152 NUM_TO_U128_CHECKED: "toU128Checked" + 153 NUM_TO_NAT: "toNat" + 154 NUM_TO_NAT_CHECKED: "toNatChecked" + 155 NUM_TO_F32: "toF32" + 156 NUM_TO_F32_CHECKED: "toF32Checked" + 157 NUM_TO_F64: "toF64" + 158 NUM_TO_F64_CHECKED: "toF64Checked" } 2 BOOL: "Bool" => { 0 BOOL_BOOL: "Bool" // the Bool.Bool type alias diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index 9a4257d2f6..98acd4ca96 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3300,6 +3300,30 @@ mod solve_expr { ); } + #[test] + fn div() { + infer_eq_without_problem( + indoc!( + r#" + Num.div + "# + ), + "Float a, Float a -> Float a", + ) + } + + #[test] + fn div_checked() { + infer_eq_without_problem( + indoc!( + r#" + Num.divChecked + "# + ), + "Float a, Float a -> Result (Float a) [ DivByZero ]*", + ) + } + #[test] fn div_ceil() { infer_eq_without_problem( @@ -3308,22 +3332,46 @@ mod solve_expr { Num.divCeil "# ), + "Int a, Int a -> Int a", + ); + } + + #[test] + fn div_ceil_checked() { + infer_eq_without_problem( + indoc!( + r#" + Num.divCeilChecked + "# + ), "Int a, Int a -> Result (Int a) [ DivByZero ]*", ); } #[test] - fn pow_int() { + fn div_floor() { infer_eq_without_problem( indoc!( r#" - Num.powInt + Num.divFloor "# ), "Int a, Int a -> Int a", ); } + #[test] + fn div_floor_checked() { + infer_eq_without_problem( + indoc!( + r#" + Num.divFloorChecked + "# + ), + "Int a, Int a -> Result (Int a) [ DivByZero ]*", + ); + } + #[test] fn atan() { infer_eq_without_problem( diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index d7cc51c396..a456dbd40c 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -723,11 +723,24 @@ fn gen_wrap_add_nums() { #[test] #[cfg(any(feature = "gen-llvm"))] fn gen_div_f64() { - // FIXME this works with normal types, but fails when checking uniqueness types assert_evals_to!( indoc!( r#" - when 48 / 2 is + 48 / 2 + "# + ), + 24.0, + f64 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn gen_div_checked_f64() { + assert_evals_to!( + indoc!( + r#" + when Num.divChecked 48 2 is Ok val -> val Err _ -> -1 "# @@ -736,6 +749,23 @@ fn gen_div_f64() { f64 ); } + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn gen_div_checked_by_zero_f64() { + assert_evals_to!( + indoc!( + r#" + when Num.divChecked 47 0 is + Ok val -> val + Err _ -> -1 + "# + ), + -1.0, + f64 + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn gen_div_dec() { @@ -748,7 +778,27 @@ fn gen_div_dec() { y : Dec y = 3 - when x / y is + x / y + "# + ), + RocDec::from_str_to_i128_unsafe("3.333333333333333333"), + i128 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn gen_div_checked_dec() { + assert_evals_to!( + indoc!( + r#" + x : Dec + x = 10 + + y : Dec + y = 3 + + when Num.divChecked x y is Ok val -> val Err _ -> -1 "# @@ -757,6 +807,27 @@ fn gen_div_dec() { i128 ); } +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn gen_div_checked_by_zero_dec() { + assert_evals_to!( + indoc!( + r#" + x : Dec + x = 10 + + y : Dec + y = 0 + + when Num.divChecked x y is + Ok val -> val + Err _ -> -1 + "# + ), + RocDec::from_str_to_i128_unsafe("-1"), + i128 + ); +} #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] @@ -965,7 +1036,21 @@ fn gen_div_i64() { assert_evals_to!( indoc!( r#" - when 1000 // 10 is + 1000 // 10 + "# + ), + 100, + i64 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn gen_div_checked_i64() { + assert_evals_to!( + indoc!( + r#" + when Num.divFloorChecked 1000 10 is Ok val -> val Err _ -> -1 "# @@ -977,11 +1062,11 @@ fn gen_div_i64() { #[test] #[cfg(any(feature = "gen-llvm"))] -fn gen_div_by_zero_i64() { +fn gen_div_checked_by_zero_i64() { assert_evals_to!( indoc!( r#" - when 1000 // 0 is + when Num.divFloorChecked 1000 0 is Err DivByZero -> 99 _ -> -24 "# diff --git a/compiler/test_mono/src/tests.rs b/compiler/test_mono/src/tests.rs index ff9b7bfcaa..777a790d52 100644 --- a/compiler/test_mono/src/tests.rs +++ b/compiler/test_mono/src/tests.rs @@ -274,7 +274,7 @@ fn ir_round() { #[mono_test] fn ir_when_idiv() { r#" - when 1000 // 10 is + when Num.divFloorChecked 1000 10 is Ok val -> val Err _ -> -1 "# diff --git a/examples/benchmarks/Deriv.roc b/examples/benchmarks/Deriv.roc index 2cad781765..caf08906a6 100644 --- a/examples/benchmarks/Deriv.roc +++ b/examples/benchmarks/Deriv.roc @@ -42,7 +42,7 @@ Expr : [ Val I64, Var Str, Add Expr Expr, Mul Expr Expr, Pow Expr Expr, Ln Expr divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]* divmod = \l, r -> when Pair (l // r) (l % r) is - Pair (Ok div) (Ok mod) -> + Pair div (Ok mod) -> Ok { div, mod } _ -> diff --git a/examples/benchmarks/RBTreeDel.roc b/examples/benchmarks/RBTreeDel.roc index 24419ef84a..43fd309e5d 100644 --- a/examples/benchmarks/RBTreeDel.roc +++ b/examples/benchmarks/RBTreeDel.roc @@ -47,7 +47,7 @@ makeMapHelp = \total, n, m -> isFrequency = n |> Num.isMultipleOf 4 - key = n1 + ((total - n1) // 5 |> resultWithDefault 0) + key = n1 + ((total - n1) // 5) t2 = if isFrequency then delete t1 key else t1 makeMapHelp total n1 t2 diff --git a/examples/false-interpreter/False.roc b/examples/false-interpreter/False.roc index d7e0ac0c4f..f8306e7d8d 100644 --- a/examples/false-interpreter/False.roc +++ b/examples/false-interpreter/False.roc @@ -434,7 +434,7 @@ stepExecCtx = \ctx, char -> ( (T popCtx1 numR) <- Result.after (popNumber ctx) (T popCtx2 numL) <- Result.after (popNumber popCtx1) - res <- Result.after (Num.divFloor numL numR) + res <- Result.after (Num.divFloorChecked numL numR) Ok (Context.pushStack popCtx2 (Number res)) ) diff --git a/examples/gui/Hello.roc b/examples/gui/Hello.roc index c15f5bd21a..653ccbd8e1 100644 --- a/examples/gui/Hello.roc +++ b/examples/gui/Hello.roc @@ -4,9 +4,7 @@ app "hello-gui" provides [ render ] to pf render = - div0 = \numerator, denominator -> (numerator / denominator) |> Result.withDefault 0 - - rgba = \r, g, b, a -> { r: div0 r 255, g: div0 g 255, b: div0 b 255, a } + rgba = \r, g, b, a -> { r: r / 255, g: g / 255, b: b / 255, a } styles = { bgColor: rgba 100 50 50 1, borderColor: rgba 10 20 30 1, borderWidth: 10, textColor: rgba 220 220 250 1 } diff --git a/repl_test/src/tests.rs b/repl_test/src/tests.rs index 884c752cde..0d1aba07a2 100644 --- a/repl_test/src/tests.rs +++ b/repl_test/src/tests.rs @@ -61,23 +61,41 @@ fn num_rem() { #[cfg(not(feature = "wasm"))] #[test] -fn num_floor_division_success() { - expect_success("Num.divFloor 4 3", "Ok 1 : Result (Int *) [ DivByZero ]*"); +fn num_floor_division() { + expect_success("Num.divFloor 4 3", "1 : Int *"); } #[cfg(not(feature = "wasm"))] #[test] -fn num_floor_division_divby_zero() { +fn num_floor_checked_division_success() { expect_success( - "Num.divFloor 4 0", + "Num.divFloorChecked 4 3", + "Ok 1 : Result (Int *) [ DivByZero ]*", + ); +} + +#[cfg(not(feature = "wasm"))] +#[test] +fn num_floor_checked_division_divby_zero() { + expect_success( + "Num.divFloorChecked 4 0", "Err DivByZero : Result (Int *) [ DivByZero ]*", ); } #[cfg(not(feature = "wasm"))] #[test] -fn num_ceil_division_success() { - expect_success("Num.divCeil 4 3", "Ok 2 : Result (Int *) [ DivByZero ]*") +fn num_ceil_division() { + expect_success("Num.divCeil 4 3", "2 : Int *") +} + +#[cfg(not(feature = "wasm"))] +#[test] +fn num_ceil_checked_division_success() { + expect_success( + "Num.divCeilChecked 4 3", + "Ok 2 : Result (Int *) [ DivByZero ]*", + ) } #[test]