diff --git a/crates/compiler/builtins/bitcode/src/dec.zig b/crates/compiler/builtins/bitcode/src/dec.zig index e439db7a98..e2be7dbe56 100644 --- a/crates/compiler/builtins/bitcode/src/dec.zig +++ b/crates/compiler/builtins/bitcode/src/dec.zig @@ -1125,6 +1125,10 @@ pub fn fromF64C(arg: f64) callconv(.C) i128 { return if (@call(.{ .modifier = always_inline }, RocDec.fromF64, .{arg})) |dec| dec.num else @panic("TODO runtime exception failing convert f64 to RocDec"); } +pub fn fromU64C(arg: u64) callconv(.C) i128 { + return @call(.{ .modifier = always_inline }, RocDec.fromU64, .{arg}).toI128(); +} + pub fn toI128(arg: RocDec) callconv(.C) i128 { return @call(.{ .modifier = always_inline }, RocDec.toI128, .{arg}); } diff --git a/crates/compiler/builtins/bitcode/src/main.zig b/crates/compiler/builtins/bitcode/src/main.zig index a349ce26c3..4d3b8a342e 100644 --- a/crates/compiler/builtins/bitcode/src/main.zig +++ b/crates/compiler/builtins/bitcode/src/main.zig @@ -21,6 +21,7 @@ comptime { exportDecFn(dec.fromStr, "from_str"); exportDecFn(dec.toStr, "to_str"); exportDecFn(dec.fromF64C, "from_f64"); + exportDecFn(dec.fromU64C, "from_u64"); exportDecFn(dec.toI128, "to_i128"); exportDecFn(dec.eqC, "eq"); exportDecFn(dec.neqC, "neq"); @@ -82,6 +83,19 @@ comptime { exportNumFn(num.shiftRightZeroFillI128, "shift_right_zero_fill.i128"); exportNumFn(num.shiftRightZeroFillU128, "shift_right_zero_fill.u128"); + exportNumFn(num.compareI128, "compare.i128"); + exportNumFn(num.compareU128, "compare.u128"); + + exportNumFn(num.lessThanI128, "less_than.i128"); + exportNumFn(num.lessThanOrEqualI128, "less_than_or_equal.i128"); + exportNumFn(num.greaterThanI128, "greater_than.i128"); + exportNumFn(num.greaterThanOrEqualI128, "greater_than_or_equal.i128"); + + exportNumFn(num.lessThanU128, "less_than.u128"); + exportNumFn(num.lessThanOrEqualU128, "less_than_or_equal.u128"); + exportNumFn(num.greaterThanU128, "greater_than.u128"); + exportNumFn(num.greaterThanOrEqualU128, "greater_than_or_equal.u128"); + inline for (INTEGERS) |T, i| { num.exportPow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".pow_int."); num.exportDivCeil(T, ROC_BUILTINS ++ "." ++ NUM ++ ".div_ceil."); diff --git a/crates/compiler/builtins/bitcode/src/num.zig b/crates/compiler/builtins/bitcode/src/num.zig index e289e4230e..d034495492 100644 --- a/crates/compiler/builtins/bitcode/src/num.zig +++ b/crates/compiler/builtins/bitcode/src/num.zig @@ -4,6 +4,7 @@ const math = std.math; const RocList = @import("list.zig").RocList; const RocStr = @import("str.zig").RocStr; const WithOverflow = @import("utils.zig").WithOverflow; +const Ordering = @import("utils.zig").Ordering; const roc_panic = @import("panic.zig").panic_help; pub fn NumParseResult(comptime T: type) type { @@ -558,6 +559,58 @@ pub fn shiftRightZeroFillU128(self: u128, other: u8) callconv(.C) u128 { } } +pub fn compareI128(self: i128, other: i128) callconv(.C) Ordering { + if (self == other) { + return Ordering.EQ; + } else if (self < other) { + return Ordering.LT; + } else { + return Ordering.GT; + } +} + +pub fn compareU128(self: u128, other: u128) callconv(.C) Ordering { + if (self == other) { + return Ordering.EQ; + } else if (self < other) { + return Ordering.LT; + } else { + return Ordering.GT; + } +} + +pub fn lessThanI128(self: i128, other: i128) callconv(.C) bool { + return self < other; +} + +pub fn lessThanOrEqualI128(self: i128, other: i128) callconv(.C) bool { + return self <= other; +} + +pub fn greaterThanI128(self: i128, other: i128) callconv(.C) bool { + return self > other; +} + +pub fn greaterThanOrEqualI128(self: i128, other: i128) callconv(.C) bool { + return self >= other; +} + +pub fn lessThanU128(self: u128, other: u128) callconv(.C) bool { + return self < other; +} + +pub fn lessThanOrEqualU128(self: u128, other: u128) callconv(.C) bool { + return self <= other; +} + +pub fn greaterThanU128(self: u128, other: u128) callconv(.C) bool { + return self > other; +} + +pub fn greaterThanOrEqualU128(self: u128, other: u128) callconv(.C) bool { + return self >= other; +} + pub fn exportMulOrPanic(comptime T: type, comptime W: type, comptime name: []const u8) void { comptime var f = struct { fn func(self: T, other: T) callconv(.C) T { diff --git a/crates/compiler/builtins/src/bitcode.rs b/crates/compiler/builtins/src/bitcode.rs index e0eb79c659..ca356053e6 100644 --- a/crates/compiler/builtins/src/bitcode.rs +++ b/crates/compiler/builtins/src/bitcode.rs @@ -310,6 +310,14 @@ pub const NUM_IS_MULTIPLE_OF: IntrinsicName = int_intrinsic!("roc_builtins.num.i pub const NUM_SHIFT_RIGHT_ZERO_FILL: IntrinsicName = int_intrinsic!("roc_builtins.num.shift_right_zero_fill"); +pub const NUM_COMPARE: IntrinsicName = int_intrinsic!("roc_builtins.num.compare"); +pub const NUM_LESS_THAN: IntrinsicName = int_intrinsic!("roc_builtins.num.less_than"); +pub const NUM_LESS_THAN_OR_EQUAL: IntrinsicName = + int_intrinsic!("roc_builtins.num.less_than_or_equal"); +pub const NUM_GREATER_THAN: IntrinsicName = int_intrinsic!("roc_builtins.num.greater_than"); +pub const NUM_GREATER_THAN_OR_EQUAL: IntrinsicName = + int_intrinsic!("roc_builtins.num.greater_than_or_equal"); + pub const NUM_COUNT_LEADING_ZERO_BITS: IntrinsicName = int_intrinsic!("roc_builtins.num.count_leading_zero_bits"); pub const NUM_COUNT_TRAILING_ZERO_BITS: IntrinsicName = @@ -381,6 +389,7 @@ pub const LIST_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.list.release_excess pub const DEC_FROM_STR: &str = "roc_builtins.dec.from_str"; pub const DEC_TO_STR: &str = "roc_builtins.dec.to_str"; pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64"; +pub const DEC_FROM_U64: &str = "roc_builtins.dec.from_u64"; pub const DEC_TO_I128: &str = "roc_builtins.dec.to_i128"; pub const DEC_EQ: &str = "roc_builtins.dec.eq"; pub const DEC_NEQ: &str = "roc_builtins.dec.neq"; diff --git a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs index 50d5c37a0b..3d13f4c439 100644 --- a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs +++ b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs @@ -1108,6 +1108,14 @@ pub(crate) fn run_low_level<'a, 'ctx>( "lt_or_gt", ) } + Decimal => { + // + call_bitcode_fn( + env, + &[lhs_arg, rhs_arg], + &bitcode::NUM_COMPARE[IntWidth::I128], + ) + } _ => { unreachable!("Compiler bug: tried to run numeric operation {:?} on invalid builtin layout: ({:?})", op, lhs_layout); @@ -2150,6 +2158,9 @@ fn build_dec_binop<'a, 'ctx>( "decimal multiplication overflowed", ), NumDivFrac => dec_binop_with_unchecked(env, bitcode::DEC_DIV, lhs, rhs), + + NumLt => call_bitcode_fn(env, &[lhs, rhs], &bitcode::NUM_LESS_THAN[IntWidth::I128]), + NumGt => call_bitcode_fn(env, &[lhs, rhs], &bitcode::NUM_GREATER_THAN[IntWidth::I128]), _ => { unreachable!("Unrecognized int binary operation: {:?}", op); } @@ -2214,19 +2225,22 @@ fn build_int_unary_op<'a, 'ctx, 'env>( NumToFrac => { // This is an Int, so we need to convert it. - let target_float_type = match layout_interner.get_repr(return_layout) { + match layout_interner.get_repr(return_layout) { LayoutRepr::Builtin(Builtin::Float(float_width)) => { - convert::float_type_from_float_width(env, float_width) + let target_float_type = convert::float_type_from_float_width(env, float_width); + + bd.build_cast( + InstructionOpcode::SIToFP, + arg, + target_float_type, + "i64_to_f64", + ) + } + LayoutRepr::Builtin(Builtin::Decimal) => { + call_bitcode_fn(env, &[arg.into()], &bitcode::DEC_FROM_U64) } _ => internal_error!("There can only be floats here!"), - }; - - bd.build_cast( - InstructionOpcode::SIToFP, - arg, - target_float_type, - "i64_to_f64", - ) + } } NumToIntChecked => { // return_layout : Result N [OutOfBounds]* ~ { result: N, out_of_bounds: bool } diff --git a/crates/compiler/test_gen/src/gen_list.rs b/crates/compiler/test_gen/src/gen_list.rs index 25f89869b7..e1c5245484 100644 --- a/crates/compiler/test_gen/src/gen_list.rs +++ b/crates/compiler/test_gen/src/gen_list.rs @@ -1518,7 +1518,7 @@ fn list_join_two_non_empty_lists() { #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn list_join_two_non_empty_lists_of_float() { assert_evals_to!( - "List.join [[1.2, 1.1], [2.1, 2.2]]", + "List.join [[1.2f64, 1.1], [2.1, 2.2]]", RocList::from_slice(&[1.2, 1.1, 2.1, 2.2]), RocList ); @@ -1532,7 +1532,7 @@ fn list_join_to_big_list() { r#" List.join [ - [1.2, 1.1], + [1.2f64, 1.1], [2.1, 2.2], [3.0, 4.0, 5.0, 6.1, 9.0], [3.0, 4.0, 5.0, 6.1, 9.0], @@ -1582,7 +1582,7 @@ fn list_join_all_empty_lists() { #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn list_join_one_empty_list() { assert_evals_to!( - "List.join [[1.2, 1.1], []]", + "List.join [[1.2f64, 1.1], []]", RocList::from_slice(&[1.2, 1.1]), RocList ); @@ -1761,8 +1761,8 @@ fn list_concat_two_non_empty_lists() { #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn list_concat_two_bigger_non_empty_lists() { assert_evals_to!( - "List.concat [1.1, 2.2] [3.3, 4.4, 5.5]", - RocList::from_slice(&[1.1, 2.2, 3.3, 4.4, 5.5]), + "List.concat [1.1f64, 2.2] [3.3, 4.4, 5.5]", + RocList::from_slice(&[1.1f64, 2.2, 3.3, 4.4, 5.5]), RocList ); } @@ -2164,7 +2164,7 @@ fn replace_shared_int_list() { { x, y } - wrapper [2.1, 4.3] + wrapper [2.1f64, 4.3] "# ), (7.7, 4.3), @@ -2214,7 +2214,7 @@ fn set_unique_int_list() { #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn set_unique_list_oob() { assert_evals_to!( - "List.set [3, 17, 4.1] 1337 9.25", + "List.set [3f64, 17, 4.1] 1337 9.25", RocList::from_slice(&[3.0, 17.0, 4.1]), RocList ); @@ -2240,7 +2240,7 @@ fn set_shared_int_list() { { x, y } - wrapper [2.1, 4.3] + wrapper [2.1f64, 4.3] "# ), (7.7, 4.3), @@ -2796,7 +2796,7 @@ fn list_max() { fn list_sum() { assert_evals_to!("List.sum []", 0, i64); assert_evals_to!("List.sum [1, 2, 3]", 6, i64); - assert_evals_to!("List.sum [1.1, 2.2, 3.3]", 6.6, f64); + assert_evals_to!("List.sum [1.1f64, 2.2, 3.3]", 6.6, f64); } #[test] @@ -2804,7 +2804,7 @@ fn list_sum() { fn list_product() { assert_evals_to!("List.product []", 1, i64); assert_evals_to!("List.product [1, 2, 3]", 6, i64); - assert_evals_to!("List.product [1.1, 2.2, 3.3]", 1.1 * 2.2 * 3.3, f64); + assert_evals_to!("List.product [1.1f64, 2.2, 3.3]", 1.1 * 2.2 * 3.3, f64); } #[test] diff --git a/crates/compiler/test_gen/src/gen_num.rs b/crates/compiler/test_gen/src/gen_num.rs index 14846d009e..3e2564ef22 100644 --- a/crates/compiler/test_gen/src/gen_num.rs +++ b/crates/compiler/test_gen/src/gen_num.rs @@ -470,19 +470,19 @@ fn f32_float_alias() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn f64_sqrt_100() { - assert_evals_to!("Num.sqrt 100", 10.0, f64); + assert_evals_to!("Num.sqrt 100f64", 10.0, f64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn f64_sqrt_checked_0() { - assert_evals_to!("Num.sqrt 0", 0.0, f64); + assert_evals_to!("Num.sqrt 0f64", 0.0, f64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn f64_sqrt_checked_positive() { - assert_evals_to!("Num.sqrtChecked 100", RocResult::ok(10.0), RocResult); + assert_evals_to!("Num.sqrtChecked 100f64", RocResult::ok(10.0), RocResult); } #[test] @@ -494,42 +494,42 @@ fn f64_sqrt_checked_negative() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn f64_log() { - assert_evals_to!("Num.log 7.38905609893", 1.999999999999912, f64); + assert_evals_to!("Num.log 7.38905609893f64", 1.999999999999912, f64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn f64_log_checked_one() { - assert_evals_to!("Num.logChecked 1", RocResult::ok(0.0), RocResult); + assert_evals_to!("Num.logChecked 1f64", RocResult::ok(0.0), RocResult); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn f64_log_checked_zero() { - assert_evals_to!("Num.logChecked 0", RocResult::err(()), RocResult); + assert_evals_to!("Num.logChecked 0f64", RocResult::err(()), RocResult); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn f64_log_negative() { - assert_evals_to!("Num.log -1", true, f64, |f: f64| f.is_nan()); + assert_evals_to!("Num.log -1f64", true, f64, |f: f64| f.is_nan()); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn f64_round() { - assert_evals_to!("Num.round 3.6", 4, i64); - assert_evals_to!("Num.round 3.4", 3, i64); - assert_evals_to!("Num.round 2.5", 3, i64); - assert_evals_to!("Num.round -2.3", -2, i64); - assert_evals_to!("Num.round -2.5", -3, i64); + assert_evals_to!("Num.round 3.6f64", 4, i64); + assert_evals_to!("Num.round 3.4f64", 3, i64); + assert_evals_to!("Num.round 2.5f64", 3, i64); + assert_evals_to!("Num.round -2.3f64", -2, i64); + assert_evals_to!("Num.round -2.5f64", -3, i64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn f64_abs() { - assert_evals_to!("Num.abs -4.7", 4.7, f64); - assert_evals_to!("Num.abs 5.8", 5.8, f64); + assert_evals_to!("Num.abs -4.7f64", 4.7, f64); + assert_evals_to!("Num.abs 5.8f64", 5.8, f64); #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] { @@ -668,7 +668,7 @@ fn gen_add_f64() { assert_evals_to!( indoc!( r#" - 1.1 + 2.4 + 3 + 1.1f64 + 2.4 + 3 "# ), 6.5, @@ -695,7 +695,7 @@ fn gen_wrap_add_nums() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn gen_div_f64() { - assert_evals_to!("48 / 2", 24.0, f64); + assert_evals_to!("48f64 / 2", 24.0, f64); } #[test] @@ -710,7 +710,7 @@ fn gen_div_checked_f64() { assert_evals_to!( indoc!( r#" - when Num.divChecked 48 2 is + when Num.divChecked 48 2f64 is Ok val -> val Err _ -> -1 "# @@ -726,7 +726,7 @@ fn gen_div_checked_by_zero_f64() { assert_evals_to!( indoc!( r#" - when Num.divChecked 47 0 is + when Num.divChecked 47 0f64 is Ok val -> val Err _ -> -1 "# @@ -1260,22 +1260,22 @@ fn gen_is_even() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn sin() { - assert_evals_to!("Num.sin 0", 0.0, f64); - assert_evals_to!("Num.sin 1.41421356237", 0.9877659459922529, f64); + assert_evals_to!("Num.sin 0f64", 0.0, f64); + assert_evals_to!("Num.sin 1.41421356237f64", 0.9877659459922529, f64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn cos() { - assert_evals_to!("Num.cos 0", 1.0, f64); - assert_evals_to!("Num.cos 3.14159265359", -1.0, f64); + assert_evals_to!("Num.cos 0f64", 1.0, f64); + assert_evals_to!("Num.cos 3.14159265359f64", -1.0, f64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn tan() { - assert_evals_to!("Num.tan 0", 0.0, f64); - assert_evals_to!("Num.tan 1", 1.557407724654902, f64); + assert_evals_to!("Num.tan 0f64", 0.0f64, f64); + assert_evals_to!("Num.tan 1f64", 1.557407724654902f64, f64); } #[test] @@ -1421,37 +1421,37 @@ fn gte_i64() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn lt_f64() { - assert_evals_to!("1.1 < 1.2", true, bool); - assert_evals_to!("1.1 < 1.1", false, bool); - assert_evals_to!("1.2 < 1.1", false, bool); - assert_evals_to!("0.0 < 0.0", false, bool); + assert_evals_to!("1.1f64 < 1.2", true, bool); + assert_evals_to!("1.1f64 < 1.1", false, bool); + assert_evals_to!("1.2f64 < 1.1", false, bool); + assert_evals_to!("0.0f64 < 0.0", false, bool); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn lte_f64() { - assert_evals_to!("1.1 <= 1.1", true, bool); - assert_evals_to!("1.2 <= 1.1", false, bool); - assert_evals_to!("1.1 <= 1.2", true, bool); - assert_evals_to!("0.0 <= 0.0", true, bool); + assert_evals_to!("1.1f64 <= 1.1", true, bool); + assert_evals_to!("1.2f64 <= 1.1", false, bool); + assert_evals_to!("1.1f64 <= 1.2", true, bool); + assert_evals_to!("0.0f64 <= 0.0", true, bool); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gt_f64() { - assert_evals_to!("2.2 > 1.1", true, bool); - assert_evals_to!("2.2 > 2.2", false, bool); - assert_evals_to!("1.1 > 2.2", false, bool); - assert_evals_to!("0.0 > 0.0", false, bool); + assert_evals_to!("2.2f64 > 1.1", true, bool); + assert_evals_to!("2.2f64 > 2.2", false, bool); + assert_evals_to!("1.1f64 > 2.2", false, bool); + assert_evals_to!("0.0f64 > 0.0", false, bool); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gte_f64() { - assert_evals_to!("1.1 >= 1.1", true, bool); - assert_evals_to!("1.1 >= 1.2", false, bool); - assert_evals_to!("1.2 >= 1.1", true, bool); - assert_evals_to!("0.0 >= 0.0", true, bool); + assert_evals_to!("1.1f64 >= 1.1", true, bool); + assert_evals_to!("1.1f64 >= 1.2", false, bool); + assert_evals_to!("1.2f64 >= 1.1", true, bool); + assert_evals_to!("0.0f64 >= 0.0", true, bool); } #[test] @@ -1474,7 +1474,7 @@ fn gen_order_of_arithmetic_ops_complex_float() { assert_evals_to!( indoc!( r#" - 3 - 48 * 2.0 + 3 - 48 * 2.0f64 "# ), -93.0, @@ -1611,13 +1611,13 @@ fn gen_basic_fn() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn int_to_float() { - assert_evals_to!("Num.toFrac 0x9", 9.0, f64); + assert_evals_to!("Num.toFrac 0x9", RocDec::from(9i32), RocDec); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn num_to_frac() { - assert_evals_to!("Num.toFrac 9", 9.0, f64); + assert_evals_to!("Num.toFrac 9", RocDec::from(9i32), RocDec); } #[test] @@ -1702,32 +1702,43 @@ fn num_to_frac_f32_to_f64() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn float_to_float() { - assert_evals_to!("Num.toFrac 0.5", 0.5, f64); + assert_evals_to!( + indoc!( + r#" + x : F64 + x = Num.toFrac 0.5f64 + + x + "# + ), + 0.5, + f64 + ); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn frac_is_nan() { - assert_evals_to!("Num.isNaN (0 / 0)", true, bool); - assert_evals_to!("Num.isNaN (1 / 0)", false, bool); - assert_evals_to!("Num.isNaN 42", false, bool); + assert_evals_to!("Num.isNaN (0 / 0f64)", true, bool); + assert_evals_to!("Num.isNaN (1 / 0f64)", false, bool); + assert_evals_to!("Num.isNaN 42f64", false, bool); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn frac_is_infinite() { - assert_evals_to!("Num.isInfinite (1 / 0)", true, bool); - assert_evals_to!("Num.isInfinite (-1 / 0)", true, bool); - assert_evals_to!("Num.isInfinite (0 / 0)", false, bool); - assert_evals_to!("Num.isInfinite 42", false, bool); + assert_evals_to!("Num.isInfinite (1 / 0f64)", true, bool); + assert_evals_to!("Num.isInfinite (-1 / 0f64)", true, bool); + assert_evals_to!("Num.isInfinite (0 / 0f64)", false, bool); + assert_evals_to!("Num.isInfinite 42f64", false, bool); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn frac_is_finite() { - assert_evals_to!("Num.isFinite 42", true, bool); - assert_evals_to!("Num.isFinite (1 / 0)", false, bool); - assert_evals_to!("Num.isFinite (0 / 0)", false, bool); + assert_evals_to!("Num.isFinite 42f64", true, bool); + assert_evals_to!("Num.isFinite (1 / 0f64)", false, bool); + assert_evals_to!("Num.isFinite (0 / 0f64)", false, bool); } #[test] @@ -1749,19 +1760,19 @@ fn float_compare() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn pow() { - assert_evals_to!("Num.pow 2.0 2.0", 4.0, f64); + assert_evals_to!("Num.pow 2.0f64 2.0f64", 4.0, f64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn ceiling() { - assert_evals_to!("Num.ceiling 1.1", 2, i64); + assert_evals_to!("Num.ceiling 1.1f64", 2, i64); } #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn floor() { - assert_evals_to!("Num.floor 1.9", 1, i64); + assert_evals_to!("Num.floor 1.9f64", 1, i64); } #[test] @@ -1773,7 +1784,7 @@ fn pow_int() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn atan() { - assert_evals_to!("Num.atan 10", 1.4711276743037347, f64); + assert_evals_to!("Num.atan 10f64", 1.4711276743037347, f64); } #[test] @@ -1825,7 +1836,7 @@ fn int_add_wrap() { #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn float_add_checked_pass() { assert_evals_to!( - "Num.addChecked 1.0 0.0", + "Num.addChecked 1.0 0.0f64", RocResult::ok(1.0), RocResult ); @@ -1845,7 +1856,7 @@ fn float_add_checked_fail() { #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn float_add_overflow() { assert_evals_to!( - "1.7976931348623157e308 + 1.7976931348623157e308", + "1.7976931348623157e308f64 + 1.7976931348623157e308", f64::INFINITY, f64 ); @@ -1874,7 +1885,7 @@ fn int_sub_wrap() { #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn float_sub_overflow() { assert_evals_to!( - "-1.7976931348623157e308 - 1.7976931348623157e308", + "-1.7976931348623157e308f64 - 1.7976931348623157e308", -f64::INFINITY, f64 ); @@ -1914,7 +1925,7 @@ fn float_sub_checked() { assert_evals_to!( indoc!( r#" - when Num.subChecked 1.0 0.0 is + when Num.subChecked 1.0 0.0f64 is Ok v -> v Err Overflow -> -1.0 "# @@ -1926,7 +1937,7 @@ fn float_sub_checked() { assert_evals_to!( indoc!( r#" - when Num.subChecked -1.7976931348623157e308 1.7976931348623157e308 is + when Num.subChecked -1.7976931348623157e308f64 1.7976931348623157e308 is Err Overflow -> -1 Ok v -> v "# @@ -1972,7 +1983,7 @@ fn float_positive_mul_overflow() { assert_evals_to!( indoc!( r#" - 1.7976931348623157e308 * 2 + 1.7976931348623157e308f64 * 2 "# ), f64::INFINITY, @@ -1986,7 +1997,7 @@ fn float_negative_mul_overflow() { assert_evals_to!( indoc!( r#" - -1.7976931348623157e308 * 2 + -1.7976931348623157e308f64 * 2 "# ), -f64::INFINITY, @@ -2040,7 +2051,7 @@ fn float_mul_checked() { assert_evals_to!( indoc!( r#" - when Num.mulChecked 20.0 2.0 is + when Num.mulChecked 20.0 2.0f64 is Ok v -> v Err Overflow -> -1.0 "# @@ -2052,7 +2063,7 @@ fn float_mul_checked() { assert_evals_to!( indoc!( r#" - when Num.mulChecked 1.7976931348623157e308 2 is + when Num.mulChecked 1.7976931348623157e308f64 2 is Err Overflow -> -1 Ok v -> v "# @@ -3649,7 +3660,7 @@ fn ceiling_to_u32() { indoc!( r#" n : U32 - n = Num.ceiling 124.5 + n = Num.ceiling 124.5f64 n "# ), @@ -3665,7 +3676,7 @@ fn floor_to_u32() { indoc!( r#" n : U32 - n = Num.floor 124.5 + n = Num.floor 124.5f64 n "# ), @@ -3681,7 +3692,7 @@ fn round_to_u32() { indoc!( r#" n : U32 - n = Num.round 124.49 + n = Num.round 124.49f64 n "# ), @@ -3867,11 +3878,11 @@ fn num_abs_diff_large_bits() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn num_abs_diff_float() { - assert_evals_to!(r#"Num.absDiff 0.0 0.0"#, 0.0, f64); - assert_evals_to!(r#"Num.absDiff 1.0 2.0"#, 1.0, f64); - assert_evals_to!(r#"Num.absDiff 2.0 1.0"#, 1.0, f64); - assert_evals_to!(r#"Num.absDiff -1.0 1.0"#, 2.0, f64); - assert_evals_to!(r#"Num.absDiff 1.0 -1.0"#, 2.0, f64); + assert_evals_to!(r#"Num.absDiff 0.0f64 0.0"#, 0.0, f64); + assert_evals_to!(r#"Num.absDiff 1.0f64 2.0"#, 1.0, f64); + assert_evals_to!(r#"Num.absDiff 2.0f64 1.0"#, 1.0, f64); + assert_evals_to!(r#"Num.absDiff -1.0f64 1.0"#, 2.0, f64); + assert_evals_to!(r#"Num.absDiff 1.0f64 -1.0"#, 2.0, f64); } #[test] diff --git a/crates/compiler/test_gen/src/gen_primitives.rs b/crates/compiler/test_gen/src/gen_primitives.rs index 8afd1e9ddd..50592fa04c 100644 --- a/crates/compiler/test_gen/src/gen_primitives.rs +++ b/crates/compiler/test_gen/src/gen_primitives.rs @@ -20,7 +20,7 @@ fn basic_int() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn basic_float() { - assert_evals_to!("1234.0", 1234.0, f64); + assert_evals_to!("1234.0f64", 1234.0, f64); } #[test] @@ -29,7 +29,7 @@ fn branch_first_float() { assert_evals_to!( indoc!( r#" - when 1.23 is + when 1.23f64 is 1.23 -> 12 _ -> 34 "# @@ -239,12 +239,12 @@ fn gen_large_when_float() { r#" foo = \num -> when num is - 0.5 -> 200.1 + 0.5f64 -> 200.1 -3.6 -> 111.2 # TODO adding more negative numbers reproduces parsing bugs here 3.6 -> 789.5 1.7 -> 123.3 2.8 -> 456.4 - _ -> 1000.6 + _ -> 1000.6f64 foo -3.6 "# @@ -314,7 +314,7 @@ fn return_unnamed_fn() { alwaysFloatIdentity = \_ -> (\a -> a) - (alwaysFloatIdentity 2) 1.23 + (alwaysFloatIdentity 2) 1.23f64 wrapper {} "# @@ -362,7 +362,7 @@ fn gen_basic_def() { assert_evals_to!( indoc!( r#" - float = 1.23 + float = 1.23f64 float "# @@ -380,7 +380,7 @@ fn gen_multiple_defs() { r#" answer = 42 - float = 1.23 + float = 1.23f64 if float > 3 then answer else answer "# @@ -394,7 +394,7 @@ fn gen_multiple_defs() { r#" answer = 42 - float = 1.23 + float = 1.23f64 if answer > 3 then float else float "# @@ -564,7 +564,7 @@ fn top_level_constant() { r#" app "test" provides [main] to "./platform" - float = 1.2315 + float = 1.2315f64 main = float + float @@ -1826,10 +1826,10 @@ fn unified_empty_closure_bool() { foo = \{} -> when A is - A -> (\_ -> 1.23) - B -> (\_ -> 1.23) + A -> (\_ -> 1.23f64) + B -> (\_ -> 1.23f64) - main : Frac * + main : F64 main = (foo {}) 0 "# @@ -1851,11 +1851,11 @@ fn unified_empty_closure_byte() { foo = \{} -> when A is - A -> (\_ -> 1.23) - B -> (\_ -> 1.23) + A -> (\_ -> 1.23f64) + B -> (\_ -> 1.23f64) C -> (\_ -> 1.23) - main : Frac * + main : F64 main = (foo {}) 0 "# diff --git a/crates/compiler/test_gen/src/gen_records.rs b/crates/compiler/test_gen/src/gen_records.rs index 33f63a6d43..03ca645191 100644 --- a/crates/compiler/test_gen/src/gen_records.rs +++ b/crates/compiler/test_gen/src/gen_records.rs @@ -53,7 +53,7 @@ fn f64_record() { assert_evals_to!( indoc!( r#" - rec = { y: 17.2, x: 15.1, z: 19.3 } + rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 } rec.x "# @@ -65,7 +65,7 @@ fn f64_record() { assert_evals_to!( indoc!( r#" - rec = { y: 17.2, x: 15.1, z: 19.3 } + rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 } rec.y "# @@ -77,7 +77,7 @@ fn f64_record() { assert_evals_to!( indoc!( r#" - rec = { y: 17.2, x: 15.1, z: 19.3 } + rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 } rec.z "# @@ -280,7 +280,7 @@ fn f64_record2_literal() { assert_evals_to!( indoc!( r#" - { x: 3.1, y: 5.1 } + { x: 3.1f64, y: 5.1f64 } "# ), (3.1, 5.1), @@ -717,7 +717,7 @@ fn return_record_float_int() { assert_evals_to!( indoc!( r#" - { a: 1.23, b: 0x1 } + { a: 1.23f64, b: 0x1 } "# ), (1.23, 0x1), @@ -731,7 +731,7 @@ fn return_record_int_float() { assert_evals_to!( indoc!( r#" - { a: 0x1, b: 1.23 } + { a: 0x1, b: 1.23f64 } "# ), (0x1, 1.23), @@ -745,7 +745,7 @@ fn return_record_float_float() { assert_evals_to!( indoc!( r#" - { a: 2.46, b: 1.23 } + { a: 2.46f64, b: 1.23f64 } "# ), (2.46, 1.23), @@ -759,7 +759,7 @@ fn return_record_float_float_float() { assert_evals_to!( indoc!( r#" - { a: 2.46, b: 1.23, c: 0.1 } + { a: 2.46f64, b: 1.23f64, c: 0.1f64 } "# ), (2.46, 1.23, 0.1), @@ -773,7 +773,7 @@ fn return_nested_record() { assert_evals_to!( indoc!( r#" - { flag: 0x0, payload: { a: 2.46, b: 1.23, c: 0.1 } } + { flag: 0x0, payload: { a: 2.46f64, b: 1.23f64, c: 0.1f64 } } "# ), (0x0, (2.46, 1.23, 0.1)), @@ -802,7 +802,7 @@ fn nested_record_load() { #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn accessor_twice() { - assert_evals_to!(".foo { foo: 4 } + .foo { bar: 2.46, foo: 3 } ", 7, i64); + assert_evals_to!(".foo { foo: 4 } + .foo { bar: 2.46f64, foo: 3 } ", 7, i64); } #[test] @@ -839,7 +839,7 @@ fn update_record() { assert_evals_to!( indoc!( r#" - rec = { foo: 42, bar: 2.46 } + rec = { foo: 42, bar: 2.46f64 } { rec & foo: rec.foo + 1 } "# diff --git a/crates/compiler/test_gen/src/gen_tags.rs b/crates/compiler/test_gen/src/gen_tags.rs index 8f5b0783c3..19279a5d50 100644 --- a/crates/compiler/test_gen/src/gen_tags.rs +++ b/crates/compiler/test_gen/src/gen_tags.rs @@ -198,7 +198,7 @@ fn gen_if_float() { assert_evals_to!( indoc!( r#" - if Bool.true then -1.0 else 1.0 + if Bool.true then -1.0 else 1.0f64 "# ), -1.0, @@ -766,7 +766,7 @@ fn join_point_when() { when x is Red -> 1 White -> 2 - Blue -> 3.1 + Blue -> 3.1f64 y diff --git a/crates/compiler/test_gen/src/gen_tuples.rs b/crates/compiler/test_gen/src/gen_tuples.rs index d74fbc9f54..0ffb2b0e56 100644 --- a/crates/compiler/test_gen/src/gen_tuples.rs +++ b/crates/compiler/test_gen/src/gen_tuples.rs @@ -53,7 +53,7 @@ fn f64_tuple() { assert_evals_to!( indoc!( r#" - tup = (17.2, 15.1, 19.3) + tup = (17.2f64, 15.1f64, 19.3f64) tup.0 "# @@ -65,7 +65,7 @@ fn f64_tuple() { assert_evals_to!( indoc!( r#" - tup = (17.2, 15.1, 19.3) + tup = (17.2f64, 15.1f64, 19.3f64) tup.1 "# @@ -77,7 +77,7 @@ fn f64_tuple() { assert_evals_to!( indoc!( r#" - tup = (17.2, 15.1, 19.3) + tup = (17.2f64, 15.1f64, 19.3f64) tup.2 "# @@ -291,7 +291,7 @@ fn f64_tuple2_literal() { assert_evals_to!( indoc!( r#" - (3.1, 5.1) + (3.1f64, 5.1f64) "# ), (3.1, 5.1), @@ -445,7 +445,7 @@ fn return_tuple_float_int() { assert_evals_to!( indoc!( r#" - (1.23, 0x1) + (1.23f64, 0x1) "# ), (1.23, 0x1), @@ -459,7 +459,7 @@ fn return_tuple_int_float() { assert_evals_to!( indoc!( r#" - ( 0x1, 1.23 ) + ( 0x1, 1.23f64 ) "# ), (0x1, 1.23), @@ -473,7 +473,7 @@ fn return_tuple_float_float() { assert_evals_to!( indoc!( r#" - ( 2.46, 1.23 ) + ( 2.46f64, 1.23f64 ) "# ), (2.46, 1.23), @@ -487,7 +487,7 @@ fn return_tuple_float_float_float() { assert_evals_to!( indoc!( r#" - ( 2.46, 1.23, 0.1 ) + ( 2.46f64, 1.23f64, 0.1f64 ) "# ), (2.46, 1.23, 0.1), @@ -501,7 +501,7 @@ fn return_nested_tuple() { assert_evals_to!( indoc!( r#" - (0x0, (2.46, 1.23, 0.1)) + (0x0, (2.46f64, 1.23f64, 0.1f64)) "# ), (0x0, (2.46, 1.23, 0.1)), diff --git a/crates/repl_cli/src/cli_gen.rs b/crates/repl_cli/src/cli_gen.rs index 2d900f7828..b191478e20 100644 --- a/crates/repl_cli/src/cli_gen.rs +++ b/crates/repl_cli/src/cli_gen.rs @@ -70,6 +70,7 @@ pub fn eval_llvm( layout_interner.into_global().fork(), target_info, ); + let expr_str = format_answer(&arena, expr).to_string(); Some(ReplOutput { diff --git a/crates/roc_std/src/lib.rs b/crates/roc_std/src/lib.rs index 219652cbd9..300140ffce 100644 --- a/crates/roc_std/src/lib.rs +++ b/crates/roc_std/src/lib.rs @@ -406,6 +406,12 @@ impl RocDec { } } +impl From for RocDec { + fn from(value: i32) -> Self { + RocDec::from_ne_bytes((RocDec::ONE_POINT_ZERO * value as i128).to_ne_bytes()) + } +} + impl fmt::Display for RocDec { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.to_str_helper(&mut ArrayString::new()))