From 3af6d5f0b3eab5ea2bbf91193d573cc2e235288b Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Fri, 19 Jun 2020 21:02:52 -0400 Subject: [PATCH 01/22] WIP --- compiler/builtins/src/std.rs | 9 +++ compiler/builtins/src/unique.rs | 24 ++++++++ compiler/gen/src/llvm/build.rs | 99 ++++++++++++++++++++++++++++++ compiler/gen/tests/gen_builtins.rs | 9 +++ compiler/module/src/symbol.rs | 1 + 5 files changed, 142 insertions(+) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index db3edf7173..5c55933fe0 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -513,6 +513,15 @@ pub fn types() -> MutMap { SolvedType::Func(vec![flex(TVAR1)], Box::new(list_type(flex(TVAR1)))), ); + // repeat : Int, a -> List a + add_type( + Symbol::LIST_REPEAT, + SolvedType::Func( + vec![int_type(), flex(TVAR1)], + Box::new(list_type(flex(TVAR1))), + ), + ); + // len : List * -> Int add_type( Symbol::LIST_LEN, diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 546747f06a..760ec6ef06 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -615,6 +615,30 @@ pub fn types() -> MutMap { ) }); + // repeat : Int, a -> List a + add_type(Symbol::LIST_REPEAT, { + let u = UVAR1; + let v = UVAR2; + let star1 = UVAR4; + let star2 = UVAR5; + + let a = TVAR1; + + unique_function( + vec![ + int_type(star1), + SolvedType::Apply(Symbol::ATTR_ATTR, vec![disjunction(u, vec![v]), flex(a)]), + ], + SolvedType::Apply( + Symbol::ATTR_ATTR, + vec![ + boolean(star2), + SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + ], + ), + ) + }); + // push : Attr (w | u | v) (List (Attr u a)) // , Attr (u | v) a // -> Attr * (List (Attr u a)) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 5ba7350734..1276ae20c9 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -1470,6 +1470,105 @@ fn call_with_args<'a, 'ctx, 'env>( "cast_collection", ) } + Symbol::LIST_REPEAT => { + // List.repeat : Int, a -> List a + debug_assert!(args.len() == 2); + + let (elem, elem_layout) = args[1]; + + let builder = env.builder; + let ctx = env.context; + + let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes); + let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64; + + let ptr = { + let bytes_len = elem_bytes; + let len_type = env.ptr_int(); + let len = len_type.const_int(bytes_len, false); + + env.builder + .build_array_malloc(elem_type, len, "create_list_ptr") + .unwrap() + + // TODO check if malloc returned null; if so, runtime error for OOM! + }; + + // List elem length, as in, the number of elements + // in the output list. This could be negative, since + // it is just whatever value the function is given. + let list_elem_len = args[1].0.into_int_value(); + + let counter : BasicValueEnum<'ctx> = env.context.i64_type().const_int(0 as u64, true).into(); + + let comparison = + + builder.build_int_compare(IntPredicate::ULT, elem_index, len, "bounds_check") + + + let loop_block = ctx.append_basic_block(parent, "loop"); + builder.build_unconditional_branch(loop_block); + builder.position_at_end(loop_block); + + let loop_step = || { + // Put the elements into the list + let elem_ptr = unsafe { + builder.build_in_bounds_gep( + ptr, + &[ctx.i32_type().const_int(0 as u64, false)], + "index", + ) + }; + + builder.build_store(elem_ptr, elem); + }; + // // Bounds check: only proceed if index < length. + // // Otherwise, return the list unaltered. + // let end_condition = builder.build_int_compare( + // IntPredicate::SLT, + // ctx.i32_type().const_int(0 as u64, true), + // list_elem_len, + // "loopcond", + // ); + // + // // let start_alloca = b.create_entry_block_alloca("#"); + // + // let i = builder.build_load() + + let ptr_bytes = env.ptr_bytes; + let int_type = ptr_int(ctx, ptr_bytes); + let ptr_as_int = builder.build_ptr_to_int(ptr, int_type, "list_cast_ptr"); + let struct_type = collection(ctx, ptr_bytes); + + let mut struct_val; + + // Store the pointer + struct_val = builder + .build_insert_value( + struct_type.get_undef(), + ptr_as_int, + Builtin::WRAPPER_PTR, + "insert_ptr", + ) + .unwrap(); + + // Store the length + struct_val = builder + .build_insert_value( + struct_val, + list_elem_len, + Builtin::WRAPPER_LEN, + "insert_len", + ) + .unwrap(); + + // + builder.build_bitcast( + struct_val.into_struct_value(), + collection(ctx, ptr_bytes), + "cast_collection", + ) + } Symbol::INT_DIV_UNSAFE => { debug_assert!(args.len() == 2); diff --git a/compiler/gen/tests/gen_builtins.rs b/compiler/gen/tests/gen_builtins.rs index 72622d2732..bc26a8ab3a 100644 --- a/compiler/gen/tests/gen_builtins.rs +++ b/compiler/gen/tests/gen_builtins.rs @@ -500,6 +500,15 @@ mod gen_builtins { assert_evals_to!("List.single 5.6", &[5.6], &'static [f64]); } + #[test] + fn list_repeat() { + assert_evals_to!("List.repeat -1 1", &[], &'static [i64]); + // assert_evals_to!("List.repeat 4 5", &[5, 5, 5, 5], &'static [i64]); + + // assert_evals_to!("List.repeat 0 []", &[], &'static [i64]); + // assert_evals_to!("List.repeat 2 []", &[&[], &[]], &'static [&'static [i64]]); + } + #[test] fn empty_list_len() { with_larger_debug_stack(|| { diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index af54fd1ff8..31cff923e0 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -692,6 +692,7 @@ define_builtins! { 15 LIST_FIRST: "first" 16 LIST_FIRST_ARG: "first#list" 17 LIST_SINGLE: "single" + 18 LIST_REPEAT: "repeat" } 7 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias From 6485b039c7f7b838d2c5653cdd31bed400473241 Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sat, 20 Jun 2020 15:49:58 -0400 Subject: [PATCH 02/22] List repeats code gen works.. so long as its 5 --- compiler/gen/src/llvm/build.rs | 59 +++++++++--------------------- compiler/gen/tests/gen_builtins.rs | 3 +- 2 files changed, 19 insertions(+), 43 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 1276ae20c9..2612a7fad4 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -1474,15 +1474,21 @@ fn call_with_args<'a, 'ctx, 'env>( // List.repeat : Int, a -> List a debug_assert!(args.len() == 2); + let ptr_bytes = env.ptr_bytes; + let (elem, elem_layout) = args[1]; + // Number of repeats + let list_len = args[0].0.into_int_value(); + let builder = env.builder; let ctx = env.context; - let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes); + // Allocate space for the new array that we'll copy into. let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64; + let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes); - let ptr = { + let list_ptr = { let bytes_len = elem_bytes; let len_type = env.ptr_int(); let len = len_type.const_int(bytes_len, false); @@ -1494,50 +1500,24 @@ fn call_with_args<'a, 'ctx, 'env>( // TODO check if malloc returned null; if so, runtime error for OOM! }; - // List elem length, as in, the number of elements - // in the output list. This could be negative, since - // it is just whatever value the function is given. - let list_elem_len = args[1].0.into_int_value(); + // dbg!(elem_type); - let counter : BasicValueEnum<'ctx> = env.context.i64_type().const_int(0 as u64, true).into(); - - let comparison = - - builder.build_int_compare(IntPredicate::ULT, elem_index, len, "bounds_check") - - - let loop_block = ctx.append_basic_block(parent, "loop"); - builder.build_unconditional_branch(loop_block); - builder.position_at_end(loop_block); - - let loop_step = || { - // Put the elements into the list + for (dummy_i) in (0..5) { let elem_ptr = unsafe { builder.build_in_bounds_gep( - ptr, - &[ctx.i32_type().const_int(0 as u64, false)], - "index", + list_ptr, + &[ctx.i64_type().const_int(dummy_i, false)], + "load_index", ) }; + // Mutate the new array in-place to change the element. builder.build_store(elem_ptr, elem); - }; - // // Bounds check: only proceed if index < length. - // // Otherwise, return the list unaltered. - // let end_condition = builder.build_int_compare( - // IntPredicate::SLT, - // ctx.i32_type().const_int(0 as u64, true), - // list_elem_len, - // "loopcond", - // ); - // - // // let start_alloca = b.create_entry_block_alloca("#"); - // - // let i = builder.build_load() + } let ptr_bytes = env.ptr_bytes; let int_type = ptr_int(ctx, ptr_bytes); - let ptr_as_int = builder.build_ptr_to_int(ptr, int_type, "list_cast_ptr"); + let ptr_as_int = builder.build_ptr_to_int(list_ptr, int_type, "list_cast_ptr"); let struct_type = collection(ctx, ptr_bytes); let mut struct_val; @@ -1554,12 +1534,7 @@ fn call_with_args<'a, 'ctx, 'env>( // Store the length struct_val = builder - .build_insert_value( - struct_val, - list_elem_len, - Builtin::WRAPPER_LEN, - "insert_len", - ) + .build_insert_value(struct_val, list_len, Builtin::WRAPPER_LEN, "insert_len") .unwrap(); // diff --git a/compiler/gen/tests/gen_builtins.rs b/compiler/gen/tests/gen_builtins.rs index bc26a8ab3a..7f1d1d9794 100644 --- a/compiler/gen/tests/gen_builtins.rs +++ b/compiler/gen/tests/gen_builtins.rs @@ -502,7 +502,8 @@ mod gen_builtins { #[test] fn list_repeat() { - assert_evals_to!("List.repeat -1 1", &[], &'static [i64]); + assert_evals_to!("List.repeat 5 1", &[1, 1, 1, 1, 1], &'static [i64]); + // assert_evals_to!("List.repeat -1 1", &[], &'static [i64]); // assert_evals_to!("List.repeat 4 5", &[5, 5, 5, 5], &'static [i64]); // assert_evals_to!("List.repeat 0 []", &[], &'static [i64]); From e4eeff5bd0a7fa42f321949ac9d87ab26f72c8d0 Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 00:55:53 -0400 Subject: [PATCH 03/22] List repeat works for all test cases except one with a negative number repeats param, and avoids malloc in the case that the number of repeats is not more than 0 --- compiler/gen/src/llvm/build.rs | 147 ++++++++++++++++++++--------- compiler/gen/tests/gen_builtins.rs | 8 +- 2 files changed, 104 insertions(+), 51 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 2612a7fad4..67fddedf4c 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -1471,77 +1471,130 @@ fn call_with_args<'a, 'ctx, 'env>( ) } Symbol::LIST_REPEAT => { - // List.repeat : Int, a -> List a + // List.repeat : Int, elem -> List elem debug_assert!(args.len() == 2); - let ptr_bytes = env.ptr_bytes; - - let (elem, elem_layout) = args[1]; - // Number of repeats let list_len = args[0].0.into_int_value(); let builder = env.builder; let ctx = env.context; - // Allocate space for the new array that we'll copy into. - let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64; + let (elem, elem_layout) = args[1]; let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes); - let list_ptr = { - let bytes_len = elem_bytes; - let len_type = env.ptr_int(); - let len = len_type.const_int(bytes_len, false); + let comparison = builder.build_int_compare( + IntPredicate::UGT, + list_len, + ctx.i64_type().const_int(0, false), + "atleastzero", + ); - env.builder - .build_array_malloc(elem_type, len, "create_list_ptr") - .unwrap() + let build_then = || { + // Allocate space for the new array that we'll copy into. + let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64; - // TODO check if malloc returned null; if so, runtime error for OOM! - }; + let list_ptr = { + let bytes_len = elem_bytes; + let len_type = env.ptr_int(); + let len = len_type.const_int(bytes_len, false); - // dbg!(elem_type); + env.builder + .build_array_malloc(elem_type, len, "create_list_ptr") + .unwrap() - for (dummy_i) in (0..5) { - let elem_ptr = unsafe { - builder.build_in_bounds_gep( - list_ptr, - &[ctx.i64_type().const_int(dummy_i, false)], - "load_index", - ) + // TODO check if malloc returned null; if so, runtime error for OOM! }; + let index_name = "#index"; + let start_alloca = builder.build_alloca(ctx.i64_type(), index_name); + + builder.build_store(start_alloca, list_len); + + let loop_bb = ctx.append_basic_block(parent, "loop"); + builder.build_unconditional_branch(loop_bb); + builder.position_at_end(loop_bb); + + // #index = #index - 1 + let curr_index = builder + .build_load(start_alloca, index_name) + .into_int_value(); + let next_index = builder.build_int_sub( + curr_index, + ctx.i64_type().const_int(1, false), + "nextindex", + ); + + builder.build_store(start_alloca, next_index); + + let elem_ptr = + unsafe { builder.build_in_bounds_gep(list_ptr, &[curr_index], "load_index") }; + // Mutate the new array in-place to change the element. builder.build_store(elem_ptr, elem); - } - let ptr_bytes = env.ptr_bytes; - let int_type = ptr_int(ctx, ptr_bytes); - let ptr_as_int = builder.build_ptr_to_int(list_ptr, int_type, "list_cast_ptr"); - let struct_type = collection(ctx, ptr_bytes); + // #index != 0 + let end_cond = builder.build_int_compare( + IntPredicate::NE, + ctx.i64_type().const_int(0, false), + curr_index, + "loopcond", + ); - let mut struct_val; + let after_bb = ctx.append_basic_block(parent, "afterloop"); - // Store the pointer - struct_val = builder - .build_insert_value( - struct_type.get_undef(), - ptr_as_int, - Builtin::WRAPPER_PTR, - "insert_ptr", + builder.build_conditional_branch(end_cond, loop_bb, after_bb); + builder.position_at_end(after_bb); + + let ptr_bytes = env.ptr_bytes; + let int_type = ptr_int(ctx, ptr_bytes); + let ptr_as_int = builder.build_ptr_to_int(list_ptr, int_type, "list_cast_ptr"); + let struct_type = collection(ctx, ptr_bytes); + + let mut struct_val; + + // Store the pointer + struct_val = builder + .build_insert_value( + struct_type.get_undef(), + ptr_as_int, + Builtin::WRAPPER_PTR, + "insert_ptr", + ) + .unwrap(); + + // Store the length + struct_val = builder + .build_insert_value(struct_val, list_len, Builtin::WRAPPER_LEN, "insert_len") + .unwrap(); + + builder.build_bitcast( + struct_val.into_struct_value(), + collection(ctx, ptr_bytes), + "cast_collection", ) - .unwrap(); + }; - // Store the length - struct_val = builder - .build_insert_value(struct_val, list_len, Builtin::WRAPPER_LEN, "insert_len") - .unwrap(); + // If the number of repeats is 0 or lower, dont even + // bother allocating memory, since that it a costly + // operation. Just return an empty list. + let build_else = || { + let struct_type = collection(ctx, env.ptr_bytes); - // - builder.build_bitcast( - struct_val.into_struct_value(), - collection(ctx, ptr_bytes), - "cast_collection", + // The pointer should be null (aka zero) and the length should be zero, + // so the whole struct should be a const_zero + BasicValueEnum::StructValue(struct_type.const_zero()) + }; + + let struct_type = collection(ctx, env.ptr_bytes); + + build_basic_phi2( + env, + parent, + comparison, + build_then, + build_else, + BasicTypeEnum::StructType(struct_type), ) } Symbol::INT_DIV_UNSAFE => { diff --git a/compiler/gen/tests/gen_builtins.rs b/compiler/gen/tests/gen_builtins.rs index 7f1d1d9794..6d07045fd4 100644 --- a/compiler/gen/tests/gen_builtins.rs +++ b/compiler/gen/tests/gen_builtins.rs @@ -503,11 +503,11 @@ mod gen_builtins { #[test] fn list_repeat() { assert_evals_to!("List.repeat 5 1", &[1, 1, 1, 1, 1], &'static [i64]); - // assert_evals_to!("List.repeat -1 1", &[], &'static [i64]); - // assert_evals_to!("List.repeat 4 5", &[5, 5, 5, 5], &'static [i64]); + assert_evals_to!("List.repeat -1 1", &[], &'static [i64]); + assert_evals_to!("List.repeat 4 2", &[2, 2, 2, 2], &'static [i64]); - // assert_evals_to!("List.repeat 0 []", &[], &'static [i64]); - // assert_evals_to!("List.repeat 2 []", &[&[], &[]], &'static [&'static [i64]]); + assert_evals_to!("List.repeat 0 []", &[], &'static [i64]); + assert_evals_to!("List.repeat 2 []", &[&[], &[]], &'static [&'static [i64]]); } #[test] From ca411b11a33ee8f78c172b5dd90ed4059a281102 Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 13:23:59 -0400 Subject: [PATCH 04/22] Switched all i32 to i64 in gen builtins --- compiler/gen/src/llvm/build.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 67fddedf4c..ab5ad339d1 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -398,7 +398,7 @@ pub fn build_expr<'a, 'ctx, 'env>( let byte_type = ctx.i8_type(); let nul_terminator = byte_type.const_zero(); - let len_val = ctx.i32_type().const_int(str_len as u64, false); + let len_val = ctx.i64_type().const_int(str_len as u64, false); let ptr = env .builder .build_array_malloc(ctx.i8_type(), len_val, "str_ptr") @@ -408,7 +408,7 @@ pub fn build_expr<'a, 'ctx, 'env>( // Copy the bytes from the string literal into the array for (index, byte) in str_literal.bytes().enumerate() { - let index_val = ctx.i32_type().const_int(index as u64, false); + let index_val = ctx.i64_type().const_int(index as u64, false); let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index_val], "byte") }; @@ -418,7 +418,7 @@ pub fn build_expr<'a, 'ctx, 'env>( // Add a NUL terminator at the end. // TODO: Instead of NUL-terminating, return a struct // with the pointer and also the length and capacity. - let index_val = ctx.i32_type().const_int(str_len as u64 - 1, false); + let index_val = ctx.i64_type().const_int(str_len as u64 - 1, false); let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index_val], "nul_terminator") }; @@ -456,7 +456,7 @@ pub fn build_expr<'a, 'ctx, 'env>( // Copy the elements from the list literal into the array for (index, elem) in elems.iter().enumerate() { - let index_val = ctx.i32_type().const_int(index as u64, false); + let index_val = ctx.i64_type().const_int(index as u64, false); let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index_val], "index") }; let val = build_expr(env, layout_ids, &scope, parent, &elem); @@ -1430,7 +1430,7 @@ fn call_with_args<'a, 'ctx, 'env>( let elem_ptr = unsafe { builder.build_in_bounds_gep( ptr, - &[ctx.i32_type().const_int( + &[ctx.i64_type().const_int( // 0 as in 0 index of our new list 0 as u64, false, )], From 197dc01ad8bc6e823c6a22a85eab101b013e56bf Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 13:24:21 -0400 Subject: [PATCH 05/22] Got rid of test for negative amount of repeats. We will worry about that later --- compiler/gen/tests/gen_builtins.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/gen/tests/gen_builtins.rs b/compiler/gen/tests/gen_builtins.rs index 6d07045fd4..65bbb868e3 100644 --- a/compiler/gen/tests/gen_builtins.rs +++ b/compiler/gen/tests/gen_builtins.rs @@ -503,7 +503,6 @@ mod gen_builtins { #[test] fn list_repeat() { assert_evals_to!("List.repeat 5 1", &[1, 1, 1, 1, 1], &'static [i64]); - assert_evals_to!("List.repeat -1 1", &[], &'static [i64]); assert_evals_to!("List.repeat 4 2", &[2, 2, 2, 2], &'static [i64]); assert_evals_to!("List.repeat 0 []", &[], &'static [i64]); From 7125af2493f99400f3a3c6ce838162a1f2a04056 Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 13:24:45 -0400 Subject: [PATCH 06/22] Switched from one list foldr type to the other in the test --- compiler/solve/tests/test_uniq_solve.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index 4a81e568fb..eff4a49f22 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -2099,8 +2099,8 @@ mod test_uniq_solve { reverse "# ), - "Attr * (Attr * (List (Attr (a | b) c)) -> Attr (* | a | b) (List (Attr b c)))", - // "Attr * (Attr * (List (Attr (a | b) c)) -> Attr (* | a | b) (List (Attr a c)))", + // "Attr * (Attr * (List (Attr (a | b) c)) -> Attr (* | a | b) (List (Attr b c)))", + "Attr * (Attr * (List (Attr (a | b) c)) -> Attr (* | a | b) (List (Attr a c)))", ); } From 3af1632edea34f4ada5f6b34f9e632fe3f764543 Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 13:30:49 -0400 Subject: [PATCH 07/22] Changed some commented out type signatures from List a to List elem --- compiler/builtins/src/std.rs | 4 ++-- compiler/builtins/src/unique.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 5c55933fe0..61ec3b2c44 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -498,7 +498,7 @@ pub fn types() -> MutMap { ), ); - // push : List a -> a -> List a + // push : List elem -> elem -> List elem add_type( Symbol::LIST_PUSH, SolvedType::Func( @@ -513,7 +513,7 @@ pub fn types() -> MutMap { SolvedType::Func(vec![flex(TVAR1)], Box::new(list_type(flex(TVAR1)))), ); - // repeat : Int, a -> List a + // repeat : Int, elem -> List elem add_type( Symbol::LIST_REPEAT, SolvedType::Func( diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 760ec6ef06..f895f02523 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -615,7 +615,7 @@ pub fn types() -> MutMap { ) }); - // repeat : Int, a -> List a + // repeat : Int, elem -> List elem add_type(Symbol::LIST_REPEAT, { let u = UVAR1; let v = UVAR2; From 10aa44e12b4cd2caece020c0cd0903f2171fc2b6 Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 14:02:52 -0400 Subject: [PATCH 08/22] More comments --- compiler/gen/src/llvm/build.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index ab5ad339d1..ac4e0166c0 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -1483,6 +1483,13 @@ fn call_with_args<'a, 'ctx, 'env>( let (elem, elem_layout) = args[1]; let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes); + // list_len > 0 + // We have to do a loop below, continuously adding the `elem` + // to the output list `List elem` until we have reached the + // number of repeats. This `comparison` is used to check + // if we need to do any looping; because if we dont, then we + // dont need to allocate memory for the index or the check + // if index != 0 let comparison = builder.build_int_compare( IntPredicate::UGT, list_len, From 9376b4b988b454db77752c63e27decb75dcde76c Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 14:03:04 -0400 Subject: [PATCH 09/22] empty_list helper --- compiler/gen/src/llvm/build.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index ac4e0166c0..6b6c7413ab 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -433,11 +433,7 @@ pub fn build_expr<'a, 'ctx, 'env>( let builder = env.builder; if elems.is_empty() { - let struct_type = collection(ctx, env.ptr_bytes); - - // The pointer should be null (aka zero) and the length should be zero, - // so the whole struct should be a const_zero - BasicValueEnum::StructValue(struct_type.const_zero()) + empty_list(env) } else { let len_u64 = elems.len() as u64; let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64; @@ -1582,16 +1578,7 @@ fn call_with_args<'a, 'ctx, 'env>( ) }; - // If the number of repeats is 0 or lower, dont even - // bother allocating memory, since that it a costly - // operation. Just return an empty list. - let build_else = || { - let struct_type = collection(ctx, env.ptr_bytes); - - // The pointer should be null (aka zero) and the length should be zero, - // so the whole struct should be a const_zero - BasicValueEnum::StructValue(struct_type.const_zero()) - }; + let build_else = || empty_list(env); let struct_type = collection(ctx, env.ptr_bytes); @@ -1770,6 +1757,16 @@ enum InPlace { Clone, } +fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> { + let ctx = env.context; + + let struct_type = collection(ctx, env.ptr_bytes); + + // The pointer should be null (aka zero) and the length should be zero, + // so the whole struct should be a const_zero + BasicValueEnum::StructValue(struct_type.const_zero()) +} + fn bounds_check_comparison<'ctx>( builder: &Builder<'ctx>, elem_index: IntValue<'ctx>, From 830394eadf4cd623b251b1741d8a2f57509a5aa3 Mon Sep 17 00:00:00 2001 From: Chad Stearns Date: Sun, 21 Jun 2020 17:24:14 -0400 Subject: [PATCH 10/22] Comply with clippy --- compiler/parse/src/expr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index 8d1f528c4a..744cecc133 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -1034,9 +1034,9 @@ mod when { branch_result(indented_more) ), |((patterns, guard), expr)| WhenBranch { - patterns: patterns, + patterns, value: expr, - guard: guard + guard } ); From 7de691b5118c73f15a04412be91cac5aa9579116 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 22 Jun 2020 20:37:28 +0200 Subject: [PATCH 11/22] clarify list uniqueness signatures --- compiler/builtins/src/unique.rs | 71 ++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index f895f02523..b9047426df 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -49,7 +49,7 @@ fn boolean(b: VarId) -> SolvedType { SolvedType::Boolean(SolvedAtom::Variable(b), vec![]) } -fn disjunction(free: VarId, rest: Vec) -> SolvedType { +fn container(free: VarId, rest: Vec) -> SolvedType { let solved_rest = rest.into_iter().map(SolvedAtom::Variable).collect(); SolvedType::Boolean(SolvedAtom::Variable(free), solved_rest) @@ -576,12 +576,12 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(w, vec![u, v]), + container(w, vec![u, v]), SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), ], ), int_type(star1), - SolvedType::Apply(Symbol::ATTR_ATTR, vec![disjunction(u, vec![v]), flex(a)]), + SolvedType::Apply(Symbol::ATTR_ATTR, vec![container(u, vec![v]), flex(a)]), ], SolvedType::Apply( Symbol::ATTR_ATTR, @@ -593,6 +593,7 @@ pub fn types() -> MutMap { ) }); + // single : Attr u elem -> Attr * (List (Attr u elem)) add_type(Symbol::LIST_SINGLE, { let u = UVAR1; let v = UVAR2; @@ -603,7 +604,7 @@ pub fn types() -> MutMap { unique_function( vec![SolvedType::Apply( Symbol::ATTR_ATTR, - vec![disjunction(u, vec![v]), flex(a)], + vec![container(u, vec![v]), flex(a)], )], SolvedType::Apply( Symbol::ATTR_ATTR, @@ -615,33 +616,37 @@ pub fn types() -> MutMap { ) }); - // repeat : Int, elem -> List elem + // repeat : Attr * Int + // , Attr u elem + // -> Attr * (List (Attr u elem)) add_type(Symbol::LIST_REPEAT, { let u = UVAR1; - let v = UVAR2; - let star1 = UVAR4; - let star2 = UVAR5; + let star1 = UVAR2; + let star2 = UVAR3; - let a = TVAR1; + let elem = TVAR1; unique_function( vec![ int_type(star1), - SolvedType::Apply(Symbol::ATTR_ATTR, vec![disjunction(u, vec![v]), flex(a)]), + SolvedType::Apply(Symbol::ATTR_ATTR, vec![boolean(u), flex(elem)]), ], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ boolean(star2), - SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, elem)]), ], ), ) }); - // push : Attr (w | u | v) (List (Attr u a)) - // , Attr (u | v) a + // push : Attr * (List (Attr u a)) + // , Attr u a // -> Attr * (List (Attr u a)) + // + // NOTE: we demand the new item to have the same uniqueness as the other list items. + // It could be allowed to add unique items to shared lists, but that requires special code gen add_type(Symbol::LIST_PUSH, { let u = UVAR1; let v = UVAR2; @@ -655,11 +660,11 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(w, vec![u, v]), + container(w, vec![u, v]), SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), ], ), - SolvedType::Apply(Symbol::ATTR_ATTR, vec![disjunction(u, vec![v]), flex(a)]), + SolvedType::Apply(Symbol::ATTR_ATTR, vec![container(u, vec![v]), flex(a)]), ], SolvedType::Apply( Symbol::ATTR_ATTR, @@ -671,7 +676,9 @@ pub fn types() -> MutMap { ) }); - // map : List a, (a -> b) -> List b + // map : Attr * (List a) + // , Attr Shared (a -> b) + // -> Attr * (List b) add_type( Symbol::LIST_MAP, unique_function( @@ -689,7 +696,10 @@ pub fn types() -> MutMap { ), ); - // foldr : List a, (a -> b -> b), b -> b + // foldr : Attr * (List a) + // , Attr Shared (a -> b -> b) + // , b + // -> b add_type( Symbol::LIST_FOLDR, unique_function( @@ -750,7 +760,7 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star1, vec![u, v]), + container(star1, vec![u, v]), SolvedType::Apply( Symbol::MAP_MAP, vec![attr_type(u, key), attr_type(v, val)], @@ -759,7 +769,7 @@ pub fn types() -> MutMap { ), SolvedType::Apply( Symbol::ATTR_ATTR, - vec![disjunction(star2, vec![u]), flex(key)], + vec![container(star2, vec![u]), flex(key)], ), ], SolvedType::Apply( @@ -792,7 +802,7 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star1, vec![u, v]), + container(star1, vec![u, v]), SolvedType::Apply( Symbol::MAP_MAP, vec![attr_type(u, key), attr_type(v, val)], @@ -801,11 +811,11 @@ pub fn types() -> MutMap { ), SolvedType::Apply( Symbol::ATTR_ATTR, - vec![disjunction(star2, vec![u]), flex(key)], + vec![container(star2, vec![u]), flex(key)], ), SolvedType::Apply( Symbol::ATTR_ATTR, - vec![disjunction(star2, vec![v]), flex(val)], + vec![container(star2, vec![v]), flex(val)], ), ], SolvedType::Apply( @@ -844,14 +854,14 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star1, vec![u]), + container(star1, vec![u]), SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star2, vec![u]), + container(star2, vec![u]), SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), @@ -886,7 +896,7 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star1, vec![u]), + container(star1, vec![u]), SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), @@ -918,14 +928,11 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star1, vec![u]), + container(star1, vec![u]), SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![disjunction(star2, vec![u]), flex(a)], - ), + SolvedType::Apply(Symbol::ATTR_ATTR, vec![container(star2, vec![u]), flex(a)]), ], SolvedType::Apply( Symbol::ATTR_ATTR, @@ -953,7 +960,7 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star1, vec![u]), + container(star1, vec![u]), SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), @@ -993,7 +1000,7 @@ pub fn types() -> MutMap { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - disjunction(star1, vec![u]), + container(star1, vec![u]), SolvedType::Apply(Symbol::RESULT_RESULT, vec![attr_type(u, a), flex(e)]), ], ), From 0fbac382d0f388851521d29b1e06decf4ca3c1d4 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 22 Jun 2020 23:28:23 +0200 Subject: [PATCH 12/22] improve uniqueness signatures --- compiler/builtins/src/unique.rs | 176 ++++++++++++++---------- compiler/load/tests/test_uniq_load.rs | 4 +- compiler/solve/tests/test_uniq_solve.rs | 104 +++++++++----- 3 files changed, 178 insertions(+), 106 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index b9047426df..ff4192af93 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -7,6 +7,22 @@ use roc_types::solved_types::{BuiltinAlias, SolvedAtom, SolvedType}; use roc_types::subs::VarId; use std::collections::HashMap; +/// A macro that increments this variable every time it is called +/// effectively gives unique variable ids every time +static mut TYPE_VAR_COUNT: u32 = 10000; + +/// Safety: +/// +/// TYPE_VAR_COUNT is not shared across threads, so mutating is safe +macro_rules! tvar { + () => {{ + unsafe { + TYPE_VAR_COUNT += 1; + VarId::from_u32(TYPE_VAR_COUNT) + } + }}; +} + /// Keep this up to date by hand! /// const NUM_BUILTIN_IMPORTS: usize = 7; @@ -266,14 +282,15 @@ pub fn types() -> MutMap { // Num module - // add or (+) : Attr u1 (Num a), Attr u2 (Num a) -> Attr u3 (Num a) - add_type( - Symbol::NUM_ADD, + // add or (+) : Attr u (Num (Attr u num)) + // , Attr v (Num (Attr v num)) + // -> Attr w (Num (Attr w num)) + add_type(Symbol::NUM_ADD, { unique_function( vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], num_type(UVAR3, TVAR1), - ), - ); + ) + }); // sub or (-) : Num a, Num a -> Num a add_type( @@ -527,31 +544,48 @@ pub fn types() -> MutMap { // List module - // isEmpty : Attr u (List *) -> Attr v Bool + // isEmpty : Attr * (List *) -> Attr * Bool add_type( Symbol::LIST_IS_EMPTY, unique_function(vec![list_type(UVAR1, TVAR1)], bool_type(UVAR2)), ); - // len : Attr u (List *) -> Attr v Int + // len : Attr * (List *) -> Attr * Int add_type( Symbol::LIST_LEN, unique_function(vec![list_type(UVAR1, TVAR1)], int_type(UVAR2)), ); - // get : List a, Int -> Result a [ OutOfBounds ]* + // get : Attr (* | u) (List (Attr u a)) + // , Attr * Int + // -> Attr * (Result (Attr u a) (Attr * [ OutOfBounds ]*)) let index_out_of_bounds = SolvedType::TagUnion( vec![(TagName::Global("OutOfBounds".into()), vec![])], Box::new(SolvedType::Wildcard), ); - add_type( - Symbol::LIST_GET, + add_type(Symbol::LIST_GET, { + let a = TVAR1; + let u = UVAR1; + let star1 = UVAR2; + let star2 = UVAR3; + let star3 = UVAR4; + let star4 = UVAR5; + unique_function( - vec![list_type(UVAR1, TVAR1), int_type(UVAR2)], - result_type(UVAR3, flex(TVAR1), lift(UVAR4, index_out_of_bounds)), - ), - ); + vec![ + SolvedType::Apply( + Symbol::ATTR_ATTR, + vec![ + container(star1, vec![u]), + SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + ], + ), + int_type(star2), + ], + result_type(star3, attr_type(u, a), lift(star4, index_out_of_bounds)), + ) + }); add_type( Symbol::LIST_GET_UNSAFE, @@ -593,84 +627,70 @@ pub fn types() -> MutMap { ) }); - // single : Attr u elem -> Attr * (List (Attr u elem)) + // single : a -> Attr * (List a) add_type(Symbol::LIST_SINGLE, { - let u = UVAR1; - let v = UVAR2; - let star = UVAR4; - - let a = TVAR1; + let a = tvar!(); + let star = tvar!(); unique_function( - vec![SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![container(u, vec![v]), flex(a)], - )], + vec![flex(a)], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ boolean(star), - SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + SolvedType::Apply(Symbol::LIST_LIST, vec![flex(a)]), ], ), ) }); // repeat : Attr * Int - // , Attr u elem - // -> Attr * (List (Attr u elem)) + // , a + // -> Attr * (List a) add_type(Symbol::LIST_REPEAT, { - let u = UVAR1; - let star1 = UVAR2; - let star2 = UVAR3; - - let elem = TVAR1; + let a = tvar!(); + let star1 = tvar!(); + let star2 = tvar!(); unique_function( - vec![ - int_type(star1), - SolvedType::Apply(Symbol::ATTR_ATTR, vec![boolean(u), flex(elem)]), - ], + vec![int_type(star1), flex(a)], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ boolean(star2), - SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, elem)]), + SolvedType::Apply(Symbol::LIST_LIST, vec![flex(a)]), ], ), ) }); - // push : Attr * (List (Attr u a)) - // , Attr u a - // -> Attr * (List (Attr u a)) + // push : Attr * (List a) + // , a + // -> Attr * (List a) // // NOTE: we demand the new item to have the same uniqueness as the other list items. // It could be allowed to add unique items to shared lists, but that requires special code gen add_type(Symbol::LIST_PUSH, { - let u = UVAR1; - let v = UVAR2; - let w = UVAR3; - let star = UVAR4; - - let a = TVAR1; + let a = tvar!(); + let star1 = tvar!(); + let star2 = tvar!(); unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(w, vec![u, v]), - SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + flex(star1), + SolvedType::Apply(Symbol::LIST_LIST, vec![flex(a)]), ], ), - SolvedType::Apply(Symbol::ATTR_ATTR, vec![container(u, vec![v]), flex(a)]), + flex(a), ], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - boolean(star), - SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + boolean(star2), + SolvedType::Apply(Symbol::LIST_LIST, vec![flex(a)]), ], ), ) @@ -679,44 +699,53 @@ pub fn types() -> MutMap { // map : Attr * (List a) // , Attr Shared (a -> b) // -> Attr * (List b) - add_type( - Symbol::LIST_MAP, + add_type(Symbol::LIST_MAP, { + let a = tvar!(); + let b = tvar!(); + let star1 = tvar!(); + let star2 = tvar!(); unique_function( vec![ - list_type(UVAR1, TVAR1), + list_type(star1, a), SolvedType::Apply( Symbol::ATTR_ATTR, - vec![ - shared(), - SolvedType::Func(vec![flex(TVAR1)], Box::new(flex(TVAR2))), - ], + vec![shared(), SolvedType::Func(vec![flex(a)], Box::new(flex(b)))], ), ], - list_type(UVAR2, TVAR2), - ), - ); + list_type(star2, b), + ) + }); - // foldr : Attr * (List a) - // , Attr Shared (a -> b -> b) + // foldr : Attr (* | u) (List (Attr u a)) + // , Attr Shared (Attr u a -> b -> b) // , b // -> b - add_type( - Symbol::LIST_FOLDR, + add_type(Symbol::LIST_FOLDR, { + let u = tvar!(); + let a = tvar!(); + let b = tvar!(); + let star1 = tvar!(); unique_function( vec![ - list_type(UVAR1, TVAR1), + SolvedType::Apply( + Symbol::ATTR_ATTR, + vec![ + container(star1, vec![u]), + SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + ], + ), SolvedType::Apply( Symbol::ATTR_ATTR, vec![ shared(), - SolvedType::Func(vec![flex(TVAR1), flex(TVAR2)], Box::new(flex(TVAR2))), + SolvedType::Func(vec![attr_type(u, a), flex(b)], Box::new(flex(b))), ], ), - flex(TVAR2), + flex(b), ], - flex(TVAR2), - ), - ); + flex(b), + ) + }); // Map module @@ -1085,7 +1114,10 @@ fn str_type(u: VarId) -> SolvedType { fn num_type(u: VarId, a: VarId) -> SolvedType { SolvedType::Apply( Symbol::ATTR_ATTR, - vec![flex(u), SolvedType::Apply(Symbol::NUM_NUM, vec![flex(a)])], + vec![ + flex(u), + SolvedType::Apply(Symbol::NUM_NUM, vec![attr_type(u, a)]), + ], ) } diff --git a/compiler/load/tests/test_uniq_load.rs b/compiler/load/tests/test_uniq_load.rs index 3423568608..4697d29eb2 100644 --- a/compiler/load/tests/test_uniq_load.rs +++ b/compiler/load/tests/test_uniq_load.rs @@ -242,8 +242,8 @@ mod test_uniq_load { loaded_module, hashmap! { "swap" => "Attr * (Attr Shared Int, Attr Shared Int, Attr * (List (Attr Shared a)) -> Attr * (List (Attr Shared a)))", - "partition" => "Attr * (Attr Shared Int, Attr Shared Int, Attr b (List (Attr Shared (Num (Attr c a)))) -> Attr * [ Pair (Attr * Int) (Attr b (List (Attr Shared (Num (Attr c a))))) ])", - "quicksort" => "Attr Shared (Attr b (List (Attr Shared (Num (Attr c a)))), Attr Shared Int, Attr Shared Int -> Attr b (List (Attr Shared (Num (Attr c a)))))", + "partition" => "Attr * (Attr Shared Int, Attr Shared Int, Attr b (List (Attr Shared (Num (Attr Shared a)))) -> Attr * [ Pair (Attr Shared Int) (Attr b (List (Attr Shared (Num (Attr Shared a))))) ])", + "quicksort" => "Attr Shared (Attr b (List (Attr Shared (Num (Attr Shared a)))), Attr Shared Int, Attr Shared Int -> Attr b (List (Attr Shared (Num (Attr Shared a)))))", }, ); }); diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index eff4a49f22..ef309ec549 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -1475,7 +1475,7 @@ mod test_uniq_solve { quicksort "# ), - "Attr Shared (Attr b (List (Attr Shared (Num (Attr c a)))), Attr Shared Int, Attr Shared Int -> Attr b (List (Attr Shared (Num (Attr c a)))))" + "Attr Shared (Attr b (List (Attr Shared (Num (Attr Shared a)))), Attr Shared Int, Attr Shared Int -> Attr b (List (Attr Shared (Num (Attr Shared a)))))" ); }) } @@ -1885,12 +1885,12 @@ mod test_uniq_solve { 4 + 4 "# ), - "Attr * (Num (Attr * *))", + "Attr a (Num (Attr a *))", ); } #[test] - fn list_get() { + fn list_get_at() { infer_eq( indoc!( r#" @@ -2004,7 +2004,7 @@ mod test_uniq_solve { list "# ), - "Attr * (Attr a (List (Attr Shared (Num (Attr b c)))) -> Attr a (List (Attr Shared (Num (Attr b c)))))", + "Attr * (Attr a (List (Attr Shared (Num (Attr Shared b)))) -> Attr a (List (Attr Shared (Num (Attr Shared b)))))", ); } @@ -2024,19 +2024,6 @@ mod test_uniq_solve { ); } - #[test] - fn list_set() { - infer_eq(indoc!(r#"List.set"#), "Attr * (Attr (* | a | b) (List (Attr a c)), Attr * Int, Attr (a | b) c -> Attr * (List (Attr a c)))"); - } - - #[test] - fn list_map() { - infer_eq( - indoc!(r#"List.map"#), - "Attr * (Attr * (List a), Attr Shared (a -> b) -> Attr * (List b))", - ); - } - #[test] fn list_map_identity() { infer_eq( @@ -2045,14 +2032,6 @@ mod test_uniq_solve { ); } - #[test] - fn list_foldr() { - infer_eq( - indoc!(r#"List.foldr"#), - "Attr * (Attr * (List a), Attr Shared (a, b -> b), b -> b)", - ); - } - #[test] fn list_foldr_sum() { infer_eq( @@ -2063,18 +2042,80 @@ mod test_uniq_solve { sum "# ), - "Attr * (Attr * (List (Attr * (Num (Attr a b)))) -> Attr * (Num (Attr a b)))", + "Attr * (Attr (* | a) (List (Attr a (Num (Attr a b)))) -> Attr c (Num (Attr c b)))", + ); + } + + #[test] + fn num_add() { + infer_eq( + indoc!("Num.add"), + "Attr * (Attr a (Num (Attr a b)), Attr c (Num (Attr c b)) -> Attr d (Num (Attr d b)))", + ); + } + + #[test] + fn list_isempty() { + infer_eq( + indoc!("List.isEmpty"), + "Attr * (Attr * (List *) -> Attr * Bool)", + ); + } + + #[test] + fn list_len() { + infer_eq(indoc!("List.len"), "Attr * (Attr * (List *) -> Attr * Int)"); + } + + #[test] + fn list_get() { + infer_eq(indoc!("List.get"), "Attr * (Attr (* | a) (List (Attr a b)), Attr * Int -> Attr * (Result (Attr a b) (Attr * [ OutOfBounds ]*)))"); + } + + #[test] + fn list_set() { + infer_eq(indoc!("List.set"), "Attr * (Attr (* | a | b) (List (Attr a c)), Attr * Int, Attr (a | b) c -> Attr * (List (Attr a c)))"); + } + + #[test] + fn list_single() { + infer_eq(indoc!("List.single"), "Attr * (a -> Attr * (List a))"); + } + + #[test] + fn list_repeat() { + infer_eq( + indoc!("List.repeat"), + "Attr * (Attr * Int, a -> Attr * (List a))", ); } #[test] fn list_push() { infer_eq( - indoc!(r#"List.push"#), - "Attr * (Attr (* | a | b) (List (Attr a c)), Attr (a | b) c -> Attr * (List (Attr a c)))" + indoc!("List.push"), + "Attr * (Attr * (List a), a -> Attr * (List a))", ); } + #[test] + fn list_map() { + infer_eq( + indoc!("List.map"), + "Attr * (Attr * (List a), Attr Shared (a -> b) -> Attr * (List b))", + ); + } + + /* + #[test] + fn list_foldr() { + infer_eq( + indoc!("List.foldr"), + "Attr * (Attr (* | a) (List (Attr a b)), Attr Shared (Attr a b, c -> c), c -> c)", + ); + } + */ + #[test] fn list_push_singleton() { infer_eq( @@ -2085,7 +2126,7 @@ mod test_uniq_solve { singleton "# ), - "Attr * (Attr (* | a) b -> Attr * (List (Attr a b)))", + "Attr * (a -> Attr * (List a))", ); } @@ -2099,8 +2140,7 @@ mod test_uniq_solve { reverse "# ), - // "Attr * (Attr * (List (Attr (a | b) c)) -> Attr (* | a | b) (List (Attr b c)))", - "Attr * (Attr * (List (Attr (a | b) c)) -> Attr (* | a | b) (List (Attr a c)))", + "Attr * (Attr (* | a) (List (Attr a b)) -> Attr * (List (Attr a b)))", ); } @@ -2409,7 +2449,7 @@ mod test_uniq_solve { _ -> 3 "# ), - "Attr * (Attr Shared (Num (Attr * *)) -> Attr * (Num (Attr * *)))", + "Attr * (Attr Shared (Num (Attr Shared *)) -> Attr * (Num (Attr * *)))", ); } } From 2a7bf2ae66930ba78ec916c5c9ea847255c4a34b Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 22 Jun 2020 23:48:37 +0200 Subject: [PATCH 13/22] fix map --- compiler/builtins/src/unique.rs | 18 ++++++++++++++---- compiler/solve/tests/test_uniq_solve.rs | 6 ++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index ff4192af93..12e3ccfa56 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -696,20 +696,30 @@ pub fn types() -> MutMap { ) }); - // map : Attr * (List a) - // , Attr Shared (a -> b) + // map : Attr (* | u) (List (Attr u a)) + // , Attr Shared (Attr u a -> b) // -> Attr * (List b) add_type(Symbol::LIST_MAP, { + let u = tvar!(); let a = tvar!(); let b = tvar!(); let star1 = tvar!(); let star2 = tvar!(); unique_function( vec![ - list_type(star1, a), SolvedType::Apply( Symbol::ATTR_ATTR, - vec![shared(), SolvedType::Func(vec![flex(a)], Box::new(flex(b)))], + vec![ + container(star1, vec![u]), + SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), + ], + ), + SolvedType::Apply( + Symbol::ATTR_ATTR, + vec![ + shared(), + SolvedType::Func(vec![attr_type(u, a)], Box::new(flex(b))), + ], ), ], list_type(star2, b), diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index ef309ec549..72d8f853f8 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -2028,7 +2028,7 @@ mod test_uniq_solve { fn list_map_identity() { infer_eq( indoc!(r#"\list -> List.map list (\x -> x)"#), - "Attr * (Attr * (List a) -> Attr * (List a))", + "Attr * (Attr (* | a) (List (Attr a b)) -> Attr * (List (Attr a b)))", ); } @@ -2102,11 +2102,10 @@ mod test_uniq_solve { fn list_map() { infer_eq( indoc!("List.map"), - "Attr * (Attr * (List a), Attr Shared (a -> b) -> Attr * (List b))", + "Attr * (Attr (* | a) (List (Attr a b)), Attr Shared (Attr a b -> c) -> Attr * (List c))", ); } - /* #[test] fn list_foldr() { infer_eq( @@ -2114,7 +2113,6 @@ mod test_uniq_solve { "Attr * (Attr (* | a) (List (Attr a b)), Attr Shared (Attr a b, c -> c), c -> c)", ); } - */ #[test] fn list_push_singleton() { From af33e26811b851f4de77ea95f20a08b0d65ddfca Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 23 Jun 2020 00:02:36 +0200 Subject: [PATCH 14/22] fix repeat --- compiler/builtins/src/unique.rs | 47 +++++++++++-------------- compiler/solve/tests/test_uniq_solve.rs | 2 +- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 12e3ccfa56..057a719a06 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -57,8 +57,11 @@ impl IDStore { } } -fn shared() -> SolvedType { - SolvedType::Boolean(SolvedAtom::Zero, vec![]) +fn shared(base: SolvedType) -> SolvedType { + SolvedType::Apply( + Symbol::ATTR_ATTR, + vec![SolvedType::Boolean(SolvedAtom::Zero, vec![]), base], + ) } fn boolean(b: VarId) -> SolvedType { @@ -644,21 +647,23 @@ pub fn types() -> MutMap { ) }); + // To repeat an item, it must be shared! + // // repeat : Attr * Int - // , a - // -> Attr * (List a) + // , Attr Shared a + // -> Attr * (List (Attr Shared a)) add_type(Symbol::LIST_REPEAT, { let a = tvar!(); let star1 = tvar!(); let star2 = tvar!(); unique_function( - vec![int_type(star1), flex(a)], + vec![int_type(star1), shared(flex(a))], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ boolean(star2), - SolvedType::Apply(Symbol::LIST_LIST, vec![flex(a)]), + SolvedType::Apply(Symbol::LIST_LIST, vec![shared(flex(a))]), ], ), ) @@ -714,13 +719,7 @@ pub fn types() -> MutMap { SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), ], ), - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![ - shared(), - SolvedType::Func(vec![attr_type(u, a)], Box::new(flex(b))), - ], - ), + shared(SolvedType::Func(vec![attr_type(u, a)], Box::new(flex(b)))), ], list_type(star2, b), ) @@ -744,13 +743,10 @@ pub fn types() -> MutMap { SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), ], ), - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![ - shared(), - SolvedType::Func(vec![attr_type(u, a), flex(b)], Box::new(flex(b))), - ], - ), + shared(SolvedType::Func( + vec![attr_type(u, a), flex(b)], + Box::new(flex(b)), + )), flex(b), ], flex(b), @@ -939,13 +935,10 @@ pub fn types() -> MutMap { SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![ - shared(), - SolvedType::Func(vec![attr_type(u, a), flex(b)], Box::new(flex(b))), - ], - ), + shared(SolvedType::Func( + vec![attr_type(u, a), flex(b)], + Box::new(flex(b)), + )), flex(b), ], flex(b), diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index 72d8f853f8..b1355a811f 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -2086,7 +2086,7 @@ mod test_uniq_solve { fn list_repeat() { infer_eq( indoc!("List.repeat"), - "Attr * (Attr * Int, a -> Attr * (List a))", + "Attr * (Attr * Int, Attr Shared a -> Attr * (List (Attr Shared a)))", ); } From 5cb993f0820ff298631837c925e8772b2704d49d Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 22 Jun 2020 19:32:05 -0400 Subject: [PATCH 15/22] Fix backspace bug on macOS --- editor/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/editor/src/lib.rs b/editor/src/lib.rs index cc40041b12..62c1fae962 100644 --- a/editor/src/lib.rs +++ b/editor/src/lib.rs @@ -129,11 +129,11 @@ fn run_event_loop() -> Result<(), Box> { .. } => { match ch { - '\u{8}' => { - // In Linux, we get one of these when you press - // backspace, but in macOS we don't. In both, we + '\u{8}' | '\u{7f}' => { + // In Linux, we get a '\u{8}' when you press backspace, + // but in macOS we get '\u{7f}'. In both, we // get a Back keydown event. Therefore, we use the - // Back keydown event and ignore this, resulting + // Back keydown event and ignore these, resulting // in a system that works in both Linux and macOS. } '\u{e000}'..='\u{f8ff}' From 0b106614f96e4cab8a9b33db40af33db13fc451a Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 22 Jun 2020 21:29:18 -0400 Subject: [PATCH 16/22] wip --- compiler/builtins/src/unique.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 057a719a06..1873c526aa 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -14,7 +14,7 @@ static mut TYPE_VAR_COUNT: u32 = 10000; /// Safety: /// /// TYPE_VAR_COUNT is not shared across threads, so mutating is safe -macro_rules! tvar { +macro_rules! let_tvar { () => {{ unsafe { TYPE_VAR_COUNT += 1; From 3691152d207cb71177f7271d5358eff7eeaee829 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 22 Jun 2020 21:39:59 -0400 Subject: [PATCH 17/22] Introduce the let_tvars! macro --- compiler/builtins/src/unique.rs | 58 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 1873c526aa..43d94bf306 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -7,20 +7,28 @@ use roc_types::solved_types::{BuiltinAlias, SolvedAtom, SolvedType}; use roc_types::subs::VarId; use std::collections::HashMap; -/// A macro that increments this variable every time it is called -/// effectively gives unique variable ids every time -static mut TYPE_VAR_COUNT: u32 = 10000; - -/// Safety: +/// Example: /// -/// TYPE_VAR_COUNT is not shared across threads, so mutating is safe -macro_rules! let_tvar { - () => {{ - unsafe { - TYPE_VAR_COUNT += 1; - VarId::from_u32(TYPE_VAR_COUNT) - } - }}; +/// let_tvars! { a, b, c } +/// +/// This is equivalent to: +/// +/// let a = VarId::from_u32(1); +/// let b = VarId::from_u32(2); +/// let c = VarId::from_u32(3); +/// +/// The idea is that this is less error-prone than assigning hardcoded IDs by hand. +macro_rules! let_tvars { + ($($name:ident,)+) => { let_tvars!($($name),+) }; + ($($name:ident),*) => { + let mut _current_tvar = 0; + + $( + _current_tvar += 1; + + let $name = VarId::from_u32(_current_tvar); + )* + }; } /// Keep this up to date by hand! @@ -632,8 +640,7 @@ pub fn types() -> MutMap { // single : a -> Attr * (List a) add_type(Symbol::LIST_SINGLE, { - let a = tvar!(); - let star = tvar!(); + let_tvars! { a, star }; unique_function( vec![flex(a)], @@ -653,9 +660,7 @@ pub fn types() -> MutMap { // , Attr Shared a // -> Attr * (List (Attr Shared a)) add_type(Symbol::LIST_REPEAT, { - let a = tvar!(); - let star1 = tvar!(); - let star2 = tvar!(); + let_tvars! { a, star1, star2 }; unique_function( vec![int_type(star1), shared(flex(a))], @@ -676,9 +681,7 @@ pub fn types() -> MutMap { // NOTE: we demand the new item to have the same uniqueness as the other list items. // It could be allowed to add unique items to shared lists, but that requires special code gen add_type(Symbol::LIST_PUSH, { - let a = tvar!(); - let star1 = tvar!(); - let star2 = tvar!(); + let_tvars! { a, star1, star2 }; unique_function( vec![ @@ -705,11 +708,8 @@ pub fn types() -> MutMap { // , Attr Shared (Attr u a -> b) // -> Attr * (List b) add_type(Symbol::LIST_MAP, { - let u = tvar!(); - let a = tvar!(); - let b = tvar!(); - let star1 = tvar!(); - let star2 = tvar!(); + let_tvars! { u, a, b, star1, star2 }; + unique_function( vec![ SolvedType::Apply( @@ -730,10 +730,8 @@ pub fn types() -> MutMap { // , b // -> b add_type(Symbol::LIST_FOLDR, { - let u = tvar!(); - let a = tvar!(); - let b = tvar!(); - let star1 = tvar!(); + let_tvars! { u, a, b, star1 }; + unique_function( vec![ SolvedType::Apply( From 0696c5aa09eaff643f3ba025151d748c9764087c Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 23 Jun 2020 14:34:47 +0200 Subject: [PATCH 18/22] polish list signatures --- compiler/builtins/src/unique.rs | 64 ++++++++++++------------- compiler/solve/tests/test_uniq_solve.rs | 27 +++++------ 2 files changed, 44 insertions(+), 47 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 43d94bf306..6b108411cd 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -556,16 +556,16 @@ pub fn types() -> MutMap { // List module // isEmpty : Attr * (List *) -> Attr * Bool - add_type( - Symbol::LIST_IS_EMPTY, - unique_function(vec![list_type(UVAR1, TVAR1)], bool_type(UVAR2)), - ); + add_type(Symbol::LIST_IS_EMPTY, { + let_tvars! { star1, a, star2 }; + unique_function(vec![list_type(star1, a)], bool_type(star2)) + }); // len : Attr * (List *) -> Attr * Int - add_type( - Symbol::LIST_LEN, - unique_function(vec![list_type(UVAR1, TVAR1)], int_type(UVAR2)), - ); + add_type(Symbol::LIST_LEN, { + let_tvars! { star1, a, star2 }; + unique_function(vec![list_type(star1, a)], int_type(star2)) + }); // get : Attr (* | u) (List (Attr u a)) // , Attr * Int @@ -576,12 +576,7 @@ pub fn types() -> MutMap { ); add_type(Symbol::LIST_GET, { - let a = TVAR1; - let u = UVAR1; - let star1 = UVAR2; - let star2 = UVAR3; - let star3 = UVAR4; - let star4 = UVAR5; + let_tvars! { a, u, star1, star2, star3, star4 }; unique_function( vec![ @@ -598,6 +593,7 @@ pub fn types() -> MutMap { ) }); + // is LIST_GET_UNSAFE still used? add_type( Symbol::LIST_GET_UNSAFE, unique_function(vec![list_type(UVAR1, TVAR1), int_type(UVAR2)], flex(TVAR1)), @@ -608,13 +604,7 @@ pub fn types() -> MutMap { // , Attr (u | v) a // -> List a add_type(Symbol::LIST_SET, { - let u = UVAR1; - let v = UVAR2; - let w = UVAR3; - let star1 = UVAR4; - let star2 = UVAR5; - - let a = TVAR1; + let_tvars! { u, v, w, star1, star2, a }; unique_function( vec![ @@ -704,22 +694,32 @@ pub fn types() -> MutMap { ) }); - // map : Attr (* | u) (List (Attr u a)) - // , Attr Shared (Attr u a -> b) + // List.map does not need to check the container rule on the input list. + // There is no way in which this signature can cause unique values to be duplicated + // + // foo : Attr Shared (List (Attr u a)) + // + // List.map : Attr * (List (Attr u a)) -> (Attr u a -> b) -> Attr * (List b) + // List.unsafeGet : Attr (* | u) (List (Attr u a)) -> Attr u a + // + // -- the elements still have uniqueness `u`, and will be made shared whenever accessing an element in `foo` + // bar1 : Attr * (List (Attr u a)) + // bar1 = List.map foo (\x -> x) + // + // -- no reference to `foo`'s elements can escape + // bar2 : Attr * (List (Attr * Int)) + // bar2 = List.map foo (\_ -> 32) + + // map : Attr * (List a) + // , Attr Shared (a -> b) // -> Attr * (List b) add_type(Symbol::LIST_MAP, { - let_tvars! { u, a, b, star1, star2 }; + let_tvars! { a, b, star1, star2 }; unique_function( vec![ - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![ - container(star1, vec![u]), - SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), - ], - ), - shared(SolvedType::Func(vec![attr_type(u, a)], Box::new(flex(b)))), + list_type(star1, a), + shared(SolvedType::Func(vec![flex(a)], Box::new(flex(b)))), ], list_type(star2, b), ) diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index b1355a811f..e60280e7c3 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -2028,7 +2028,7 @@ mod test_uniq_solve { fn list_map_identity() { infer_eq( indoc!(r#"\list -> List.map list (\x -> x)"#), - "Attr * (Attr (* | a) (List (Attr a b)) -> Attr * (List (Attr a b)))", + "Attr * (Attr * (List a) -> Attr * (List a))", ); } @@ -2049,43 +2049,40 @@ mod test_uniq_solve { #[test] fn num_add() { infer_eq( - indoc!("Num.add"), + "Num.add", "Attr * (Attr a (Num (Attr a b)), Attr c (Num (Attr c b)) -> Attr d (Num (Attr d b)))", ); } #[test] fn list_isempty() { - infer_eq( - indoc!("List.isEmpty"), - "Attr * (Attr * (List *) -> Attr * Bool)", - ); + infer_eq("List.isEmpty", "Attr * (Attr * (List *) -> Attr * Bool)"); } #[test] fn list_len() { - infer_eq(indoc!("List.len"), "Attr * (Attr * (List *) -> Attr * Int)"); + infer_eq("List.len", "Attr * (Attr * (List *) -> Attr * Int)"); } #[test] fn list_get() { - infer_eq(indoc!("List.get"), "Attr * (Attr (* | a) (List (Attr a b)), Attr * Int -> Attr * (Result (Attr a b) (Attr * [ OutOfBounds ]*)))"); + infer_eq("List.get", "Attr * (Attr (* | a) (List (Attr a b)), Attr * Int -> Attr * (Result (Attr a b) (Attr * [ OutOfBounds ]*)))"); } #[test] fn list_set() { - infer_eq(indoc!("List.set"), "Attr * (Attr (* | a | b) (List (Attr a c)), Attr * Int, Attr (a | b) c -> Attr * (List (Attr a c)))"); + infer_eq("List.set", "Attr * (Attr (* | a | b) (List (Attr a c)), Attr * Int, Attr (a | b) c -> Attr * (List (Attr a c)))"); } #[test] fn list_single() { - infer_eq(indoc!("List.single"), "Attr * (a -> Attr * (List a))"); + infer_eq("List.single", "Attr * (a -> Attr * (List a))"); } #[test] fn list_repeat() { infer_eq( - indoc!("List.repeat"), + "List.repeat", "Attr * (Attr * Int, Attr Shared a -> Attr * (List (Attr Shared a)))", ); } @@ -2093,7 +2090,7 @@ mod test_uniq_solve { #[test] fn list_push() { infer_eq( - indoc!("List.push"), + "List.push", "Attr * (Attr * (List a), a -> Attr * (List a))", ); } @@ -2101,15 +2098,15 @@ mod test_uniq_solve { #[test] fn list_map() { infer_eq( - indoc!("List.map"), - "Attr * (Attr (* | a) (List (Attr a b)), Attr Shared (Attr a b -> c) -> Attr * (List c))", + "List.map", + "Attr * (Attr * (List a), Attr Shared (a -> b) -> Attr * (List b))", ); } #[test] fn list_foldr() { infer_eq( - indoc!("List.foldr"), + "List.foldr", "Attr * (Attr (* | a) (List (Attr a b)), Attr Shared (Attr a b, c -> c), c -> c)", ); } From c0c4f4c74bac35eae48fcd0a1176e2233a2cbd41 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 23 Jun 2020 14:36:48 +0200 Subject: [PATCH 19/22] polish list signatures --- compiler/builtins/src/unique.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 6b108411cd..8f33fbdad3 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -304,13 +304,10 @@ pub fn types() -> MutMap { }); // sub or (-) : Num a, Num a -> Num a - add_type( - Symbol::NUM_SUB, - unique_function( - vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], - num_type(UVAR3, TVAR1), - ), - ); + add_type(Symbol::NUM_SUB, { + let_tvars! { u, v, w, num }; + unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num)) + }); // mul or (*) : Num a, Num a -> Num a add_type( From 6f1639959a1da23f2875ea66b5c2cb1dbec89323 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 23 Jun 2020 15:08:23 +0200 Subject: [PATCH 20/22] use let_tvars for the Num, Int, Float, Bool --- compiler/builtins/src/unique.rs | 306 +++++++++++------------- compiler/solve/tests/test_uniq_solve.rs | 18 +- 2 files changed, 156 insertions(+), 168 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 8f33fbdad3..af4aa859b1 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -44,7 +44,7 @@ const TVAR3: VarId = VarId::from_u32(3); const FUVAR: VarId = VarId::from_u32(1000); const UVAR1: VarId = VarId::from_u32(1001); const UVAR2: VarId = VarId::from_u32(1002); -const UVAR3: VarId = VarId::from_u32(1003); +// const UVAR3: VarId = VarId::from_u32(1003); const UVAR4: VarId = VarId::from_u32(1004); const UVAR5: VarId = VarId::from_u32(1005); const UVAR6: VarId = VarId::from_u32(1006); @@ -297,10 +297,8 @@ pub fn types() -> MutMap { // , Attr v (Num (Attr v num)) // -> Attr w (Num (Attr w num)) add_type(Symbol::NUM_ADD, { - unique_function( - vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], - num_type(UVAR3, TVAR1), - ) + let_tvars! { u, v, w, num }; + unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num)) }); // sub or (-) : Num a, Num a -> Num a @@ -310,61 +308,41 @@ pub fn types() -> MutMap { }); // mul or (*) : Num a, Num a -> Num a - add_type( - Symbol::NUM_MUL, - unique_function( - vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], - num_type(UVAR3, TVAR1), - ), - ); + add_type(Symbol::NUM_MUL, { + let_tvars! { u, v, w, num }; + unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num)) + }); // abs : Num a -> Num a - add_type( - Symbol::NUM_ABS, - unique_function(vec![num_type(UVAR1, TVAR1)], num_type(UVAR2, TVAR1)), - ); + add_type(Symbol::NUM_ABS, { + let_tvars! { u, v, num }; + unique_function(vec![num_type(u, num)], num_type(v, num)) + }); // neg : Num a -> Num a - add_type( - Symbol::NUM_NEG, - unique_function(vec![num_type(UVAR1, TVAR1)], num_type(UVAR2, TVAR1)), - ); + add_type(Symbol::NUM_NEG, { + let_tvars! { u, v, num }; + unique_function(vec![num_type(u, num)], num_type(v, num)) + }); + + let mut add_num_comparison = |symbol| { + add_type(symbol, { + let_tvars! { u, v, w, num }; + unique_function(vec![num_type(u, num), num_type(v, num)], bool_type(w)) + }); + }; // isLt or (<) : Num a, Num a -> Bool - add_type( - Symbol::NUM_LT, - unique_function( - vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], - bool_type(UVAR3), - ), - ); + add_num_comparison(Symbol::NUM_LT); // isLte or (<=) : Num a, Num a -> Bool - add_type( - Symbol::NUM_LTE, - unique_function( - vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], - bool_type(UVAR3), - ), - ); + add_num_comparison(Symbol::NUM_LTE); // isGt or (>) : Num a, Num a -> Bool - add_type( - Symbol::NUM_GT, - unique_function( - vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], - bool_type(UVAR3), - ), - ); + add_num_comparison(Symbol::NUM_GT); // isGte or (>=) : Num a, Num a -> Bool - add_type( - Symbol::NUM_GTE, - unique_function( - vec![num_type(UVAR1, TVAR1), num_type(UVAR2, TVAR1)], - bool_type(UVAR3), - ), - ); + add_num_comparison(Symbol::NUM_GTE); // toFloat : Num a -> Float add_type( @@ -375,42 +353,42 @@ pub fn types() -> MutMap { // Int module // isLt or (<) : Num a, Num a -> Bool - add_type( - Symbol::INT_LT, - unique_function(vec![int_type(UVAR1), int_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::INT_LT, { + let_tvars! { u, v, w }; + unique_function(vec![int_type(u), int_type(v)], bool_type(w)) + }); // equals or (==) : Int, Int -> Bool - add_type( - Symbol::INT_EQ_I64, - unique_function(vec![int_type(UVAR1), int_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::INT_EQ_I64, { + let_tvars! { u, v, w }; + unique_function(vec![int_type(u), int_type(v)], bool_type(w)) + }); // not equals or (!=) : Int, Int -> Bool - add_type( - Symbol::INT_NEQ_I64, - unique_function(vec![int_type(UVAR1), int_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::INT_NEQ_I64, { + let_tvars! { u, v, w }; + unique_function(vec![int_type(u), int_type(v)], bool_type(w)) + }); // abs : Int -> Int - add_type( - Symbol::INT_ABS, - unique_function(vec![int_type(UVAR1)], int_type(UVAR2)), - ); + add_type(Symbol::INT_ABS, { + let_tvars! { u, v }; + unique_function(vec![int_type(u)], int_type(v)) + }); - // rem : Int, Int -> Result Int [ DivByZero ]* - add_type( - Symbol::INT_REM, + // rem : Attr * Int, Attr * Int -> Attr * (Result (Attr * Int) (Attr * [ DivByZero ]*)) + add_type(Symbol::INT_REM, { + let_tvars! { star1, star2, star3, star4, star5 }; unique_function( - vec![int_type(UVAR1), int_type(UVAR2)], - result_type(UVAR3, int_type(UVAR4), lift(UVAR5, div_by_zero())), - ), - ); + vec![int_type(star1), int_type(star2)], + result_type(star3, int_type(star4), lift(star5, div_by_zero())), + ) + }); - add_type( - Symbol::INT_REM_UNSAFE, - unique_function(vec![int_type(UVAR1), int_type(UVAR2)], int_type(UVAR3)), - ); + add_type(Symbol::INT_REM_UNSAFE, { + let_tvars! { star1, star2, star3, }; + unique_function(vec![int_type(star1), int_type(star2)], int_type(star3)) + }); // highest : Int add_type(Symbol::INT_HIGHEST, int_type(UVAR1)); @@ -419,92 +397,92 @@ pub fn types() -> MutMap { add_type(Symbol::INT_LOWEST, int_type(UVAR1)); // div or (//) : Int, Int -> Result Int [ DivByZero ]* - add_type( - Symbol::INT_DIV, + add_type(Symbol::INT_DIV, { + let_tvars! { star1, star2, star3, star4, star5 }; unique_function( - vec![int_type(UVAR1), int_type(UVAR2)], - result_type(UVAR3, int_type(UVAR4), lift(UVAR5, div_by_zero())), - ), - ); + vec![int_type(star1), int_type(star2)], + result_type(star3, int_type(star4), lift(star5, div_by_zero())), + ) + }); - add_type( - Symbol::INT_DIV_UNSAFE, - unique_function(vec![int_type(UVAR1), int_type(UVAR2)], int_type(UVAR3)), - ); + add_type(Symbol::INT_DIV_UNSAFE, { + let_tvars! { star1, star2, star3, }; + unique_function(vec![int_type(star1), int_type(star2)], int_type(star3)) + }); // mod : Int, Int -> Int - add_type( - Symbol::INT_MOD, - unique_function(vec![int_type(UVAR1), int_type(UVAR2)], int_type(UVAR3)), - ); + add_type(Symbol::INT_MOD, { + let_tvars! { star1, star2, star3, }; + unique_function(vec![int_type(star1), int_type(star2)], int_type(star3)) + }); // Float module // isGt or (>) : Num a, Num a -> Bool - add_type( - Symbol::FLOAT_GT, - unique_function(vec![float_type(UVAR1), float_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::FLOAT_GT, { + let_tvars! { star1, star2, star3} + unique_function(vec![float_type(star1), float_type(star2)], bool_type(star3)) + }); // eq or (==) : Num a, Num a -> Bool - add_type( - Symbol::FLOAT_EQ, - unique_function(vec![float_type(UVAR1), float_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::FLOAT_EQ, { + let_tvars! { star1, star2, star3} + unique_function(vec![float_type(star1), float_type(star2)], bool_type(star3)) + }); // div : Float, Float -> Float - add_type( - Symbol::FLOAT_DIV, + add_type(Symbol::FLOAT_DIV, { + let_tvars! { star1, star2, star3}; unique_function( - vec![float_type(UVAR1), float_type(UVAR2)], - float_type(UVAR3), - ), - ); + vec![float_type(star1), float_type(star2)], + float_type(star3), + ) + }); // mod : Float, Float -> Float - add_type( - Symbol::FLOAT_MOD, + add_type(Symbol::FLOAT_MOD, { + let_tvars! { star1, star2, star3}; unique_function( - vec![float_type(UVAR1), float_type(UVAR2)], - float_type(UVAR3), - ), - ); - - // sqrt : Float -> Float - add_type( - Symbol::FLOAT_SQRT, - unique_function(vec![float_type(UVAR1)], float_type(UVAR2)), - ); + vec![float_type(star1), float_type(star2)], + float_type(star3), + ) + }); // round : Float -> Int - add_type( - Symbol::FLOAT_ROUND, - unique_function(vec![float_type(UVAR1)], int_type(UVAR2)), - ); + add_type(Symbol::FLOAT_ROUND, { + let_tvars! { star1, star2 }; + unique_function(vec![float_type(star1)], int_type(star2)) + }); + + // sqrt : Float -> Float + add_type(Symbol::FLOAT_SQRT, { + let_tvars! { star1, star2 }; + unique_function(vec![float_type(star1)], float_type(star2)) + }); // abs : Float -> Float - add_type( - Symbol::FLOAT_ABS, - unique_function(vec![float_type(UVAR1)], float_type(UVAR2)), - ); + add_type(Symbol::FLOAT_ABS, { + let_tvars! { star1, star2 }; + unique_function(vec![float_type(star1)], float_type(star2)) + }); // sin : Float -> Float - add_type( - Symbol::FLOAT_SIN, - unique_function(vec![float_type(UVAR1)], float_type(UVAR2)), - ); + add_type(Symbol::FLOAT_SIN, { + let_tvars! { star1, star2 }; + unique_function(vec![float_type(star1)], float_type(star2)) + }); // cos : Float -> Float - add_type( - Symbol::FLOAT_COS, - unique_function(vec![float_type(UVAR1)], float_type(UVAR2)), - ); + add_type(Symbol::FLOAT_COS, { + let_tvars! { star1, star2 }; + unique_function(vec![float_type(star1)], float_type(star2)) + }); // tan : Float -> Float - add_type( - Symbol::FLOAT_TAN, - unique_function(vec![float_type(UVAR1)], float_type(UVAR2)), - ); + add_type(Symbol::FLOAT_TAN, { + let_tvars! { star1, star2 }; + unique_function(vec![float_type(star1)], float_type(star2)) + }); // highest : Float add_type(Symbol::FLOAT_HIGHEST, float_type(UVAR1)); @@ -514,41 +492,47 @@ pub fn types() -> MutMap { // Bool module - // isEq or (==) : a, a -> Attr u Bool - add_type( - Symbol::BOOL_EQ, - unique_function(vec![flex(TVAR1), flex(TVAR1)], bool_type(UVAR3)), - ); + // isEq or (==) : Attr * a, Attr * a -> Attr * Bool + add_type(Symbol::BOOL_EQ, { + let_tvars! { star1, star2, star3, a }; + unique_function( + vec![attr_type(star1, a), attr_type(star2, a)], + bool_type(star3), + ) + }); - // isNeq or (!=) : a, a -> Attr u Bool - add_type( - Symbol::BOOL_NEQ, - unique_function(vec![flex(TVAR1), flex(TVAR1)], bool_type(UVAR3)), - ); + // isNeq or (!=) : Attr * a, Attr * a -> Attr * Bool + add_type(Symbol::BOOL_NEQ, { + let_tvars! { star1, star2, star3, a }; + unique_function( + vec![attr_type(star1, a), attr_type(star2, a)], + bool_type(star3), + ) + }); // and or (&&) : Attr u1 Bool, Attr u2 Bool -> Attr u3 Bool - add_type( - Symbol::BOOL_AND, - unique_function(vec![bool_type(UVAR1), bool_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::BOOL_AND, { + let_tvars! { star1, star2, star3}; + unique_function(vec![bool_type(star1), bool_type(star2)], bool_type(star3)) + }); // or or (||) : Attr u1 Bool, Attr u2 Bool -> Attr u3 Bool - add_type( - Symbol::BOOL_OR, - unique_function(vec![bool_type(UVAR1), bool_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::BOOL_OR, { + let_tvars! { star1, star2, star3}; + unique_function(vec![bool_type(star1), bool_type(star2)], bool_type(star3)) + }); // xor : Attr u1 Bool, Attr u2 Bool -> Attr u3 Bool - add_type( - Symbol::BOOL_XOR, - unique_function(vec![bool_type(UVAR1), bool_type(UVAR2)], bool_type(UVAR3)), - ); + add_type(Symbol::BOOL_XOR, { + let_tvars! { star1, star2, star3}; + unique_function(vec![bool_type(star1), bool_type(star2)], bool_type(star3)) + }); // not : Attr u1 Bool -> Attr u2 Bool - add_type( - Symbol::BOOL_NOT, - unique_function(vec![bool_type(UVAR1)], bool_type(UVAR2)), - ); + add_type(Symbol::BOOL_NOT, { + let_tvars! { star1, star2 }; + unique_function(vec![bool_type(star1)], bool_type(star2)) + }); // List module diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index e60280e7c3..9a0c65e174 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -2402,14 +2402,18 @@ mod test_uniq_solve { } #[test] - fn equals() { + fn bool_eq() { infer_eq( - indoc!( - r#" - \a, b -> a == b - "# - ), - "Attr * (a, a -> Attr * Bool)", + "\\a, b -> a == b", + "Attr * (Attr * a, Attr * a -> Attr * Bool)", + ); + } + + #[test] + fn bool_neq() { + infer_eq( + "\\a, b -> a != b", + "Attr * (Attr * a, Attr * a -> Attr * Bool)", ); } From b88dfcb5376cccb89928a15cd4ad551f4057246b Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 23 Jun 2020 15:36:02 +0200 Subject: [PATCH 21/22] revise Set --- compiler/builtins/src/unique.rs | 96 ++++++++++++------------- compiler/solve/tests/test_uniq_solve.rs | 47 ++++++++++++ 2 files changed, 92 insertions(+), 51 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index af4aa859b1..68a390e72e 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -845,72 +845,73 @@ pub fn types() -> MutMap { // Set module // empty : Set a - add_type(Symbol::SET_EMPTY, set_type(UVAR1, TVAR1)); + add_type(Symbol::SET_EMPTY, { + let_tvars! { star, a }; + set_type(star, a) + }); // singleton : a -> Set a - add_type( - Symbol::SET_SINGLETON, - unique_function(vec![flex(TVAR1)], set_type(UVAR1, TVAR1)), - ); + add_type(Symbol::SET_SINGLETON, { + let_tvars! { star, a }; + unique_function(vec![flex(a)], set_type(star, a)) + }); - // op : Attr (u | *) (Set (Attr u a)), Attr (u | *) (Set (Attr u a)) -> Attr * Set (Attr u a) + // union : Attr * (Set * a) + // , Attr * (Set * a) + // -> Attr * (Set * a) let set_combine = { - let mut store = IDStore::new(); - - let u = store.fresh(); - let a = store.fresh(); - let star1 = store.fresh(); - let star2 = store.fresh(); - let star3 = store.fresh(); + let_tvars! { star1, star2, star3, star4, star5, star6, a }; unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star1, vec![u]), - SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), + flex(star1), + SolvedType::Apply(Symbol::SET_SET, vec![attr_type(star2, a)]), ], ), SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star2, vec![u]), - SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), + flex(star3), + SolvedType::Apply(Symbol::SET_SET, vec![attr_type(star4, a)]), ], ), ], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - flex(star3), - SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), + flex(star5), + SolvedType::Apply(Symbol::SET_SET, vec![attr_type(star6, a)]), ], ), ) }; - // union : Set a, Set a -> Set a + // union : Attr * (Set * a) + // , Attr * (Set * a) + // -> Attr * (Set * a) add_type(Symbol::SET_UNION, set_combine.clone()); - // diff : Set a, Set a -> Set a + // diff : Attr * (Set * a) + // , Attr * (Set * a) + // -> Attr * (Set * a) add_type(Symbol::SET_DIFF, set_combine); - // foldl : Attr (u | *) (Set (Attr u a)), Attr Shared (Attr u a -> b -> b), b -> b + // foldl : Attr (* | u) (Set (Attr u a)) + // , Attr Shared (Attr u a -> b -> b) + // , b + // -> b add_type(Symbol::SET_FOLDL, { - let mut store = IDStore::new(); - - let u = store.fresh(); - let a = store.fresh(); - let b = store.fresh(); - let star1 = store.fresh(); + let_tvars! { star, u, a, b }; unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star1, vec![u]), + container(star, vec![u]), SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), @@ -924,54 +925,47 @@ pub fn types() -> MutMap { ) }); - // insert : Attr (u | *) (Set (Attr u a)), Attr (u | *) a -> Attr * (Set (Attr u a)) + // insert : Attr * (Set a) + // , a + // , Attr * (Set a) add_type(Symbol::SET_INSERT, { - let mut store = IDStore::new(); - - let u = store.fresh(); - let a = store.fresh(); - let star1 = store.fresh(); - let star2 = store.fresh(); - let star3 = store.fresh(); + let_tvars! { star1, star2, a }; unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star1, vec![u]), - SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), + flex(star1), + SolvedType::Apply(Symbol::SET_SET, vec![flex(a)]), ], ), - SolvedType::Apply(Symbol::ATTR_ATTR, vec![container(star2, vec![u]), flex(a)]), + flex(a), ], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - flex(star3), - SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), + flex(star2), + SolvedType::Apply(Symbol::SET_SET, vec![flex(a)]), ], ), ) }); // we can remove a key that is shared from a set of unique keys - // remove : Attr (u | *) (Set (Attr u a)), Attr * a -> Attr * (Set (Attr u a)) + // + // remove : Attr * (Set (Attr u a)) + // , Attr * a + // , Attr * (Set (Attr u a)) add_type(Symbol::SET_REMOVE, { - let mut store = IDStore::new(); - - let u = store.fresh(); - let a = store.fresh(); - let star1 = store.fresh(); - let star2 = store.fresh(); - let star3 = store.fresh(); + let_tvars! { u, a, star1, star2, star3 }; unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star1, vec![u]), + flex(star1), SolvedType::Apply(Symbol::SET_SET, vec![attr_type(u, a)]), ], ), diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index 9a0c65e174..30d5f4a904 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -2151,6 +2151,53 @@ mod test_uniq_solve { ); } + #[test] + fn set_empty() { + infer_eq("Set.empty", "Attr * (Set *)"); + } + + #[test] + fn set_singelton() { + infer_eq("Set.singleton", "Attr * (a -> Attr * (Set a))"); + } + + #[test] + fn set_union() { + infer_eq( + "Set.union", + "Attr * (Attr * (Set (Attr * a)), Attr * (Set (Attr * a)) -> Attr * (Set (Attr * a)))", + ); + } + + #[test] + fn set_diff() { + infer_eq( + "Set.diff", + "Attr * (Attr * (Set (Attr * a)), Attr * (Set (Attr * a)) -> Attr * (Set (Attr * a)))", + ); + } + + #[test] + fn set_foldl() { + infer_eq( + "Set.foldl", + "Attr * (Attr (* | a) (Set (Attr a b)), Attr Shared (Attr a b, c -> c), c -> c)", + ); + } + + #[test] + fn set_insert() { + infer_eq("Set.insert", "Attr * (Attr * (Set a), a -> Attr * (Set a))"); + } + + #[test] + fn set_remove() { + infer_eq( + "Set.remove", + "Attr * (Attr * (Set (Attr a b)), Attr * b -> Attr * (Set (Attr a b)))", + ); + } + #[test] fn use_correct_ext_var() { infer_eq( From 41ad8f29528968404291d378e0a1246a12d16dd0 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 23 Jun 2020 21:16:29 +0200 Subject: [PATCH 22/22] revise Map and cleanup --- compiler/builtins/src/unique.rs | 190 ++++++++++-------------- compiler/module/src/symbol.rs | 1 + compiler/solve/tests/test_uniq_solve.rs | 44 ++++++ 3 files changed, 123 insertions(+), 112 deletions(-) diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 68a390e72e..826a8d56f8 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -35,35 +35,8 @@ macro_rules! let_tvars { /// const NUM_BUILTIN_IMPORTS: usize = 7; -/// These can be shared between definitions, they will get instantiated when converted to Type -const TVAR1: VarId = VarId::from_u32(1); -const TVAR2: VarId = VarId::from_u32(2); -const TVAR3: VarId = VarId::from_u32(3); - /// These can be shared between definitions, they will get instantiated when converted to Type const FUVAR: VarId = VarId::from_u32(1000); -const UVAR1: VarId = VarId::from_u32(1001); -const UVAR2: VarId = VarId::from_u32(1002); -// const UVAR3: VarId = VarId::from_u32(1003); -const UVAR4: VarId = VarId::from_u32(1004); -const UVAR5: VarId = VarId::from_u32(1005); -const UVAR6: VarId = VarId::from_u32(1006); - -pub struct IDStore(u32); - -impl IDStore { - fn new() -> Self { - IDStore(2000) - } - - fn fresh(&mut self) -> VarId { - let result = VarId::from_u32(self.0); - - self.0 += 1; - - result - } -} fn shared(base: SolvedType) -> SolvedType { SolvedType::Apply( @@ -145,7 +118,6 @@ pub fn uniq_stdlib() -> StdLib { } pub fn aliases() -> MutMap { - // let mut aliases = builtins::aliases(); let mut aliases = MutMap::default(); let mut add_alias = |symbol, alias| { @@ -168,13 +140,16 @@ pub fn aliases() -> MutMap { ) }; + // NOTE: `a` must be the first variable bound here! + let_tvars! { a, err, star }; + // Num : Num Integer add_alias( Symbol::NUM_NUM, BuiltinAlias { region: Region::zero(), vars: vec![Located::at(Region::zero(), "a".into())], - typ: single_private_tag(Symbol::NUM_AT_NUM, vec![flex(TVAR1)]), + typ: single_private_tag(Symbol::NUM_AT_NUM, vec![flex(a)]), }, ); @@ -207,7 +182,7 @@ pub fn aliases() -> MutMap { typ: SolvedType::Apply( Symbol::NUM_NUM, vec![lift( - UVAR1, + star, SolvedType::Apply(Symbol::INT_INTEGER, Vec::new()), )], ), @@ -223,7 +198,7 @@ pub fn aliases() -> MutMap { typ: SolvedType::Apply( Symbol::NUM_NUM, vec![lift( - UVAR1, + star, SolvedType::Apply(Symbol::FLOAT_FLOATINGPOINT, Vec::new()), )], ), @@ -257,8 +232,8 @@ pub fn aliases() -> MutMap { ], typ: SolvedType::TagUnion( vec![ - (TagName::Global("Ok".into()), vec![flex(TVAR1)]), - (TagName::Global("Err".into()), vec![flex(TVAR2)]), + (TagName::Global("Ok".into()), vec![flex(a)]), + (TagName::Global("Err".into()), vec![flex(err)]), ], Box::new(SolvedType::EmptyTagUnion), ), @@ -345,10 +320,10 @@ pub fn types() -> MutMap { add_num_comparison(Symbol::NUM_GTE); // toFloat : Num a -> Float - add_type( - Symbol::NUM_TO_FLOAT, - unique_function(vec![num_type(UVAR1, TVAR1)], float_type(UVAR2)), - ); + add_type(Symbol::NUM_TO_FLOAT, { + let_tvars! { star1, star2, a }; + unique_function(vec![num_type(star1, a)], float_type(star2)) + }); // Int module @@ -391,10 +366,16 @@ pub fn types() -> MutMap { }); // highest : Int - add_type(Symbol::INT_HIGHEST, int_type(UVAR1)); + add_type(Symbol::INT_HIGHEST, { + let_tvars! { star }; + int_type(star) + }); // lowest : Int - add_type(Symbol::INT_LOWEST, int_type(UVAR1)); + add_type(Symbol::INT_LOWEST, { + let_tvars! { star }; + int_type(star) + }); // div or (//) : Int, Int -> Result Int [ DivByZero ]* add_type(Symbol::INT_DIV, { @@ -485,10 +466,16 @@ pub fn types() -> MutMap { }); // highest : Float - add_type(Symbol::FLOAT_HIGHEST, float_type(UVAR1)); + add_type(Symbol::FLOAT_HIGHEST, { + let_tvars! { star }; + float_type(star) + }); // lowest : Float - add_type(Symbol::FLOAT_LOWEST, float_type(UVAR1)); + add_type(Symbol::FLOAT_LOWEST, { + let_tvars! { star }; + float_type(star) + }); // Bool module @@ -575,10 +562,10 @@ pub fn types() -> MutMap { }); // is LIST_GET_UNSAFE still used? - add_type( - Symbol::LIST_GET_UNSAFE, - unique_function(vec![list_type(UVAR1, TVAR1), int_type(UVAR2)], flex(TVAR1)), - ); + add_type(Symbol::LIST_GET_UNSAFE, { + let_tvars! { star1, star2, a }; + unique_function(vec![list_type(star1, a), int_type(star2)], flex(a)) + }); // set : Attr (w | u | v) (List (Attr u a)) // , Attr * Int @@ -734,19 +721,18 @@ pub fn types() -> MutMap { // Map module - // empty : Map k v - add_type(Symbol::MAP_EMPTY, map_type(UVAR1, TVAR1, TVAR2)); + // empty : Attr * (Map k v) + add_type(Symbol::MAP_EMPTY, { + let_tvars! { star, k , v }; + map_type(star, k, v) + }); - // singleton : k, v -> Map k v - add_type( - Symbol::MAP_SINGLETON, - unique_function( - vec![flex(TVAR1), flex(TVAR2)], - map_type(UVAR1, TVAR1, TVAR2), - ), - ); + // singleton : k, v -> Attr * (Map k v) + add_type(Symbol::MAP_SINGLETON, { + let_tvars! { star, k , v }; + unique_function(vec![flex(k), flex(v)], map_type(star, k, v)) + }); - // get : Attr (u | v | *) (Map (Attr u key) (Attr v val), (Attr * key) -> Attr * (Result (Attr v val) [ KeyNotFound ]*) let key_not_found = SolvedType::Apply( Symbol::ATTR_ATTR, vec![ @@ -758,85 +744,63 @@ pub fn types() -> MutMap { ], ); + // get : Attr (* | u) (Map (Attr * key) (Attr u val)) + // , Attr * key + // -> Attr * (Result (Attr u val) [ KeyNotFound ]*) add_type(Symbol::MAP_GET, { - let mut store = IDStore::new(); - - let u = store.fresh(); - let v = store.fresh(); - let key = store.fresh(); - let val = store.fresh(); - let star1 = store.fresh(); - let star2 = store.fresh(); - let star3 = store.fresh(); + let_tvars! { u, key, val, star1, star2, star3, star4 }; unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star1, vec![u, v]), + container(star1, vec![u]), SolvedType::Apply( Symbol::MAP_MAP, - vec![attr_type(u, key), attr_type(v, val)], + vec![attr_type(star2, key), attr_type(u, val)], ), ], ), - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![container(star2, vec![u]), flex(key)], - ), + SolvedType::Apply(Symbol::ATTR_ATTR, vec![flex(star3), flex(key)]), ], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - flex(star3), + flex(star4), SolvedType::Apply( Symbol::RESULT_RESULT, - vec![attr_type(v, val), key_not_found], + vec![attr_type(u, val), key_not_found], ), ], ), ) }); - // insert : Attr (u | v | *) (Map (Attr u key) (Attr v val)), Attr (u | *) key, Attr (v | *) val -> Attr * (Map (Attr u key) (Attr v val)) + // insert : Attr * (Map key value) + // , key + // , value + // , Attr * (Map key value) add_type(Symbol::MAP_INSERT, { - let mut store = IDStore::new(); - - let u = store.fresh(); - let v = store.fresh(); - let key = store.fresh(); - let val = store.fresh(); - let star1 = store.fresh(); - let star2 = store.fresh(); - let star3 = store.fresh(); + let_tvars! { star1, star2, key, value }; unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star1, vec![u, v]), - SolvedType::Apply( - Symbol::MAP_MAP, - vec![attr_type(u, key), attr_type(v, val)], - ), + flex(star1), + SolvedType::Apply(Symbol::MAP_MAP, vec![flex(key), flex(value)]), ], ), - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![container(star2, vec![u]), flex(key)], - ), - SolvedType::Apply( - Symbol::ATTR_ATTR, - vec![container(star2, vec![v]), flex(val)], - ), + flex(key), + flex(value), ], SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - flex(star3), - SolvedType::Apply(Symbol::MAP_MAP, vec![attr_type(u, key), attr_type(v, val)]), + flex(star2), + SolvedType::Apply(Symbol::MAP_MAP, vec![flex(key), flex(value)]), ], ), ) @@ -983,37 +947,39 @@ pub fn types() -> MutMap { // Str module - // isEmpty : Attr u Str -> Attr v Bool + // isEmpty : Attr * Str -> Attr * Bool add_type(Symbol::STR_ISEMPTY, { - unique_function(vec![str_type(UVAR1)], bool_type(UVAR2)) + let_tvars! { star1, star2 }; + unique_function(vec![str_type(star1)], bool_type(star2)) + }); + + // append : Attr * Str, Attr * Str -> Attr * Str + add_type(Symbol::STR_APPEND, { + let_tvars! { star1, star2, star3 }; + unique_function(vec![str_type(star1), str_type(star2)], str_type(star3)) }); // Result module - // map : Attr (* | u | v) (Result (Attr u a) e), Attr * (Attr u a -> b) -> Attr * (Result b e) + // map : Attr * (Result (Attr a e)) + // , Attr * (a -> b) + // -> Attr * (Result b e) add_type(Symbol::RESULT_MAP, { - let u = UVAR1; - let star1 = UVAR4; - let star2 = UVAR5; - let star3 = UVAR6; - - let a = TVAR1; - let b = TVAR2; - let e = TVAR3; + let_tvars! { star1, star2, star3, a, b, e }; unique_function( vec![ SolvedType::Apply( Symbol::ATTR_ATTR, vec![ - container(star1, vec![u]), - SolvedType::Apply(Symbol::RESULT_RESULT, vec![attr_type(u, a), flex(e)]), + flex(star1), + SolvedType::Apply(Symbol::RESULT_RESULT, vec![flex(a), flex(e)]), ], ), SolvedType::Apply( Symbol::ATTR_ATTR, vec![ flex(star2), - SolvedType::Func(vec![attr_type(u, a)], Box::new(flex(b))), + SolvedType::Func(vec![flex(a)], Box::new(flex(b))), ], ), ], diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 31cff923e0..e228169ff5 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -672,6 +672,7 @@ define_builtins! { 0 STR_STR: "Str" imported // the Str.Str type alias 1 STR_AT_STR: "@Str" // the Str.@Str private tag 2 STR_ISEMPTY: "isEmpty" + 3 STR_APPEND: "append" } 6 LIST: "List" => { 0 LIST_LIST: "List" imported // the List.List type alias diff --git a/compiler/solve/tests/test_uniq_solve.rs b/compiler/solve/tests/test_uniq_solve.rs index 30d5f4a904..cfe210200b 100644 --- a/compiler/solve/tests/test_uniq_solve.rs +++ b/compiler/solve/tests/test_uniq_solve.rs @@ -2198,6 +2198,50 @@ mod test_uniq_solve { ); } + #[test] + fn map_empty() { + infer_eq("Map.empty", "Attr * (Map * *)"); + } + + #[test] + fn map_singelton() { + infer_eq("Map.singleton", "Attr * (a, b -> Attr * (Map a b))"); + } + + #[test] + fn map_get() { + infer_eq("Map.get", "Attr * (Attr (* | a) (Map (Attr * b) (Attr a c)), Attr * b -> Attr * (Result (Attr a c) (Attr * [ KeyNotFound ]*)))"); + } + + #[test] + fn map_insert() { + infer_eq( + "Map.insert", + "Attr * (Attr * (Map a b), a, b -> Attr * (Map a b))", + ); + } + + #[test] + fn str_is_empty() { + infer_eq("Str.isEmpty", "Attr * (Attr * Str -> Attr * Bool)"); + } + + #[test] + fn str_append() { + infer_eq( + "Str.append", + "Attr * (Attr * Str, Attr * Str -> Attr * Str)", + ); + } + + #[test] + fn result_map() { + infer_eq( + "Result.map", + "Attr * (Attr * (Result a b), Attr * (a -> c) -> Attr * (Result c b))", + ); + } + #[test] fn use_correct_ext_var() { infer_eq(