mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
Merge remote-tracking branch 'origin/trunk' into mono-lowlevel
This commit is contained in:
commit
031c7cc2e2
20 changed files with 447 additions and 165 deletions
8
AUTHORS
8
AUTHORS
|
@ -28,3 +28,11 @@ Ju Liu <ju@noredink.com>
|
|||
Peter Fields <pcfields@gmail.com>
|
||||
Brian J. Cardiff <bcardiff@gmail.com>
|
||||
Basile Henry <bjm.henry@gmail.com>
|
||||
Tarjei Skjærset <tskj@tarjei.org>
|
||||
Brian Hicks <brian@brianthicks.com>
|
||||
Dan Gieschen Knutson <dan.knutson@gmail.com>
|
||||
Joshua Hoeflich <joshuaharry411@icloud.com>
|
||||
Brian Carroll <brian.carroll.ireland@gmail.com>
|
||||
Kofi Gumbs <h.kofigumbs@gmail.com>
|
||||
Luiz de Oliveira <luizcarlos1405@gmail.com>
|
||||
Chelsea Troy <chelsea.dommert@gmail.com>
|
||||
|
|
|
@ -535,16 +535,21 @@ fn single_tag_union_to_ast<'a>(
|
|||
tag_name: &TagName,
|
||||
payload_vars: &[Variable],
|
||||
) -> Expr<'a> {
|
||||
debug_assert_eq!(field_layouts.len(), payload_vars.len());
|
||||
|
||||
let arena = env.arena;
|
||||
|
||||
let tag_expr = tag_name_to_expr(env, tag_name);
|
||||
|
||||
let loc_tag_expr = &*arena.alloc(Located::at_zero(tag_expr));
|
||||
|
||||
let output = if field_layouts.len() == payload_vars.len() {
|
||||
let it = payload_vars.iter().copied().zip(field_layouts);
|
||||
let output = sequence_of_expr(env, ptr as *const u8, it).into_bump_slice();
|
||||
sequence_of_expr(env, ptr as *const u8, it).into_bump_slice()
|
||||
} else if field_layouts.is_empty() && !payload_vars.is_empty() {
|
||||
// happens for e.g. `Foo Bar` where unit structures are nested and the inner one is dropped
|
||||
let it = payload_vars.iter().copied().zip([&Layout::Struct(&[])]);
|
||||
sequence_of_expr(env, ptr as *const u8, it).into_bump_slice()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
Expr::Apply(loc_tag_expr, output, CalledVia::Space)
|
||||
}
|
||||
|
|
|
@ -103,6 +103,24 @@ mod repl_eval {
|
|||
expect_success("299 % 10", "Ok 9 : Result (Int *) [ DivByZero ]*");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn num_floor_division_success() {
|
||||
expect_success("Num.divFloor 4 3", "Ok 1 : Result (Int *) [ DivByZero ]*");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn num_floor_division_divby_zero() {
|
||||
expect_success(
|
||||
"Num.divFloor 4 0",
|
||||
"Err DivByZero : Result (Int *) [ DivByZero ]*",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn num_ceil_division_success() {
|
||||
expect_success("Num.divCeil 4 3", "Ok 2 : Result (Int *) [ DivByZero ]*")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bool_in_record() {
|
||||
expect_success("{ x: 1 == 1 }", "{ x: True } : { x : Bool }");
|
||||
|
@ -167,6 +185,11 @@ mod repl_eval {
|
|||
expect_success("Foo 1 3.14", "Foo 1 3.14 : [ Foo (Num *) (Float *) ]*");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn newtype_of_unit() {
|
||||
expect_success("Foo Bar", "Foo Bar : [ Foo [ Bar ]* ]*");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tag_with_arguments() {
|
||||
expect_success("True 1", "True 1 : [ True (Num *) ]*");
|
||||
|
@ -307,7 +330,7 @@ mod repl_eval {
|
|||
expect_success("Num.addChecked 1 1", "Ok 2 : Result (Num *) [ Overflow ]*");
|
||||
expect_success(
|
||||
"Num.addChecked Num.maxInt 1",
|
||||
"Err (Overflow) : Result I64 [ Overflow ]*",
|
||||
"Err Overflow : Result I64 [ Overflow ]*",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -316,7 +339,7 @@ mod repl_eval {
|
|||
expect_success("Num.subChecked 1 1", "Ok 0 : Result (Num *) [ Overflow ]*");
|
||||
expect_success(
|
||||
"Num.subChecked Num.minInt 1",
|
||||
"Err (Overflow) : Result I64 [ Overflow ]*",
|
||||
"Err Overflow : Result I64 [ Overflow ]*",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -328,7 +351,7 @@ mod repl_eval {
|
|||
);
|
||||
expect_success(
|
||||
"Num.mulChecked Num.maxInt 2",
|
||||
"Err (Overflow) : Result I64 [ Overflow ]*",
|
||||
"Err Overflow : Result I64 [ Overflow ]*",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -362,7 +385,7 @@ mod repl_eval {
|
|||
);
|
||||
expect_success(
|
||||
"List.first []",
|
||||
"Err (ListWasEmpty) : Result * [ ListWasEmpty ]*",
|
||||
"Err ListWasEmpty : Result * [ ListWasEmpty ]*",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -375,7 +398,7 @@ mod repl_eval {
|
|||
|
||||
expect_success(
|
||||
"List.last []",
|
||||
"Err (ListWasEmpty) : Result * [ ListWasEmpty ]*",
|
||||
"Err ListWasEmpty : Result * [ ListWasEmpty ]*",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ comptime {
|
|||
exportNumFn(num.atan, "atan");
|
||||
exportNumFn(num.isFinite, "is_finite");
|
||||
exportNumFn(num.powInt, "pow_int");
|
||||
exportNumFn(num.divCeil, "div_ceil");
|
||||
exportNumFn(num.acos, "acos");
|
||||
exportNumFn(num.asin, "asin");
|
||||
exportNumFn(num.bytesToU16C, "bytes_to_u16");
|
||||
|
|
|
@ -15,6 +15,10 @@ pub fn powInt(base: i64, exp: i64) callconv(.C) i64 {
|
|||
return @call(.{ .modifier = always_inline }, math.pow, .{ i64, base, exp });
|
||||
}
|
||||
|
||||
pub fn divCeil(numerator: i64, denominator: i64) callconv(.C) i64 {
|
||||
return @call(.{ .modifier = always_inline }, math.divCeil, .{ i64, numerator, denominator }) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn acos(num: f64) callconv(.C) f64 {
|
||||
return @call(.{ .modifier = always_inline }, math.acos, .{num});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ pub const NUM_ACOS: &str = "roc_builtins.num.acos";
|
|||
pub const NUM_ATAN: &str = "roc_builtins.num.atan";
|
||||
pub const NUM_IS_FINITE: &str = "roc_builtins.num.is_finite";
|
||||
pub const NUM_POW_INT: &str = "roc_builtins.num.pow_int";
|
||||
pub const NUM_DIV_CEIL: &str = "roc_builtins.num.div_ceil";
|
||||
pub const NUM_BYTES_TO_U16: &str = "roc_builtins.num.bytes_to_u16";
|
||||
pub const NUM_BYTES_TO_U32: &str = "roc_builtins.num.bytes_to_u32";
|
||||
pub const NUM_ROUND: &str = "roc_builtins.num.round";
|
||||
|
|
|
@ -293,18 +293,25 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
// minInt : Int range
|
||||
add_type!(Symbol::NUM_MIN_INT, int_type(flex(TVAR1)));
|
||||
|
||||
// divInt : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||
let div_by_zero = SolvedType::TagUnion(
|
||||
vec![(TagName::Global("DivByZero".into()), vec![])],
|
||||
Box::new(SolvedType::Wildcard),
|
||||
);
|
||||
|
||||
// divInt : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||
add_top_level_function_type!(
|
||||
Symbol::NUM_DIV_INT,
|
||||
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
||||
Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
|
||||
);
|
||||
|
||||
//divCeil: Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||
add_top_level_function_type!(
|
||||
Symbol::NUM_DIV_CEIL,
|
||||
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
||||
Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
|
||||
);
|
||||
|
||||
// bitwiseAnd : Int a, Int a -> Int a
|
||||
add_top_level_function_type!(
|
||||
Symbol::NUM_BITWISE_AND,
|
||||
|
|
|
@ -143,6 +143,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
NUM_TAN => num_tan,
|
||||
NUM_DIV_FLOAT => num_div_float,
|
||||
NUM_DIV_INT => num_div_int,
|
||||
NUM_DIV_CEIL => num_div_ceil,
|
||||
NUM_ABS => num_abs,
|
||||
NUM_NEG => num_neg,
|
||||
NUM_REM => num_rem,
|
||||
|
@ -2844,6 +2845,72 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
)
|
||||
}
|
||||
|
||||
/// Num.divCeil : Int a , Int a -> Result (Int a) [ DivByZero ]*
|
||||
fn num_div_ceil(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let bool_var = var_store.fresh();
|
||||
let num_var = var_store.fresh();
|
||||
let unbound_zero_var = var_store.fresh();
|
||||
let unbound_zero_precision_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.neq denominator 0
|
||||
RunLowLevel {
|
||||
op: LowLevel::NotEq,
|
||||
args: vec![
|
||||
(num_var, Var(Symbol::ARG_2)),
|
||||
(
|
||||
num_var,
|
||||
int(unbound_zero_var, unbound_zero_precision_var, 0),
|
||||
),
|
||||
],
|
||||
ret_var: bool_var,
|
||||
},
|
||||
),
|
||||
// denominator was not zero
|
||||
no_region(
|
||||
// Ok (Int.#divUnchecked numerator denominator)
|
||||
tag(
|
||||
"Ok",
|
||||
vec![
|
||||
// Num.#divUnchecked numerator denominator
|
||||
RunLowLevel {
|
||||
op: LowLevel::NumDivCeilUnchecked,
|
||||
args: vec![
|
||||
(num_var, Var(Symbol::ARG_1)),
|
||||
(num_var, Var(Symbol::ARG_2)),
|
||||
],
|
||||
ret_var: num_var,
|
||||
},
|
||||
],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
)],
|
||||
final_else: Box::new(
|
||||
// denominator was zero
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.first : List elem -> Result elem [ ListWasEmpty ]*
|
||||
///
|
||||
/// List.first :
|
||||
|
|
|
@ -18,7 +18,7 @@ use roc_region::all::Located;
|
|||
/// Just (Just a)
|
||||
/// List (List a)
|
||||
/// reverse (reverse l)
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum Parens {
|
||||
NotNeeded,
|
||||
InFunctionType,
|
||||
|
|
|
@ -133,10 +133,14 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
|||
}
|
||||
}
|
||||
ParensAround(sub_expr) => {
|
||||
if parens == Parens::NotNeeded && !sub_expr_requests_parens(sub_expr) {
|
||||
sub_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
} else {
|
||||
buf.push('(');
|
||||
sub_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
Str(literal) => {
|
||||
use roc_parse::ast::StrLiteral::*;
|
||||
|
||||
|
@ -199,7 +203,7 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
|||
buf.push_str(name);
|
||||
}
|
||||
Apply(loc_expr, loc_args, _) => {
|
||||
if apply_needs_parens {
|
||||
if apply_needs_parens && !loc_args.is_empty() {
|
||||
buf.push('(');
|
||||
}
|
||||
|
||||
|
@ -221,7 +225,7 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if apply_needs_parens {
|
||||
if apply_needs_parens && !loc_args.is_empty() {
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +319,7 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
|||
buf.push_str(key);
|
||||
}
|
||||
Access(expr, key) => {
|
||||
expr.format_with_options(buf, parens, Newlines::Yes, indent);
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
buf.push('.');
|
||||
buf.push_str(key);
|
||||
}
|
||||
|
@ -394,6 +398,8 @@ fn fmt_bin_ops<'a>(
|
|||
|| lefts.iter().any(|(expr, _)| expr.value.is_multiline());
|
||||
|
||||
for (loc_left_side, loc_bin_op) in lefts {
|
||||
let bin_op = loc_bin_op.value;
|
||||
|
||||
loc_left_side.format_with_options(buf, apply_needs_parens, Newlines::No, indent);
|
||||
|
||||
if is_multiline {
|
||||
|
@ -402,7 +408,7 @@ fn fmt_bin_ops<'a>(
|
|||
buf.push(' ');
|
||||
}
|
||||
|
||||
push_op(buf, loc_bin_op.value);
|
||||
push_op(buf, bin_op);
|
||||
|
||||
buf.push(' ');
|
||||
}
|
||||
|
@ -1046,3 +1052,32 @@ fn format_field_multiline<'a, T>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
||||
match expr {
|
||||
Expr::BinOps(left_side, _) => {
|
||||
left_side
|
||||
.iter()
|
||||
.any(|(_, loc_bin_op)| match loc_bin_op.value {
|
||||
BinOp::Caret
|
||||
| BinOp::Star
|
||||
| BinOp::Slash
|
||||
| BinOp::DoubleSlash
|
||||
| BinOp::Percent
|
||||
| BinOp::DoublePercent
|
||||
| BinOp::Plus
|
||||
| BinOp::Minus
|
||||
| BinOp::Equals
|
||||
| BinOp::NotEquals
|
||||
| BinOp::LessThan
|
||||
| BinOp::GreaterThan
|
||||
| BinOp::LessThanOrEq
|
||||
| BinOp::GreaterThanOrEq
|
||||
| BinOp::And
|
||||
| BinOp::Or => true,
|
||||
BinOp::Pizza | BinOp::Assignment | BinOp::HasType | BinOp::Backpassing => false,
|
||||
})
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -362,32 +362,57 @@ mod test_fmt {
|
|||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn defs_with_defs() {
|
||||
// expr_formats_to(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// x =
|
||||
// y = 4
|
||||
// z = 8
|
||||
// w
|
||||
#[test]
|
||||
fn excess_parens() {
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
x = (5)
|
||||
|
||||
// x
|
||||
// "#
|
||||
// ),
|
||||
// indoc!(
|
||||
// r#"
|
||||
// x =
|
||||
// y = 4
|
||||
// z = 8
|
||||
|
||||
// w
|
||||
y = ((10))
|
||||
|
||||
// x
|
||||
// "#
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
42
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
x = 5
|
||||
|
||||
y = 10
|
||||
|
||||
42
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defs_with_defs() {
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
x =
|
||||
y = 4
|
||||
z = 8
|
||||
w
|
||||
|
||||
x
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
x =
|
||||
y = 4
|
||||
z = 8
|
||||
|
||||
w
|
||||
|
||||
x
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_between_two_defs() {
|
||||
|
@ -548,15 +573,16 @@ mod test_fmt {
|
|||
));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn record_field_destructuring() {
|
||||
// expr_formats_same(indoc!(
|
||||
// r#"
|
||||
// when foo is
|
||||
// { x: 5 } -> 42
|
||||
// "#
|
||||
// ));
|
||||
// }
|
||||
#[test]
|
||||
fn record_field_destructuring() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
when foo is
|
||||
{ x: 5 } ->
|
||||
42
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_updating() {
|
||||
|
@ -917,24 +943,43 @@ mod test_fmt {
|
|||
"#
|
||||
));
|
||||
|
||||
// expr_formats_to(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// identity = \a
|
||||
// -> a
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
identity = \a
|
||||
-> a
|
||||
|
||||
// identity 41
|
||||
// "#
|
||||
// ),
|
||||
// indoc!(
|
||||
// r#"
|
||||
// identity = \a ->
|
||||
// a
|
||||
identity 41
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
identity = \a -> a
|
||||
|
||||
// identity 41
|
||||
// "#
|
||||
// ),
|
||||
// );
|
||||
identity 41
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
identity = \a
|
||||
->
|
||||
a + b
|
||||
|
||||
identity 4010
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
identity = \a ->
|
||||
a + b
|
||||
|
||||
identity 4010
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
|
@ -956,7 +1001,7 @@ mod test_fmt {
|
|||
// identity 43
|
||||
// "#
|
||||
// ));
|
||||
//
|
||||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
identity = \a,
|
||||
|
@ -1212,17 +1257,17 @@ mod test_fmt {
|
|||
}
|
||||
#[test]
|
||||
fn multi_line_list_def() {
|
||||
// expr_formats_same(indoc!(
|
||||
// r#"
|
||||
// l =
|
||||
// [
|
||||
// 1,
|
||||
// 2
|
||||
// ]
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
l =
|
||||
[
|
||||
1,
|
||||
2,
|
||||
]
|
||||
|
||||
// l
|
||||
// "#
|
||||
// ));
|
||||
l
|
||||
"#
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
|
@ -1248,32 +1293,32 @@ mod test_fmt {
|
|||
),
|
||||
);
|
||||
|
||||
// expr_formats_to(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// results =
|
||||
// # Let's count past 6
|
||||
// [
|
||||
// Ok 6,
|
||||
// Err CountError
|
||||
// ]
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
results =
|
||||
# Let's count past 6
|
||||
[
|
||||
Ok 6,
|
||||
Err CountError
|
||||
]
|
||||
|
||||
// allOks results
|
||||
// "#
|
||||
// ),
|
||||
// indoc!(
|
||||
// r#"
|
||||
// results =
|
||||
// # Let's count past 6
|
||||
// [
|
||||
// Ok 6,
|
||||
// Err CountError
|
||||
// ]
|
||||
allOks results
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
results =
|
||||
# Let's count past 6
|
||||
[
|
||||
Ok 6,
|
||||
Err CountError,
|
||||
]
|
||||
|
||||
// allOks results
|
||||
// "#
|
||||
// ),
|
||||
// );
|
||||
allOks results
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// RECORD LITERALS
|
||||
|
@ -1330,18 +1375,18 @@ mod test_fmt {
|
|||
|
||||
#[test]
|
||||
fn multi_line_record_def() {
|
||||
// expr_formats_same(indoc!(
|
||||
// r#"
|
||||
// pos =
|
||||
// {
|
||||
// x: 4,
|
||||
// y: 11,
|
||||
// z: 16
|
||||
// }
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
pos =
|
||||
{
|
||||
x: 4,
|
||||
y: 11,
|
||||
z: 16,
|
||||
}
|
||||
|
||||
// pos
|
||||
// "#
|
||||
// ));
|
||||
pos
|
||||
"#
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
|
@ -2204,7 +2249,7 @@ mod test_fmt {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn precedence_conflict_exponents() {
|
||||
fn binop_parens() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
if 4 == (6 ^ 6 ^ 7 ^ 8) then
|
||||
|
@ -2213,6 +2258,39 @@ mod test_fmt {
|
|||
"Naturally"
|
||||
"#
|
||||
));
|
||||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
if 5 == 1 ^ 1 ^ 1 ^ 1 then
|
||||
"Not buying it"
|
||||
else
|
||||
"True"
|
||||
"#
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
if (1 == 1)
|
||||
&& (2 == 1) && (3 == 2) then
|
||||
"true"
|
||||
else
|
||||
"false"
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
if
|
||||
(1 == 1)
|
||||
&& (2 == 1)
|
||||
&& (3 == 2)
|
||||
then
|
||||
"true"
|
||||
else
|
||||
"false"
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -5295,8 +5295,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
|
||||
| NumIsMultipleOf | NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt
|
||||
| NumSubWrap | NumSubChecked | NumMulWrap | NumMulChecked => {
|
||||
| NumIsMultipleOf | NumAddWrap | NumAddChecked | NumDivUnchecked | NumDivCeilUnchecked
|
||||
| NumPow | NumPowInt | NumSubWrap | NumSubChecked | NumMulWrap | NumMulChecked => {
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
|
@ -6041,6 +6041,9 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
|||
}
|
||||
NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
|
||||
NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_POW_INT),
|
||||
NumDivCeilUnchecked => {
|
||||
call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_DIV_CEIL)
|
||||
}
|
||||
NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(),
|
||||
NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(),
|
||||
NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(),
|
||||
|
|
|
@ -736,11 +736,40 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(modification_block);
|
||||
|
||||
if element_layout.contains_refcounted() {
|
||||
let ptr_type = basic_type_from_layout(env, element_layout).ptr_type(AddressSpace::Generic);
|
||||
|
||||
if element_layout.contains_refcounted() {
|
||||
let (len, ptr) = load_list(env.builder, original_wrapper, ptr_type);
|
||||
|
||||
let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, ptr);
|
||||
let call_mode = mode_to_call_mode(fn_val, mode);
|
||||
|
||||
match mode {
|
||||
Mode::Inc => {
|
||||
// inc is cheap; we never recurse
|
||||
refcount_ptr.modify(call_mode, layout, env);
|
||||
builder.build_unconditional_branch(cont_block);
|
||||
}
|
||||
|
||||
Mode::Dec => {
|
||||
let do_recurse_block = env.context.append_basic_block(parent, "do_recurse");
|
||||
let no_recurse_block = env.context.append_basic_block(parent, "no_recurse");
|
||||
|
||||
builder.build_conditional_branch(
|
||||
refcount_ptr.is_1(env),
|
||||
do_recurse_block,
|
||||
no_recurse_block,
|
||||
);
|
||||
|
||||
{
|
||||
env.builder.position_at_end(no_recurse_block);
|
||||
|
||||
refcount_ptr.modify(call_mode, layout, env);
|
||||
builder.build_unconditional_branch(cont_block);
|
||||
}
|
||||
|
||||
{
|
||||
env.builder.position_at_end(do_recurse_block);
|
||||
|
||||
let loop_fn = |_index, element| {
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
|
@ -754,13 +783,21 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
incrementing_elem_loop(env, parent, ptr, len, "modify_rc_index", loop_fn);
|
||||
builder.build_unconditional_branch(cont_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// just increment/decrement the list itself, don't touch the elements
|
||||
let (_, ptr) = load_list(env.builder, original_wrapper, ptr_type);
|
||||
|
||||
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper);
|
||||
let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, ptr);
|
||||
let call_mode = mode_to_call_mode(fn_val, mode);
|
||||
|
||||
refcount_ptr.modify(call_mode, layout, env);
|
||||
|
||||
builder.build_unconditional_branch(cont_block);
|
||||
}
|
||||
|
||||
builder.position_at_end(cont_block);
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ pub enum LowLevel {
|
|||
NumLte,
|
||||
NumCompare,
|
||||
NumDivUnchecked,
|
||||
NumDivCeilUnchecked,
|
||||
NumRemUnchecked,
|
||||
NumIsMultipleOf,
|
||||
NumAbs,
|
||||
|
@ -165,6 +166,7 @@ macro_rules! first_order {
|
|||
| NumLte
|
||||
| NumCompare
|
||||
| NumDivUnchecked
|
||||
| NumDivCeilUnchecked
|
||||
| NumRemUnchecked
|
||||
| NumIsMultipleOf
|
||||
| NumAbs
|
||||
|
|
|
@ -943,6 +943,7 @@ define_builtins! {
|
|||
103 NUM_BYTES_TO_U16: "bytesToU16"
|
||||
104 NUM_BYTES_TO_U32: "bytesToU32"
|
||||
105 NUM_CAST_TO_NAT: "#castToNat"
|
||||
106 NUM_DIV_CEIL: "divCeil"
|
||||
}
|
||||
2 BOOL: "Bool" => {
|
||||
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
||||
|
|
|
@ -953,9 +953,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
|
||||
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumSubWrap | NumSubChecked
|
||||
| NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare
|
||||
| NumDivUnchecked | NumRemUnchecked | NumIsMultipleOf | NumPow | NumPowInt
|
||||
| NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy
|
||||
| NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
|
||||
| NumDivUnchecked | NumDivCeilUnchecked | NumRemUnchecked | NumIsMultipleOf | NumPow
|
||||
| NumPowInt | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy
|
||||
| NumShiftRightBy | NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
|
||||
|
||||
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked | NumRound
|
||||
| NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin
|
||||
|
|
|
@ -1778,7 +1778,6 @@ fn union_sorted_tags_help_new<'a>(
|
|||
|
||||
// just one tag in the union (but with arguments) can be a struct
|
||||
let mut layouts = Vec::with_capacity_in(tags_vec.len(), arena);
|
||||
let mut contains_zero_sized = false;
|
||||
|
||||
// special-case NUM_AT_NUM: if its argument is a FlexVar, make it Int
|
||||
match tag_name {
|
||||
|
@ -1791,12 +1790,7 @@ fn union_sorted_tags_help_new<'a>(
|
|||
let var = subs[var_index];
|
||||
match Layout::from_var(&mut env, var) {
|
||||
Ok(layout) => {
|
||||
// Drop any zero-sized arguments like {}
|
||||
if !layout.is_dropped_because_empty() {
|
||||
layouts.push(layout);
|
||||
} else {
|
||||
contains_zero_sized = true;
|
||||
}
|
||||
}
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
// If we encounter an unbound type var (e.g. `Ok *`)
|
||||
|
@ -1821,11 +1815,7 @@ fn union_sorted_tags_help_new<'a>(
|
|||
});
|
||||
|
||||
if layouts.is_empty() {
|
||||
if contains_zero_sized {
|
||||
UnionVariant::UnitWithArguments
|
||||
} else {
|
||||
UnionVariant::Unit
|
||||
}
|
||||
} else if opt_rec_var.is_some() {
|
||||
UnionVariant::Wrapped(WrappedVariant::NonNullableUnwrapped {
|
||||
tag_name,
|
||||
|
|
|
@ -3305,6 +3305,18 @@ mod solve_expr {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn div_ceil() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
Num.divCeil
|
||||
"#
|
||||
),
|
||||
"Int a, Int a -> Result (Int a) [ DivByZero ]*",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pow_int() {
|
||||
infer_eq_without_problem(
|
||||
|
|
|
@ -397,7 +397,15 @@ fn subs_fmt_flat_type(this: &FlatType, subs: &Subs, f: &mut fmt::Formatter) -> f
|
|||
|
||||
write!(f, "]<{:?}>", new_ext)
|
||||
}
|
||||
FlatType::FunctionOrTagUnion(_, _, _) => todo!(),
|
||||
FlatType::FunctionOrTagUnion(tagname_index, symbol, ext) => {
|
||||
let tagname: &TagName = &subs[*tagname_index];
|
||||
|
||||
write!(
|
||||
f,
|
||||
"FunctionOrTagUnion({:?}, {:?}, {:?})",
|
||||
tagname, symbol, ext
|
||||
)
|
||||
}
|
||||
FlatType::RecursiveTagUnion(rec, tags, ext) => {
|
||||
write!(f, "[ ")?;
|
||||
|
||||
|
|
|
@ -77,11 +77,11 @@ export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
|||
std.process.exit(0);
|
||||
}
|
||||
|
||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void{
|
||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
||||
return memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void{
|
||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue