mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
Merge remote-tracking branch 'origin/gen-equality' into dict-insert
This commit is contained in:
commit
e7efcb74e6
6 changed files with 1495 additions and 149 deletions
|
@ -11,8 +11,7 @@ use crate::llvm::build_str::{
|
||||||
str_concat, str_count_graphemes, str_ends_with, str_from_int, str_join_with,
|
str_concat, str_count_graphemes, str_ends_with, str_from_int, str_join_with,
|
||||||
str_number_of_bytes, str_split, str_starts_with, CHAR_LAYOUT,
|
str_number_of_bytes, str_split, str_starts_with, CHAR_LAYOUT,
|
||||||
};
|
};
|
||||||
|
use crate::llvm::compare::{generic_eq, generic_neq};
|
||||||
use crate::llvm::compare::{build_eq, build_neq};
|
|
||||||
use crate::llvm::convert::{
|
use crate::llvm::convert::{
|
||||||
basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices,
|
basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices,
|
||||||
collection, get_fn_type, get_ptr_type, ptr_int,
|
collection, get_fn_type, get_ptr_type, ptr_int,
|
||||||
|
@ -3860,7 +3859,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
let (rhs_arg, rhs_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (rhs_arg, rhs_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
build_eq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
generic_eq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
||||||
}
|
}
|
||||||
NotEq => {
|
NotEq => {
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
@ -3868,7 +3867,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
let (rhs_arg, rhs_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (rhs_arg, rhs_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
build_neq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
generic_neq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
||||||
}
|
}
|
||||||
And => {
|
And => {
|
||||||
// The (&&) operator
|
// The (&&) operator
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::llvm::build::{
|
use crate::llvm::build::{
|
||||||
allocate_with_refcount_help, build_num_binop, cast_basic_basic, Env, InPlace,
|
allocate_with_refcount_help, build_num_binop, cast_basic_basic, Env, InPlace,
|
||||||
};
|
};
|
||||||
use crate::llvm::compare::build_eq;
|
use crate::llvm::compare::generic_eq;
|
||||||
use crate::llvm::convert::{basic_type_from_layout, collection, get_ptr_type};
|
use crate::llvm::convert::{basic_type_from_layout, collection, get_ptr_type};
|
||||||
use crate::llvm::refcounting::{
|
use crate::llvm::refcounting::{
|
||||||
decrement_refcount_layout, increment_refcount_layout, refcount_is_one_comparison,
|
decrement_refcount_layout, increment_refcount_layout, refcount_is_one_comparison,
|
||||||
|
@ -1114,7 +1114,7 @@ pub fn list_contains_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let current_elem = builder.build_load(current_elem_ptr, "load_elem");
|
let current_elem = builder.build_load(current_elem_ptr, "load_elem");
|
||||||
|
|
||||||
let has_found = build_eq(
|
let has_found = generic_eq(
|
||||||
env,
|
env,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
current_elem,
|
current_elem,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
419
compiler/gen/tests/gen_compare.rs
Normal file
419
compiler/gen/tests/gen_compare.rs
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate pretty_assertions;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate indoc;
|
||||||
|
|
||||||
|
extern crate bumpalo;
|
||||||
|
extern crate inkwell;
|
||||||
|
extern crate libc;
|
||||||
|
extern crate roc_gen;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod gen_num {
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_i64() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
i : I64
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
i == i
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn neq_i64() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
i : I64
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
i != i
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_u64() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
i : U64
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
i == i
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn neq_u64() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
i : U64
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
i != i
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_f64() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
i : F64
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
i == i
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn neq_f64() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
i : F64
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
i != i
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_bool_tag() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
true : Bool
|
||||||
|
true = True
|
||||||
|
|
||||||
|
true == True
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn neq_bool_tag() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
true : Bool
|
||||||
|
true = True
|
||||||
|
|
||||||
|
true == False
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_record() {
|
||||||
|
assert_evals_to!("{} == {}", true, bool);
|
||||||
|
assert_evals_to!("{} != {}", false, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unit() {
|
||||||
|
assert_evals_to!("Unit == Unit", true, bool);
|
||||||
|
assert_evals_to!("Unit != Unit", false, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype() {
|
||||||
|
assert_evals_to!("Identity 42 == Identity 42", true, bool);
|
||||||
|
assert_evals_to!("Identity 42 != Identity 42", false, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn small_str() {
|
||||||
|
assert_evals_to!("\"aaa\" == \"aaa\"", true, bool);
|
||||||
|
assert_evals_to!("\"aaa\" == \"bbb\"", false, bool);
|
||||||
|
assert_evals_to!("\"aaa\" != \"aaa\"", false, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn large_str() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x = "Unicode can represent text values which span multiple languages"
|
||||||
|
y = "Unicode can represent text values which span multiple languages"
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x = "Unicode can represent text values which span multiple languages"
|
||||||
|
y = "Here are some valid Roc strings"
|
||||||
|
|
||||||
|
x != y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_result_tag_true() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : Result I64 I64
|
||||||
|
x = Ok 1
|
||||||
|
|
||||||
|
y : Result I64 I64
|
||||||
|
y = Ok 1
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_result_tag_false() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : Result I64 I64
|
||||||
|
x = Ok 1
|
||||||
|
|
||||||
|
y : Result I64 I64
|
||||||
|
y = Err 1
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_expr() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Expr : [ Add Expr Expr, Mul Expr Expr, Val I64, Var I64 ]
|
||||||
|
|
||||||
|
x : Expr
|
||||||
|
x = Val 0
|
||||||
|
|
||||||
|
y : Expr
|
||||||
|
y = Val 0
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_linked_list() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
x : LinkedList I64
|
||||||
|
x = Nil
|
||||||
|
|
||||||
|
y : LinkedList I64
|
||||||
|
y = Nil
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
x : LinkedList I64
|
||||||
|
x = Cons 1 Nil
|
||||||
|
|
||||||
|
y : LinkedList I64
|
||||||
|
y = Cons 1 Nil
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
x : LinkedList I64
|
||||||
|
x = Cons 1 (Cons 2 Nil)
|
||||||
|
|
||||||
|
y : LinkedList I64
|
||||||
|
y = Cons 1 (Cons 2 Nil)
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_linked_list_false() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
x : LinkedList I64
|
||||||
|
x = Cons 1 Nil
|
||||||
|
|
||||||
|
y : LinkedList I64
|
||||||
|
y = Cons 1 (Cons 2 Nil)
|
||||||
|
|
||||||
|
y == x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_nullable_expr() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Expr : [ Add Expr Expr, Mul Expr Expr, Val I64, Empty ]
|
||||||
|
|
||||||
|
x : Expr
|
||||||
|
x = Val 0
|
||||||
|
|
||||||
|
y : Expr
|
||||||
|
y = Add x x
|
||||||
|
|
||||||
|
x != y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_rosetree() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Rose a : [ Rose (List (Rose a)) ]
|
||||||
|
|
||||||
|
x : Rose I64
|
||||||
|
x = Rose []
|
||||||
|
|
||||||
|
y : Rose I64
|
||||||
|
y = Rose []
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Rose a : [ Rose (List (Rose a)) ]
|
||||||
|
|
||||||
|
x : Rose I64
|
||||||
|
x = Rose []
|
||||||
|
|
||||||
|
y : Rose I64
|
||||||
|
y = Rose []
|
||||||
|
|
||||||
|
x != y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn rosetree_with_tag() {
|
||||||
|
// currently stack overflows in type checking
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Rose a : [ Rose (Result (List (Rose a)) I64) ]
|
||||||
|
|
||||||
|
x : Rose I64
|
||||||
|
x = (Rose (Ok []))
|
||||||
|
|
||||||
|
y : Rose I64
|
||||||
|
y = (Rose (Ok []))
|
||||||
|
|
||||||
|
x == y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -741,10 +741,14 @@ define_builtins! {
|
||||||
11 DEC: "#dec" // internal function that increments the refcount
|
11 DEC: "#dec" // internal function that increments the refcount
|
||||||
12 ARG_CLOSURE: "#arg_closure" // symbol used to store the closure record
|
12 ARG_CLOSURE: "#arg_closure" // symbol used to store the closure record
|
||||||
13 LIST_EQ: "#list_eq" // internal function that checks list equality
|
13 LIST_EQ: "#list_eq" // internal function that checks list equality
|
||||||
|
|
||||||
14 GENERIC_HASH: "#generic_hash" // hash of arbitrary layouts
|
14 GENERIC_HASH: "#generic_hash" // hash of arbitrary layouts
|
||||||
15 GENERIC_HASH_REF: "#generic_hash_by_ref" // hash of arbitrary layouts, passed as an opaque pointer
|
15 GENERIC_HASH_REF: "#generic_hash_by_ref" // hash of arbitrary layouts, passed as an opaque pointer
|
||||||
|
|
||||||
16 GENERIC_EQ_REF: "#generic_eq_by_ref" // equality of arbitrary layouts, passed as an opaque pointer
|
16 GENERIC_EQ_REF: "#generic_eq_by_ref" // equality of arbitrary layouts, passed as an opaque pointer
|
||||||
17 GENERIC_RC_REF: "#generic_rc_by_ref" // refcount of arbitrary layouts, passed as an opaque pointer
|
17 GENERIC_RC_REF: "#generic_rc_by_ref" // refcount of arbitrary layouts, passed as an opaque pointer
|
||||||
|
|
||||||
|
18 GENERIC_EQ: "#generic_eq" // internal function that checks generic equality
|
||||||
}
|
}
|
||||||
1 NUM: "Num" => {
|
1 NUM: "Num" => {
|
||||||
0 NUM_NUM: "Num" imported // the Num.Num type alias
|
0 NUM_NUM: "Num" imported // the Num.Num type alias
|
||||||
|
|
|
@ -19,6 +19,28 @@ use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||||
|
|
||||||
pub const PRETTY_PRINT_IR_SYMBOLS: bool = false;
|
pub const PRETTY_PRINT_IR_SYMBOLS: bool = false;
|
||||||
|
|
||||||
|
macro_rules! return_on_layout_error {
|
||||||
|
($env:expr, $layout_result:expr) => {
|
||||||
|
match $layout_result {
|
||||||
|
Ok(cached) => cached,
|
||||||
|
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||||
|
return Stmt::RuntimeError($env.arena.alloc(format!(
|
||||||
|
"UnresolvedTypeVar {} line {}",
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Err(LayoutProblem::Erroneous) => {
|
||||||
|
return Stmt::RuntimeError($env.arena.alloc(format!(
|
||||||
|
"Erroneous {} line {}",
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum MonoProblem {
|
pub enum MonoProblem {
|
||||||
PatternProblem(crate::exhaustive::Error),
|
PatternProblem(crate::exhaustive::Error),
|
||||||
|
@ -3790,11 +3812,10 @@ pub fn with_hole<'a>(
|
||||||
)
|
)
|
||||||
.into_bump_slice();
|
.into_bump_slice();
|
||||||
|
|
||||||
let full_layout = layout_cache
|
let full_layout = return_on_layout_error!(
|
||||||
.from_var(env.arena, fn_var, env.subs)
|
env,
|
||||||
.unwrap_or_else(|err| {
|
layout_cache.from_var(env.arena, fn_var, env.subs)
|
||||||
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
|
);
|
||||||
});
|
|
||||||
|
|
||||||
let arg_layouts = match full_layout {
|
let arg_layouts = match full_layout {
|
||||||
Layout::FunctionPointer(args, _) => args,
|
Layout::FunctionPointer(args, _) => args,
|
||||||
|
@ -3802,11 +3823,10 @@ pub fn with_hole<'a>(
|
||||||
_ => unreachable!("function has layout that is not function pointer"),
|
_ => unreachable!("function has layout that is not function pointer"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret_layout = layout_cache
|
let ret_layout = return_on_layout_error!(
|
||||||
.from_var(env.arena, ret_var, env.subs)
|
env,
|
||||||
.unwrap_or_else(|err| {
|
layout_cache.from_var(env.arena, ret_var, env.subs)
|
||||||
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
|
);
|
||||||
});
|
|
||||||
|
|
||||||
// if the function expression (loc_expr) is already a symbol,
|
// if the function expression (loc_expr) is already a symbol,
|
||||||
// re-use that symbol, and don't define its value again
|
// re-use that symbol, and don't define its value again
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue