mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Merge pull request #7277 from shua/jd/powi
Num.powInt: panic on overflow
This commit is contained in:
commit
7cc24cbced
3 changed files with 28 additions and 19 deletions
|
@ -110,7 +110,21 @@ pub fn exportNumToFloatCast(comptime T: type, comptime F: type, comptime name: [
|
||||||
pub fn exportPow(comptime T: type, comptime name: []const u8) void {
|
pub fn exportPow(comptime T: type, comptime name: []const u8) void {
|
||||||
comptime var f = struct {
|
comptime var f = struct {
|
||||||
fn func(base: T, exp: T) callconv(.C) T {
|
fn func(base: T, exp: T) callconv(.C) T {
|
||||||
return std.math.pow(T, base, exp);
|
switch (@typeInfo(T)) {
|
||||||
|
// std.math.pow can handle ints via powi, but it turns any errors to unreachable
|
||||||
|
// we want to catch overflow and report a proper error to the user
|
||||||
|
.Int => {
|
||||||
|
if (std.math.powi(T, base, exp)) |value| {
|
||||||
|
return value;
|
||||||
|
} else |err| switch (err) {
|
||||||
|
error.Overflow => roc_panic("Integer raised to power overflowed!", 0),
|
||||||
|
error.Underflow => return 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
return std.math.pow(T, base, exp);
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.func;
|
}.func;
|
||||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||||
|
|
|
@ -1829,24 +1829,12 @@ impl<'a> LowLevelCall<'a> {
|
||||||
_ => panic_ret_type(),
|
_ => panic_ret_type(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NumPowInt => {
|
NumPowInt => match self.ret_layout_raw {
|
||||||
self.load_args(backend);
|
LayoutRepr::Builtin(Builtin::Int(width)) => {
|
||||||
let base_type = CodeGenNumType::for_symbol(backend, self.arguments[0]);
|
self.load_args_and_call_zig(backend, &bitcode::NUM_POW_INT[width])
|
||||||
let exponent_type = CodeGenNumType::for_symbol(backend, self.arguments[1]);
|
}
|
||||||
let ret_type = CodeGenNumType::from(self.ret_layout);
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
debug_assert!(base_type == exponent_type);
|
|
||||||
debug_assert!(exponent_type == ret_type);
|
|
||||||
|
|
||||||
let width = match ret_type {
|
|
||||||
CodeGenNumType::I32 => IntWidth::I32,
|
|
||||||
CodeGenNumType::I64 => IntWidth::I64,
|
|
||||||
CodeGenNumType::I128 => todo!("{:?} for I128", self.lowlevel),
|
|
||||||
_ => internal_error!("Invalid return type for pow: {:?}", ret_type),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.load_args_and_call_zig(backend, &bitcode::NUM_POW_INT[width])
|
|
||||||
}
|
|
||||||
|
|
||||||
NumIsNan => num_is_nan(backend, self.arguments[0]),
|
NumIsNan => num_is_nan(backend, self.arguments[0]),
|
||||||
NumIsInfinite => num_is_infinite(backend, self.arguments[0]),
|
NumIsInfinite => num_is_infinite(backend, self.arguments[0]),
|
||||||
|
|
|
@ -1926,6 +1926,13 @@ fn pow_int() {
|
||||||
assert_evals_to!("Num.powInt 2 3", 8, i64);
|
assert_evals_to!("Num.powInt 2 3", 8, i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
|
#[should_panic(expected = r#"Roc failed with message: "Integer raised to power overflowed!"#)]
|
||||||
|
fn pow_int_overflow() {
|
||||||
|
assert_evals_to!("Num.powInt 2u8 8", 0, u8);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
fn atan() {
|
fn atan() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue