mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
integer addition operations
This commit is contained in:
parent
f732eb3e83
commit
95177eee5a
4 changed files with 184 additions and 1 deletions
|
@ -68,6 +68,8 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
|
|||
Symbol::LIST_KEEP_IF => list_keep_if,
|
||||
Symbol::LIST_WALK_RIGHT => list_walk_right,
|
||||
Symbol::NUM_ADD => num_add,
|
||||
Symbol::NUM_ADD_CHECKED => num_add_checked,
|
||||
Symbol::NUM_ADD_WRAP => num_add_wrap,
|
||||
Symbol::NUM_SUB => num_sub,
|
||||
Symbol::NUM_MUL => num_mul,
|
||||
Symbol::NUM_GT => num_gt,
|
||||
|
@ -238,6 +240,107 @@ fn num_add(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
num_binop(symbol, var_store, LowLevel::NumAdd)
|
||||
}
|
||||
|
||||
/// Num.add : Num a, Num a -> Num a
|
||||
fn num_add_wrap(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
num_binop(symbol, var_store, LowLevel::NumAddWrap)
|
||||
}
|
||||
|
||||
/// Num.add : Num a, Num a -> Num a
|
||||
fn num_add_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 NumAddChecked arg_1 arg_2
|
||||
//
|
||||
// if arg_3.b then
|
||||
// # overflow
|
||||
// Err IntOverflow
|
||||
// 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(
|
||||
// Num.neq denominator 0
|
||||
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("DivByZero", Vec::new(), var_store)],
|
||||
var_store,
|
||||
)),
|
||||
)],
|
||||
final_else: Box::new(
|
||||
// all is well
|
||||
no_region(
|
||||
// Ok (Float.#divUnchecked numerator denominator)
|
||||
tag(
|
||||
"Ok",
|
||||
vec![
|
||||
// Num.#divUnchecked numerator denominator
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
let def = crate::def::Def {
|
||||
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_3)),
|
||||
loc_expr: no_region(
|
||||
// Num.neq denominator 0
|
||||
RunLowLevel {
|
||||
op: LowLevel::NumAddChecked,
|
||||
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,
|
||||
SendMap::default(),
|
||||
);
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(num_var_1, Symbol::ARG_1), (num_var_2, Symbol::ARG_2)],
|
||||
var_store,
|
||||
body,
|
||||
ret_var,
|
||||
)
|
||||
}
|
||||
|
||||
/// Num.sub : Num a, Num a -> Num a
|
||||
fn num_sub(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
num_binop(symbol, var_store, LowLevel::NumSub)
|
||||
|
|
|
@ -2467,7 +2467,7 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
|||
add_result
|
||||
}
|
||||
NumAddWrap => bd.build_int_add(lhs, rhs, "add_int_wrap").into(),
|
||||
NumAddChecked => bd.build_int_add(lhs, rhs, "add_int_checked").into(),
|
||||
NumAddChecked => env.call_intrinsic(LLVM_SADD_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]),
|
||||
NumSub => bd.build_int_sub(lhs, rhs, "sub_int").into(),
|
||||
NumMul => bd.build_int_mul(lhs, rhs, "mul_int").into(),
|
||||
NumGt => bd.build_int_compare(SGT, lhs, rhs, "int_gt").into(),
|
||||
|
|
|
@ -699,4 +699,57 @@ mod gen_num {
|
|||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_checked() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.addChecked 1 2 is
|
||||
Ok 3 -> True
|
||||
_ -> False
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.addChecked 9_223_372_036_854_775_807 1 is
|
||||
Err IntOverflow -> True
|
||||
_ -> False
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_wrap() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Num.addWrap 9_223_372_036_854_775_807 1
|
||||
"#
|
||||
),
|
||||
std::i64::MIN,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_overflow() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
1.7976931348623157E+308 + 1
|
||||
"#
|
||||
),
|
||||
0.0,
|
||||
f64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3847,4 +3847,31 @@ mod test_reporting {
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn foobar() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
Num.addChecked 1 2
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── REDUNDANT PATTERN ───────────────────────────────────────────────────────────
|
||||
|
||||
The 3rd pattern is redundant:
|
||||
|
||||
1│ when Foo 1 2 3 is
|
||||
2│ Foo _ 1 _ -> 1
|
||||
3│ _ -> 2
|
||||
4│ _ -> 3
|
||||
^
|
||||
|
||||
Any value of this shape will be handled by a previous pattern, so this
|
||||
one should be removed.
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue