Merge pull request #2832 from rtfeldman/div-no-result

`div`, `divCeil`, `divFloor` panic + add checked versions returning `Result`
This commit is contained in:
Richard Feldman 2022-04-12 15:10:06 -04:00 committed by GitHub
commit f39f7eda03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 352 additions and 150 deletions

View File

@ -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

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 {
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 });

View File

@ -69,6 +69,7 @@ interface Num
isNegative,
rem,
div,
divChecked,
modInt,
modFloat,
sqrt,
@ -97,7 +98,9 @@ interface Num
bytesToU16,
bytesToU32,
divCeil,
divCeilChecked,
divFloor,
divFloorChecked,
toStr,
isMultipleOf,
minI8,
@ -229,10 +232,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 ]*

View File

@ -316,17 +316,31 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
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<Symbol, (SolvedType, Region)> {
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())),
);

View File

@ -195,8 +195,11 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
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,
@ -4295,8 +4298,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();
@ -4361,8 +4369,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();
@ -4432,8 +4445,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();

View File

@ -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 *",
},
);

View File

@ -289,8 +289,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),

View File

@ -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" imported
59 NUM_AT_SIGNED64: "@Signed64"
60 NUM_SIGNED64: "Signed64" imported
61 NUM_AT_SIGNED32: "@Signed32"
62 NUM_SIGNED32: "Signed32" imported
63 NUM_AT_SIGNED16: "@Signed16"
64 NUM_SIGNED16: "Signed16" imported
65 NUM_AT_SIGNED8: "@Signed8"
66 NUM_SIGNED8: "Signed8" imported
67 NUM_AT_UNSIGNED128: "@Unsigned128"
68 NUM_UNSIGNED128: "Unsigned128" imported
69 NUM_AT_UNSIGNED64: "@Unsigned64"
70 NUM_UNSIGNED64: "Unsigned64" imported
71 NUM_AT_UNSIGNED32: "@Unsigned32"
72 NUM_UNSIGNED32: "Unsigned32" imported
73 NUM_AT_UNSIGNED16: "@Unsigned16"
74 NUM_UNSIGNED16: "Unsigned16" imported
75 NUM_AT_UNSIGNED8: "@Unsigned8"
76 NUM_UNSIGNED8: "Unsigned8" imported
77 NUM_AT_BINARY64: "@Binary64"
78 NUM_BINARY64: "Binary64" imported
79 NUM_AT_BINARY32: "@Binary32"
80 NUM_BINARY32: "Binary32" imported
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" imported
93 NUM_FLOAT: "Float" imported
94 NUM_AT_NATURAL: "@Natural"
95 NUM_NATURAL: "Natural" imported
96 NUM_NAT: "Nat" imported
97 NUM_INT_CAST: "intCast"
98 NUM_IS_MULTIPLE_OF: "isMultipleOf"
99 NUM_AT_DECIMAL: "@Decimal"
100 NUM_DECIMAL: "Decimal" imported
101 NUM_DEC: "Dec" imported // 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" imported
66 NUM_AT_SIGNED64: "@Signed64"
67 NUM_SIGNED64: "Signed64" imported
68 NUM_AT_SIGNED32: "@Signed32"
69 NUM_SIGNED32: "Signed32" imported
70 NUM_AT_SIGNED16: "@Signed16"
71 NUM_SIGNED16: "Signed16" imported
72 NUM_AT_SIGNED8: "@Signed8"
73 NUM_SIGNED8: "Signed8" imported
74 NUM_AT_UNSIGNED128: "@Unsigned128"
75 NUM_UNSIGNED128: "Unsigned128" imported
76 NUM_AT_UNSIGNED64: "@Unsigned64"
77 NUM_UNSIGNED64: "Unsigned64" imported
78 NUM_AT_UNSIGNED32: "@Unsigned32"
79 NUM_UNSIGNED32: "Unsigned32" imported
80 NUM_AT_UNSIGNED16: "@Unsigned16"
81 NUM_UNSIGNED16: "Unsigned16" imported
82 NUM_AT_UNSIGNED8: "@Unsigned8"
83 NUM_UNSIGNED8: "Unsigned8" imported
84 NUM_AT_BINARY64: "@Binary64"
85 NUM_BINARY64: "Binary64" imported
86 NUM_AT_BINARY32: "@Binary32"
87 NUM_BINARY32: "Binary32" imported
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" imported
100 NUM_FLOAT: "Float" imported
101 NUM_AT_NATURAL: "@Natural"
102 NUM_NATURAL: "Natural" imported
103 NUM_NAT: "Nat" imported
104 NUM_INT_CAST: "intCast"
105 NUM_IS_MULTIPLE_OF: "isMultipleOf"
106 NUM_AT_DECIMAL: "@Decimal"
107 NUM_DECIMAL: "Decimal" imported
108 NUM_DEC: "Dec" imported // 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" 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]
fn div_ceil() {
infer_eq_without_problem(
@ -3304,22 +3328,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(

View File

@ -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
"#

View File

@ -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
"#

View File

@ -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 }
_ ->

View File

@ -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

View File

@ -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))
)

View File

@ -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 }

View File

@ -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]