Modify division behaviour to panic when dividing by 0, and add divChecked, divFloorChecked and divCeilingChecked` for safe alternatives which return a Result, mimicking the previous behaviour.

This commit is contained in:
Nikita Mounier 2022-04-11 11:23:33 +00:00
parent 23bc8aab49
commit 4ecf2a8c24
9 changed files with 318 additions and 129 deletions

View file

@ -310,9 +310,7 @@ pub const RocDec = extern struct {
// (n / 0) is an error // (n / 0) is an error
if (denominator_i128 == 0) { if (denominator_i128 == 0) {
// The compiler frontend does the `denominator == 0` check for us, @panic("TODO runtime exception for dividing by 0!");
// therefore this case is unreachable from roc user code
unreachable;
} }
// If they're both negative, or if neither is negative, the final answer // If they're both negative, or if neither is negative, the final answer

View file

@ -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 { pub fn exportDivCeil(comptime T: type, comptime name: []const u8) void {
comptime var f = struct { comptime var f = struct {
fn func(a: T, b: T) callconv(.C) T { 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; }.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong }); @export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });

View file

@ -69,6 +69,7 @@ interface Num
isNegative, isNegative,
rem, rem,
div, div,
divChecked,
modInt, modInt,
modFloat, modFloat,
sqrt, sqrt,
@ -97,7 +98,9 @@ interface Num
bytesToU16, bytesToU16,
bytesToU32, bytesToU32,
divCeil, divCeil,
divCeilChecked,
divFloor, divFloor,
divFloorChecked,
toStr, toStr,
isMultipleOf, isMultipleOf,
minI8, minI8,
@ -229,10 +232,13 @@ atan : Float a -> Float a
sqrt : Float a -> Result (Float a) [ SqrtOfNegative ]* sqrt : Float a -> Result (Float a) [ SqrtOfNegative ]*
log : Float a -> Result (Float a) [ LogNeedsPositive ]* 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 ]* divCeil : Int a, Int a -> Int a
divFloor: Int a, Int a -> Result (Int a) [ DivByZero ]* 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 ]* # mod : Float a, Float a -> Result (Float a) [ DivByZero ]*
rem : Int a, Int a -> Result (Int a) [ DivByZero ]* rem : Int a, Int a -> Result (Int a) [ DivByZero ]*

View file

@ -316,17 +316,31 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(SolvedType::Wildcard), 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!( add_top_level_function_type!(
Symbol::NUM_DIV_INT, Symbol::NUM_DIV_INT,
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], 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())), 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!( add_top_level_function_type!(
Symbol::NUM_DIV_CEIL, Symbol::NUM_DIV_CEIL,
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], 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())), Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
); );
@ -631,6 +645,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_top_level_function_type!( add_top_level_function_type!(
Symbol::NUM_DIV_FLOAT, Symbol::NUM_DIV_FLOAT,
vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], 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())), Box::new(result_type(float_type(flex(TVAR1)), div_by_zero.clone())),
); );

View file

@ -195,8 +195,11 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
NUM_COS => num_cos, NUM_COS => num_cos,
NUM_TAN => num_tan, NUM_TAN => num_tan,
NUM_DIV_FLOAT => num_div_float, NUM_DIV_FLOAT => num_div_float,
NUM_DIV_FLOAT_CHECKED => num_div_float_checked,
NUM_DIV_INT => num_div_int, NUM_DIV_INT => num_div_int,
NUM_DIV_INT_CHECKED => num_div_int_checked,
NUM_DIV_CEIL => num_div_ceil, NUM_DIV_CEIL => num_div_ceil,
NUM_DIV_CEIL_CHECKED => num_div_ceil_checked,
NUM_ABS => num_abs, NUM_ABS => num_abs,
NUM_NEG => num_neg, NUM_NEG => num_neg,
NUM_REM => num_rem, NUM_REM => num_rem,
@ -4277,8 +4280,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 { 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 bool_var = var_store.fresh();
let num_var = var_store.fresh(); let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();
@ -4343,8 +4351,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 { 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 bool_var = var_store.fresh();
let num_var = var_store.fresh(); let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();
@ -4414,8 +4427,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 { 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 bool_var = var_store.fresh();
let num_var = var_store.fresh(); let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();

View file

@ -287,8 +287,10 @@ impl LowLevelWrapperType {
Symbol::NUM_LT => CanBeReplacedBy(NumLt), Symbol::NUM_LT => CanBeReplacedBy(NumLt),
Symbol::NUM_LTE => CanBeReplacedBy(NumLte), Symbol::NUM_LTE => CanBeReplacedBy(NumLte),
Symbol::NUM_COMPARE => CanBeReplacedBy(NumCompare), Symbol::NUM_COMPARE => CanBeReplacedBy(NumCompare),
Symbol::NUM_DIV_FLOAT => WrapperIsRequired, Symbol::NUM_DIV_FLOAT => CanBeReplacedBy(NumDivUnchecked),
Symbol::NUM_DIV_CEIL => WrapperIsRequired, Symbol::NUM_DIV_FLOAT_CHECKED => WrapperIsRequired,
Symbol::NUM_DIV_CEIL => CanBeReplacedBy(NumDivCeilUnchecked),
Symbol::NUM_DIV_CEIL_CHECKED => WrapperIsRequired,
Symbol::NUM_REM => WrapperIsRequired, Symbol::NUM_REM => WrapperIsRequired,
Symbol::NUM_IS_MULTIPLE_OF => CanBeReplacedBy(NumIsMultipleOf), Symbol::NUM_IS_MULTIPLE_OF => CanBeReplacedBy(NumIsMultipleOf),
Symbol::NUM_ABS => CanBeReplacedBy(NumAbs), Symbol::NUM_ABS => CanBeReplacedBy(NumAbs),

View file

@ -945,114 +945,122 @@ define_builtins! {
36 NUM_IS_POSITIVE: "isPositive" 36 NUM_IS_POSITIVE: "isPositive"
37 NUM_IS_NEGATIVE: "isNegative" 37 NUM_IS_NEGATIVE: "isNegative"
38 NUM_REM: "rem" 38 NUM_REM: "rem"
39 NUM_DIV_FLOAT: "div" 39 NUM_REM_CHECKED: "remChecked"
40 NUM_DIV_INT: "divFloor" 40 NUM_DIV_FLOAT: "div"
41 NUM_MOD_INT: "modInt" 41 NUM_DIV_FLOAT_CHECKED: "divChecked"
42 NUM_MOD_FLOAT: "modFloat" 42 NUM_DIV_INT: "divFloor"
43 NUM_SQRT: "sqrt" 43 NUM_DIV_INT_CHECKED: "divFloorChecked"
44 NUM_LOG: "log" 44 NUM_MOD_INT: "modInt"
45 NUM_ROUND: "round" 45 NUM_MOD_INT_CHECKED: "modIntChecked"
46 NUM_COMPARE: "compare" 46 NUM_MOD_FLOAT: "modFloat"
47 NUM_POW: "pow" 47 NUM_MOD_FLOAT_CHECKED: "modFloatChecked"
48 NUM_CEILING: "ceiling" 48 NUM_SQRT: "sqrt"
49 NUM_POW_INT: "powInt" 49 NUM_SQRT_CHECKED: "sqrtChecked"
50 NUM_FLOOR: "floor" 50 NUM_LOG: "log"
51 NUM_ADD_WRAP: "addWrap" 51 NUM_LOG_CHECKED: "logChecked"
52 NUM_ADD_CHECKED: "addChecked" 52 NUM_ROUND: "round"
53 NUM_ADD_SATURATED: "addSaturated" 53 NUM_COMPARE: "compare"
54 NUM_ATAN: "atan" 54 NUM_POW: "pow"
55 NUM_ACOS: "acos" 55 NUM_CEILING: "ceiling"
56 NUM_ASIN: "asin" 56 NUM_POW_INT: "powInt"
57 NUM_AT_SIGNED128: "@Signed128" 57 NUM_FLOOR: "floor"
58 NUM_SIGNED128: "Signed128" imported 58 NUM_ADD_WRAP: "addWrap"
59 NUM_AT_SIGNED64: "@Signed64" 59 NUM_ADD_CHECKED: "addChecked"
60 NUM_SIGNED64: "Signed64" imported 60 NUM_ADD_SATURATED: "addSaturated"
61 NUM_AT_SIGNED32: "@Signed32" 61 NUM_ATAN: "atan"
62 NUM_SIGNED32: "Signed32" imported 62 NUM_ACOS: "acos"
63 NUM_AT_SIGNED16: "@Signed16" 63 NUM_ASIN: "asin"
64 NUM_SIGNED16: "Signed16" imported 64 NUM_AT_SIGNED128: "@Signed128"
65 NUM_AT_SIGNED8: "@Signed8" 65 NUM_SIGNED128: "Signed128" imported
66 NUM_SIGNED8: "Signed8" imported 66 NUM_AT_SIGNED64: "@Signed64"
67 NUM_AT_UNSIGNED128: "@Unsigned128" 67 NUM_SIGNED64: "Signed64" imported
68 NUM_UNSIGNED128: "Unsigned128" imported 68 NUM_AT_SIGNED32: "@Signed32"
69 NUM_AT_UNSIGNED64: "@Unsigned64" 69 NUM_SIGNED32: "Signed32" imported
70 NUM_UNSIGNED64: "Unsigned64" imported 70 NUM_AT_SIGNED16: "@Signed16"
71 NUM_AT_UNSIGNED32: "@Unsigned32" 71 NUM_SIGNED16: "Signed16" imported
72 NUM_UNSIGNED32: "Unsigned32" imported 72 NUM_AT_SIGNED8: "@Signed8"
73 NUM_AT_UNSIGNED16: "@Unsigned16" 73 NUM_SIGNED8: "Signed8" imported
74 NUM_UNSIGNED16: "Unsigned16" imported 74 NUM_AT_UNSIGNED128: "@Unsigned128"
75 NUM_AT_UNSIGNED8: "@Unsigned8" 75 NUM_UNSIGNED128: "Unsigned128" imported
76 NUM_UNSIGNED8: "Unsigned8" imported 76 NUM_AT_UNSIGNED64: "@Unsigned64"
77 NUM_AT_BINARY64: "@Binary64" 77 NUM_UNSIGNED64: "Unsigned64" imported
78 NUM_BINARY64: "Binary64" imported 78 NUM_AT_UNSIGNED32: "@Unsigned32"
79 NUM_AT_BINARY32: "@Binary32" 79 NUM_UNSIGNED32: "Unsigned32" imported
80 NUM_BINARY32: "Binary32" imported 80 NUM_AT_UNSIGNED16: "@Unsigned16"
81 NUM_BITWISE_AND: "bitwiseAnd" 81 NUM_UNSIGNED16: "Unsigned16" imported
82 NUM_BITWISE_XOR: "bitwiseXor" 82 NUM_AT_UNSIGNED8: "@Unsigned8"
83 NUM_BITWISE_OR: "bitwiseOr" 83 NUM_UNSIGNED8: "Unsigned8" imported
84 NUM_SHIFT_LEFT: "shiftLeftBy" 84 NUM_AT_BINARY64: "@Binary64"
85 NUM_SHIFT_RIGHT: "shiftRightBy" 85 NUM_BINARY64: "Binary64" imported
86 NUM_SHIFT_RIGHT_ZERO_FILL: "shiftRightZfBy" 86 NUM_AT_BINARY32: "@Binary32"
87 NUM_SUB_WRAP: "subWrap" 87 NUM_BINARY32: "Binary32" imported
88 NUM_SUB_CHECKED: "subChecked" 88 NUM_BITWISE_AND: "bitwiseAnd"
89 NUM_SUB_SATURATED: "subSaturated" 89 NUM_BITWISE_XOR: "bitwiseXor"
90 NUM_MUL_WRAP: "mulWrap" 90 NUM_BITWISE_OR: "bitwiseOr"
91 NUM_MUL_CHECKED: "mulChecked" 91 NUM_SHIFT_LEFT: "shiftLeftBy"
92 NUM_INT: "Int" imported 92 NUM_SHIFT_RIGHT: "shiftRightBy"
93 NUM_FLOAT: "Float" imported 93 NUM_SHIFT_RIGHT_ZERO_FILL: "shiftRightZfBy"
94 NUM_AT_NATURAL: "@Natural" 94 NUM_SUB_WRAP: "subWrap"
95 NUM_NATURAL: "Natural" imported 95 NUM_SUB_CHECKED: "subChecked"
96 NUM_NAT: "Nat" imported 96 NUM_SUB_SATURATED: "subSaturated"
97 NUM_INT_CAST: "intCast" 97 NUM_MUL_WRAP: "mulWrap"
98 NUM_IS_MULTIPLE_OF: "isMultipleOf" 98 NUM_MUL_CHECKED: "mulChecked"
99 NUM_AT_DECIMAL: "@Decimal" 99 NUM_INT: "Int" imported
100 NUM_DECIMAL: "Decimal" imported 100 NUM_FLOAT: "Float" imported
101 NUM_DEC: "Dec" imported // the Num.Dectype alias 101 NUM_AT_NATURAL: "@Natural"
102 NUM_BYTES_TO_U16: "bytesToU16" 102 NUM_NATURAL: "Natural" imported
103 NUM_BYTES_TO_U32: "bytesToU32" 103 NUM_NAT: "Nat" imported
104 NUM_CAST_TO_NAT: "#castToNat" 104 NUM_INT_CAST: "intCast"
105 NUM_DIV_CEIL: "divCeil" 105 NUM_IS_MULTIPLE_OF: "isMultipleOf"
106 NUM_TO_STR: "toStr" 106 NUM_AT_DECIMAL: "@Decimal"
107 NUM_MIN_I8: "minI8" 107 NUM_DECIMAL: "Decimal" imported
108 NUM_MAX_I8: "maxI8" 108 NUM_DEC: "Dec" imported // the Num.Dectype alias
109 NUM_MIN_U8: "minU8" 109 NUM_BYTES_TO_U16: "bytesToU16"
110 NUM_MAX_U8: "maxU8" 110 NUM_BYTES_TO_U32: "bytesToU32"
111 NUM_MIN_I16: "minI16" 111 NUM_CAST_TO_NAT: "#castToNat"
112 NUM_MAX_I16: "maxI16" 112 NUM_DIV_CEIL: "divCeil"
113 NUM_MIN_U16: "minU16" 113 NUM_DIV_CEIL_CHECKED: "divCeilChecked"
114 NUM_MAX_U16: "maxU16" 114 NUM_TO_STR: "toStr"
115 NUM_MIN_I32: "minI32" 115 NUM_MIN_I8: "minI8"
116 NUM_MAX_I32: "maxI32" 116 NUM_MAX_I8: "maxI8"
117 NUM_MIN_U32: "minU32" 117 NUM_MIN_U8: "minU8"
118 NUM_MAX_U32: "maxU32" 118 NUM_MAX_U8: "maxU8"
119 NUM_MIN_I64: "minI64" 119 NUM_MIN_I16: "minI16"
120 NUM_MAX_I64: "maxI64" 120 NUM_MAX_I16: "maxI16"
121 NUM_MIN_U64: "minU64" 121 NUM_MIN_U16: "minU16"
122 NUM_MAX_U64: "maxU64" 122 NUM_MAX_U16: "maxU16"
123 NUM_MIN_I128: "minI128" 123 NUM_MIN_I32: "minI32"
124 NUM_MAX_I128: "maxI128" 124 NUM_MAX_I32: "maxI32"
125 NUM_TO_I8: "toI8" 125 NUM_MIN_U32: "minU32"
126 NUM_TO_I8_CHECKED: "toI8Checked" 126 NUM_MAX_U32: "maxU32"
127 NUM_TO_I16: "toI16" 127 NUM_MIN_I64: "minI64"
128 NUM_TO_I16_CHECKED: "toI16Checked" 128 NUM_MAX_I64: "maxI64"
129 NUM_TO_I32: "toI32" 129 NUM_MIN_U64: "minU64"
130 NUM_TO_I32_CHECKED: "toI32Checked" 130 NUM_MAX_U64: "maxU64"
131 NUM_TO_I64: "toI64" 131 NUM_MIN_I128: "minI128"
132 NUM_TO_I64_CHECKED: "toI64Checked" 132 NUM_MAX_I128: "maxI128"
133 NUM_TO_I128: "toI128" 133 NUM_TO_I8: "toI8"
134 NUM_TO_I128_CHECKED: "toI128Checked" 134 NUM_TO_I8_CHECKED: "toI8Checked"
135 NUM_TO_U8: "toU8" 135 NUM_TO_I16: "toI16"
136 NUM_TO_U8_CHECKED: "toU8Checked" 136 NUM_TO_I16_CHECKED: "toI16Checked"
137 NUM_TO_U16: "toU16" 137 NUM_TO_I32: "toI32"
138 NUM_TO_U16_CHECKED: "toU16Checked" 138 NUM_TO_I32_CHECKED: "toI32Checked"
139 NUM_TO_U32: "toU32" 139 NUM_TO_I64: "toI64"
140 NUM_TO_U32_CHECKED: "toU32Checked" 140 NUM_TO_I64_CHECKED: "toI64Checked"
141 NUM_TO_U64: "toU64" 141 NUM_TO_I128: "toI128"
142 NUM_TO_U64_CHECKED: "toU64Checked" 142 NUM_TO_I128_CHECKED: "toI128Checked"
143 NUM_TO_U128: "toU128" 143 NUM_TO_U8: "toU8"
144 NUM_TO_U128_CHECKED: "toU128Checked" 144 NUM_TO_U8_CHECKED: "toU8Checked"
145 NUM_TO_NAT: "toNat" 145 NUM_TO_U16: "toU16"
146 NUM_TO_NAT_CHECKED: "toNatChecked" 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"
} }
2 BOOL: "Bool" => { 2 BOOL: "Bool" => {
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias 0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias

View file

@ -3296,6 +3296,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] #[test]
fn div_ceil() { fn div_ceil() {
infer_eq_without_problem( infer_eq_without_problem(
@ -3304,22 +3328,46 @@ mod solve_expr {
Num.divCeil Num.divCeil
"# "#
), ),
"Int a, Int a -> Result (Int a) [ DivByZero ]*", "Int a, Int a -> Int a"
); );
} }
#[test] #[test]
fn pow_int() { fn div_ceil_checked() {
infer_eq_without_problem( infer_eq_without_problem(
indoc!( indoc!(
r#" r#"
Num.powInt Num.divCeilChecked
"# "#
), ),
"Int a, Int a -> Int a", "Int a, Int a -> Int a",
); );
} }
#[test]
fn div_floor() {
infer_eq_without_problem(
indoc!(
r#"
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) [ DivByZer ]*"
);
}
#[test] #[test]
fn atan() { fn atan() {
infer_eq_without_problem( infer_eq_without_problem(

View file

@ -723,6 +723,21 @@ fn gen_wrap_add_nums() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn gen_div_f64() { fn gen_div_f64() {
// FIXME this works with normal types, but fails when checking uniqueness types
assert_evals_to!(
indoc!(
r#"
48 / 2
"#
),
24.0,
f64
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn gen_div_checked_f64() {
// FIXME this works with normal types, but fails when checking uniqueness types // FIXME this works with normal types, but fails when checking uniqueness types
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -736,6 +751,24 @@ fn gen_div_f64() {
f64 f64
); );
} }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn gen_div_checked_by_zero_f64() {
// FIXME this works with normal types, but fails when checking uniqueness types
assert_evals_to!(
indoc!(
r#"
when 48 / 0 is
Ok val -> val
Err _ -> -1
"#
),
-1,
f64
);
}
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn gen_div_dec() { fn gen_div_dec() {
@ -748,7 +781,27 @@ fn gen_div_dec() {
y : Dec y : Dec
y = 3 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 Ok val -> val
Err _ -> -1 Err _ -> -1
"# "#
@ -757,6 +810,27 @@ fn gen_div_dec() {
i128 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
"#
),
-1,
i128
);
}
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
@ -965,7 +1039,21 @@ fn gen_div_i64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" 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 Ok val -> val
Err _ -> -1 Err _ -> -1
"# "#
@ -977,11 +1065,11 @@ fn gen_div_i64() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn gen_div_by_zero_i64() { fn gen_div_checked_by_zero_i64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when 1000 // 0 is when Num.divFloorChecked 1000 0 is
Err DivByZero -> 99 Err DivByZero -> 99
_ -> -24 _ -> -24
"# "#