Skip to content

Commit

Permalink
Merge pull request #6457 from roc-lang/division-by-zero
Browse files Browse the repository at this point in the history
Division by zero
  • Loading branch information
rtfeldman authored Jan 29, 2024
2 parents 2dc9509 + 979128c commit 7c19b42
Show file tree
Hide file tree
Showing 90 changed files with 506 additions and 489 deletions.
10 changes: 9 additions & 1 deletion crates/compiler/builtins/roc/Num.roc
Original file line number Diff line number Diff line change
Expand Up @@ -1002,13 +1002,21 @@ divCeilChecked = \a, b ->
## Num.divTrunc 8 -3
## ```
divTrunc : Int a, Int a -> Int a
divTrunc = \a, b ->
if Num.isZero b then
crash "Integer division by 0!"
else
Num.divTruncUnchecked a b

divTruncChecked : Int a, Int a -> Result (Int a) [DivByZero]
divTruncChecked = \a, b ->
if Num.isZero b then
Err DivByZero
else
Ok (Num.divTrunc a b)
Ok (Num.divTruncUnchecked a b)

## traps (hardware fault) when given zero as the second argument.
divTruncUnchecked : Int a, Int a -> Int a

## Obtains the remainder (truncating modulo) from the division of two integers.
##
Expand Down
2 changes: 1 addition & 1 deletion crates/compiler/can/src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ map_symbol_to_lowlevel_and_arity! {
NumLte; NUM_LTE; 2,
NumCompare; NUM_COMPARE; 2,
NumDivFrac; NUM_DIV_FRAC; 2,
NumDivTruncUnchecked; NUM_DIV_TRUNC; 2,
NumDivTruncUnchecked; NUM_DIV_TRUNC_UNCHECKED; 2,
NumDivCeilUnchecked; NUM_DIV_CEIL; 2,
NumRemUnchecked; NUM_REM; 2,
NumIsMultipleOf; NUM_IS_MULTIPLE_OF; 2,
Expand Down
2 changes: 1 addition & 1 deletion crates/compiler/module/src/low_level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ map_symbol_to_lowlevel! {
NumCompare <= NUM_COMPARE;
NumDivFrac <= NUM_DIV_FRAC;
NumDivCeilUnchecked <= NUM_DIV_CEIL;
NumDivTruncUnchecked <= NUM_DIV_TRUNC;
NumDivTruncUnchecked <= NUM_DIV_TRUNC_UNCHECKED;
NumRemUnchecked <= NUM_REM;
NumIsMultipleOf <= NUM_IS_MULTIPLE_OF;
NumAbs <= NUM_ABS;
Expand Down
1 change: 1 addition & 0 deletions crates/compiler/module/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,7 @@ define_builtins! {
163 NUM_TAU: "tau"
164 NUM_BITWISE_NOT: "bitwiseNot"
165 NUM_IS_APPROX_EQ: "isApproxEq"
166 NUM_DIV_TRUNC_UNCHECKED: "divTruncUnchecked" // traps on division by zero
}
4 BOOL: "Bool" => {
0 BOOL_BOOL: "Bool" exposed_type=true // the Bool.Bool type alias
Expand Down
31 changes: 13 additions & 18 deletions crates/compiler/test_gen/src/gen_num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,35 +1154,30 @@ fn gen_div_u64() {
assert_evals_to!("1000u64 // 10", 100, u64);
}

#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
#[should_panic(expected = r#"User crash with message: "Integer division by 0!"#)]
fn gen_div_by_zero_i64() {
assert_evals_to!("1i64 // 0", 100, i64);
}

#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn gen_div_checked_i64() {
assert_evals_to!(
indoc!(
r"
when Num.divTruncChecked 1000 10 is
Ok val -> val
Err _ -> -1
"
),
100,
i64
"Num.divTruncChecked 1000 10",
RocResult::ok(100),
RocResult<i64, ()>
);
}

#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn gen_div_checked_by_zero_i64() {
assert_evals_to!(
indoc!(
r"
when Num.divTruncChecked 1000 0 is
Err DivByZero -> 99
_ -> -24
"
),
99,
i64
"Num.divTruncChecked 1000 0",
RocResult::err(()),
RocResult<i64, ()>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,16 @@ procedure List.80 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.
jump List.591 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;

procedure Num.22 (#Attr.2, #Attr.3):
let Num.300 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.300;
let Num.303 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.303;

procedure Num.51 (#Attr.2, #Attr.3):
let Num.299 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.299;
let Num.302 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.302;

procedure Num.77 (#Attr.2, #Attr.3):
let Num.298 : U64 = lowlevel NumSubSaturated #Attr.2 #Attr.3;
ret Num.298;
let Num.301 : U64 = lowlevel NumSubSaturated #Attr.2 #Attr.3;
ret Num.301;

procedure Test.1 (Test.2):
let Test.13 : U64 = 0i64;
Expand Down
4 changes: 2 additions & 2 deletions crates/compiler/test_mono/generated/binary_tree_fbip.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3):
let Num.297 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.300;

procedure Test.4 (Test.27):
let Test.39 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = TagId(0) ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ procedure List.90 (#Derived_gen.3, #Derived_gen.4, #Derived_gen.5, #Derived_gen.
jump List.574 #Derived_gen.3 #Derived_gen.4 #Derived_gen.5 #Derived_gen.6 #Derived_gen.7;

procedure Num.22 (#Attr.2, #Attr.3):
let Num.298 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.298;
let Num.301 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.301;

procedure Num.51 (#Attr.2, #Attr.3):
let Num.297 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.300;

procedure Test.10 (Test.69, #Attr.12):
let Test.72 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ procedure List.9 (List.333):
ret List.573;

procedure Num.22 (#Attr.2, #Attr.3):
let Num.297 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.300;

procedure Result.5 (Result.12, Result.13):
let Result.39 : U8 = 1i64;
Expand Down
4 changes: 2 additions & 2 deletions crates/compiler/test_mono/generated/choose_i128_layout.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3):
let Num.298 : I128 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.298;
let Num.301 : I128 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.301;

procedure Test.0 ():
let Test.6 : I128 = 18446744073709551616i64;
Expand Down
4 changes: 2 additions & 2 deletions crates/compiler/test_mono/generated/choose_u128_layout.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3):
let Num.297 : U128 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : U128 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.300;

procedure Test.0 ():
let Test.2 : U128 = 170141183460469231731687303715884105728u128;
Expand Down
4 changes: 2 additions & 2 deletions crates/compiler/test_mono/generated/choose_u64_layout.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3):
let Num.297 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.300;

procedure Test.0 ():
let Test.2 : U64 = 9999999999999999999i64;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ procedure List.90 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.
jump List.574 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;

procedure Num.22 (#Attr.2, #Attr.3):
let Num.298 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.298;
let Num.301 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.301;

procedure Num.51 (#Attr.2, #Attr.3):
let Num.297 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.300;

procedure Str.3 (#Attr.2, #Attr.3):
let Str.253 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
Expand Down
4 changes: 2 additions & 2 deletions crates/compiler/test_mono/generated/dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ procedure List.6 (#Attr.2):
ret List.571;

procedure Num.20 (#Attr.2, #Attr.3):
let Num.297 : U8 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : U8 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.300;

procedure Test.0 ():
let Test.3 : {} = Struct {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ procedure List.66 (#Attr.2, #Attr.3):
ret List.576;

procedure Num.22 (#Attr.2, #Attr.3):
let Num.297 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.297;
let Num.300 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.300;

procedure Test.2 (Test.5):
dec Test.5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,40 +250,40 @@ procedure List.90 (#Derived_gen.45, #Derived_gen.46, #Derived_gen.47, #Derived_g
jump List.629 #Derived_gen.45 #Derived_gen.46 #Derived_gen.47 #Derived_gen.48 #Derived_gen.49;

procedure Num.127 (#Attr.2):
let Num.312 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.312;
let Num.315 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.315;

procedure Num.19 (#Attr.2, #Attr.3):
let Num.316 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.316;
let Num.319 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.319;

procedure Num.20 (#Attr.2, #Attr.3):
let Num.313 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.313;
let Num.316 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.316;

procedure Num.21 (#Attr.2, #Attr.3):
let Num.318 : U64 = lowlevel NumMul #Attr.2 #Attr.3;
ret Num.318;
let Num.321 : U64 = lowlevel NumMul #Attr.2 #Attr.3;
ret Num.321;

procedure Num.22 (#Attr.2, #Attr.3):
let Num.324 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.324;
let Num.327 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.327;

procedure Num.24 (#Attr.2, #Attr.3):
let Num.326 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.326;
let Num.329 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.329;

procedure Num.51 (#Attr.2, #Attr.3):
let Num.321 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.321;
let Num.324 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.324;

procedure Num.75 (#Attr.2, #Attr.3):
let Num.325 : U64 = lowlevel NumSubWrap #Attr.2 #Attr.3;
ret Num.325;
let Num.328 : U64 = lowlevel NumSubWrap #Attr.2 #Attr.3;
ret Num.328;

procedure Num.94 (#Attr.2, #Attr.3):
let Num.317 : U64 = lowlevel NumDivCeilUnchecked #Attr.2 #Attr.3;
ret Num.317;
let Num.320 : U64 = lowlevel NumDivCeilUnchecked #Attr.2 #Attr.3;
ret Num.320;

procedure Str.12 (#Attr.2):
let Str.263 : List U8 = lowlevel StrToUtf8 #Attr.2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,40 +193,40 @@ procedure List.90 (#Derived_gen.26, #Derived_gen.27, #Derived_gen.28, #Derived_g
jump List.595 #Derived_gen.26 #Derived_gen.27 #Derived_gen.28 #Derived_gen.29 #Derived_gen.30;

procedure Num.127 (#Attr.2):
let Num.302 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.302;
let Num.305 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.305;

procedure Num.19 (#Attr.2, #Attr.3):
let Num.306 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.306;
let Num.309 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.309;

procedure Num.20 (#Attr.2, #Attr.3):
let Num.303 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.303;
let Num.306 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.306;

procedure Num.21 (#Attr.2, #Attr.3):
let Num.308 : U64 = lowlevel NumMul #Attr.2 #Attr.3;
ret Num.308;
let Num.311 : U64 = lowlevel NumMul #Attr.2 #Attr.3;
ret Num.311;

procedure Num.22 (#Attr.2, #Attr.3):
let Num.314 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.314;
let Num.317 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.317;

procedure Num.24 (#Attr.2, #Attr.3):
let Num.316 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.316;
let Num.319 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.319;

procedure Num.51 (#Attr.2, #Attr.3):
let Num.311 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.311;
let Num.314 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3;
ret Num.314;

procedure Num.75 (#Attr.2, #Attr.3):
let Num.315 : U64 = lowlevel NumSubWrap #Attr.2 #Attr.3;
ret Num.315;
let Num.318 : U64 = lowlevel NumSubWrap #Attr.2 #Attr.3;
ret Num.318;

procedure Num.94 (#Attr.2, #Attr.3):
let Num.307 : U64 = lowlevel NumDivCeilUnchecked #Attr.2 #Attr.3;
ret Num.307;
let Num.310 : U64 = lowlevel NumDivCeilUnchecked #Attr.2 #Attr.3;
ret Num.310;

procedure Str.12 (#Attr.2):
let Str.262 : List U8 = lowlevel StrToUtf8 #Attr.2;
Expand Down
Loading

0 comments on commit 7c19b42

Please sign in to comment.