rem, sqrt, log are unchecked but have checked variants

mod exists but is not implemented due to lack of hardware support
(emulation, possibly in terms of rem, is needed).
This commit is contained in:
Kevin Gillette 2022-04-15 00:04:38 -06:00
parent d23d5f249f
commit 1908ff41c3
No known key found for this signature in database
GPG key ID: 9009F701BBC0D562
15 changed files with 208 additions and 75 deletions

View file

@ -61,6 +61,7 @@ interface Num
isPositive, isPositive,
isZero, isZero,
log, log,
logChecked,
maxFloat, maxFloat,
maxI8, maxI8,
maxU8, maxU8,
@ -81,8 +82,8 @@ interface Num
minI64, minI64,
minU64, minU64,
minI128, minI128,
modInt, mod,
modFloat, modChecked,
mul, mul,
mulChecked, mulChecked,
mulWrap, mulWrap,
@ -90,6 +91,7 @@ interface Num
pow, pow,
powInt, powInt,
rem, rem,
remChecked,
round, round,
shiftLeftBy, shiftLeftBy,
shiftRightBy, shiftRightBy,
@ -99,6 +101,7 @@ interface Num
subChecked, subChecked,
subWrap, subWrap,
sqrt, sqrt,
sqrtChecked,
tan, tan,
toI8, toI8,
toI8Checked, toI8Checked,
@ -1316,7 +1319,7 @@ isInfinite : Float * -> Bool
## ##
## >>> Num.isNaN 12.3 ## >>> Num.isNaN 12.3
## ##
## >>> Num.isNaN (Num.sqrt -2) ## >>> Num.isNaN (Num.pow -1 0.5)
## ##
## *NaN* is unusual from other numberic values in that: ## *NaN* is unusual from other numberic values in that:
## * *NaN* is not equal to any other number, even itself. [Bool.isEq] always returns `False` if either argument is *NaN*. ## * *NaN* is not equal to any other number, even itself. [Bool.isEq] always returns `False` if either argument is *NaN*.

View file

@ -68,12 +68,15 @@ interface Num
isPositive, isPositive,
isNegative, isNegative,
rem, rem,
remChecked,
div, div,
divChecked, divChecked,
modInt, mod,
modFloat, modChecked,
sqrt, sqrt,
sqrtChecked,
log, log,
logChecked,
round, round,
ceiling, ceiling,
floor, floor,
@ -230,19 +233,23 @@ asin : Float a -> Float a
acos : Float a -> Float a acos : Float a -> Float a
atan : Float a -> Float a atan : Float a -> Float a
sqrt : Float a -> Result (Float a) [ SqrtOfNegative ]* sqrt : Float a -> Float a
log : Float a -> Result (Float a) [ LogNeedsPositive ]* sqrtChecked : Float a -> Result (Float a) [ SqrtOfNegative ]*
log : Float a -> Float a
logChecked : Float a -> Result (Float a) [ LogNeedsPositive ]*
div : Float a, Float a -> Float a div : Float a, Float a -> Float a
divChecked : Float a, Float a -> Result (Float a) [ DivByZero ]* divChecked : Float a, Float a -> Result (Float a) [ DivByZero ]*
divCeil : Int a, Int a -> Int a divCeil : Int a, Int a -> Int a
divCeilChecked : Int a, Int a -> Result (Int a) [ DivByZero ]* divCeilChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
divFloor : Int a, Int a -> Int a divFloor : Int a, Int a -> Int a
divFloorChecked : Int a, Int a -> Result (Int a) [ DivByZero ]* 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 ]* rem : Int a, Int a -> Int a
# mod : Int a, Int a -> Result (Int a) [ DivByZero ]* remChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
mod : Int a, Int a -> Int a
modChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
isMultipleOf : Int a, Int a -> Bool isMultipleOf : Int a, Int a -> Bool
bitwiseAnd : Int a, Int a -> Int a bitwiseAnd : Int a, Int a -> Int a

View file

@ -393,16 +393,30 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(int_type(flex(TVAR2))) Box::new(int_type(flex(TVAR2)))
); );
// rem : Int a, Int a -> Result (Int a) [ DivByZero ]* // rem : Int a, Int a -> Int a
add_top_level_function_type!( add_top_level_function_type!(
Symbol::NUM_REM, Symbol::NUM_REM,
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR1))),
);
// remChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
add_top_level_function_type!(
Symbol::NUM_REM_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())),
); );
// mod : Int a, Int a -> Result (Int a) [ DivByZero ]* // mod : Int a, Int a -> Int a
add_top_level_function_type!( add_top_level_function_type!(
Symbol::NUM_MOD_INT, Symbol::NUM_MOD,
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR1))),
);
// modChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
add_top_level_function_type!(
Symbol::NUM_MOD_CHECKED,
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], 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())),
); );
@ -680,36 +694,43 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_top_level_function_type!( add_top_level_function_type!(
Symbol::NUM_DIV_FLOAT_CHECKED, Symbol::NUM_DIV_FLOAT_CHECKED,
vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
Box::new(result_type(float_type(flex(TVAR1)), div_by_zero.clone())),
);
// mod : Float a, Float a -> Result (Float a) [ DivByZero ]*
add_top_level_function_type!(
Symbol::NUM_MOD_FLOAT,
vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
Box::new(result_type(float_type(flex(TVAR1)), div_by_zero)), Box::new(result_type(float_type(flex(TVAR1)), div_by_zero)),
); );
// sqrt : Float a -> Float a // sqrt : Float a -> Float a
add_top_level_function_type!(
Symbol::NUM_SQRT,
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
);
// sqrtChecked : Float a -> Result (Float a) [ SqrtOfNegative ]*
let sqrt_of_negative = SolvedType::TagUnion( let sqrt_of_negative = SolvedType::TagUnion(
vec![(TagName::Global("SqrtOfNegative".into()), vec![])], vec![(TagName::Global("SqrtOfNegative".into()), vec![])],
Box::new(SolvedType::Wildcard), Box::new(SolvedType::Wildcard),
); );
add_top_level_function_type!( add_top_level_function_type!(
Symbol::NUM_SQRT, Symbol::NUM_SQRT_CHECKED,
vec![float_type(flex(TVAR1))], vec![float_type(flex(TVAR1))],
Box::new(result_type(float_type(flex(TVAR1)), sqrt_of_negative)), Box::new(result_type(float_type(flex(TVAR1)), sqrt_of_negative)),
); );
// log : Float a -> Float a // log : Float a -> Float a
add_top_level_function_type!(
Symbol::NUM_LOG,
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
);
// logChecked : Float a -> Result (Float a) [ LogNeedsPositive ]*
let log_needs_positive = SolvedType::TagUnion( let log_needs_positive = SolvedType::TagUnion(
vec![(TagName::Global("LogNeedsPositive".into()), vec![])], vec![(TagName::Global("LogNeedsPositive".into()), vec![])],
Box::new(SolvedType::Wildcard), Box::new(SolvedType::Wildcard),
); );
add_top_level_function_type!( add_top_level_function_type!(
Symbol::NUM_LOG, Symbol::NUM_LOG_CHECKED,
vec![float_type(flex(TVAR1))], vec![float_type(flex(TVAR1))],
Box::new(result_type(float_type(flex(TVAR1)), log_needs_positive)), Box::new(result_type(float_type(flex(TVAR1)), log_needs_positive)),
); );

View file

