mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Merge branch 'trunk' into new_num_layer
This commit is contained in:
commit
eda5b72060
9 changed files with 356 additions and 31 deletions
|
@ -260,6 +260,16 @@ mod repl_eval {
|
||||||
expect_success("Num.bitwiseAnd 200 0", "0 : I64")
|
expect_success("Num.bitwiseAnd 200 0", "0 : I64")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn num_add_wrap() {
|
||||||
|
expect_success("Num.addWrap Num.maxInt 1", "-9223372036854775808 : I64");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn num_sub_wrap() {
|
||||||
|
expect_success("Num.subWrap Num.minInt 1", "9223372036854775807 : I64");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_concat() {
|
fn list_concat() {
|
||||||
expect_success(
|
expect_success(
|
||||||
|
|
|
@ -75,7 +75,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// addChecked : Num a, Num a -> Result (Num a) [ IntOverflow ]*
|
// addChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||||
let overflow = SolvedType::TagUnion(
|
let overflow = SolvedType::TagUnion(
|
||||||
vec![(TagName::Global("Overflow".into()), vec![])],
|
vec![(TagName::Global("Overflow".into()), vec![])],
|
||||||
Box::new(SolvedType::Wildcard),
|
Box::new(SolvedType::Wildcard),
|
||||||
|
@ -85,7 +85,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
Symbol::NUM_ADD_CHECKED,
|
Symbol::NUM_ADD_CHECKED,
|
||||||
top_level_function(
|
top_level_function(
|
||||||
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
|
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
|
||||||
Box::new(result_type(num_type(flex(TVAR1)), overflow)),
|
Box::new(result_type(num_type(flex(TVAR1)), overflow.clone())),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -104,6 +104,21 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// subWrap : Int, Int -> Int
|
||||||
|
add_type(
|
||||||
|
Symbol::NUM_SUB_WRAP,
|
||||||
|
top_level_function(vec![int_type(), int_type()], Box::new(int_type())),
|
||||||
|
);
|
||||||
|
|
||||||
|
// subChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||||
|
add_type(
|
||||||
|
Symbol::NUM_SUB_CHECKED,
|
||||||
|
top_level_function(
|
||||||
|
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
|
||||||
|
Box::new(result_type(num_type(flex(TVAR1)), overflow)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// mul or (*) : Num a, Num a -> Num a
|
// mul or (*) : Num a, Num a -> Num a
|
||||||
add_type(
|
add_type(
|
||||||
Symbol::NUM_MUL,
|
Symbol::NUM_MUL,
|
||||||
|
|
|
@ -148,17 +148,19 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num))
|
unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num))
|
||||||
});
|
});
|
||||||
|
|
||||||
// addChecked : Num a, Num a -> Result (Num a) [ IntOverflow ]*
|
fn overflow() -> SolvedType {
|
||||||
let overflow = SolvedType::TagUnion(
|
SolvedType::TagUnion(
|
||||||
vec![(TagName::Global("Overflow".into()), vec![])],
|
vec![(TagName::Global("Overflow".into()), vec![])],
|
||||||
Box::new(SolvedType::Wildcard),
|
Box::new(SolvedType::Wildcard),
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||||
add_type(Symbol::NUM_ADD_CHECKED, {
|
add_type(Symbol::NUM_ADD_CHECKED, {
|
||||||
let_tvars! { u, v, w, num, result, star };
|
let_tvars! { u, v, w, num, result, star };
|
||||||
unique_function(
|
unique_function(
|
||||||
vec![num_type(u, num), num_type(v, num)],
|
vec![num_type(u, num), num_type(v, num)],
|
||||||
result_type(result, num_type(w, num), lift(star, overflow)),
|
result_type(result, num_type(w, num), lift(star, overflow())),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -174,6 +176,21 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num))
|
unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// subWrap : Int, Int -> Int
|
||||||
|
add_type(Symbol::NUM_SUB_WRAP, {
|
||||||
|
let_tvars! { u, v, w, num };
|
||||||
|
unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num))
|
||||||
|
});
|
||||||
|
|
||||||
|
// subChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||||
|
add_type(Symbol::NUM_SUB_CHECKED, {
|
||||||
|
let_tvars! { u, v, w, num, result, star };
|
||||||
|
unique_function(
|
||||||
|
vec![num_type(u, num), num_type(v, num)],
|
||||||
|
result_type(result, num_type(w, num), lift(star, overflow())),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
// mul or (*) : Num a, Num a -> Num a
|
// mul or (*) : Num a, Num a -> Num a
|
||||||
add_type(Symbol::NUM_MUL, {
|
add_type(Symbol::NUM_MUL, {
|
||||||
let_tvars! { u, v, w, num };
|
let_tvars! { u, v, w, num };
|
||||||
|
|
|
@ -82,6 +82,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
NUM_ADD_CHECKED => num_add_checked,
|
NUM_ADD_CHECKED => num_add_checked,
|
||||||
NUM_ADD_WRAP => num_add_wrap,
|
NUM_ADD_WRAP => num_add_wrap,
|
||||||
NUM_SUB => num_sub,
|
NUM_SUB => num_sub,
|
||||||
|
NUM_SUB_WRAP => num_sub_wrap,
|
||||||
|
NUM_SUB_CHECKED => num_sub_checked,
|
||||||
NUM_MUL => num_mul,
|
NUM_MUL => num_mul,
|
||||||
NUM_GT => num_gt,
|
NUM_GT => num_gt,
|
||||||
NUM_GTE => num_gte,
|
NUM_GTE => num_gte,
|
||||||
|
@ -373,12 +375,12 @@ fn num_add(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
num_binop(symbol, var_store, LowLevel::NumAdd)
|
num_binop(symbol, var_store, LowLevel::NumAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.add : Num a, Num a -> Num a
|
/// Num.addWrap : Int, Int -> Int
|
||||||
fn num_add_wrap(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_add_wrap(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
num_binop(symbol, var_store, LowLevel::NumAddWrap)
|
num_binop(symbol, var_store, LowLevel::NumAddWrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.add : Num a, Num a -> Num a
|
/// Num.addChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||||
fn num_add_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_add_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let bool_var = var_store.fresh();
|
let bool_var = var_store.fresh();
|
||||||
let num_var_1 = var_store.fresh();
|
let num_var_1 = var_store.fresh();
|
||||||
|
@ -472,6 +474,100 @@ fn num_sub(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
num_binop(symbol, var_store, LowLevel::NumSub)
|
num_binop(symbol, var_store, LowLevel::NumSub)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Num.subWrap : Int, Int -> Int
|
||||||
|
fn num_sub_wrap(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
num_binop(symbol, var_store, LowLevel::NumSubWrap)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Num.subChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||||
|
fn num_sub_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
|
let num_var_1 = var_store.fresh();
|
||||||
|
let num_var_2 = var_store.fresh();
|
||||||
|
let num_var_3 = var_store.fresh();
|
||||||
|
let ret_var = var_store.fresh();
|
||||||
|
let record_var = var_store.fresh();
|
||||||
|
|
||||||
|
// let arg_3 = RunLowLevel NumSubChecked arg_1 arg_2
|
||||||
|
//
|
||||||
|
// if arg_3.b then
|
||||||
|
// # overflow
|
||||||
|
// Err Overflow
|
||||||
|
// else
|
||||||
|
// # all is well
|
||||||
|
// Ok arg_3.a
|
||||||
|
|
||||||
|
let cont = If {
|
||||||
|
branch_var: ret_var,
|
||||||
|
cond_var: bool_var,
|
||||||
|
branches: vec![(
|
||||||
|
// if-condition
|
||||||
|
no_region(
|
||||||
|
// arg_3.b
|
||||||
|
Access {
|
||||||
|
record_var,
|
||||||
|
ext_var: var_store.fresh(),
|
||||||
|
field: "b".into(),
|
||||||
|
field_var: var_store.fresh(),
|
||||||
|
loc_expr: Box::new(no_region(Var(Symbol::ARG_3))),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// overflow!
|
||||||
|
no_region(tag(
|
||||||
|
"Err",
|
||||||
|
vec![tag("Overflow", Vec::new(), var_store)],
|
||||||
|
var_store,
|
||||||
|
)),
|
||||||
|
)],
|
||||||
|
final_else: Box::new(
|
||||||
|
// all is well
|
||||||
|
no_region(
|
||||||
|
// Ok arg_3.a
|
||||||
|
tag(
|
||||||
|
"Ok",
|
||||||
|
vec![
|
||||||
|
// arg_3.a
|
||||||
|
Access {
|
||||||
|
record_var,
|
||||||
|
ext_var: var_store.fresh(),
|
||||||
|
field: "a".into(),
|
||||||
|
field_var: num_var_3,
|
||||||
|
loc_expr: Box::new(no_region(Var(Symbol::ARG_3))),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
var_store,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// arg_3 = RunLowLevel NumSubChecked arg_1 arg_2
|
||||||
|
let def = crate::def::Def {
|
||||||
|
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_3)),
|
||||||
|
loc_expr: no_region(RunLowLevel {
|
||||||
|
op: LowLevel::NumSubChecked,
|
||||||
|
args: vec![
|
||||||
|
(num_var_1, Var(Symbol::ARG_1)),
|
||||||
|
(num_var_2, Var(Symbol::ARG_2)),
|
||||||
|
],
|
||||||
|
ret_var: record_var,
|
||||||
|
}),
|
||||||
|
expr_var: record_var,
|
||||||
|
pattern_vars: SendMap::default(),
|
||||||
|
annotation: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let body = LetNonRec(Box::new(def), Box::new(no_region(cont)), ret_var);
|
||||||
|
|
||||||
|
defn(
|
||||||
|
symbol,
|
||||||
|
vec![(num_var_1, Symbol::ARG_1), (num_var_2, Symbol::ARG_2)],
|
||||||
|
var_store,
|
||||||
|
body,
|
||||||
|
ret_var,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Num.mul : Num a, Num a -> Num a
|
/// Num.mul : Num a, Num a -> Num a
|
||||||
fn num_mul(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_mul(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
num_binop(symbol, var_store, LowLevel::NumMul)
|
num_binop(symbol, var_store, LowLevel::NumMul)
|
||||||
|
@ -1952,7 +2048,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
len_var,
|
len_var,
|
||||||
// Num.sub (List.len list) 1
|
// Num.sub (List.len list) 1
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumSub,
|
op: LowLevel::NumSubWrap,
|
||||||
args: vec![
|
args: vec![
|
||||||
(
|
(
|
||||||
arg_var,
|
arg_var,
|
||||||
|
|
|
@ -349,6 +349,12 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
|
||||||
ctx.struct_type(&fields, false)
|
ctx.struct_type(&fields, false)
|
||||||
.fn_type(&[i64_type.into(), i64_type.into()], false)
|
.fn_type(&[i64_type.into(), i64_type.into()], false)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_intrinsic(module, LLVM_SSUB_WITH_OVERFLOW_I64, {
|
||||||
|
let fields = [i64_type.into(), i1_type.into()];
|
||||||
|
ctx.struct_type(&fields, false)
|
||||||
|
.fn_type(&[i64_type.into(), i64_type.into()], false)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64";
|
static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64";
|
||||||
|
@ -362,6 +368,7 @@ static LLVM_POW_F64: &str = "llvm.pow.f64";
|
||||||
static LLVM_CEILING_F64: &str = "llvm.ceil.f64";
|
static LLVM_CEILING_F64: &str = "llvm.ceil.f64";
|
||||||
static LLVM_FLOOR_F64: &str = "llvm.floor.f64";
|
static LLVM_FLOOR_F64: &str = "llvm.floor.f64";
|
||||||
pub static LLVM_SADD_WITH_OVERFLOW_I64: &str = "llvm.sadd.with.overflow.i64";
|
pub static LLVM_SADD_WITH_OVERFLOW_I64: &str = "llvm.sadd.with.overflow.i64";
|
||||||
|
pub static LLVM_SSUB_WITH_OVERFLOW_I64: &str = "llvm.ssub.with.overflow.i64";
|
||||||
|
|
||||||
fn add_intrinsic<'ctx>(
|
fn add_intrinsic<'ctx>(
|
||||||
module: &Module<'ctx>,
|
module: &Module<'ctx>,
|
||||||
|
@ -2995,7 +3002,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
|
|
||||||
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
|
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
|
||||||
| NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt => {
|
| NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt | NumSubWrap
|
||||||
|
| NumSubChecked => {
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(env, scope, &args[0]);
|
let (lhs_arg, lhs_layout) = load_symbol_and_layout(env, scope, &args[0]);
|
||||||
|
@ -3220,7 +3228,37 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
NumAddWrap => bd.build_int_add(lhs, rhs, "add_int_wrap").into(),
|
NumAddWrap => bd.build_int_add(lhs, rhs, "add_int_wrap").into(),
|
||||||
NumAddChecked => env.call_intrinsic(LLVM_SADD_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]),
|
NumAddChecked => env.call_intrinsic(LLVM_SADD_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]),
|
||||||
NumSub => bd.build_int_sub(lhs, rhs, "sub_int").into(),
|
NumSub => {
|
||||||
|
let context = env.context;
|
||||||
|
let result = env
|
||||||
|
.call_intrinsic(LLVM_SSUB_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()])
|
||||||
|
.into_struct_value();
|
||||||
|
|
||||||
|
let sub_result = bd.build_extract_value(result, 0, "sub_result").unwrap();
|
||||||
|
let has_overflowed = bd.build_extract_value(result, 1, "has_overflowed").unwrap();
|
||||||
|
|
||||||
|
let condition = bd.build_int_compare(
|
||||||
|
IntPredicate::EQ,
|
||||||
|
has_overflowed.into_int_value(),
|
||||||
|
context.bool_type().const_zero(),
|
||||||
|
"has_not_overflowed",
|
||||||
|
);
|
||||||
|
|
||||||
|
let then_block = context.append_basic_block(parent, "then_block");
|
||||||
|
let throw_block = context.append_basic_block(parent, "throw_block");
|
||||||
|
|
||||||
|
bd.build_conditional_branch(condition, then_block, throw_block);
|
||||||
|
|
||||||
|
bd.position_at_end(throw_block);
|
||||||
|
|
||||||
|
throw_exception(env, "integer subtraction overflowed!");
|
||||||
|
|
||||||
|
bd.position_at_end(then_block);
|
||||||
|
|
||||||
|
sub_result
|
||||||
|
}
|
||||||
|
NumSubWrap => bd.build_int_sub(lhs, rhs, "sub_int").into(),
|
||||||
|
NumSubChecked => env.call_intrinsic(LLVM_SSUB_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]),
|
||||||
NumMul => bd.build_int_mul(lhs, rhs, "mul_int").into(),
|
NumMul => bd.build_int_mul(lhs, rhs, "mul_int").into(),
|
||||||
NumGt => bd.build_int_compare(SGT, lhs, rhs, "int_gt").into(),
|
NumGt => bd.build_int_compare(SGT, lhs, rhs, "int_gt").into(),
|
||||||
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
|
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
|
||||||
|
@ -3388,7 +3426,55 @@ fn build_float_binop<'a, 'ctx, 'env>(
|
||||||
struct_value.into()
|
struct_value.into()
|
||||||
}
|
}
|
||||||
NumAddWrap => unreachable!("wrapping addition is not defined on floats"),
|
NumAddWrap => unreachable!("wrapping addition is not defined on floats"),
|
||||||
NumSub => bd.build_float_sub(lhs, rhs, "sub_float").into(),
|
NumSub => {
|
||||||
|
let builder = env.builder;
|
||||||
|
let context = env.context;
|
||||||
|
|
||||||
|
let result = bd.build_float_sub(lhs, rhs, "sub_float");
|
||||||
|
|
||||||
|
let is_finite =
|
||||||
|
call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE).into_int_value();
|
||||||
|
|
||||||
|
let then_block = context.append_basic_block(parent, "then_block");
|
||||||
|
let throw_block = context.append_basic_block(parent, "throw_block");
|
||||||
|
|
||||||
|
builder.build_conditional_branch(is_finite, then_block, throw_block);
|
||||||
|
|
||||||
|
builder.position_at_end(throw_block);
|
||||||
|
|
||||||
|
throw_exception(env, "float subtraction overflowed!");
|
||||||
|
|
||||||
|
builder.position_at_end(then_block);
|
||||||
|
|
||||||
|
result.into()
|
||||||
|
}
|
||||||
|
NumSubChecked => {
|
||||||
|
let context = env.context;
|
||||||
|
|
||||||
|
let result = bd.build_float_sub(lhs, rhs, "sub_float");
|
||||||
|
|
||||||
|
let is_finite =
|
||||||
|
call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE).into_int_value();
|
||||||
|
let is_infinite = bd.build_not(is_finite, "negate");
|
||||||
|
|
||||||
|
let struct_type = context.struct_type(
|
||||||
|
&[context.f64_type().into(), context.bool_type().into()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
let struct_value = {
|
||||||
|
let v1 = struct_type.const_zero();
|
||||||
|
let v2 = bd.build_insert_value(v1, result, 0, "set_result").unwrap();
|
||||||
|
let v3 = bd
|
||||||
|
.build_insert_value(v2, is_infinite, 1, "set_is_infinite")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
v3.into_struct_value()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct_value.into()
|
||||||
|
}
|
||||||
|
NumSubWrap => unreachable!("wrapping subtraction is not defined on floats"),
|
||||||
NumMul => bd.build_float_mul(lhs, rhs, "mul_float").into(),
|
NumMul => bd.build_float_mul(lhs, rhs, "mul_float").into(),
|
||||||
NumGt => bd.build_float_compare(OGT, lhs, rhs, "float_gt").into(),
|
NumGt => bd.build_float_compare(OGT, lhs, rhs, "float_gt").into(),
|
||||||
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
|
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
|
||||||
|
|
|
@ -622,7 +622,7 @@ mod gen_num {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
|
#[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
|
||||||
fn int_overflow() {
|
fn int_add_overflow() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -704,19 +704,19 @@ mod gen_num {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// #[should_panic(expected = r#"Roc failed with message: "float addition overflowed!"#)]
|
#[should_panic(expected = r#"Roc failed with message: "float addition overflowed!"#)]
|
||||||
// fn float_overflow() {
|
fn float_add_overflow() {
|
||||||
// assert_evals_to!(
|
assert_evals_to!(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// 1.7976931348623157e308 + 1.7976931348623157e308
|
1.7976931348623157e308 + 1.7976931348623157e308
|
||||||
// "#
|
"#
|
||||||
// ),
|
),
|
||||||
// 0.0,
|
0.0,
|
||||||
// f64
|
f64
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn num_max_int() {
|
fn num_max_int() {
|
||||||
|
@ -743,4 +743,99 @@ mod gen_num {
|
||||||
i64
|
i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = r#"Roc failed with message: "integer subtraction overflowed!"#)]
|
||||||
|
fn int_sub_overflow() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
-9_223_372_036_854_775_808 - 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn int_sub_wrap() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Num.subWrap -9_223_372_036_854_775_808 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
std::i64::MAX,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = r#"Roc failed with message: "float subtraction overflowed!"#)]
|
||||||
|
fn float_sub_overflow() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
-1.7976931348623157e308 - 1.7976931348623157e308
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
0.0,
|
||||||
|
f64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn int_sub_checked() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when Num.subChecked 1 2 is
|
||||||
|
Ok v -> v
|
||||||
|
_ -> -1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
-1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when Num.subChecked Num.minInt 1 is
|
||||||
|
Err Overflow -> -1
|
||||||
|
Ok v -> v
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
-1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn float_sub_checked() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when Num.subChecked 1.0 0.0 is
|
||||||
|
Ok v -> v
|
||||||
|
Err Overflow -> -1.0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1.0,
|
||||||
|
f64
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when Num.subChecked -1.7976931348623157e308 1.7976931348623157e308 is
|
||||||
|
Err Overflow -> -1
|
||||||
|
Ok v -> v
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
-1.0,
|
||||||
|
f64
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ pub enum LowLevel {
|
||||||
NumAddWrap,
|
NumAddWrap,
|
||||||
NumAddChecked,
|
NumAddChecked,
|
||||||
NumSub,
|
NumSub,
|
||||||
|
NumSubWrap,
|
||||||
|
NumSubChecked,
|
||||||
NumMul,
|
NumMul,
|
||||||
NumGt,
|
NumGt,
|
||||||
NumGte,
|
NumGte,
|
||||||
|
|
|
@ -822,6 +822,8 @@ define_builtins! {
|
||||||
79 NUM_AT_BINARY32: "@Binary32"
|
79 NUM_AT_BINARY32: "@Binary32"
|
||||||
80 NUM_BINARY32: "Binary32" imported
|
80 NUM_BINARY32: "Binary32" imported
|
||||||
81 NUM_BITWISE_AND: "bitwiseAnd"
|
81 NUM_BITWISE_AND: "bitwiseAnd"
|
||||||
|
82 NUM_SUB_WRAP: "subWrap"
|
||||||
|
83 NUM_SUB_CHECKED: "subChecked"
|
||||||
}
|
}
|
||||||
2 BOOL: "Bool" => {
|
2 BOOL: "Bool" => {
|
||||||
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
||||||
|
|
|
@ -539,9 +539,11 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
ListWalkBackwards => arena.alloc_slice_copy(&[borrowed, irrelevant, owned]),
|
ListWalkBackwards => arena.alloc_slice_copy(&[borrowed, irrelevant, owned]),
|
||||||
ListSum => arena.alloc_slice_copy(&[borrowed]),
|
ListSum => arena.alloc_slice_copy(&[borrowed]),
|
||||||
|
|
||||||
Eq | NotEq | And | Or | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumMul | NumGt
|
Eq | NotEq | And | Or | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumSubWrap
|
||||||
| NumGte | NumLt | NumLte | NumCompare | NumDivUnchecked | NumRemUnchecked | NumPow
|
| NumSubChecked | NumMul | NumGt | NumGte | NumLt | NumLte | NumCompare
|
||||||
| NumPowInt | NumBitwiseAnd => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
|
| NumDivUnchecked | NumRemUnchecked | NumPow | NumPowInt | NumBitwiseAnd => {
|
||||||
|
arena.alloc_slice_copy(&[irrelevant, irrelevant])
|
||||||
|
}
|
||||||
|
|
||||||
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumRound | NumCeiling | NumFloor
|
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumRound | NumCeiling | NumFloor
|
||||||
| NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin => {
|
| NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue