mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +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_KEEP_IF => list_keep_if,
|
||||||
Symbol::LIST_WALK_RIGHT => list_walk_right,
|
Symbol::LIST_WALK_RIGHT => list_walk_right,
|
||||||
Symbol::NUM_ADD => num_add,
|
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_SUB => num_sub,
|
||||||
Symbol::NUM_MUL => num_mul,
|
Symbol::NUM_MUL => num_mul,
|
||||||
Symbol::NUM_GT => num_gt,
|
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_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
|
/// Num.sub : Num a, Num a -> Num a
|
||||||
fn num_sub(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_sub(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
num_binop(symbol, var_store, LowLevel::NumSub)
|
num_binop(symbol, var_store, LowLevel::NumSub)
|
||||||
|
|
|
@ -2467,7 +2467,7 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
add_result
|
add_result
|
||||||
}
|
}
|
||||||
NumAddWrap => bd.build_int_add(lhs, rhs, "add_int_wrap").into(),
|
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(),
|
NumSub => bd.build_int_sub(lhs, rhs, "sub_int").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(),
|
||||||
|
|
|
@ -699,4 +699,57 @@ mod gen_num {
|
||||||
i64
|
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