Merge remote-tracking branch 'origin/gen-equality' into dict-insert

This commit is contained in:
Folkert 2021-02-13 19:45:33 +01:00
commit e7efcb74e6
6 changed files with 1495 additions and 149 deletions

View file

@ -11,8 +11,7 @@ use crate::llvm::build_str::{
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,
};
use crate::llvm::compare::{build_eq, build_neq};
use crate::llvm::compare::{generic_eq, generic_neq};
use crate::llvm::convert::{
basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices,
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 (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 => {
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 (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 => {
// The (&&) operator

View file

@ -1,7 +1,7 @@
use crate::llvm::build::{
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::refcounting::{
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 has_found = build_eq(
let has_found = generic_eq(
env,
layout_ids,
current_elem,

File diff suppressed because it is too large Load diff

View 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
);
}
}

View file

@ -741,10 +741,14 @@ define_builtins! {
11 DEC: "#dec" // internal function that increments the refcount
12 ARG_CLOSURE: "#arg_closure" // symbol used to store the closure record
13 LIST_EQ: "#list_eq" // internal function that checks list equality
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
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
18 GENERIC_EQ: "#generic_eq" // internal function that checks generic equality
}
1 NUM: "Num" => {
0 NUM_NUM: "Num" imported // the Num.Num type alias

View file

@ -19,6 +19,28 @@ use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
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)]
pub enum MonoProblem {
PatternProblem(crate::exhaustive::Error),
@ -3790,11 +3812,10 @@ pub fn with_hole<'a>(
)
.into_bump_slice();
let full_layout = layout_cache
.from_var(env.arena, fn_var, env.subs)
.unwrap_or_else(|err| {
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
});
let full_layout = return_on_layout_error!(
env,
layout_cache.from_var(env.arena, fn_var, env.subs)
);
let arg_layouts = match full_layout {
Layout::FunctionPointer(args, _) => args,
@ -3802,11 +3823,10 @@ pub fn with_hole<'a>(
_ => unreachable!("function has layout that is not function pointer"),
};
let ret_layout = layout_cache
.from_var(env.arena, ret_var, env.subs)
.unwrap_or_else(|err| {
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
});
let ret_layout = return_on_layout_error!(
env,
layout_cache.from_var(env.arena, ret_var, env.subs)
);
// if the function expression (loc_expr) is already a symbol,
// re-use that symbol, and don't define its value again