@ -203,9 +203,14 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
NUM_ABS => num_abs, NUM_ABS => num_abs,
NUM_NEG => num_neg, NUM_NEG => num_neg,
NUM_REM => num_rem, NUM_REM => num_rem,
NUM_REM_CHECKED => num_rem_checked,
NUM_MOD => num_mod,
NUM_MOD_CHECKED => num_mod_checked,
NUM_IS_MULTIPLE_OF => num_is_multiple_of, NUM_IS_MULTIPLE_OF => num_is_multiple_of,
NUM_SQRT => num_sqrt, NUM_SQRT => num_sqrt,
NUM_SQRT_CHECKED => num_sqrt_checked,
NUM_LOG => num_log, NUM_LOG => num_log,
NUM_LOG_CHECKED => num_log_checked,
NUM_ROUND => num_round, NUM_ROUND => num_round,
NUM_IS_ODD => num_is_odd, NUM_IS_ODD => num_is_odd,
NUM_IS_EVEN => num_is_even, NUM_IS_EVEN => num_is_even,
@ -730,6 +735,23 @@ fn bool_and(symbol: Symbol, var_store: &mut VarStore) -> Def {
) )
} }
fn num_unaryop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def {
let num_var = var_store.fresh();
let body = RunLowLevel {
op,
args: vec![(num_var, Var(Symbol::ARG_1))],
ret_var: num_var,
};
defn(
symbol,
vec![(num_var, Symbol::ARG_1)],
var_store,
body,
num_var,
)
}
/// Num a, Num a -> Num a /// Num a, Num a -> Num a
fn num_binop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def { fn num_binop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def {
let num_var = var_store.fresh(); let num_var = var_store.fresh();
@ -1169,8 +1191,13 @@ fn num_to_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
) )
} }
/// Num.sqrt : Float -> Result Float [ SqrtOfNegative ]* /// Num.sqrt : Float a -> Float a
fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_unaryop(symbol, var_store, LowLevel::NumSqrtUnchecked)
}
/// Num.sqrtChecked : Float a -> Result (Float a) [ SqrtOfNegative ]*
fn num_sqrt_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh(); let bool_var = var_store.fresh();
let float_var = var_store.fresh(); let float_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();
@ -1218,8 +1245,13 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
) )
} }
/// Num.log : Float -> Result Float [ LogNeedsPositive ]* /// Num.log : Float a -> Float a
fn num_log(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_log(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_unaryop(symbol, var_store, LowLevel::NumLogUnchecked)
}
/// Num.logChecked : Float a -> Result (Float a) [ LogNeedsPositive ]*
fn num_log_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh(); let bool_var = var_store.fresh();
let float_var = var_store.fresh(); let float_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();
@ -4196,8 +4228,13 @@ fn set_walk(symbol: Symbol, var_store: &mut VarStore) -> Def {
) )
} }
/// Num.rem : Int a, Int a -> Result (Int a) [ DivByZero ]* /// Num.rem : Int a, Int a -> Int a
fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_binop(symbol, var_store, LowLevel::NumRemUnchecked)
}
/// Num.remChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
fn num_rem_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
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();
let bool_var = var_store.fresh(); let bool_var = var_store.fresh();
@ -4255,6 +4292,70 @@ fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
) )
} }
/// Num.mod : Int a, Int a -> Int a
fn num_mod(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_binop(symbol, var_store, LowLevel::NumModUnchecked)
}
/// Num.modChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
fn num_mod_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh();
let bool_var = var_store.fresh();
let ret_var = var_store.fresh();
let body = If {
branch_var: ret_var,
cond_var: bool_var,
branches: vec![(
// if condition
no_region(
// Num.isNeq arg2 0
RunLowLevel {
op: LowLevel::NotEq,
args: vec![
(num_var, Var(Symbol::ARG_2)),
(num_var, num(unbound_zero_var, 0, num_no_bound())),
],
ret_var: bool_var,
},
),
// arg1 was not zero
no_region(
// Ok (Int.#modUnsafe arg1 arg2)
tag(
"Ok",
vec![
// Num.#modUnsafe arg1 arg2
RunLowLevel {
op: LowLevel::NumModUnchecked,
args: vec![
(num_var, Var(Symbol::ARG_1)),
(num_var, Var(Symbol::ARG_2)),
],
ret_var: num_var,
},
],
var_store,
),
),
)],
final_else: Box::new(no_region(tag(
"Err",
vec![tag("DivByZero", Vec::new(), var_store)],
var_store,
))),
};
defn(
symbol,
vec![(num_var, Symbol::ARG_1), (num_var, Symbol::ARG_2)],
var_store,
body,
ret_var,
)
}
/// Num.isMultipleOf : Int a, Int a -> Bool /// Num.isMultipleOf : Int a, Int a -> Bool
fn num_is_multiple_of(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_is_multiple_of(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::NumIsMultipleOf, var_store) lowlevel_2(symbol, LowLevel::NumIsMultipleOf, var_store)

View file

@ -5814,9 +5814,9 @@ fn run_low_level<'a, 'ctx, 'env>(
} }
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
| NumIsMultipleOf | NumAddWrap | NumAddChecked | NumAddSaturated | NumDivUnchecked | NumModUnchecked | NumIsMultipleOf | NumAddWrap | NumAddChecked | NumAddSaturated
| NumDivCeilUnchecked | NumPow | NumPowInt | NumSubWrap | NumSubChecked | NumDivUnchecked | NumDivCeilUnchecked | NumPow | NumPowInt | NumSubWrap
| NumSubSaturated | NumMulWrap | NumMulChecked => { | NumSubChecked | NumSubSaturated | NumMulWrap | NumMulChecked => {
debug_assert_eq!(args.len(), 2); debug_assert_eq!(args.len(), 2);
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]); let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
@ -6578,6 +6578,11 @@ fn build_int_binop<'a, 'ctx, 'env>(
bd.build_int_unsigned_rem(lhs, rhs, "rem_uint").into() bd.build_int_unsigned_rem(lhs, rhs, "rem_uint").into()
} }
} }
NumModUnchecked => {
// there generally is not hardware support for flooring mod;
// it could probably be implemented in pure Roc in terms of Num.rem.
todo!("mod is not implemented")
}
NumIsMultipleOf => { NumIsMultipleOf => {
// this builds the following construct // this builds the following construct
// //
@ -6908,7 +6913,6 @@ fn build_float_binop<'a, 'ctx, 'env>(
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(), NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(), NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(),
NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(), NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(),
NumRemUnchecked => bd.build_float_rem(lhs, rhs, "rem_float").into(),
NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(), NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(),
NumPow => env.call_intrinsic(&LLVM_POW[float_width], &[lhs.into(), rhs.into()]), NumPow => env.call_intrinsic(&LLVM_POW[float_width], &[lhs.into(), rhs.into()]),
_ => { _ => {

View file

@ -434,6 +434,11 @@ impl<'a> LowLevelCall<'a> {
_ => todo!("{:?} for {:?}", self.lowlevel, self.ret_layout), _ => todo!("{:?} for {:?}", self.lowlevel, self.ret_layout),
} }
} }
NumModUnchecked => {
// wasm does not provide a flooring modulo instruction,
// so it would need to be emulated.
todo!("{:?}", self.lowlevel)
}
NumIsMultipleOf => todo!("{:?}", self.lowlevel), NumIsMultipleOf => todo!("{:?}", self.lowlevel),
NumAbs => { NumAbs => {
self.load_args(backend); self.load_args(backend);

View file

@ -85,6 +85,7 @@ pub enum LowLevel {
NumDivUnchecked, NumDivUnchecked,
NumDivCeilUnchecked, NumDivCeilUnchecked,
NumRemUnchecked, NumRemUnchecked,
NumModUnchecked,
NumIsMultipleOf, NumIsMultipleOf,
NumAbs, NumAbs,
NumNeg, NumNeg,
@ -293,14 +294,19 @@ impl LowLevelWrapperType {
Symbol::NUM_DIV_FLOAT_CHECKED => WrapperIsRequired, Symbol::NUM_DIV_FLOAT_CHECKED => WrapperIsRequired,
Symbol::NUM_DIV_CEIL => CanBeReplacedBy(NumDivCeilUnchecked), Symbol::NUM_DIV_CEIL => CanBeReplacedBy(NumDivCeilUnchecked),
Symbol::NUM_DIV_CEIL_CHECKED => WrapperIsRequired, Symbol::NUM_DIV_CEIL_CHECKED => WrapperIsRequired,
Symbol::NUM_REM => WrapperIsRequired, Symbol::NUM_REM => CanBeReplacedBy(NumRemUnchecked),
Symbol::NUM_REM_CHECKED => WrapperIsRequired,
Symbol::NUM_MOD => CanBeReplacedBy(NumModUnchecked),
Symbol::NUM_MOD_CHECKED => 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),
Symbol::NUM_NEG => CanBeReplacedBy(NumNeg), Symbol::NUM_NEG => CanBeReplacedBy(NumNeg),
Symbol::NUM_SIN => CanBeReplacedBy(NumSin), Symbol::NUM_SIN => CanBeReplacedBy(NumSin),
Symbol::NUM_COS => CanBeReplacedBy(NumCos), Symbol::NUM_COS => CanBeReplacedBy(NumCos),
Symbol::NUM_SQRT => WrapperIsRequired, Symbol::NUM_SQRT => CanBeReplacedBy(NumSqrtUnchecked),
Symbol::NUM_LOG => WrapperIsRequired, Symbol::NUM_SQRT_CHECKED => WrapperIsRequired,
Symbol::NUM_LOG => CanBeReplacedBy(NumLogUnchecked),
Symbol::NUM_LOG_CHECKED => WrapperIsRequired,
Symbol::NUM_ROUND => CanBeReplacedBy(NumRound), Symbol::NUM_ROUND => CanBeReplacedBy(NumRound),
Symbol::NUM_TO_FLOAT => CanBeReplacedBy(NumToFloat), Symbol::NUM_TO_FLOAT => CanBeReplacedBy(NumToFloat),
Symbol::NUM_POW => CanBeReplacedBy(NumPow), Symbol::NUM_POW => CanBeReplacedBy(NumPow),

View file

@ -950,8 +950,8 @@ define_builtins! {
41 NUM_DIV_FLOAT_CHECKED: "divChecked" 41 NUM_DIV_FLOAT_CHECKED: "divChecked"
42 NUM_DIV_FLOOR: "divFloor" 42 NUM_DIV_FLOOR: "divFloor"
43 NUM_DIV_FLOOR_CHECKED: "divFloorChecked" 43 NUM_DIV_FLOOR_CHECKED: "divFloorChecked"
44 NUM_MOD_INT: "modInt" 44 NUM_MOD: "mod"
45 NUM_MOD_INT_CHECKED: "modIntChecked" 45 NUM_MOD_CHECKED: "modChecked"
46 NUM_MOD_FLOAT: "modFloat" 46 NUM_MOD_FLOAT: "modFloat"
47 NUM_MOD_FLOAT_CHECKED: "modFloatChecked" 47 NUM_MOD_FLOAT_CHECKED: "modFloatChecked"
48 NUM_SQRT: "sqrt" 48 NUM_SQRT: "sqrt"

View file

@ -994,10 +994,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
| NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulChecked | NumGt | NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulChecked | NumGt
| NumGte | NumLt | NumLte | NumCompare | NumDivUnchecked | NumDivCeilUnchecked | NumGte | NumLt | NumLte | NumCompare | NumDivUnchecked | NumDivCeilUnchecked
| NumRemUnchecked | NumIsMultipleOf | NumPow | NumPowInt | NumBitwiseAnd | NumRemUnchecked | NumModUnchecked | NumIsMultipleOf | NumPow | NumPowInt
| NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy | NumShiftRightZfBy => { | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy
arena.alloc_slice_copy(&[irrelevant, irrelevant]) | NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
}
NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked
| NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos

View file

@ -144,6 +144,7 @@ enum FirstOrder {
NumCompare, NumCompare,
NumDivUnchecked, NumDivUnchecked,
NumRemUnchecked, NumRemUnchecked,
NumModUnchecked,
NumIsMultipleOf, NumIsMultipleOf,
NumAbs, NumAbs,
NumNeg, NumNeg,

View file

@ -2534,7 +2534,7 @@ fn list_keep_oks() {
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
"List.keepOks [1,2] (\\x -> x % 2)", "List.keepOks [1,2] (\\x -> Num.remChecked x 2)",
RocList::from_slice(&[1, 0]), RocList::from_slice(&[1, 0]),
RocList<i64> RocList<i64>
); );
@ -2561,7 +2561,7 @@ fn list_keep_errs() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
List.keepErrs [0,1,2] (\x -> x % 0 |> Result.mapErr (\_ -> 32)) List.keepErrs [0,1,2] (\x -> Num.remChecked x 0 |> Result.mapErr (\_ -> 32))
"# "#
), ),
RocList::from_slice(&[32, 32, 32]), RocList::from_slice(&[32, 32, 32]),

View file

@ -473,7 +473,7 @@ fn f64_sqrt() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.sqrt 100 is when Num.sqrtChecked 100 is
Ok val -> val Ok val -> val
Err _ -> -1 Err _ -> -1
"# "#
@ -489,9 +489,7 @@ fn f64_log() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.log 7.38905609893 is Num.log 7.38905609893
Ok val -> val
Err _ -> -1
"# "#
), ),
1.999999999999912, 1.999999999999912,
@ -501,11 +499,11 @@ fn f64_log() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn f64_log_one() { fn f64_log_checked_one() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.log 1 is when Num.logChecked 1 is
Ok val -> val Ok val -> val
Err _ -> -1 Err _ -> -1
"# "#
@ -521,7 +519,7 @@ fn f64_sqrt_zero() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.sqrt 0 is when Num.sqrtChecked 0 is
Ok val -> val Ok val -> val
Err _ -> -1 Err _ -> -1
"# "#
@ -533,11 +531,11 @@ fn f64_sqrt_zero() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn f64_sqrt_negative() { fn f64_sqrt_checked_negative() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.sqrt -1 is when Num.sqrtChecked -1 is
Err _ -> 42 Err _ -> 42
Ok val -> val Ok val -> val
"# "#
@ -549,11 +547,11 @@ fn f64_sqrt_negative() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn f64_log_zero() { fn f64_log_checked_zero() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.log 0 is when Num.logChecked 0 is
Err _ -> 42 Err _ -> 42
Ok val -> val Ok val -> val
"# "#
@ -569,13 +567,12 @@ fn f64_log_negative() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.log -1 is Num.log -1
Err _ -> 42
Ok val -> val
"# "#
), ),
42.0, true,
f64 f64,
|f: f64| f.is_nan()
); );
} }
@ -1082,9 +1079,7 @@ fn gen_rem_i64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.rem 8 3 is Num.rem 8 3
Ok val -> val
Err _ -> -1
"# "#
), ),
2, 2,
@ -1094,11 +1089,11 @@ fn gen_rem_i64() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn gen_rem_div_by_zero_i64() { fn gen_rem_checked_div_by_zero_i64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Num.rem 8 0 is when Num.remChecked 8 0 is
Err DivByZero -> 4 Err DivByZero -> 4
Ok _ -> -23 Ok _ -> -23
"# "#

View file

@ -41,7 +41,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 : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
divmod = \l, r -> divmod = \l, r ->
when Pair (l // r) (l % r) is when Pair (Num.divFloorChecked l r) (Num.remChecked l r) is
Pair div (Ok mod) -> Pair div (Ok mod) ->
Ok { div, mod } Ok { div, mod }

View file

@ -23,12 +23,12 @@ makeMapHelp = \freq, n, m, acc ->
_ -> _ ->
powerOf10 = powerOf10 =
(n % 10 |> resultWithDefault 0) == 0 n % 10 == 0
m1 = insert m n powerOf10 m1 = insert m n powerOf10
isFrequency = isFrequency =
(n % freq |> resultWithDefault 0) == 0 n % freq == 0
x = (if isFrequency then Cons m1 acc else acc) x = (if isFrequency then Cons m1 acc else acc)
@ -43,15 +43,6 @@ fold = \f, tree, b ->
Node _ l k v r -> Node _ l k v r ->
fold f r (f k v (fold f l b)) fold f r (f k v (fold f l b))
resultWithDefault : Result a e, a -> a
resultWithDefault = \res, default ->
when res is
Ok v ->
v
Err _ ->
default
main : Task.Task {} [] main : Task.Task {} []
main = main =
Task.after Task.after

View file

@ -56,7 +56,7 @@ fn float_addition() {
#[cfg(not(feature = "wasm"))] #[cfg(not(feature = "wasm"))]
#[test] #[test]
fn num_rem() { fn num_rem() {
expect_success("299 % 10", "Ok 9 : Result (Int *) [ DivByZero ]*"); expect_success("299 % 10", "9 : Int *");
} }
#[cfg(not(feature = "wasm"))] #[cfg(not(feature = "wasm"))]