From e73ac60053acab900385a0917be8bbeb956f8f3a Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 23:49:53 +0200 Subject: [PATCH 001/223] improve Tag literal generation --- compiler/gen_llvm/src/llvm/build.rs | 115 +++++++++++++++------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index bacda91a69..15bba5307b 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -618,8 +618,8 @@ pub fn construct_optimization_passes<'a>( mpm.add_always_inliner_pass(); // tail-call elimination is always on - fpm.add_instruction_combining_pass(); - fpm.add_tail_call_elimination_pass(); + // fpm.add_instruction_combining_pass(); + // fpm.add_tail_call_elimination_pass(); let pmb = PassManagerBuilder::create(); match opt_level { @@ -629,7 +629,7 @@ pub fn construct_optimization_passes<'a>( OptLevel::Optimize => { pmb.set_optimization_level(OptimizationLevel::Aggressive); // this threshold seems to do what we want - pmb.set_inliner_with_threshold(275); + pmb.set_inliner_with_threshold(0); // TODO figure out which of these actually help @@ -1241,17 +1241,26 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let struct_type = basic_type_from_layout(env, &struct_layout); - let struct_value = access_index_struct_value( - builder, - argument.into_struct_value(), - struct_type.into_struct_type(), + let argument_pointer = builder.build_alloca(argument.get_type(), "cast_alloca"); + builder.build_store(argument_pointer, argument); + + let struct_ptr = builder.build_pointer_cast( + argument_pointer, + struct_type.ptr_type(AddressSpace::Generic), + "foobar", ); + // let struct_value = access_index_struct_value( + // builder, + // argument.into_struct_value(), + // struct_type.into_struct_type(), + // ); + let result = builder - .build_extract_value(struct_value, *index as u32, "") + .build_struct_gep(struct_ptr, *index as u32, "") .expect("desired field did not decode"); - result + builder.build_load(result, "foobarbaz") } UnionLayout::Recursive(tag_layouts) => { debug_assert!(argument.is_pointer_value()); @@ -1453,7 +1462,13 @@ pub fn build_tag<'a, 'ctx, 'env>( UnionLayout::NonRecursive(tags) => { debug_assert!(union_size > 1); - let ctx = env.context; + let internal_type = block_of_memory_slices(env.context, tags, env.ptr_bytes); + + let tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type(); + let wrapper_type = env + .context + .struct_type(&[internal_type, tag_id_type.into()], false); + let result_alloca = env.builder.build_alloca(wrapper_type, "tag_opaque"); // Determine types let num_fields = arguments.len() + 1; @@ -1484,54 +1499,46 @@ pub fn build_tag<'a, 'ctx, 'env>( } } } - - // Create the struct_type - let struct_type = ctx.struct_type(field_types.into_bump_slice(), false); - - // Insert field exprs into struct_val - let struct_val = - struct_from_fields(env, struct_type, field_vals.into_iter().enumerate()); - - // How we create tag values - // - // The memory layout of tags can be different. e.g. in - // - // [ Ok Int, Err Str ] - // - // the `Ok` tag stores a 64-bit integer, the `Err` tag stores a struct. - // All tags of a union must have the same length, for easy addressing (e.g. array lookups). - // So we need to ask for the maximum of all tag's sizes, even if most tags won't use - // all that memory, and certainly won't use it in the same way (the tags have fields of - // different types/sizes) - // - // In llvm, we must be explicit about the type of value we're creating: we can't just - // make a unspecified block of memory. So what we do is create a byte array of the - // desired size. Then when we know which tag we have (which is here, in this function), - // we need to cast that down to the array of bytes that llvm expects - // - // There is the bitcast instruction, but it doesn't work for arrays. So we need to jump - // through some hoops using store and load to get this to work: the array is put into a - // one-element struct, which can be cast to the desired type. - // - // This tricks comes from - // https://github.com/raviqqe/ssf/blob/bc32aae68940d5bddf5984128e85af75ca4f4686/ssf-llvm/src/expression_compiler.rs#L116 - - let internal_type = block_of_memory_slices(env.context, tags, env.ptr_bytes); - - let data = cast_tag_to_block_of_memory(env, struct_val, internal_type); - let tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type(); - let wrapper_type = env - .context - .struct_type(&[data.get_type(), tag_id_type.into()], false); + // store the tag id + let tag_id_ptr = env + .builder + .build_struct_gep(result_alloca, TAG_ID_INDEX, "get_opaque_data") + .unwrap(); let tag_id_intval = tag_id_type.const_int(tag_id as u64, false); + env.builder.build_store(tag_id_ptr, tag_id_intval); - let field_vals = [ - (TAG_DATA_INDEX as usize, data), - (TAG_ID_INDEX as usize, tag_id_intval.into()), - ]; + // Create the struct_type + let struct_type = env + .context + .struct_type(field_types.into_bump_slice(), false); - struct_from_fields(env, wrapper_type, field_vals.iter().copied()).into() + let struct_opaque_ptr = env + .builder + .build_struct_gep(result_alloca, TAG_DATA_INDEX, "get_opaque_data") + .unwrap(); + let struct_ptr = env.builder.build_pointer_cast( + struct_opaque_ptr, + struct_type.ptr_type(AddressSpace::Generic), + "to_specific", + ); + + // Insert field exprs into struct_val + //let struct_val = + //struct_from_fields(env, struct_type, field_vals.into_iter().enumerate()); + + // Insert field exprs into struct_val + for (index, field_val) in field_vals.iter().copied().enumerate() { + let index: u32 = index as u32; + + let ptr = env + .builder + .build_struct_gep(struct_ptr, index, "get_tag_field_ptr") + .unwrap(); + env.builder.build_store(ptr, field_val); + } + + env.builder.build_load(result_alloca, "load_result") } UnionLayout::Recursive(tags) => { debug_assert!(union_size > 1); From 7d1bd0ffe7c562f2191f30e1697052f0a5af1a1b Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 21 Oct 2021 22:08:32 +0200 Subject: [PATCH 002/223] make refcount take tag union by reference --- compiler/gen_llvm/src/llvm/build.rs | 2 +- compiler/gen_llvm/src/llvm/refcounting.rs | 61 ++++++++++++++++++----- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 15bba5307b..80c588bfb0 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -971,7 +971,7 @@ pub fn build_exp_call<'a, 'ctx, 'env>( } } -const TAG_ID_INDEX: u32 = 1; +pub const TAG_ID_INDEX: u32 = 1; pub const TAG_DATA_INDEX: u32 = 0; pub fn struct_from_fields<'a, 'ctx, 'env, I>( diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 8a89c924d7..0e8f275554 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -2,7 +2,7 @@ use crate::debug_info_init; use crate::llvm::bitcode::call_void_bitcode_fn; use crate::llvm::build::{ add_func, cast_basic_basic, cast_block_of_memory_to_tag, get_tag_id, get_tag_id_non_recursive, - tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, TAG_DATA_INDEX, + tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, TAG_DATA_INDEX, TAG_ID_INDEX, }; use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list}; use crate::llvm::convert::{basic_type_from_layout, ptr_int}; @@ -542,6 +542,24 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( } }, _ => { + if let Layout::Union(UnionLayout::NonRecursive(_)) = layout { + let alloca = env.builder.build_alloca(value.get_type(), "tag_union"); + env.builder.build_store(alloca, value); + call_help(env, function, call_mode, alloca.into()); + return; + } + + if let Layout::LambdaSet(lambda_set) = layout { + if let Layout::Union(UnionLayout::NonRecursive(_)) = + lambda_set.runtime_representation() + { + let alloca = env.builder.build_alloca(value.get_type(), "tag_union"); + env.builder.build_store(alloca, value); + call_help(env, function, call_mode, alloca.into()); + return; + } + } + call_help(env, function, call_mode, value); } } @@ -1603,7 +1621,9 @@ fn modify_refcount_union<'a, 'ctx, 'env>( Some(function_value) => function_value, None => { let basic_type = basic_type_from_layout(env, &layout); - let function_value = build_header(env, basic_type, mode, &fn_name); + // we pass tag unions by reference for efficiency + let ptr_type = basic_type.ptr_type(AddressSpace::Generic).into(); + let function_value = build_header(env, ptr_type, mode, &fn_name); modify_refcount_union_help( env, @@ -1647,18 +1667,27 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( // Add args to scope let arg_symbol = Symbol::ARG_1; - let arg_val = fn_val.get_param_iter().next().unwrap(); + let arg_ptr = fn_val.get_param_iter().next().unwrap().into_pointer_value(); - arg_val.set_name(arg_symbol.as_str(&env.interns)); + arg_ptr.set_name(arg_symbol.as_str(&env.interns)); let parent = fn_val; let before_block = env.builder.get_insert_block().expect("to be in a function"); + let arg_val = env.builder.build_load(arg_ptr, "load_tag_union"); let wrapper_struct = arg_val.into_struct_value(); // read the tag_id - let tag_id = get_tag_id_non_recursive(env, wrapper_struct); + let tag_id_ptr = env + .builder + .build_struct_gep(arg_ptr, TAG_ID_INDEX, "tag_id_ptr") + .unwrap(); + + let tag_id = env + .builder + .build_load(tag_id_ptr, "load_tag_id") + .into_int_value(); let tag_id_u8 = env .builder @@ -1686,12 +1715,18 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( let wrapper_type = basic_type_from_layout(env, &Layout::Struct(field_layouts)); debug_assert!(wrapper_type.is_struct_type()); - let data_bytes = env + let opaque_tag_data_ptr = env .builder - .build_extract_value(wrapper_struct, TAG_DATA_INDEX, "read_tag_id") - .unwrap() - .into_struct_value(); - let wrapper_struct = cast_block_of_memory_to_tag(env.builder, data_bytes, wrapper_type); + .build_struct_gep(arg_ptr, TAG_DATA_INDEX, "tag_id_ptr") + .unwrap(); + + let cast_tag_data_pointer = env.builder.build_pointer_cast( + opaque_tag_data_ptr, + wrapper_type.ptr_type(AddressSpace::Generic), + "cast_to_concrete_tag", + ); + + // let wrapper_struct = cast_block_of_memory_to_tag(env.builder, data_bytes, wrapper_type); for (i, field_layout) in field_layouts.iter().enumerate() { if let Layout::RecursivePointer = field_layout { @@ -1699,16 +1734,18 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( } else if field_layout.contains_refcounted() { let field_ptr = env .builder - .build_extract_value(wrapper_struct, i as u32, "modify_tag_field") + .build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field") .unwrap(); + let field_value = env.builder.build_load(field_ptr, "field_value"); + modify_refcount_layout_help( env, parent, layout_ids, mode.to_call_mode(fn_val), when_recursive, - field_ptr, + field_value, field_layout, ); } From 28b15cdf67949402b4e0019a82526be8b4a2a824 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 21 Oct 2021 22:57:22 +0200 Subject: [PATCH 003/223] prettier --- compiler/gen_llvm/src/llvm/build.rs | 4 ++-- compiler/gen_llvm/src/llvm/refcounting.rs | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 80c588bfb0..1ec0d634ed 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -618,8 +618,8 @@ pub fn construct_optimization_passes<'a>( mpm.add_always_inliner_pass(); // tail-call elimination is always on - // fpm.add_instruction_combining_pass(); - // fpm.add_tail_call_elimination_pass(); + fpm.add_instruction_combining_pass(); + fpm.add_tail_call_elimination_pass(); let pmb = PassManagerBuilder::create(); match opt_level { diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 0e8f275554..f183e029f6 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -1675,9 +1675,6 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( let before_block = env.builder.get_insert_block().expect("to be in a function"); - let arg_val = env.builder.build_load(arg_ptr, "load_tag_union"); - let wrapper_struct = arg_val.into_struct_value(); - // read the tag_id let tag_id_ptr = env .builder @@ -1717,7 +1714,7 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( debug_assert!(wrapper_type.is_struct_type()); let opaque_tag_data_ptr = env .builder - .build_struct_gep(arg_ptr, TAG_DATA_INDEX, "tag_id_ptr") + .build_struct_gep(arg_ptr, TAG_DATA_INDEX, "field_ptr") .unwrap(); let cast_tag_data_pointer = env.builder.build_pointer_cast( From 171c0836e4fffd81226bad6bdc1fd0facb1aa5ec Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 22 Oct 2021 11:45:24 +0200 Subject: [PATCH 004/223] return tag unions by pointer --- compiler/gen_llvm/src/llvm/build.rs | 121 +++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 20 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 1ec0d634ed..82dfdd2b36 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -629,7 +629,7 @@ pub fn construct_optimization_passes<'a>( OptLevel::Optimize => { pmb.set_optimization_level(OptimizationLevel::Aggressive); // this threshold seems to do what we want - pmb.set_inliner_with_threshold(0); + pmb.set_inliner_with_threshold(275); // TODO figure out which of these actually help @@ -2377,15 +2377,42 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( result } Ret(symbol) => { - let value = load_symbol(scope, symbol); + let (value, layout) = load_symbol_and_layout(scope, symbol); - if let Some(block) = env.builder.get_insert_block() { - if block.get_terminator().is_none() { - env.builder.build_return(Some(&value)); + match RocReturn::from_layout(env, layout) { + RocReturn::Return => { + if let Some(block) = env.builder.get_insert_block() { + if block.get_terminator().is_none() { + env.builder.build_return(Some(&value)); + } + } + + value + } + RocReturn::ByPointer => { + // we need to write our value into the final argument of the current function + let parameters = parent.get_params(); + let out_parameter = parameters.last().unwrap(); + debug_assert!(out_parameter.is_pointer_value()); + + env.builder + .build_store(out_parameter.into_pointer_value(), value); + + if let Some(block) = env.builder.get_insert_block() { + match block.get_terminator() { + None => { + env.builder.build_return(None); + } + Some(terminator) => { + terminator.remove_from_basic_block(); + env.builder.build_return(None); + } + } + } + + env.context.i8_type().const_zero().into() } } - - value } Switch { @@ -3106,7 +3133,6 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( c_function_name: &str, ) -> FunctionValue<'ctx> { // NOTE we ingore env.is_gen_test here - let wrapper_return_type = roc_function.get_type().get_return_type().unwrap(); let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena); for layout in arguments { @@ -3116,12 +3142,19 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( // STEP 1: turn `f : a,b,c -> d` into `f : a,b,c, &d -> {}` // let mut argument_types = roc_function.get_type().get_param_types(); let mut argument_types = cc_argument_types; - let return_type = wrapper_return_type; - let output_type = return_type.ptr_type(AddressSpace::Generic); - argument_types.push(output_type.into()); + let c_function_type = match roc_function.get_type().get_return_type() { + None => { + // this function already returns by-pointer + roc_function.get_type() + } + Some(return_type) => { + let output_type = return_type.ptr_type(AddressSpace::Generic); + argument_types.push(output_type.into()); - let c_function_type = env.context.void_type().fn_type(&argument_types, false); + env.context.void_type().fn_type(&argument_types, false) + } + }; let c_function = add_func( env.module, @@ -3167,10 +3200,10 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( let arguments_for_call = &arguments_for_call.into_bump_slice(); - debug_assert_eq!(args.len(), roc_function.get_params().len()); - let call_result = { if env.is_gen_test { + debug_assert_eq!(args.len(), roc_function.get_params().len()); + let roc_wrapper_function = make_exception_catcher(env, roc_function); debug_assert_eq!( arguments_for_call.len(), @@ -3375,7 +3408,8 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( ) .into() } else { - roc_function.get_type().get_return_type().unwrap() + // roc_function.get_type().get_return_type().unwrap() + basic_type_from_layout(env, &return_layout) }; let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena); @@ -3432,10 +3466,15 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( CCReturn::Void => { debug_assert_eq!(args.len(), roc_function.get_params().len()); } - CCReturn::ByPointer => { - args = &args[..args.len() - 1]; - debug_assert_eq!(args.len(), roc_function.get_params().len()); - } + CCReturn::ByPointer => match RocReturn::from_layout(env, &return_layout) { + RocReturn::ByPointer => { + debug_assert_eq!(args.len(), roc_function.get_params().len()); + } + RocReturn::Return => { + args = &args[..args.len() - 1]; + debug_assert_eq!(args.len(), roc_function.get_params().len()); + } + }, } let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena); @@ -3975,7 +4014,17 @@ fn build_proc_header<'a, 'ctx, 'env>( arg_basic_types.push(arg_type); } - let fn_type = ret_type.fn_type(&arg_basic_types, false); + let fn_type = match RocReturn::from_layout(env, &proc.ret_layout) { + RocReturn::Return => ret_type.fn_type(&arg_basic_types, false), + RocReturn::ByPointer => { + println!( + "{:?} will return void instead of {:?}", + symbol, proc.ret_layout + ); + arg_basic_types.push(ret_type.ptr_type(AddressSpace::Generic).into()); + env.context.void_type().fn_type(&arg_basic_types, false) + } + }; let fn_val = add_func( env.module, @@ -4340,6 +4389,7 @@ fn roc_call_with_args<'a, 'ctx, 'env>( let fn_val = function_value_by_func_spec(env, func_spec, symbol, argument_layouts, result_layout); +<<<<<<< HEAD call_roc_function(env, fn_val, result_layout, arguments) } @@ -5690,6 +5740,37 @@ fn to_cc_type_builtin<'a, 'ctx, 'env>( } } +enum RocReturn { + /// Return as normal + Return, + /// require an extra argument, a pointer + /// where the result is written into returns void + ByPointer, +} + +impl RocReturn { + fn roc_return_by_pointer(layout: Layout) -> bool { + match layout { + Layout::Union(union_layout) => match union_layout { + UnionLayout::NonRecursive(_) => true, + _ => false, + }, + Layout::LambdaSet(lambda_set) => { + RocReturn::roc_return_by_pointer(lambda_set.runtime_representation()) + } + _ => false, + } + } + + fn from_layout<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> Self { + if false && Self::roc_return_by_pointer(*layout) { + RocReturn::ByPointer + } else { + RocReturn::Return + } + } +} + enum CCReturn { /// Return as normal Return, From 2ff3a97adaa85bf2bcc6b02e87d8c4d8c9d401f2 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 22 Oct 2021 13:24:18 +0200 Subject: [PATCH 005/223] re-implement roc returning by pointer --- compiler/gen_llvm/src/llvm/build.rs | 58 ++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 82dfdd2b36..9140b147a9 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -4389,28 +4389,55 @@ fn roc_call_with_args<'a, 'ctx, 'env>( let fn_val = function_value_by_func_spec(env, func_spec, symbol, argument_layouts, result_layout); -<<<<<<< HEAD call_roc_function(env, fn_val, result_layout, arguments) } fn call_roc_function<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, roc_function: FunctionValue<'ctx>, - _result_layout: &Layout<'a>, + result_layout: &Layout<'a>, arguments: &[BasicValueEnum<'ctx>], ) -> BasicValueEnum<'ctx> { - let call = env.builder.build_call(roc_function, arguments, "call"); + match RocReturn::from_layout(env, result_layout) { + RocReturn::Return => { + debug_assert_eq!( + roc_function.get_type().get_param_types().len(), + arguments.len() + ); + let call = env.builder.build_call(roc_function, arguments, "call"); - // roc functions should have the fast calling convention - debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); - call.set_call_convention(FAST_CALL_CONV); + // roc functions should have the fast calling convention + debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); + call.set_call_convention(FAST_CALL_CONV); - call.try_as_basic_value().left().unwrap_or_else(|| { - panic!( - "LLVM error: Invalid call by name for name {:?}", - roc_function.get_name() - ) - }) + call.try_as_basic_value().left().unwrap_or_else(|| { + panic!( + "LLVM error: Invalid call by name for name {:?}", + roc_function.get_name() + ) + }) + } + RocReturn::ByPointer => { + let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); + + let result_type = basic_type_from_layout(env, result_layout); + let result_alloca = env.builder.build_alloca(result_type, "result_value"); + + arguments.push(result_alloca.into()); + + debug_assert_eq!( + roc_function.get_type().get_param_types().len(), + arguments.len() + ); + let call = env.builder.build_call(roc_function, &arguments, "call"); + + // roc functions should have the fast calling convention + debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); + call.set_call_convention(FAST_CALL_CONV); + + env.builder.build_load(result_alloca, "load_result") + } + } } /// Translates a target_lexicon::Triple to a LLVM calling convention u32 @@ -5751,10 +5778,7 @@ enum RocReturn { impl RocReturn { fn roc_return_by_pointer(layout: Layout) -> bool { match layout { - Layout::Union(union_layout) => match union_layout { - UnionLayout::NonRecursive(_) => true, - _ => false, - }, + Layout::Union(union_layout) => matches!(union_layout, UnionLayout::NonRecursive(_)), Layout::LambdaSet(lambda_set) => { RocReturn::roc_return_by_pointer(lambda_set.runtime_representation()) } @@ -5762,7 +5786,7 @@ impl RocReturn { } } - fn from_layout<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> Self { + fn from_layout<'a, 'ctx, 'env>(_env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> Self { if false && Self::roc_return_by_pointer(*layout) { RocReturn::ByPointer } else { From 1d1bd3d0513f3ef810aa54e81f724ea62242a597 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 22 Oct 2021 14:54:15 +0200 Subject: [PATCH 006/223] working, but generates more code --- compiler/gen_llvm/src/llvm/build.rs | 62 +++++++++++++++++++---------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 9140b147a9..44c3565104 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -4398,26 +4398,30 @@ fn call_roc_function<'a, 'ctx, 'env>( result_layout: &Layout<'a>, arguments: &[BasicValueEnum<'ctx>], ) -> BasicValueEnum<'ctx> { + let pass_by_pointer = roc_function.get_type().get_param_types().len() == arguments.len() + 1; + match RocReturn::from_layout(env, result_layout) { - RocReturn::Return => { - debug_assert_eq!( - roc_function.get_type().get_param_types().len(), - arguments.len() - ); - let call = env.builder.build_call(roc_function, arguments, "call"); - - // roc functions should have the fast calling convention - debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); - call.set_call_convention(FAST_CALL_CONV); - - call.try_as_basic_value().left().unwrap_or_else(|| { - panic!( - "LLVM error: Invalid call by name for name {:?}", - roc_function.get_name() - ) - }) - } RocReturn::ByPointer => { + if !pass_by_pointer { + let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); + + let result_type = basic_type_from_layout(env, result_layout); + let result_alloca = env.builder.build_alloca(result_type, "result_value"); + + //arguments.push(result_alloca.into()); + + debug_assert_eq!( + roc_function.get_type().get_param_types().len(), + arguments.len() + ); + let call = env.builder.build_call(roc_function, &arguments, "call"); + + // roc functions should have the fast calling convention + debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); + call.set_call_convention(FAST_CALL_CONV); + + return env.builder.build_load(result_alloca, "load_result"); + } let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); let result_type = basic_type_from_layout(env, result_layout); @@ -4437,6 +4441,24 @@ fn call_roc_function<'a, 'ctx, 'env>( env.builder.build_load(result_alloca, "load_result") } + RocReturn::Return => { + debug_assert_eq!( + roc_function.get_type().get_param_types().len(), + arguments.len() + ); + let call = env.builder.build_call(roc_function, arguments, "call"); + + // roc functions should have the fast calling convention + debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); + call.set_call_convention(FAST_CALL_CONV); + + call.try_as_basic_value().left().unwrap_or_else(|| { + panic!( + "LLVM error: Invalid call by name for name {:?}", + roc_function.get_name() + ) + }) + } } } @@ -5778,7 +5800,7 @@ enum RocReturn { impl RocReturn { fn roc_return_by_pointer(layout: Layout) -> bool { match layout { - Layout::Union(union_layout) => matches!(union_layout, UnionLayout::NonRecursive(_)), + Layout::Union(UnionLayout::NonRecursive(_)) => true, Layout::LambdaSet(lambda_set) => { RocReturn::roc_return_by_pointer(lambda_set.runtime_representation()) } @@ -5787,7 +5809,7 @@ impl RocReturn { } fn from_layout<'a, 'ctx, 'env>(_env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> Self { - if false && Self::roc_return_by_pointer(*layout) { + if Self::roc_return_by_pointer(*layout) { RocReturn::ByPointer } else { RocReturn::Return From e378f0d2f997ff66b5af95f01acc961e223ec650 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 5 Nov 2021 10:35:17 +0100 Subject: [PATCH 007/223] fix tags tests --- compiler/gen_llvm/src/llvm/bitcode.rs | 20 +++---- compiler/gen_llvm/src/llvm/build.rs | 82 +++++++++++++++------------ 2 files changed, 54 insertions(+), 48 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/bitcode.rs b/compiler/gen_llvm/src/llvm/bitcode.rs index 52b604dff3..5116f5a033 100644 --- a/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/compiler/gen_llvm/src/llvm/bitcode.rs @@ -191,6 +191,7 @@ pub fn build_transform_caller<'a, 'ctx, 'env>( function: FunctionValue<'ctx>, closure_data_layout: LambdaSet<'a>, argument_layouts: &[Layout<'a>], + result_layout: Layout<'a>, ) -> FunctionValue<'ctx> { let fn_name: &str = &format!( "{}_zig_function_caller", @@ -204,6 +205,7 @@ pub fn build_transform_caller<'a, 'ctx, 'env>( function, closure_data_layout, argument_layouts, + result_layout, fn_name, ), } @@ -214,6 +216,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( roc_function: FunctionValue<'ctx>, closure_data_layout: LambdaSet<'a>, argument_layouts: &[Layout<'a>], + result_layout: Layout<'a>, fn_name: &str, ) -> FunctionValue<'ctx> { debug_assert!(argument_layouts.len() <= 7); @@ -288,17 +291,12 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( } } - let call = { - env.builder - .build_call(roc_function, arguments_cast.as_slice(), "tmp") - }; - - call.set_call_convention(FAST_CALL_CONV); - - let result = call - .try_as_basic_value() - .left() - .unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer.")); + let result = crate::llvm::build::call_roc_function( + env, + roc_function, + &result_layout, + arguments_cast.as_slice(), + ); let result_u8_ptr = function_value .get_nth_param(argument_layouts.len() as u32 + 1) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index ed17333c28..242695fa0e 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -3216,7 +3216,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( if env.is_gen_test { debug_assert_eq!(args.len(), roc_function.get_params().len()); - let roc_wrapper_function = make_exception_catcher(env, roc_function); + let roc_wrapper_function = make_exception_catcher(env, roc_function, return_layout); debug_assert_eq!( arguments_for_call.len(), roc_wrapper_function.get_params().len() @@ -3261,7 +3261,7 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( let wrapper_return_type = context.struct_type( &[ context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), + basic_type_from_layout(env, &return_layout), ], false, ); @@ -3326,18 +3326,14 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( let arguments_for_call = &arguments_for_call.into_bump_slice(); let call_result = { - let roc_wrapper_function = make_exception_catcher(env, roc_function); - debug_assert_eq!( - arguments_for_call.len(), - roc_wrapper_function.get_params().len() - ); + let roc_wrapper_function = make_exception_catcher(env, roc_function, return_layout); builder.position_at_end(entry); call_roc_function( env, roc_wrapper_function, - &return_layout, + &Layout::Struct(&[Layout::Builtin(Builtin::Int64), return_layout]), arguments_for_call, ) }; @@ -3574,21 +3570,18 @@ pub fn get_sjlj_buffer<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValu .into_pointer_value() } -fn set_jump_and_catch_long_jump<'a, 'ctx, 'env, F, T>( +fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, parent: FunctionValue<'ctx>, - function: F, - calling_convention: u32, + roc_function: FunctionValue<'ctx>, arguments: &[BasicValueEnum<'ctx>], - return_type: T, -) -> BasicValueEnum<'ctx> -where - T: inkwell::types::BasicType<'ctx>, - F: Into>, -{ + return_layout: Layout<'a>, +) -> BasicValueEnum<'ctx> { let context = env.context; let builder = env.builder; + let return_type = basic_type_from_layout(env, &return_layout); + let call_result_type = context.struct_type( &[context.i64_type().into(), return_type.as_basic_type_enum()], false, @@ -3661,11 +3654,7 @@ where { builder.position_at_end(then_block); - let call = env.builder.build_call(function, arguments, "call_function"); - - call.set_call_convention(calling_convention); - - let call_result = call.try_as_basic_value().left().unwrap(); + let call_result = call_roc_function(env, roc_function, &return_layout, arguments); let return_value = make_good_roc_result(env, call_result); @@ -3738,10 +3727,12 @@ where fn make_exception_catcher<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, roc_function: FunctionValue<'ctx>, + return_layout: Layout<'a>, ) -> FunctionValue<'ctx> { let wrapper_function_name = format!("{}_catcher", roc_function.get_name().to_str().unwrap()); - let function_value = make_exception_catching_wrapper(env, roc_function, &wrapper_function_name); + let function_value = + make_exception_catching_wrapper(env, roc_function, return_layout, &wrapper_function_name); function_value.set_linkage(Linkage::Internal); @@ -3775,6 +3766,7 @@ fn make_good_roc_result<'a, 'ctx, 'env>( fn make_exception_catching_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, roc_function: FunctionValue<'ctx>, + return_layout: Layout<'a>, wrapper_function_name: &str, ) -> FunctionValue<'ctx> { // build the C calling convention wrapper @@ -3783,12 +3775,20 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( let builder = env.builder; let roc_function_type = roc_function.get_type(); - let argument_types = roc_function_type.get_param_types(); + let argument_types = match RocReturn::from_layout(env, &return_layout) { + RocReturn::Return => roc_function_type.get_param_types(), + RocReturn::ByPointer => { + let mut types = roc_function_type.get_param_types(); + types.remove(0); + + types + } + }; let wrapper_return_type = context.struct_type( &[ context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), + basic_type_from_layout(env, &return_layout), ], false, ); @@ -3825,9 +3825,8 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( env, wrapper_function, roc_function, - roc_function.get_call_conventions(), &arguments, - roc_function_type.get_return_type().unwrap(), + return_layout, ); builder.build_return(Some(&result)); @@ -4029,10 +4028,7 @@ fn build_proc_header<'a, 'ctx, 'env>( let fn_type = match RocReturn::from_layout(env, &proc.ret_layout) { RocReturn::Return => ret_type.fn_type(&arg_basic_types, false), RocReturn::ByPointer => { - println!( - "{:?} will return void instead of {:?}", - symbol, proc.ret_layout - ); + // println!( "{:?} will return void instead of {:?}", symbol, proc.ret_layout); arg_basic_types.push(ret_type.ptr_type(AddressSpace::Generic).into()); env.context.void_type().fn_type(&arg_basic_types, false) } @@ -4141,9 +4137,8 @@ pub fn build_closure_caller<'a, 'ctx, 'env>( env, function_value, evaluator, - evaluator.get_call_conventions(), &evaluator_arguments, - result_type, + *return_layout, ) } else { call_roc_function(env, evaluator, return_layout, &evaluator_arguments) @@ -4404,7 +4399,7 @@ fn roc_call_with_args<'a, 'ctx, 'env>( call_roc_function(env, fn_val, result_layout, arguments) } -fn call_roc_function<'a, 'ctx, 'env>( +pub fn call_roc_function<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, roc_function: FunctionValue<'ctx>, result_layout: &Layout<'a>, @@ -4510,6 +4505,7 @@ fn roc_function_call<'a, 'ctx, 'env>( lambda_set: LambdaSet<'a>, closure_data_is_owned: bool, argument_layouts: &[Layout<'a>], + result_layout: Layout<'a>, ) -> RocFunctionCall<'ctx> { use crate::llvm::bitcode::{build_inc_n_wrapper, build_transform_caller}; @@ -4518,9 +4514,10 @@ fn roc_function_call<'a, 'ctx, 'env>( .build_alloca(closure_data.get_type(), "closure_data_ptr"); env.builder.build_store(closure_data_ptr, closure_data); - let stepper_caller = build_transform_caller(env, transform, lambda_set, argument_layouts) - .as_global_value() - .as_pointer_value(); + let stepper_caller = + build_transform_caller(env, transform, lambda_set, argument_layouts, result_layout) + .as_global_value() + .as_pointer_value(); let inc_closure_data = build_inc_n_wrapper(env, layout_ids, &lambda_set.runtime_representation()) @@ -4593,6 +4590,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + *result_layout, ); crate::llvm::build_list::list_walk_generic( @@ -4634,6 +4632,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + **result_layout, ); list_map(env, roc_function_call, list, element_layout, result_layout) @@ -4663,6 +4662,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + **result_layout, ); list_map2( @@ -4706,6 +4706,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + **result_layout, ); list_map3( @@ -4764,6 +4765,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + **result_layout, ); list_map4( @@ -4810,6 +4812,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + **result_layout, ); list_map_with_index(env, roc_function_call, list, element_layout, result_layout) @@ -4836,6 +4839,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + *result_layout, ); list_keep_if(env, layout_ids, roc_function_call, list, element_layout) @@ -4866,6 +4870,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + *result_layout, ); list_keep_oks( @@ -4906,6 +4911,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + *result_layout, ); list_keep_errs( @@ -4958,6 +4964,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + *result_layout, ); list_sort_with( @@ -4993,6 +5000,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + *result_layout, ); dict_walk( From 51756cbc894eef2455cf9b63c34f3ce5726d8e0b Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 5 Nov 2021 11:21:06 +0100 Subject: [PATCH 008/223] fix uninitialized alloca --- compiler/gen_llvm/src/llvm/build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 242695fa0e..52d18411ed 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -3499,7 +3499,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( } } - let arguments_for_call = &arguments_for_call.into_bump_slice(); + let arguments_for_call = arguments_for_call.into_bump_slice(); let call_result = call_roc_function(env, roc_function, &return_layout, arguments_for_call); @@ -4411,11 +4411,12 @@ pub fn call_roc_function<'a, 'ctx, 'env>( RocReturn::ByPointer => { if !pass_by_pointer { let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); + arguments.pop(); let result_type = basic_type_from_layout(env, result_layout); let result_alloca = env.builder.build_alloca(result_type, "result_value"); - //arguments.push(result_alloca.into()); + arguments.push(result_alloca.into()); debug_assert_eq!( roc_function.get_type().get_param_types().len(), From 5cd232816b9ee4635cd1fa6a9cb7ac076f4271d7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 5 Nov 2021 21:30:20 +0100 Subject: [PATCH 009/223] waypoint --- cli/src/build.rs | 2 +- compiler/gen_llvm/src/llvm/bitcode.rs | 72 +++--- compiler/gen_llvm/src/llvm/build.rs | 269 +++++++++++++++------- compiler/gen_llvm/src/llvm/convert.rs | 60 +++++ compiler/gen_llvm/src/llvm/refcounting.rs | 33 +-- compiler/mono/src/layout.rs | 50 +++- compiler/test_gen/src/gen_tags.rs | 3 +- compiler/test_gen/src/helpers/eval.rs | 4 + 8 files changed, 337 insertions(+), 156 deletions(-) diff --git a/cli/src/build.rs b/cli/src/build.rs index 39766a9e67..4f500974e9 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -255,7 +255,7 @@ pub fn build_file<'a>( link( target, binary_path.clone(), - &inputs, + &inputs, link_type ) .map_err(|_| { diff --git a/compiler/gen_llvm/src/llvm/bitcode.rs b/compiler/gen_llvm/src/llvm/bitcode.rs index 5116f5a033..d006b5b508 100644 --- a/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/compiler/gen_llvm/src/llvm/bitcode.rs @@ -1,7 +1,7 @@ /// Helpers for interacting with the zig that generates bitcode use crate::debug_info_init; use crate::llvm::build::{struct_from_fields, Env, C_CALL_CONV, FAST_CALL_CONV, TAG_DATA_INDEX}; -use crate::llvm::convert::basic_type_from_layout; +use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1}; use crate::llvm::refcounting::{ decrement_refcount_layout, increment_n_refcount_layout, increment_refcount_layout, }; @@ -128,20 +128,19 @@ fn build_has_tag_id_help<'a, 'ctx, 'env>( [tag_id, tag_value_ptr] => { let tag_type = basic_type_from_layout(env, &Layout::Union(union_layout)); - let argument_cast = env - .builder - .build_bitcast( - *tag_value_ptr, - tag_type.ptr_type(AddressSpace::Generic), - "load_opaque", - ) - .into_pointer_value(); - - let tag_value = env.builder.build_load(argument_cast, "get_value"); + let tag_value = env.builder.build_pointer_cast( + tag_value_ptr.into_pointer_value(), + tag_type.ptr_type(AddressSpace::Generic), + "load_opaque_get_tag_id", + ); let actual_tag_id = { - let tag_id_i64 = - crate::llvm::build::get_tag_id(env, function_value, &union_layout, tag_value); + let tag_id_i64 = crate::llvm::build::get_tag_id( + env, + function_value, + &union_layout, + tag_value.into(), + ); env.builder .build_int_cast(tag_id_i64, env.context.i16_type(), "to_i16") @@ -263,12 +262,22 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) { let basic_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic); - let argument_cast = env - .builder - .build_bitcast(*argument_ptr, basic_type, "load_opaque") - .into_pointer_value(); + let argument = if layout.is_passed_by_reference() { + env.builder + .build_pointer_cast( + argument_ptr.into_pointer_value(), + basic_type, + "cast_ptr_to_tag", + ) + .into() + } else { + let argument_cast = env + .builder + .build_bitcast(*argument_ptr, basic_type, "load_opaque_1") + .into_pointer_value(); - let argument = env.builder.build_load(argument_cast, "load_opaque"); + env.builder.build_load(argument_cast, "load_opaque_2") + }; arguments_cast.push(argument); } @@ -300,17 +309,10 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( let result_u8_ptr = function_value .get_nth_param(argument_layouts.len() as u32 + 1) - .unwrap(); - let result_ptr = env - .builder - .build_bitcast( - result_u8_ptr, - result.get_type().ptr_type(AddressSpace::Generic), - "write_result", - ) + .unwrap() .into_pointer_value(); - env.builder.build_store(result_ptr, result); + crate::llvm::build::store_roc_value_opaque(env, result_layout, result_u8_ptr, result); env.builder.build_return(None); env.builder.position_at_end(block); @@ -412,12 +414,18 @@ fn build_rc_wrapper<'a, 'ctx, 'env>( let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic); - let value_cast = env - .builder - .build_bitcast(value_ptr, value_type, "load_opaque") - .into_pointer_value(); + let value = if layout.is_passed_by_reference() { + env.builder + .build_pointer_cast(value_ptr, value_type, "cast_ptr_to_tag") + .into() + } else { + let value_cast = env + .builder + .build_bitcast(value_ptr, value_type, "load_opaque") + .into_pointer_value(); - let value = env.builder.build_load(value_cast, "load_opaque"); + env.builder.build_load(value_cast, "load_opaque") + }; match rc_operation { Mode::Inc => { diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 52d18411ed..a6fe38761a 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -21,7 +21,8 @@ use crate::llvm::build_str::{ }; use crate::llvm::compare::{generic_eq, generic_neq}; use crate::llvm::convert::{ - basic_type_from_builtin, basic_type_from_layout, block_of_memory_slices, ptr_int, + basic_type_from_builtin, basic_type_from_layout, basic_type_from_layout_1, + block_of_memory_slices, ptr_int, }; use crate::llvm::refcounting::{ build_reset, decrement_refcount_layout, increment_refcount_layout, PointerToRefcount, @@ -618,8 +619,8 @@ pub fn construct_optimization_passes<'a>( mpm.add_always_inliner_pass(); // tail-call elimination is always on - fpm.add_instruction_combining_pass(); - fpm.add_tail_call_elimination_pass(); + // fpm.add_instruction_combining_pass(); + // fpm.add_tail_call_elimination_pass(); let pmb = PassManagerBuilder::create(); match opt_level { @@ -1235,32 +1236,21 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( match union_layout { UnionLayout::NonRecursive(tag_layouts) => { - debug_assert!(argument.is_struct_value()); + debug_assert!(argument.is_pointer_value()); + let field_layouts = tag_layouts[*tag_id as usize]; - let struct_layout = Layout::Struct(field_layouts); - let struct_type = basic_type_from_layout(env, &struct_layout); + let tag_id_type = + basic_type_from_layout(env, &union_layout.tag_id_layout()).into_int_type(); - let argument_pointer = builder.build_alloca(argument.get_type(), "cast_alloca"); - builder.build_store(argument_pointer, argument); - - let struct_ptr = builder.build_pointer_cast( - argument_pointer, - struct_type.ptr_type(AddressSpace::Generic), - "foobar", - ); - - // let struct_value = access_index_struct_value( - // builder, - // argument.into_struct_value(), - // struct_type.into_struct_type(), - // ); - - let result = builder - .build_struct_gep(struct_ptr, *index as u32, "") - .expect("desired field did not decode"); - - builder.build_load(result, "foobarbaz") + lookup_at_index_ptr2( + env, + union_layout, + tag_id_type, + field_layouts, + *index as usize, + argument.into_pointer_value(), + ) } UnionLayout::Recursive(tag_layouts) => { debug_assert!(argument.is_pointer_value()); @@ -1555,10 +1545,13 @@ pub fn build_tag<'a, 'ctx, 'env>( .builder .build_struct_gep(struct_ptr, index, "get_tag_field_ptr") .unwrap(); - env.builder.build_store(ptr, field_val); + + let field_layout = tag_field_layouts[index as usize]; + store_roc_value(env, field_layout, ptr, field_val); } - env.builder.build_load(result_alloca, "load_result") + // env.builder.build_load(result_alloca, "load_result") + result_alloca.into() } UnionLayout::Recursive(tags) => { debug_assert!(union_size > 1); @@ -1866,9 +1859,10 @@ pub fn get_tag_id<'a, 'ctx, 'env>( match union_layout { UnionLayout::NonRecursive(_) => { - let tag = argument.into_struct_value(); + debug_assert!(argument.is_pointer_value(), "{:?}", argument); - get_tag_id_non_recursive(env, tag) + let argument_ptr = argument.into_pointer_value(); + get_tag_id_wrapped(env, argument_ptr) } UnionLayout::Recursive(_) => { let argument_ptr = argument.into_pointer_value(); @@ -2008,7 +2002,26 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>( .build_struct_gep(data_ptr, index as u32, "at_index_struct_gep") .unwrap(); - let result = builder.build_load(elem_ptr, "load_at_index_ptr"); + let field_layout = field_layouts[index]; + let result = if field_layout.is_passed_by_reference() { + let field_type = basic_type_from_layout(env, &field_layout); + + let align_bytes = field_layout.alignment_bytes(env.ptr_bytes); + let alloca = env.builder.build_alloca(field_type, "copied_tag"); + if align_bytes > 0 { + let size = env + .ptr_int() + .const_int(field_layout.stack_size(env.ptr_bytes) as u64, false); + + env.builder + .build_memcpy(alloca, align_bytes, elem_ptr, align_bytes, size) + .unwrap(); + } + + alloca.into() + } else { + builder.build_load(elem_ptr, "load_at_index_ptr") + }; if let Some(Layout::RecursivePointer) = field_layouts.get(index as usize) { // a recursive field is stored as a `i64*`, to use it we must cast it to @@ -2155,17 +2168,12 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>( let ptr_type = value_type.ptr_type(AddressSpace::Generic); unsafe { - builder - .build_bitcast( - env.builder.build_in_bounds_gep( - as_usize_ptr, - &[index_intvalue], - "get_data_ptr", - ), - ptr_type, - "alloc_cast_to_desired", - ) - .into_pointer_value() + builder.build_pointer_cast( + env.builder + .build_in_bounds_gep(as_usize_ptr, &[index_intvalue], "get_data_ptr"), + ptr_type, + "alloc_cast_to_desired", + ) } }; @@ -2191,13 +2199,13 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>( fn list_literal<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, scope: &Scope<'a, 'ctx>, - elem_layout: &Layout<'a>, + element_layout: &Layout<'a>, elems: &[ListLiteralElement], ) -> BasicValueEnum<'ctx> { let ctx = env.context; let builder = env.builder; - let element_type = basic_type_from_layout(env, elem_layout); + let element_type = basic_type_from_layout(env, element_layout); let list_length = elems.len(); let list_length_intval = env.ptr_int().const_int(list_length as _, false); @@ -2207,9 +2215,9 @@ fn list_literal<'a, 'ctx, 'env>( // if element_type.is_int_type() { if false { let element_type = element_type.into_int_type(); - let element_width = elem_layout.stack_size(env.ptr_bytes); + let element_width = element_layout.stack_size(env.ptr_bytes); let size = list_length * element_width as usize; - let alignment = elem_layout + let alignment = element_layout .alignment_bytes(env.ptr_bytes) .max(env.ptr_bytes); @@ -2241,7 +2249,7 @@ fn list_literal<'a, 'ctx, 'env>( for (index, element) in elems.iter().enumerate() { match element { ListLiteralElement::Literal(literal) => { - let val = build_exp_literal(env, elem_layout, literal); + let val = build_exp_literal(env, element_layout, literal); global_elements.push(val.into_int_value()); } ListLiteralElement::Symbol(symbol) => { @@ -2296,7 +2304,7 @@ fn list_literal<'a, 'ctx, 'env>( super::build_list::store_list(env, ptr, list_length_intval) } else { // some of our elements are non-constant, so we must allocate space on the heap - let ptr = allocate_list(env, elem_layout, list_length_intval); + let ptr = allocate_list(env, element_layout, list_length_intval); // then, copy the relevant segment from the constant section into the heap env.builder @@ -2320,26 +2328,69 @@ fn list_literal<'a, 'ctx, 'env>( super::build_list::store_list(env, ptr, list_length_intval) } } else { - let ptr = allocate_list(env, elem_layout, list_length_intval); + let ptr = allocate_list(env, element_layout, list_length_intval); // Copy the elements from the list literal into the array for (index, element) in elems.iter().enumerate() { let val = match element { ListLiteralElement::Literal(literal) => { - build_exp_literal(env, elem_layout, literal) + build_exp_literal(env, element_layout, literal) } ListLiteralElement::Symbol(symbol) => load_symbol(scope, symbol), }; 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") }; - builder.build_store(elem_ptr, val); + store_roc_value(env, *element_layout, elem_ptr, val); } super::build_list::store_list(env, ptr, list_length_intval) } } +pub fn store_roc_value_opaque<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout: Layout<'a>, + opaque_destination: PointerValue<'ctx>, + value: BasicValueEnum<'ctx>, +) { + let target_type = basic_type_from_layout(env, &layout).ptr_type(AddressSpace::Generic); + let destination = + env.builder + .build_pointer_cast(opaque_destination, target_type, "store_roc_value_opaque"); + + store_roc_value(env, layout, destination, value) +} + +pub fn store_roc_value<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout: Layout<'a>, + destination: PointerValue<'ctx>, + value: BasicValueEnum<'ctx>, +) { + if layout.is_passed_by_reference() { + let align_bytes = layout.alignment_bytes(env.ptr_bytes); + + if align_bytes > 0 { + let size = env + .ptr_int() + .const_int(layout.stack_size(env.ptr_bytes) as u64, false); + + env.builder + .build_memcpy( + destination, + align_bytes, + value.into_pointer_value(), + align_bytes, + size, + ) + .unwrap(); + } + } else { + env.builder.build_store(destination, value); + } +} + pub fn build_exp_stmt<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, @@ -2415,8 +2466,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( let out_parameter = parameters.last().unwrap(); debug_assert!(out_parameter.is_pointer_value()); - env.builder - .build_store(out_parameter.into_pointer_value(), value); + store_roc_value(env, *layout, out_parameter.into_pointer_value(), value); if let Some(block) = env.builder.get_insert_block() { match block.get_terminator() { @@ -3656,7 +3706,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( let call_result = call_roc_function(env, roc_function, &return_layout, arguments); - let return_value = make_good_roc_result(env, call_result); + let return_value = make_good_roc_result(env, return_layout, call_result); builder.build_store(result_alloca, return_value); @@ -3721,7 +3771,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( env.builder.position_at_end(cont_block); - builder.build_load(result_alloca, "load_result") + builder.build_load(result_alloca, "set_jump_and_catch_long_jump_load_result") } fn make_exception_catcher<'a, 'ctx, 'env>( @@ -3741,12 +3791,13 @@ fn make_exception_catcher<'a, 'ctx, 'env>( fn make_good_roc_result<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + return_layout: Layout<'a>, return_value: BasicValueEnum<'ctx>, ) -> BasicValueEnum<'ctx> { let context = env.context; let builder = env.builder; - let content_type = return_value.get_type(); + let content_type = basic_type_from_layout(env, &return_layout); let wrapper_return_type = context.struct_type(&[context.i64_type().into(), content_type], false); @@ -3756,9 +3807,19 @@ fn make_good_roc_result<'a, 'ctx, 'env>( .build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error") .unwrap(); - let v3 = builder - .build_insert_value(v2, return_value, 1, "set_call_result") - .unwrap(); + let v3 = if return_layout.is_passed_by_reference() { + let loaded = env.builder.build_load( + return_value.into_pointer_value(), + "load_call_result_passed_by_ptr", + ); + builder + .build_insert_value(v2, loaded, 1, "set_call_result") + .unwrap() + } else { + builder + .build_insert_value(v2, return_value, 1, "set_call_result") + .unwrap() + }; v3.into_struct_value().into() } @@ -3971,6 +4032,8 @@ fn build_procedures_help<'a, 'ctx, 'env>( app_ll_file, ); } else { + env.module.print_to_stderr(); + panic!( "The preceding code was from {:?}, which failed LLVM verification in {} build.", fn_val.get_name().to_str().unwrap(), @@ -4020,7 +4083,7 @@ fn build_proc_header<'a, 'ctx, 'env>( let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena); for (layout, _) in args.iter() { - let arg_type = basic_type_from_layout(env, layout); + let arg_type = basic_type_from_layout_1(env, layout); arg_basic_types.push(arg_type); } @@ -4132,19 +4195,41 @@ pub fn build_closure_caller<'a, 'ctx, 'env>( } } - let call_result = if env.is_gen_test { - set_jump_and_catch_long_jump( + if env.is_gen_test { + let call_result = set_jump_and_catch_long_jump( env, function_value, evaluator, &evaluator_arguments, *return_layout, - ) - } else { - call_roc_function(env, evaluator, return_layout, &evaluator_arguments) - }; + ); - builder.build_store(output, call_result); + builder.build_store(output, call_result); + } else { + let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments); + + if return_layout.is_passed_by_reference() { + let align_bytes = return_layout.alignment_bytes(env.ptr_bytes); + + if align_bytes > 0 { + let size = env + .ptr_int() + .const_int(return_layout.stack_size(env.ptr_bytes) as u64, false); + + env.builder + .build_memcpy( + output, + align_bytes, + call_result.into_pointer_value(), + align_bytes, + size, + ) + .unwrap(); + } + } else { + builder.build_store(output, call_result); + } + }; builder.build_return(None); @@ -4408,29 +4493,10 @@ pub fn call_roc_function<'a, 'ctx, 'env>( let pass_by_pointer = roc_function.get_type().get_param_types().len() == arguments.len() + 1; match RocReturn::from_layout(env, result_layout) { - RocReturn::ByPointer => { - if !pass_by_pointer { - let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); - arguments.pop(); - - let result_type = basic_type_from_layout(env, result_layout); - let result_alloca = env.builder.build_alloca(result_type, "result_value"); - - arguments.push(result_alloca.into()); - - debug_assert_eq!( - roc_function.get_type().get_param_types().len(), - arguments.len() - ); - let call = env.builder.build_call(roc_function, &arguments, "call"); - - // roc functions should have the fast calling convention - debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); - call.set_call_convention(FAST_CALL_CONV); - - return env.builder.build_load(result_alloca, "load_result"); - } + RocReturn::ByPointer if !pass_by_pointer => { + // WARNING this is a hack!! let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); + arguments.pop(); let result_type = basic_type_from_layout(env, result_layout); let result_alloca = env.builder.build_alloca(result_type, "result_value"); @@ -4449,6 +4515,31 @@ pub fn call_roc_function<'a, 'ctx, 'env>( env.builder.build_load(result_alloca, "load_result") } + RocReturn::ByPointer => { + let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); + + let result_type = basic_type_from_layout(env, result_layout); + let result_alloca = env.builder.build_alloca(result_type, "result_value"); + + arguments.push(result_alloca.into()); + + debug_assert_eq!( + roc_function.get_type().get_param_types().len(), + arguments.len() + ); + let call = env.builder.build_call(roc_function, &arguments, "call"); + + // roc functions should have the fast calling convention + debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); + call.set_call_convention(FAST_CALL_CONV); + + if result_layout.is_passed_by_reference() { + result_alloca.into() + } else { + env.builder + .build_load(result_alloca, "return_by_pointer_load_result") + } + } RocReturn::Return => { debug_assert_eq!( roc_function.get_type().get_param_types().len(), diff --git a/compiler/gen_llvm/src/llvm/convert.rs b/compiler/gen_llvm/src/llvm/convert.rs index d32216c10a..559945b083 100644 --- a/compiler/gen_llvm/src/llvm/convert.rs +++ b/compiler/gen_llvm/src/llvm/convert.rs @@ -76,6 +76,66 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>( } } +pub fn basic_type_from_layout_1<'a, 'ctx, 'env>( + env: &crate::llvm::build::Env<'a, 'ctx, 'env>, + layout: &Layout<'_>, +) -> BasicTypeEnum<'ctx> { + use Layout::*; + + match layout { + Struct(sorted_fields) => basic_type_from_record(env, sorted_fields), + LambdaSet(lambda_set) => { + basic_type_from_layout_1(env, &lambda_set.runtime_representation()) + } + Union(union_layout) => { + use UnionLayout::*; + + let tag_id_type = basic_type_from_layout_1(env, &union_layout.tag_id_layout()); + + match union_layout { + NonRecursive(tags) => { + let data = block_of_memory_slices(env.context, tags, env.ptr_bytes); + let struct_type = env.context.struct_type(&[data, tag_id_type], false); + + struct_type.ptr_type(AddressSpace::Generic).into() + } + Recursive(tags) + | NullableWrapped { + other_tags: tags, .. + } => { + let data = block_of_memory_slices(env.context, tags, env.ptr_bytes); + + if union_layout.stores_tag_id_as_data(env.ptr_bytes) { + env.context + .struct_type(&[data, tag_id_type], false) + .ptr_type(AddressSpace::Generic) + .into() + } else { + data.ptr_type(AddressSpace::Generic).into() + } + } + NullableUnwrapped { other_fields, .. } => { + let block = block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes); + block.ptr_type(AddressSpace::Generic).into() + } + NonNullableUnwrapped(fields) => { + let block = block_of_memory_slices(env.context, &[fields], env.ptr_bytes); + block.ptr_type(AddressSpace::Generic).into() + } + } + } + RecursivePointer => { + // TODO make this dynamic + env.context + .i64_type() + .ptr_type(AddressSpace::Generic) + .as_basic_type_enum() + } + + Builtin(builtin) => basic_type_from_builtin(env, builtin), + } +} + pub fn basic_type_from_builtin<'a, 'ctx, 'env>( env: &crate::llvm::build::Env<'a, 'ctx, 'env>, builtin: &Builtin<'_>, diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index f183e029f6..5944f19e25 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -1,11 +1,11 @@ use crate::debug_info_init; use crate::llvm::bitcode::call_void_bitcode_fn; use crate::llvm::build::{ - add_func, cast_basic_basic, cast_block_of_memory_to_tag, get_tag_id, get_tag_id_non_recursive, - tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, TAG_DATA_INDEX, TAG_ID_INDEX, + add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, + TAG_DATA_INDEX, TAG_ID_INDEX, }; use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list}; -use crate::llvm::convert::{basic_type_from_layout, ptr_int}; +use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1, ptr_int}; use bumpalo::collections::Vec; use inkwell::basic_block::BasicBlock; use inkwell::context::Context; @@ -542,24 +542,6 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( } }, _ => { - if let Layout::Union(UnionLayout::NonRecursive(_)) = layout { - let alloca = env.builder.build_alloca(value.get_type(), "tag_union"); - env.builder.build_store(alloca, value); - call_help(env, function, call_mode, alloca.into()); - return; - } - - if let Layout::LambdaSet(lambda_set) = layout { - if let Layout::Union(UnionLayout::NonRecursive(_)) = - lambda_set.runtime_representation() - { - let alloca = env.builder.build_alloca(value.get_type(), "tag_union"); - env.builder.build_store(alloca, value); - call_help(env, function, call_mode, alloca.into()); - return; - } - } - call_help(env, function, call_mode, value); } } @@ -1620,10 +1602,9 @@ fn modify_refcount_union<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let basic_type = basic_type_from_layout(env, &layout); - // we pass tag unions by reference for efficiency - let ptr_type = basic_type.ptr_type(AddressSpace::Generic).into(); - let function_value = build_header(env, ptr_type, mode, &fn_name); + let basic_type = basic_type_from_layout_1(env, &layout); + let function_value = build_header(env, basic_type, mode, &fn_name); + dbg!(function_value); modify_refcount_union_help( env, @@ -1675,6 +1656,8 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( let before_block = env.builder.get_insert_block().expect("to be in a function"); + dbg!(fn_val, arg_ptr); + // read the tag_id let tag_id_ptr = env .builder diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 2c63b7658d..cf30803e3b 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -863,6 +863,16 @@ impl<'a> Layout<'a> { false } + pub fn is_passed_by_reference(&self) -> bool { + match self { + Layout::Union(UnionLayout::NonRecursive(_)) => true, + Layout::LambdaSet(lambda_set) => { + lambda_set.runtime_representation().is_passed_by_reference() + } + _ => false, + } + } + pub fn stack_size(&self, pointer_size: u32) -> u32 { let width = self.stack_size_without_alignment(pointer_size); let alignment = self.alignment_bytes(pointer_size); @@ -941,16 +951,16 @@ impl<'a> Layout<'a> { }) .max(); + let tag_id_builtin = variant.tag_id_builtin(); match max_alignment { - Some(align) => { - let tag_id_builtin = variant.tag_id_builtin(); - - round_up_to_alignment( - align, - tag_id_builtin.alignment_bytes(pointer_size), - ) + Some(align) => round_up_to_alignment( + align.max(tag_id_builtin.alignment_bytes(pointer_size)), + tag_id_builtin.alignment_bytes(pointer_size), + ), + None => { + // none of the tags had any payload, but the tag id still contains information + tag_id_builtin.alignment_bytes(pointer_size) } - None => 0, } } Recursive(_) @@ -2675,3 +2685,27 @@ impl<'a> std::convert::TryFrom<&Layout<'a>> for ListLayout<'a> { } } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn width_and_alignment_union_empty_struct() { + let lambda_set = LambdaSet { + set: &[(Symbol::LIST_MAP, &[])], + representation: &Layout::Struct(&[]), + }; + + let a = &[Layout::Struct(&[])] as &[_]; + let b = &[Layout::LambdaSet(lambda_set)] as &[_]; + let tt = [a, b]; + + let layout = Layout::Union(UnionLayout::NonRecursive(&tt)); + + // at the moment, the tag id uses an I64, so + let ptr_width = 8; + assert_eq!(layout.stack_size(ptr_width), 8); + assert_eq!(layout.alignment_bytes(ptr_width), 8); + } +} diff --git a/compiler/test_gen/src/gen_tags.rs b/compiler/test_gen/src/gen_tags.rs index fe50a16cde..9c5989b174 100644 --- a/compiler/test_gen/src/gen_tags.rs +++ b/compiler/test_gen/src/gen_tags.rs @@ -3,6 +3,7 @@ use crate::assert_evals_to; // use crate::assert_wasm_evals_to as assert_evals_to; use indoc::indoc; +use roc_mono::layout::LambdaSet; use roc_std::{RocList, RocStr}; #[test] @@ -423,7 +424,7 @@ fn result_with_guard_pattern() { } #[test] -fn maybe_is_just() { +fn maybe_is_just_not_nested() { assert_evals_to!( indoc!( r#" diff --git a/compiler/test_gen/src/helpers/eval.rs b/compiler/test_gen/src/helpers/eval.rs index e844d420ea..f6e4bffad2 100644 --- a/compiler/test_gen/src/helpers/eval.rs +++ b/compiler/test_gen/src/helpers/eval.rs @@ -198,6 +198,10 @@ fn create_llvm_module<'a>( if name.starts_with("roc_builtins.dict") { function.add_attribute(AttributeLoc::Function, attr); } + + if name.starts_with("roc_builtins.list") { + function.add_attribute(AttributeLoc::Function, attr); + } } // Compile and add all the Procs before adding main From bd0f02c542343b3454fb52137ef2c1ea4c975a8d Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 6 Nov 2021 19:27:16 +0100 Subject: [PATCH 010/223] another waypoint --- compiler/gen_llvm/src/llvm/build.rs | 41 ++++++++++++++--- compiler/gen_llvm/src/llvm/build_hash.rs | 29 ++++-------- compiler/gen_llvm/src/llvm/compare.rs | 55 +++++++++++------------ compiler/gen_llvm/src/llvm/convert.rs | 2 +- compiler/gen_llvm/src/llvm/refcounting.rs | 18 ++++++-- 5 files changed, 84 insertions(+), 61 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index a6fe38761a..83d6d8d253 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -1065,7 +1065,16 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( if !field_layout.is_dropped_because_empty() { field_types.push(basic_type_from_layout(env, field_layout)); - field_vals.push(field_expr); + if field_layout.is_passed_by_reference() { + let field_value = env.builder.build_load( + field_expr.into_pointer_value(), + "load_tag_to_put_in_struct", + ); + + field_vals.push(field_value); + } else { + field_vals.push(field_expr); + } } } @@ -1173,14 +1182,29 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( match (value, layout) { (StructValue(argument), Layout::Struct(fields)) => { debug_assert!(!fields.is_empty()); - env.builder + + let field_value = env + .builder .build_extract_value( argument, *index as u32, env.arena .alloc(format!("struct_field_access_record_{}", index)), ) - .unwrap() + .unwrap(); + + let field_layout = fields[*index as usize]; + if field_layout.is_passed_by_reference() { + let alloca = env.builder.build_alloca( + basic_type_from_layout(env, &field_layout), + "struct_field_tag", + ); + env.builder.build_store(alloca, field_value); + + alloca.into() + } else { + field_value + } } ( PointerValue(argument), @@ -2555,7 +2579,11 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( builder.position_at_end(cont_block); for (ptr, param) in joinpoint_args.iter().zip(parameters.iter()) { - let value = env.builder.build_load(*ptr, "load_jp_argument"); + let value = if param.layout.is_passed_by_reference() { + (*ptr).into() + } else { + env.builder.build_load(*ptr, "load_jp_argument") + }; scope.insert(param.symbol, (param.layout, value)); } @@ -2582,8 +2610,9 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( let (cont_block, argument_pointers) = scope.join_points.get(join_point).unwrap(); for (pointer, argument) in argument_pointers.iter().zip(arguments.iter()) { - let value = load_symbol(scope, argument); - builder.build_store(*pointer, value); + let (value, layout) = load_symbol_and_layout(scope, argument); + + store_roc_value(env, *layout, *pointer, value); } builder.build_unconditional_branch(*cont_block); diff --git a/compiler/gen_llvm/src/llvm/build_hash.rs b/compiler/gen_llvm/src/llvm/build_hash.rs index d3dc006198..7064cc100d 100644 --- a/compiler/gen_llvm/src/llvm/build_hash.rs +++ b/compiler/gen_llvm/src/llvm/build_hash.rs @@ -4,7 +4,7 @@ use crate::llvm::build::tag_pointer_clear_tag_id; use crate::llvm::build::Env; use crate::llvm::build::{cast_block_of_memory_to_tag, get_tag_id, FAST_CALL_CONV, TAG_DATA_INDEX}; use crate::llvm::build_str; -use crate::llvm::convert::basic_type_from_layout; +use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1}; use bumpalo::collections::Vec; use inkwell::values::{ BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue, @@ -339,7 +339,8 @@ fn build_hash_tag<'a, 'ctx, 'env>( None => { let seed_type = env.context.i64_type(); - let arg_type = basic_type_from_layout(env, layout); + let arg_type = basic_type_from_layout_1(env, layout); + dbg!(layout, arg_type); let function_value = crate::llvm::refcounting::build_header_help( env, @@ -423,14 +424,6 @@ fn hash_tag<'a, 'ctx, 'env>( let block = env.context.append_basic_block(parent, "tag_id_modify"); env.builder.position_at_end(block); - let struct_layout = Layout::Struct(field_layouts); - - let wrapper_type = basic_type_from_layout(env, &struct_layout); - debug_assert!(wrapper_type.is_struct_type()); - - let as_struct = - cast_block_of_memory_to_tag(env.builder, tag.into_struct_value(), wrapper_type); - // hash the tag id let hash_bytes = store_and_use_as_u8_ptr( env, @@ -440,7 +433,6 @@ fn hash_tag<'a, 'ctx, 'env>( .into(), &tag_id_layout, ); - let seed = hash_bitcode_fn( env, seed, @@ -449,14 +441,9 @@ fn hash_tag<'a, 'ctx, 'env>( ); // hash the tag data - let answer = build_hash_struct( - env, - layout_ids, - field_layouts, - WhenRecursive::Unreachable, - seed, - as_struct, - ); + let tag = tag.into_pointer_value(); + let answer = + hash_ptr_to_struct(env, layout_ids, union_layout, field_layouts, seed, tag); merge_phi.add_incoming(&[(&answer, block)]); env.builder.build_unconditional_branch(merge_block); @@ -822,12 +809,12 @@ fn hash_ptr_to_struct<'a, 'ctx, 'env>( ) -> IntValue<'ctx> { use inkwell::types::BasicType; - let wrapper_type = basic_type_from_layout(env, &Layout::Union(*union_layout)); + let wrapper_type = basic_type_from_layout_1(env, &Layout::Union(*union_layout)); // cast the opaque pointer to a pointer of the correct shape let wrapper_ptr = env .builder - .build_bitcast(tag, wrapper_type, "opaque_to_correct") + .build_bitcast(tag, wrapper_type, "hash_ptr_to_struct_opaque_to_correct") .into_pointer_value(); let struct_ptr = env diff --git a/compiler/gen_llvm/src/llvm/compare.rs b/compiler/gen_llvm/src/llvm/compare.rs index 1ca6178c0b..83c8887ce8 100644 --- a/compiler/gen_llvm/src/llvm/compare.rs +++ b/compiler/gen_llvm/src/llvm/compare.rs @@ -1,10 +1,8 @@ use crate::llvm::bitcode::call_bitcode_fn; -use crate::llvm::build::{ - cast_block_of_memory_to_tag, get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, -}; +use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV}; use crate::llvm::build_list::{list_len, load_list_ptr}; use crate::llvm::build_str::str_equal; -use crate::llvm::convert::basic_type_from_layout; +use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1}; use bumpalo::collections::Vec; use inkwell::types::BasicType; use inkwell::values::{ @@ -751,7 +749,7 @@ fn build_tag_eq<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let arg_type = basic_type_from_layout(env, tag_layout); + let arg_type = basic_type_from_layout_1(env, tag_layout); let function_value = crate::llvm::refcounting::build_header_help( env, @@ -844,9 +842,29 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( match union_layout { NonRecursive(tags) => { + let ptr_equal = env.builder.build_int_compare( + IntPredicate::EQ, + env.builder + .build_ptr_to_int(tag1.into_pointer_value(), env.ptr_int(), "pti"), + env.builder + .build_ptr_to_int(tag2.into_pointer_value(), env.ptr_int(), "pti"), + "compare_pointers", + ); + + let compare_tag_ids = ctx.append_basic_block(parent, "compare_tag_ids"); + + env.builder + .build_conditional_branch(ptr_equal, return_true, compare_tag_ids); + + env.builder.position_at_end(compare_tag_ids); + let id1 = get_tag_id(env, parent, union_layout, tag1); let id2 = get_tag_id(env, parent, union_layout, tag2); + // clear the tag_id so we get a pointer to the actual data + let tag1 = tag1.into_pointer_value(); + let tag2 = tag2.into_pointer_value(); + let compare_tag_fields = ctx.append_basic_block(parent, "compare_tag_fields"); let same_tag = @@ -866,31 +884,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let block = env.context.append_basic_block(parent, "tag_id_modify"); env.builder.position_at_end(block); - // TODO drop tag id? - let struct_layout = Layout::Struct(field_layouts); - - let wrapper_type = basic_type_from_layout(env, &struct_layout); - debug_assert!(wrapper_type.is_struct_type()); - - let struct1 = cast_block_of_memory_to_tag( - env.builder, - tag1.into_struct_value(), - wrapper_type, - ); - let struct2 = cast_block_of_memory_to_tag( - env.builder, - tag2.into_struct_value(), - wrapper_type, - ); - - let answer = build_struct_eq( - env, - layout_ids, - field_layouts, - when_recursive.clone(), - struct1, - struct2, - ); + let answer = + eq_ptr_to_struct(env, layout_ids, union_layout, field_layouts, tag1, tag2); env.builder.build_return(Some(&answer)); diff --git a/compiler/gen_llvm/src/llvm/convert.rs b/compiler/gen_llvm/src/llvm/convert.rs index 559945b083..98306210ad 100644 --- a/compiler/gen_llvm/src/llvm/convert.rs +++ b/compiler/gen_llvm/src/llvm/convert.rs @@ -90,7 +90,7 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>( Union(union_layout) => { use UnionLayout::*; - let tag_id_type = basic_type_from_layout_1(env, &union_layout.tag_id_layout()); + let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout()); match union_layout { NonRecursive(tags) => { diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 5944f19e25..30c309f540 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -349,18 +349,30 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>( for (i, field_layout) in layouts.iter().enumerate() { if field_layout.contains_refcounted() { - let field_ptr = env + let raw_value = env .builder .build_extract_value(wrapper_struct, i as u32, "decrement_struct_field") .unwrap(); + let field_value = if field_layout.is_passed_by_reference() { + let field_type = basic_type_from_layout(env, field_layout); + let alloca = env + .builder + .build_alloca(field_type, "load_struct_tag_field_for_decrement"); + env.builder.build_store(alloca, raw_value); + + alloca.into() + } else { + raw_value + }; + modify_refcount_layout_help( env, parent, layout_ids, mode.to_call_mode(fn_val), when_recursive, - field_ptr, + field_value, field_layout, ); } @@ -1289,7 +1301,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( .build_bitcast( value_ptr, wrapper_type.ptr_type(AddressSpace::Generic), - "opaque_to_correct", + "opaque_to_correct_recursive_decrement", ) .into_pointer_value(); From 180575852aea9efe412054ef4e54132c6c800d3b Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 7 Nov 2021 14:56:24 +0100 Subject: [PATCH 011/223] all tests passing --- compiler/gen_llvm/src/llvm/build.rs | 27 ++++++++++++++++++++--- compiler/gen_llvm/src/llvm/build_hash.rs | 10 ++++++++- compiler/gen_llvm/src/llvm/build_list.rs | 23 ++++++++++++++----- compiler/gen_llvm/src/llvm/refcounting.rs | 19 +++++++++++----- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 83d6d8d253..35832f8f8d 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -2372,6 +2372,25 @@ fn list_literal<'a, 'ctx, 'env>( } } +pub fn load_roc_value<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout: Layout<'a>, + source: PointerValue<'ctx>, + name: &str, +) -> BasicValueEnum<'ctx> { + if layout.is_passed_by_reference() { + let alloca = env + .builder + .build_alloca(basic_type_from_layout(env, &layout), name); + + store_roc_value(env, layout, alloca, source.into()); + + alloca.into() + } else { + env.builder.build_load(source, name) + } +} + pub fn store_roc_value_opaque<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout: Layout<'a>, @@ -3318,7 +3337,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( .unwrap() .into_pointer_value(); - builder.build_store(output_arg, call_result); + store_roc_value(env, return_layout, output_arg, call_result); builder.build_return(None); c_function @@ -4218,8 +4237,10 @@ pub fn build_closure_caller<'a, 'ctx, 'env>( // NOTE this may be incorrect in the long run // here we load any argument that is a pointer - for param in evaluator_arguments.iter_mut() { - if param.is_pointer_value() { + let closure_layout = lambda_set.runtime_representation(); + let layouts_it = arguments.iter().chain(std::iter::once(&closure_layout)); + for (param, layout) in evaluator_arguments.iter_mut().zip(layouts_it) { + if param.is_pointer_value() && !layout.is_passed_by_reference() { *param = builder.build_load(param.into_pointer_value(), "load_param"); } } diff --git a/compiler/gen_llvm/src/llvm/build_hash.rs b/compiler/gen_llvm/src/llvm/build_hash.rs index 7064cc100d..b73fe7bd4e 100644 --- a/compiler/gen_llvm/src/llvm/build_hash.rs +++ b/compiler/gen_llvm/src/llvm/build_hash.rs @@ -780,7 +780,15 @@ fn hash_list<'a, 'ctx, 'env>( env.builder.build_store(result, answer); }; - incrementing_elem_loop(env, parent, ptr, length, "current_index", loop_fn); + incrementing_elem_loop( + env, + parent, + *element_layout, + ptr, + length, + "current_index", + loop_fn, + ); env.builder.build_unconditional_branch(done_block); diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index 8b84bb6677..b581c3653e 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -17,6 +17,8 @@ use morphic_lib::UpdateMode; use roc_builtins::bitcode; use roc_mono::layout::{Builtin, Layout, LayoutIds}; +use super::build::load_roc_value; + pub fn pass_update_mode<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, update_mode: UpdateMode, @@ -216,10 +218,15 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>( // Assume the bounds have already been checked earlier // (e.g. by List.get or List.first, which wrap List.#getUnsafe) - let elem_ptr = - unsafe { builder.build_in_bounds_gep(array_data_ptr, &[elem_index], "elem") }; + let elem_ptr = unsafe { + builder.build_in_bounds_gep(array_data_ptr, &[elem_index], "list_get_element") + }; - let result = builder.build_load(elem_ptr, "List.get"); + let result = if elem_layout.is_passed_by_reference() { + elem_ptr.into() + } else { + builder.build_load(elem_ptr, "list_get_load_element") + }; increment_refcount_layout(env, parent, layout_ids, 1, result, elem_layout); @@ -975,6 +982,7 @@ where pub fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>( env: &Env<'a, 'ctx, 'env>, parent: FunctionValue<'ctx>, + element_layout: Layout<'a>, ptr: PointerValue<'ctx>, len: IntValue<'ctx>, index_name: &str, @@ -987,9 +995,14 @@ where incrementing_index_loop(env, parent, len, index_name, |index| { // The pointer to the element in the list - let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index], "load_index") }; + let element_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index], "load_index") }; - let elem = builder.build_load(elem_ptr, "get_elem"); + let elem = load_roc_value( + env, + element_layout, + element_ptr, + "incrementing_element_loop_load", + ); loop_fn(index, elem); }) diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 30c309f540..37f4e4cf42 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -765,7 +765,15 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>( ); }; - incrementing_elem_loop(env, parent, ptr, len, "modify_rc_index", loop_fn); + incrementing_elem_loop( + env, + parent, + *element_layout, + ptr, + len, + "modify_rc_index", + loop_fn, + ); } let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper); @@ -1616,7 +1624,6 @@ fn modify_refcount_union<'a, 'ctx, 'env>( None => { let basic_type = basic_type_from_layout_1(env, &layout); let function_value = build_header(env, basic_type, mode, &fn_name); - dbg!(function_value); modify_refcount_union_help( env, @@ -1668,8 +1675,6 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( let before_block = env.builder.get_insert_block().expect("to be in a function"); - dbg!(fn_val, arg_ptr); - // read the tag_id let tag_id_ptr = env .builder @@ -1729,7 +1734,11 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( .build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field") .unwrap(); - let field_value = env.builder.build_load(field_ptr, "field_value"); + let field_value = if field_layout.is_passed_by_reference() { + field_ptr.into() + } else { + env.builder.build_load(field_ptr, "field_value") + }; modify_refcount_layout_help( env, From 3138fc43ec8e9662f381bbc0325c8be52794173e Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 7 Nov 2021 16:31:43 +0100 Subject: [PATCH 012/223] cosmetic changes --- compiler/gen_llvm/src/llvm/build.rs | 4 ++-- compiler/gen_llvm/src/llvm/build_list.rs | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index ea4107c91d..f83656da09 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -1536,7 +1536,7 @@ pub fn build_tag<'a, 'ctx, 'env>( // store the tag id let tag_id_ptr = env .builder - .build_struct_gep(result_alloca, TAG_ID_INDEX, "get_opaque_data") + .build_struct_gep(result_alloca, TAG_ID_INDEX, "tag_id_ptr") .unwrap(); let tag_id_intval = tag_id_type.const_int(tag_id as u64, false); @@ -1549,7 +1549,7 @@ pub fn build_tag<'a, 'ctx, 'env>( let struct_opaque_ptr = env .builder - .build_struct_gep(result_alloca, TAG_DATA_INDEX, "get_opaque_data") + .build_struct_gep(result_alloca, TAG_DATA_INDEX, "opaque_data_ptr") .unwrap(); let struct_ptr = env.builder.build_pointer_cast( struct_opaque_ptr, diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index b581c3653e..4c0e7423af 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -222,11 +222,7 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>( builder.build_in_bounds_gep(array_data_ptr, &[elem_index], "list_get_element") }; - let result = if elem_layout.is_passed_by_reference() { - elem_ptr.into() - } else { - builder.build_load(elem_ptr, "list_get_load_element") - }; + let result = load_roc_value(env, **elem_layout, elem_ptr, "list_get_load_element"); increment_refcount_layout(env, parent, layout_ids, 1, result, elem_layout); From e7ec575a81f5a8b335e8e01d3dfc309e4c4e2462 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 7 Nov 2021 21:41:12 +0100 Subject: [PATCH 013/223] trying to track down uninitialized memory creation --- compiler/gen_llvm/src/llvm/build.rs | 79 ++++++++++++++++++----------- compiler/mono/src/alias_analysis.rs | 2 +- 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index f83656da09..480a5ccdfe 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -619,8 +619,8 @@ pub fn construct_optimization_passes<'a>( mpm.add_always_inliner_pass(); // tail-call elimination is always on - // fpm.add_instruction_combining_pass(); - // fpm.add_tail_call_elimination_pass(); + fpm.add_instruction_combining_pass(); + fpm.add_tail_call_elimination_pass(); let pmb = PassManagerBuilder::create(); match opt_level { @@ -1460,6 +1460,36 @@ fn build_wrapped_tag<'a, 'ctx, 'env>( } } +pub fn tag_alloca<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + type_: BasicTypeEnum<'ctx>, + name: &str, +) -> PointerValue<'ctx> { + let result_alloca = env.builder.build_alloca(type_, name); + + // Initialize all memory of the alloca. This _should_ not be required, but currently + // LLVM can access uninitialized memory after applying some optimizations. Hopefully + // we can in the future adjust code gen so this is no longer an issue. + // + // An example is + // + // main : Task.Task {} [] + // main = + // when List.len [ Ok "foo", Err 42, Ok "spam" ] is + // n -> Task.putLine (Str.fromInt n) + // + // Here the decrement function of result must first check it's an Ok tag, + // then defers to string decrement, which must check is the string is small or large + // + // After inlining, those checks are combined. That means that even if the tag is Err, + // a check is done on the "string" to see if it is big or small, which will touch the + // uninitialized memory. + let all_zeros = type_.const_zero(); + env.builder.build_store(result_alloca, all_zeros); + + result_alloca +} + pub fn build_tag<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, scope: &Scope<'a, 'ctx>, @@ -1482,27 +1512,7 @@ pub fn build_tag<'a, 'ctx, 'env>( let wrapper_type = env .context .struct_type(&[internal_type, tag_id_type.into()], false); - let result_alloca = env.builder.build_alloca(wrapper_type, "tag_opaque"); - - // Initialize all memory of the alloca. This _should_ not be required, but currently - // LLVM can access uninitialized memory after applying some optimizations. Hopefully - // we can in the future adjust code gen so this is no longer an issue. - // - // An example is - // - // main : Task.Task {} [] - // main = - // when List.len [ Ok "foo", Err 42, Ok "spam" ] is - // n -> Task.putLine (Str.fromInt n) - // - // Here the decrement function of result must first check it's an Ok tag, - // then defers to string decrement, which must check is the string is small or large - // - // After inlining, those checks are combined. That means that even if the tag is Err, - // a check is done on the "string" to see if it is big or small, which will touch the - // uninitialized memory. - let all_zeros = wrapper_type.const_zero(); - env.builder.build_store(result_alloca, all_zeros); + let result_alloca = tag_alloca(env, wrapper_type.into(), "opaque_tag"); // Determine types let num_fields = arguments.len() + 1; @@ -2031,7 +2041,7 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>( let field_type = basic_type_from_layout(env, &field_layout); let align_bytes = field_layout.alignment_bytes(env.ptr_bytes); - let alloca = env.builder.build_alloca(field_type, "copied_tag"); + let alloca = tag_alloca(env, field_type, "copied_tag"); if align_bytes > 0 { let size = env .ptr_int() @@ -2379,9 +2389,7 @@ pub fn load_roc_value<'a, 'ctx, 'env>( name: &str, ) -> BasicValueEnum<'ctx> { if layout.is_passed_by_reference() { - let alloca = env - .builder - .build_alloca(basic_type_from_layout(env, &layout), name); + let alloca = tag_alloca(env, basic_type_from_layout(env, &layout), name); store_roc_value(env, layout, alloca, source.into()); @@ -2509,7 +2517,20 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( let out_parameter = parameters.last().unwrap(); debug_assert!(out_parameter.is_pointer_value()); - store_roc_value(env, *layout, out_parameter.into_pointer_value(), value); + // store_roc_value(env, *layout, out_parameter.into_pointer_value(), value); + + let destination = out_parameter.into_pointer_value(); + if layout.is_passed_by_reference() { + let align_bytes = layout.alignment_bytes(env.ptr_bytes); + + if align_bytes > 0 { + let value_ptr = value.into_pointer_value(); + + value_ptr.replace_all_uses_with(destination); + } + } else { + env.builder.build_store(destination, value); + } if let Some(block) = env.builder.get_insert_block() { match block.get_terminator() { @@ -4569,7 +4590,7 @@ pub fn call_roc_function<'a, 'ctx, 'env>( let mut arguments = Vec::from_iter_in(arguments.iter().copied(), env.arena); let result_type = basic_type_from_layout(env, result_layout); - let result_alloca = env.builder.build_alloca(result_type, "result_value"); + let result_alloca = tag_alloca(env, result_type, "result_value"); arguments.push(result_alloca.into()); diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 2a0d4b1c18..e2f9bd582c 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -243,7 +243,7 @@ where match opt_level { OptLevel::Development | OptLevel::Normal => morphic_lib::solve_trivial(program), - OptLevel::Optimize => morphic_lib::solve(program), + OptLevel::Optimize => morphic_lib::solve_trivial(program), } } From 826628456786493018a698b5dda43075fd71ea64 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 8 Nov 2021 22:31:08 +0100 Subject: [PATCH 014/223] clippy --- compiler/gen_llvm/src/llvm/bitcode.rs | 2 +- compiler/gen_llvm/src/llvm/build.rs | 64 +++++++++++++---------- compiler/gen_llvm/src/llvm/build_hash.rs | 2 +- compiler/gen_llvm/src/llvm/compare.rs | 38 +++++++++++--- compiler/gen_llvm/src/llvm/refcounting.rs | 21 +++----- compiler/load/src/file.rs | 2 +- compiler/mono/src/alias_analysis.rs | 2 +- compiler/test_gen/src/gen_tags.rs | 1 - 8 files changed, 79 insertions(+), 53 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/bitcode.rs b/compiler/gen_llvm/src/llvm/bitcode.rs index fa89ceacf9..0fad482fef 100644 --- a/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/compiler/gen_llvm/src/llvm/bitcode.rs @@ -1,7 +1,7 @@ /// Helpers for interacting with the zig that generates bitcode use crate::debug_info_init; use crate::llvm::build::{struct_from_fields, Env, C_CALL_CONV, FAST_CALL_CONV, TAG_DATA_INDEX}; -use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1}; +use crate::llvm::convert::basic_type_from_layout; use crate::llvm::refcounting::{ decrement_refcount_layout, increment_n_refcount_layout, increment_refcount_layout, }; diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 480a5ccdfe..66a2e0013b 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -1194,17 +1194,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( .unwrap(); let field_layout = fields[*index as usize]; - if field_layout.is_passed_by_reference() { - let alloca = env.builder.build_alloca( - basic_type_from_layout(env, &field_layout), - "struct_field_tag", - ); - env.builder.build_store(alloca, field_value); - - alloca.into() - } else { - field_value - } + use_roc_value(env, field_layout, field_value, "struct_field_tag") } ( PointerValue(argument), @@ -1253,8 +1243,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( index, union_layout, } => { - let builder = env.builder; - // cast the argument bytes into the desired shape for this tag let (argument, _structure_layout) = load_symbol_and_layout(scope, structure); @@ -2399,6 +2387,23 @@ pub fn load_roc_value<'a, 'ctx, 'env>( } } +pub fn use_roc_value<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout: Layout<'a>, + source: BasicValueEnum<'ctx>, + name: &str, +) -> BasicValueEnum<'ctx> { + if layout.is_passed_by_reference() { + let alloca = tag_alloca(env, basic_type_from_layout(env, &layout), name); + + env.builder.build_store(alloca, source); + + alloca.into() + } else { + source + } +} + pub fn store_roc_value_opaque<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout: Layout<'a>, @@ -2526,7 +2531,23 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( if align_bytes > 0 { let value_ptr = value.into_pointer_value(); - value_ptr.replace_all_uses_with(destination); + if true { + value_ptr.replace_all_uses_with(destination); + } else { + let size = env + .ptr_int() + .const_int(layout.stack_size(env.ptr_bytes) as u64, false); + + env.builder + .build_memcpy( + destination, + align_bytes, + value.into_pointer_value(), + align_bytes, + size, + ) + .unwrap(); + } } } else { env.builder.build_store(destination, value); @@ -2794,20 +2815,6 @@ pub fn load_symbol_and_lambda_set<'a, 'ctx, 'b>( } } -fn access_index_struct_value<'ctx>( - builder: &Builder<'ctx>, - from_value: StructValue<'ctx>, - to_type: StructType<'ctx>, -) -> StructValue<'ctx> { - complex_bitcast( - builder, - from_value.into(), - to_type.into(), - "access_index_struct_value", - ) - .into_struct_value() -} - /// Cast a value to another value of the same (or smaller?) size pub fn cast_basic_basic<'ctx>( builder: &Builder<'ctx>, @@ -4660,6 +4667,7 @@ pub struct RocFunctionCall<'ctx> { pub data_is_owned: IntValue<'ctx>, } +#[allow(clippy::too_many_arguments)] fn roc_function_call<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, diff --git a/compiler/gen_llvm/src/llvm/build_hash.rs b/compiler/gen_llvm/src/llvm/build_hash.rs index b73fe7bd4e..261af4e7d4 100644 --- a/compiler/gen_llvm/src/llvm/build_hash.rs +++ b/compiler/gen_llvm/src/llvm/build_hash.rs @@ -2,7 +2,7 @@ use crate::debug_info_init; use crate::llvm::bitcode::call_bitcode_fn; use crate::llvm::build::tag_pointer_clear_tag_id; use crate::llvm::build::Env; -use crate::llvm::build::{cast_block_of_memory_to_tag, get_tag_id, FAST_CALL_CONV, TAG_DATA_INDEX}; +use crate::llvm::build::{get_tag_id, FAST_CALL_CONV, TAG_DATA_INDEX}; use crate::llvm::build_str; use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1}; use bumpalo::collections::Vec; diff --git a/compiler/gen_llvm/src/llvm/compare.rs b/compiler/gen_llvm/src/llvm/compare.rs index 83c8887ce8..c624890616 100644 --- a/compiler/gen_llvm/src/llvm/compare.rs +++ b/compiler/gen_llvm/src/llvm/compare.rs @@ -884,8 +884,15 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let block = env.context.append_basic_block(parent, "tag_id_modify"); env.builder.position_at_end(block); - let answer = - eq_ptr_to_struct(env, layout_ids, union_layout, field_layouts, tag1, tag2); + let answer = eq_ptr_to_struct( + env, + layout_ids, + union_layout, + Some(when_recursive.clone()), + field_layouts, + tag1, + tag2, + ); env.builder.build_return(Some(&answer)); @@ -941,8 +948,15 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let block = env.context.append_basic_block(parent, "tag_id_modify"); env.builder.position_at_end(block); - let answer = - eq_ptr_to_struct(env, layout_ids, union_layout, field_layouts, tag1, tag2); + let answer = eq_ptr_to_struct( + env, + layout_ids, + union_layout, + None, + field_layouts, + tag1, + tag2, + ); env.builder.build_return(Some(&answer)); @@ -998,6 +1012,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( env, layout_ids, union_layout, + None, other_fields, tag1.into_pointer_value(), tag2.into_pointer_value(), @@ -1088,8 +1103,15 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let block = env.context.append_basic_block(parent, "tag_id_modify"); env.builder.position_at_end(block); - let answer = - eq_ptr_to_struct(env, layout_ids, union_layout, field_layouts, tag1, tag2); + let answer = eq_ptr_to_struct( + env, + layout_ids, + union_layout, + None, + field_layouts, + tag1, + tag2, + ); env.builder.build_return(Some(&answer)); @@ -1123,6 +1145,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( env, layout_ids, union_layout, + None, field_layouts, tag1.into_pointer_value(), tag2.into_pointer_value(), @@ -1137,6 +1160,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, union_layout: &UnionLayout<'a>, + opt_when_recursive: Option>, field_layouts: &'a [Layout<'a>], tag1: PointerValue<'ctx>, tag2: PointerValue<'ctx>, @@ -1179,7 +1203,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>( env, layout_ids, field_layouts, - WhenRecursive::Loop(*union_layout), + opt_when_recursive.unwrap_or(WhenRecursive::Loop(*union_layout)), struct1, struct2, ) diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 9c40a8d367..de55b101ff 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -1,8 +1,8 @@ use crate::debug_info_init; use crate::llvm::bitcode::call_void_bitcode_fn; use crate::llvm::build::{ - add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, - TAG_DATA_INDEX, TAG_ID_INDEX, + add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, use_roc_value, Env, + FAST_CALL_CONV, TAG_DATA_INDEX, TAG_ID_INDEX, }; use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list}; use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1, ptr_int}; @@ -354,17 +354,12 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>( .build_extract_value(wrapper_struct, i as u32, "decrement_struct_field") .unwrap(); - let field_value = if field_layout.is_passed_by_reference() { - let field_type = basic_type_from_layout(env, field_layout); - let alloca = env - .builder - .build_alloca(field_type, "load_struct_tag_field_for_decrement"); - env.builder.build_store(alloca, raw_value); - - alloca.into() - } else { - raw_value - }; + let field_value = use_roc_value( + env, + *field_layout, + raw_value, + "load_struct_tag_field_for_decrement", + ); modify_refcount_layout_help( env, diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 60e8d7a5f2..e0dfe8fd0a 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2152,7 +2152,7 @@ fn update<'a>( println!("{}", result); } - Proc::insert_refcount_operations(arena, &mut state.procedures); + // Proc::insert_refcount_operations(arena, &mut state.procedures); // This is not safe with the new non-recursive RC updates that we do for tag unions // diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index e2f9bd582c..2a0d4b1c18 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -243,7 +243,7 @@ where match opt_level { OptLevel::Development | OptLevel::Normal => morphic_lib::solve_trivial(program), - OptLevel::Optimize => morphic_lib::solve_trivial(program), + OptLevel::Optimize => morphic_lib::solve(program), } } diff --git a/compiler/test_gen/src/gen_tags.rs b/compiler/test_gen/src/gen_tags.rs index 9c5989b174..c62140fd96 100644 --- a/compiler/test_gen/src/gen_tags.rs +++ b/compiler/test_gen/src/gen_tags.rs @@ -3,7 +3,6 @@ use crate::assert_evals_to; // use crate::assert_wasm_evals_to as assert_evals_to; use indoc::indoc; -use roc_mono::layout::LambdaSet; use roc_std::{RocList, RocStr}; #[test] From 7ff4ad6f7ba6aa75dab5df3702d05ba572de6a1a Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 8 Nov 2021 23:57:56 +0100 Subject: [PATCH 015/223] fix merge conflict --- compiler/gen_llvm/src/llvm/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index ba9b67a858..642332171b 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -5166,6 +5166,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, + Layout::Builtin(Builtin::Int1), ); list_any(env, roc_function_call, list, element_layout) From 4fdb8d354b501120972d736d026693b966eef20b Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 10 Nov 2021 00:22:49 +0100 Subject: [PATCH 016/223] turn on refcounting again, turning it off does not help (builtins still decrement and potentially free) --- compiler/load/src/file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index e0dfe8fd0a..60e8d7a5f2 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2152,7 +2152,7 @@ fn update<'a>( println!("{}", result); } - // Proc::insert_refcount_operations(arena, &mut state.procedures); + Proc::insert_refcount_operations(arena, &mut state.procedures); // This is not safe with the new non-recursive RC updates that we do for tag unions // From 4ed25fb351202ba41a58395533d1a0f334d28970 Mon Sep 17 00:00:00 2001 From: Joost Baas Date: Thu, 11 Nov 2021 21:39:39 +0100 Subject: [PATCH 017/223] make sure get_macos_version() returns string without newline --- compiler/build/src/link.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index d5285b3602..579c1343bb 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -863,6 +863,7 @@ fn get_macos_version() -> String { .expect("Failed to convert output of command 'sw_vers -productVersion' into a utf8 string"); full_version_string + .trim_end() .split('.') .take(2) .collect::>() From 38da99b1ac017abda1b8eb9274cce54e131410bd Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 11 Nov 2021 23:36:35 +0100 Subject: [PATCH 018/223] make it work --- cli/src/repl/gen.rs | 4 ++-- compiler/gen_llvm/src/llvm/bitcode.rs | 15 ++++----------- compiler/gen_llvm/src/llvm/build.rs | 13 +++++++------ compiler/gen_llvm/src/llvm/refcounting.rs | 23 +++++++++++++++++++---- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/cli/src/repl/gen.rs b/cli/src/repl/gen.rs index 200941919d..3e789da85b 100644 --- a/cli/src/repl/gen.rs +++ b/cli/src/repl/gen.rs @@ -218,8 +218,8 @@ pub fn gen_and_eval<'a>( // Verify the module if let Err(errors) = env.module.verify() { panic!( - "Errors defining module: {}\n\nUncomment things nearby to see more details.", - errors + "Errors defining module:\n{}\n\nUncomment things nearby to see more details.", + errors.to_string() ); } diff --git a/compiler/gen_llvm/src/llvm/bitcode.rs b/compiler/gen_llvm/src/llvm/bitcode.rs index 0fad482fef..2afb1c7159 100644 --- a/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/compiler/gen_llvm/src/llvm/bitcode.rs @@ -154,18 +154,11 @@ fn build_has_tag_id_help<'a, 'ctx, 'env>( ); let tag_data_ptr = { - let data_index = env - .context - .i64_type() - .const_int(TAG_DATA_INDEX as u64, false); + let ptr = env + .builder + .build_struct_gep(tag_value, TAG_DATA_INDEX, "get_data_ptr") + .unwrap(); - let ptr = unsafe { - env.builder.build_gep( - tag_value_ptr.into_pointer_value(), - &[data_index], - "get_data_ptr", - ) - }; env.builder.build_bitcast(ptr, i8_ptr_type, "to_opaque") }; diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index b89096f4a5..711116bc80 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -2532,7 +2532,10 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( if align_bytes > 0 { let value_ptr = value.into_pointer_value(); - if true { + // We can only do this if the function itself writes data into this + // pointer. If the pointer is passed as an argument, then we must copy + // from one pointer to our destination pointer + if value_ptr.get_first_use().is_some() { value_ptr.replace_all_uses_with(destination); } else { let size = env @@ -3382,8 +3385,7 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( // a tagged union to indicate to the test loader that a panic occurred. // especially when running 32-bit binaries on a 64-bit machine, there // does not seem to be a smarter solution - let wrapper_return_type = - roc_result_type(env, roc_function.get_type().get_return_type().unwrap()); + let wrapper_return_type = roc_result_type(env, basic_type_from_layout(env, &return_layout)); let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena); for layout in arguments { @@ -3861,7 +3863,7 @@ fn make_good_roc_result<'a, 'ctx, 'env>( let context = env.context; let builder = env.builder; - let v1 = roc_result_type(env, return_value.get_type()).const_zero(); + let v1 = roc_result_type(env, basic_type_from_layout(env, &return_layout)).const_zero(); let v2 = builder .build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error") @@ -3906,8 +3908,7 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( } }; - let wrapper_return_type = - roc_result_type(env, roc_function.get_type().get_return_type().unwrap()); + let wrapper_return_type = roc_result_type(env, basic_type_from_layout(env, &return_layout)); // argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into()); diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index de55b101ff..0a956f8bce 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -139,8 +139,10 @@ impl<'ctx> PointerToRefcount<'ctx> { let block = env.builder.get_insert_block().expect("to be in a function"); let parent = block.get_parent().unwrap(); - let modify_block = env.context.append_basic_block(parent, "inc_str_modify"); - let cont_block = env.context.append_basic_block(parent, "inc_str_cont"); + let modify_block = env + .context + .append_basic_block(parent, "inc_refcount_modify"); + let cont_block = env.context.append_basic_block(parent, "inc_refcount_cont"); env.builder .build_conditional_branch(is_static_allocation, cont_block, modify_block); @@ -1718,12 +1720,25 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( "cast_to_concrete_tag", ); - // let wrapper_struct = cast_block_of_memory_to_tag(env.builder, data_bytes, wrapper_type); - for (i, field_layout) in field_layouts.iter().enumerate() { if let Layout::RecursivePointer = field_layout { panic!("non-recursive tag unions cannot contain naked recursion pointers!"); } else if field_layout.contains_refcounted() { + // crazy hack + match field_layout { + Layout::Builtin(Builtin::Str | Builtin::List(_)) => { + use inkwell::attributes::{Attribute, AttributeLoc}; + let kind_id = Attribute::get_named_enum_kind_id("noinline"); + debug_assert!(kind_id > 0); + let enum_attr = env.context.create_enum_attribute(kind_id, 1); + + fn_val.add_attribute(AttributeLoc::Function, enum_attr); + } + _ => { + // do nothing + } + } + let field_ptr = env .builder .build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field") From 65a9febe7dd1e6294d34619d5dd00e151fafea68 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 11 Nov 2021 23:38:45 +0100 Subject: [PATCH 019/223] clippy --- compiler/gen_llvm/src/llvm/refcounting.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 0a956f8bce..47f2ecf24c 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -1724,19 +1724,15 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( if let Layout::RecursivePointer = field_layout { panic!("non-recursive tag unions cannot contain naked recursion pointers!"); } else if field_layout.contains_refcounted() { - // crazy hack - match field_layout { - Layout::Builtin(Builtin::Str | Builtin::List(_)) => { - use inkwell::attributes::{Attribute, AttributeLoc}; - let kind_id = Attribute::get_named_enum_kind_id("noinline"); - debug_assert!(kind_id > 0); - let enum_attr = env.context.create_enum_attribute(kind_id, 1); + // crazy hack: inlining this function when it decrements a list or string results + // in many, many valgrind errors in `--optimize` mode. We do not know why. + if let Layout::Builtin(Builtin::Str | Builtin::List(_)) = field_layout { + use inkwell::attributes::{Attribute, AttributeLoc}; + let kind_id = Attribute::get_named_enum_kind_id("noinline"); + debug_assert!(kind_id > 0); + let enum_attr = env.context.create_enum_attribute(kind_id, 1); - fn_val.add_attribute(AttributeLoc::Function, enum_attr); - } - _ => { - // do nothing - } + fn_val.add_attribute(AttributeLoc::Function, enum_attr); } let field_ptr = env From d5301817b73a8fc1792a1e864bbe529066786dbc Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Thu, 11 Nov 2021 20:04:37 -0800 Subject: [PATCH 020/223] Apply `cargo fmt --all` to Cargo.toml --- cli_utils/Cargo.lock | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/cli_utils/Cargo.lock b/cli_utils/Cargo.lock index f41f503d27..4889a1da49 100644 --- a/cli_utils/Cargo.lock +++ b/cli_utils/Cargo.lock @@ -2398,8 +2398,6 @@ name = "roc_build" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "libloading 0.7.1", "roc_builtins", @@ -2440,8 +2438,6 @@ name = "roc_can" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "roc_builtins", "roc_collections", "roc_module", @@ -2459,8 +2455,6 @@ dependencies = [ "bumpalo", "clap 3.0.0-beta.5", "const_format", - "im", - "im-rc", "inkwell 0.1.0", "libloading 0.7.1", "mimalloc", @@ -2562,8 +2556,6 @@ dependencies = [ "fs_extra", "futures", "glyph_brush", - "im", - "im-rc", "libc", "log", "nonempty", @@ -2599,8 +2591,6 @@ name = "roc_fmt" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "roc_collections", "roc_module", "roc_parse", @@ -2612,8 +2602,6 @@ name = "roc_gen_dev" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "object 0.26.2", "roc_builtins", "roc_collections", @@ -2632,20 +2620,13 @@ name = "roc_gen_llvm" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "morphic_lib", "roc_builtins", "roc_collections", "roc_module", "roc_mono", - "roc_problem", - "roc_region", - "roc_solve", "roc_std", - "roc_types", - "roc_unify", "target-lexicon", ] @@ -2654,6 +2635,7 @@ name = "roc_gen_wasm" version = "0.1.0" dependencies = [ "bumpalo", + "roc_builtins", "roc_collections", "roc_module", "roc_mono", @@ -2726,7 +2708,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "hashbrown 0.11.2", - "linked-hash-map", "morphic_lib", "roc_can", "roc_collections", @@ -2737,7 +2718,6 @@ dependencies = [ "roc_std", "roc_types", "roc_unify", - "ven_ena", "ven_graph", "ven_pretty", ] @@ -2773,8 +2753,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "distance", - "im", - "im-rc", "roc_can", "roc_collections", "roc_module", From d63849c5a331db04d793fb5d9ea71adbe05b7b53 Mon Sep 17 00:00:00 2001 From: satotake Date: Fri, 12 Nov 2021 12:23:41 +0000 Subject: [PATCH 021/223] Add List.takeFisrt2, List.takeLast2 for demo --- compiler/builtins/src/std.rs | 14 +++ compiler/can/src/builtins.rs | 188 +++++++++++++++++++++++++++++ compiler/module/src/symbol.rs | 4 + compiler/solve/tests/solve_expr.rs | 24 ++++ compiler/test_gen/src/gen_list.rs | 35 ++++++ 5 files changed, 265 insertions(+) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 335340c256..4f59c441d3 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -985,6 +985,13 @@ pub fn types() -> MutMap { Box::new(list_type(flex(TVAR1))), ); + // takeFirst2 : List elem, Nat -> List elem + add_top_level_function_type!( + Symbol::LIST_TAKE_FIRST_2, + vec![list_type(flex(TVAR1)), nat_type()], + Box::new(list_type(flex(TVAR1))), + ); + // takeLast : List elem, Nat -> List elem add_top_level_function_type!( Symbol::LIST_TAKE_LAST, @@ -992,6 +999,13 @@ pub fn types() -> MutMap { Box::new(list_type(flex(TVAR1))), ); + // takeLast2 : List elem, Nat -> List elem + add_top_level_function_type!( + Symbol::LIST_TAKE_LAST_2, + vec![list_type(flex(TVAR1)), nat_type()], + Box::new(list_type(flex(TVAR1))), + ); + // sublist : List elem, { start : Nat, len : Nat } -> List elem add_top_level_function_type!( Symbol::LIST_SUBLIST, diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 01fb6c404c..ca6b74585d 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -94,6 +94,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option LIST_MAP4 => list_map4, LIST_TAKE_FIRST => list_take_first, LIST_TAKE_LAST => list_take_last, + LIST_TAKE_FIRST_2 => list_take_first_2, + LIST_TAKE_LAST_2 => list_take_last_2, LIST_SUBLIST => list_sublist, LIST_DROP => list_drop, LIST_DROP_AT => list_drop_at, @@ -2038,6 +2040,120 @@ fn list_take_first(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +/// List.takeFirst2 : List elem, Nat -> List elem +fn list_take_first_2(symbol: Symbol, var_store: &mut VarStore) -> Def { + let list_var = var_store.fresh(); + let len_var = var_store.fresh(); + + let sym_rec = Symbol::LIST_TAKE_3_TEMP; + + let int_var = var_store.fresh(); + let bool_var = var_store.fresh(); + let clos_var = var_store.fresh(); + let list_after = var_store.fresh(); + + let one = || int(int_var, Variable::NATURAL, 1); + + let clos = Closure(ClosureData { + function_type: clos_var, + closure_type: var_store.fresh(), + closure_ext_var: var_store.fresh(), + return_type: list_after, + name: sym_rec, + recursive: Recursive::Recursive, + captured_symbols: vec![], + arguments: vec![(list_after, no_region(Pattern::Identifier(Symbol::ARG_3)))], + loc_body: { + Box::new(no_region(If { + cond_var: var_store.fresh(), + branch_var: var_store.fresh(), + branches: vec![( + no_region(RunLowLevel { + op: LowLevel::NumLte, + args: vec![ + ( + int_var, + RunLowLevel { + op: LowLevel::ListLen, + args: vec![(list_after, Var(Symbol::ARG_3))], + ret_var: int_var, + }, + ), + (int_var, Var(Symbol::ARG_2)), + ], + ret_var: bool_var, + }), + no_region(Var(Symbol::ARG_3)), + )], + final_else: Box::new(no_region(Call( + Box::new(( + clos_var, + no_region(Var(sym_rec)), + var_store.fresh(), + list_after, + )), + vec![( + list_after, + no_region(RunLowLevel { + // DropLast + op: LowLevel::ListDrop, + args: vec![ + (list_after, Var(Symbol::ARG_3)), + ( + int_var, + RunLowLevel { + ret_var: int_var, + op: LowLevel::NumSubWrap, + args: vec![ + ( + int_var, + RunLowLevel { + ret_var: int_var, + op: LowLevel::ListLen, + args: vec![(list_after, Var(Symbol::ARG_3))], + }, + ), + (int_var, one()), + ], + }, + ), + ], + ret_var: list_after, + }), + )], + CalledVia::Space, + ))), + })) + }, + }); + + let def_rec = Def { + annotation: None, + expr_var: int_var, + loc_expr: no_region(clos), + loc_pattern: no_region(Pattern::Identifier(sym_rec)), + pattern_vars: Default::default(), + }; + let body = Call( + Box::new(( + clos_var, + no_region(Var(sym_rec)), + var_store.fresh(), + list_var, + )), + vec![(list_var, no_region(Var(Symbol::ARG_1)))], + CalledVia::Space, + ); + + defn( + symbol, + vec![(list_var, Symbol::ARG_1), (len_var, Symbol::ARG_2)], + var_store, + LetRec(vec![def_rec], Box::new(no_region(body)), list_var), + list_var, + ) +} + /// List.takeLast : List elem, Nat -> List elem fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); @@ -2061,6 +2177,78 @@ fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +/// List.takeLast2 : List elem, Nat -> List elem +fn list_take_last_2(symbol: Symbol, var_store: &mut VarStore) -> Def { + let list_var = var_store.fresh(); + let len_var = var_store.fresh(); + + let sym_list = Symbol::ARG_1; + let sym_len = Symbol::ARG_2; + + let drop_len = Symbol::LIST_TAKE_2_TEMP; + + let bool_var = var_store.fresh(); + let int_var = var_store.fresh(); + + let zero = || int(int_var, Variable::NATURAL, 0); + + let def_drop_len = Def { + annotation: None, + expr_var: int_var, + loc_expr: no_region(RunLowLevel { + op: LowLevel::NumSubWrap, + args: vec![ + ( + int_var, + RunLowLevel { + op: LowLevel::ListLen, + args: vec![(list_var, Var(sym_list))], + ret_var: int_var, + }, + ), + (int_var, Var(sym_len)), + ], + ret_var: int_var, + }), + loc_pattern: no_region(Pattern::Identifier(drop_len)), + pattern_vars: Default::default(), + }; + + let get_larger = If { + cond_var: bool_var, + branch_var: int_var, + branches: vec![( + no_region(RunLowLevel { + op: LowLevel::NumGte, + args: vec![(int_var, Var(drop_len)), (int_var, zero())], + ret_var: bool_var, + }), + no_region(Var(drop_len)), + )], + final_else: Box::new(no_region(zero())), + }; + + let body_drop = RunLowLevel { + op: LowLevel::ListDrop, + args: vec![(list_var, Var(sym_list)), (int_var, get_larger)], + ret_var: list_var, + }; + + let body = LetNonRec( + Box::new(def_drop_len), + Box::new(no_region(body_drop)), + list_var, + ); + + defn( + symbol, + vec![(list_var, sym_list), (len_var, sym_len)], + var_store, + body, + list_var, + ) +} + /// List.sublist : List elem, { start : Nat, len : Nat } -> List elem fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 31a02a5050..d65b511595 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1071,6 +1071,10 @@ define_builtins! { 47 LIST_FIND: "find" 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" + 50 LIST_TAKE_FIRST_2: "takeFirst2" + 51 LIST_TAKE_LAST_2: "takeLast2" + 52 LIST_TAKE_2_TEMP: "#take2" + 53 LIST_TAKE_3_TEMP: "#take3" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index dcf74d79bb..bd59a6a7e3 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3769,6 +3769,18 @@ mod solve_expr { ); } + #[test] + fn list_take_first_2() { + infer_eq_without_problem( + indoc!( + r#" + List.takeFirst2 + "# + ), + "List a, Nat -> List a", + ); + } + #[test] fn list_take_last() { infer_eq_without_problem( @@ -3781,6 +3793,18 @@ mod solve_expr { ); } + #[test] + fn list_take_last_2() { + infer_eq_without_problem( + indoc!( + r#" + List.takeLast2 + "# + ), + "List a, Nat -> List a", + ); + } + #[test] fn list_sublist() { infer_eq_without_problem( diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 5e0f737e72..46a5adee99 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -187,6 +187,16 @@ fn list_take_first() { ); } +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn list_take_first_2() { + assert_evals_to!( + "List.takeFirst2 [1, 2, 3] 2", + RocList::from_slice(&[1, 2]), + RocList + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn list_take_last() { @@ -208,6 +218,31 @@ fn list_take_last() { ); } +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn list_take_last_2() { + assert_evals_to!( + "List.takeLast2 [1, 2, 3] 2", + RocList::from_slice(&[2, 3]), + RocList + ); + assert_evals_to!( + "List.takeLast2 [1, 2, 3] 0", + RocList::from_slice(&[]), + RocList + ); + assert_evals_to!( + "List.takeLast2 [] 1", + RocList::from_slice(&[]), + RocList + ); + assert_evals_to!( + "List.takeLast2 [1,2] 5", + RocList::from_slice(&[1, 2]), + RocList + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn list_sublist() { From 9a74ca441d4ce881a489dd90f261ab9ec9e055e7 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 07:33:53 -0800 Subject: [PATCH 022/223] Name all "error" enums in the parser starting with E --- compiler/parse/src/expr.rs | 155 +++++++++++------------ compiler/parse/src/number_literal.rs | 27 ++-- compiler/parse/src/parser.rs | 52 ++++---- compiler/parse/src/type_annotation.rs | 174 ++++++++++++++------------ compiler/reporting/src/error/parse.rs | 168 ++++++++++++------------- 5 files changed, 294 insertions(+), 282 deletions(-) diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index 612389da92..ad3b94f7f6 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -4,8 +4,8 @@ use crate::ident::{lowercase_ident, parse_ident, Ident}; use crate::keyword; use crate::parser::{ self, backtrackable, optional, sep_by1, sep_by1_e, specialize, specialize_ref, then, - trailing_sep_by0, word1, word2, EExpr, EInParens, ELambda, EPattern, ERecord, EString, Either, - Expect, If, List, Number, ParseResult, Parser, State, Type, When, + trailing_sep_by0, word1, word2, EExpect, EExpr, EIf, EInParens, ELambda, EList, ENumber, + EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, Parser, State, }; use crate::pattern::loc_closure_param; use crate::type_annotation; @@ -801,7 +801,7 @@ fn parse_defs_end<'a>( Err((NoProgress, _, _)) => { let start = state.get_position(); - match crate::parser::keyword_e(crate::keyword::EXPECT, Expect::Expect) + match crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect) .parse(arena, state) { Err((_, _, _)) => { @@ -861,8 +861,8 @@ fn parse_defs_end<'a>( space0_before_e( type_annotation::located_help(min_indent + 1), min_indent + 1, - Type::TSpace, - Type::TIndentStart, + EType::TSpace, + EType::TIndentStart, ), ) .parse(arena, state)?; @@ -1099,8 +1099,8 @@ fn parse_expr_operator<'a>( space0_before_e( type_annotation::located_help(indented_more), min_indent, - Type::TSpace, - Type::TIndentStart, + EType::TSpace, + EType::TIndentStart, ), ) .parse(arena, state)?; @@ -1126,8 +1126,8 @@ fn parse_expr_operator<'a>( space0_before_e( type_annotation::located_help(indented_more), min_indent, - Type::TSpace, - Type::TIndentStart, + EType::TSpace, + EType::TIndentStart, ), ); @@ -1651,21 +1651,21 @@ mod when { pub fn expr_help<'a>( min_indent: u16, options: ExprParseOptions, - ) -> impl Parser<'a, Expr<'a>, When<'a>> { + ) -> impl Parser<'a, Expr<'a>, EWhen<'a>> { then( and!( when_with_indent(), skip_second!( space0_around_ee( - specialize_ref(When::Condition, move |arena, state| { + specialize_ref(EWhen::Condition, move |arena, state| { parse_loc_expr_with_options(min_indent, options, arena, state) }), min_indent, - When::Space, - When::IndentCondition, - When::IndentIs, + EWhen::Space, + EWhen::IndentCondition, + EWhen::IndentIs, ), - parser::keyword_e(keyword::IS, When::Is) + parser::keyword_e(keyword::IS, EWhen::Is) ) ), move |arena, state, progress, (case_indent, loc_condition)| { @@ -1673,7 +1673,7 @@ mod when { return Err(( progress, // TODO maybe pass case_indent here? - When::PatternAlignment(5, state.line, state.column), + EWhen::PatternAlignment(5, state.line, state.column), state, )); } @@ -1693,9 +1693,9 @@ mod when { } /// Parsing when with indentation. - fn when_with_indent<'a>() -> impl Parser<'a, u16, When<'a>> { + fn when_with_indent<'a>() -> impl Parser<'a, u16, EWhen<'a>> { move |arena, state: State<'a>| { - parser::keyword_e(keyword::WHEN, When::When) + parser::keyword_e(keyword::WHEN, EWhen::When) .parse(arena, state) .map(|(progress, (), state)| (progress, state.indent_col, state)) } @@ -1704,7 +1704,7 @@ mod when { fn branches<'a>( min_indent: u16, options: ExprParseOptions, - ) -> impl Parser<'a, Vec<'a, &'a WhenBranch<'a>>, When<'a>> { + ) -> impl Parser<'a, Vec<'a, &'a WhenBranch<'a>>, EWhen<'a>> { move |arena, state: State<'a>| { let when_indent = state.indent_col; @@ -1741,7 +1741,7 @@ mod when { let indent = pattern_indent_level - indent_col; Err(( MadeProgress, - When::PatternAlignment(indent, state.line, state.column), + EWhen::PatternAlignment(indent, state.line, state.column), state, )) } @@ -1799,7 +1799,7 @@ mod when { (Col, Vec<'a, Located>>), Option>>, ), - When<'a>, + EWhen<'a>, > { let options = ExprParseOptions { check_for_arrow: false, @@ -1810,16 +1810,16 @@ mod when { one_of![ map!( skip_first!( - parser::keyword_e(keyword::IF, When::IfToken), + parser::keyword_e(keyword::IF, EWhen::IfToken), // TODO we should require space before the expression but not after space0_around_ee( - specialize_ref(When::IfGuard, move |arena, state| { + specialize_ref(EWhen::IfGuard, move |arena, state| { parse_loc_expr_with_options(min_indent + 1, options, arena, state) }), min_indent, - When::Space, - When::IndentIfGuard, - When::IndentArrow, + EWhen::Space, + EWhen::IndentIfGuard, + EWhen::IndentArrow, ) ), Some @@ -1831,17 +1831,17 @@ mod when { fn branch_single_alternative<'a>( min_indent: u16, - ) -> impl Parser<'a, Located>, When<'a>> { + ) -> impl Parser<'a, Located>, EWhen<'a>> { move |arena, state| { let (_, spaces, state) = - backtrackable(space0_e(min_indent, When::Space, When::IndentPattern)) + backtrackable(space0_e(min_indent, EWhen::Space, EWhen::IndentPattern)) .parse(arena, state)?; let (_, loc_pattern, state) = space0_after_e( - specialize(When::Pattern, crate::pattern::loc_pattern_help(min_indent)), + specialize(EWhen::Pattern, crate::pattern::loc_pattern_help(min_indent)), min_indent, - When::Space, - When::IndentPattern, + EWhen::Space, + EWhen::IndentPattern, ) .parse(arena, state)?; @@ -1862,12 +1862,12 @@ mod when { fn branch_alternatives_help<'a>( min_indent: u16, pattern_indent_level: Option, - ) -> impl Parser<'a, (Col, Vec<'a, Located>>), When<'a>> { + ) -> impl Parser<'a, (Col, Vec<'a, Located>>), EWhen<'a>> { move |arena, state: State<'a>| { let initial = state; // put no restrictions on the indent after the spaces; we'll check it manually - match space0_e(0, When::Space, When::IndentPattern).parse(arena, state) { + match space0_e(0, EWhen::Space, EWhen::IndentPattern).parse(arena, state) { Err((MadeProgress, fail, _)) => Err((NoProgress, fail, initial)), Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)), Ok((_progress, spaces, state)) => { @@ -1876,7 +1876,7 @@ mod when { // this branch is indented too much Err(( NoProgress, - When::IndentPattern(state.line, state.column), + EWhen::IndentPattern(state.line, state.column), initial, )) } @@ -1884,7 +1884,7 @@ mod when { let indent = wanted - state.column; Err(( NoProgress, - When::PatternAlignment(indent, state.line, state.column), + EWhen::PatternAlignment(indent, state.line, state.column), initial, )) } @@ -1896,7 +1896,7 @@ mod when { let pattern_indent_col = state.column; let parser = sep_by1( - word1(b'|', When::Bar), + word1(b'|', EWhen::Bar), branch_single_alternative(pattern_indent + 1), ); @@ -1930,16 +1930,16 @@ mod when { } /// Parsing the righthandside of a branch in a when conditional. - fn branch_result<'a>(indent: u16) -> impl Parser<'a, Located>, When<'a>> { + fn branch_result<'a>(indent: u16) -> impl Parser<'a, Located>, EWhen<'a>> { skip_first!( - word2(b'-', b'>', When::Arrow), + word2(b'-', b'>', EWhen::Arrow), space0_before_e( - specialize_ref(When::Branch, move |arena, state| parse_loc_expr( + specialize_ref(EWhen::Branch, move |arena, state| parse_loc_expr( indent, arena, state )), indent, - When::Space, - When::IndentBranch, + EWhen::Space, + EWhen::IndentBranch, ) ) } @@ -1947,38 +1947,38 @@ mod when { fn if_branch<'a>( min_indent: u16, -) -> impl Parser<'a, (Located>, Located>), If<'a>> { +) -> impl Parser<'a, (Located>, Located>), EIf<'a>> { move |arena, state| { // NOTE: only parse spaces before the expression let (_, cond, state) = space0_around_ee( - specialize_ref(If::Condition, move |arena, state| { + specialize_ref(EIf::Condition, move |arena, state| { parse_loc_expr(min_indent, arena, state) }), min_indent, - If::Space, - If::IndentCondition, - If::IndentThenToken, + EIf::Space, + EIf::IndentCondition, + EIf::IndentThenToken, ) .parse(arena, state) .map_err(|(_, f, s)| (MadeProgress, f, s))?; - let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then) + let (_, _, state) = parser::keyword_e(keyword::THEN, EIf::Then) .parse(arena, state) .map_err(|(_, f, s)| (MadeProgress, f, s))?; let (_, then_branch, state) = space0_around_ee( - specialize_ref(If::ThenBranch, move |arena, state| { + specialize_ref(EIf::ThenBranch, move |arena, state| { parse_loc_expr(min_indent, arena, state) }), min_indent, - If::Space, - If::IndentThenBranch, - If::IndentElseToken, + EIf::Space, + EIf::IndentThenBranch, + EIf::IndentElseToken, ) .parse(arena, state) .map_err(|(_, f, s)| (MadeProgress, f, s))?; - let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else) + let (_, _, state) = parser::keyword_e(keyword::ELSE, EIf::Else) .parse(arena, state) .map_err(|(_, f, s)| (MadeProgress, f, s))?; @@ -1989,26 +1989,26 @@ fn if_branch<'a>( fn expect_help<'a>( min_indent: u16, options: ExprParseOptions, -) -> impl Parser<'a, Expr<'a>, Expect<'a>> { +) -> impl Parser<'a, Expr<'a>, EExpect<'a>> { move |arena: &'a Bump, state: State<'a>| { let start = state.get_position(); let (_, _, state) = - parser::keyword_e(keyword::EXPECT, Expect::Expect).parse(arena, state)?; + parser::keyword_e(keyword::EXPECT, EExpect::Expect).parse(arena, state)?; let (_, condition, state) = space0_before_e( - specialize_ref(Expect::Condition, move |arena, state| { + specialize_ref(EExpect::Condition, move |arena, state| { parse_loc_expr_with_options(start.col + 1, options, arena, state) }), start.col + 1, - Expect::Space, - Expect::IndentCondition, + EExpect::Space, + EExpect::IndentCondition, ) .parse(arena, state) .map_err(|(_, f, s)| (MadeProgress, f, s))?; let parse_cont = specialize_ref( - Expect::Continuation, + EExpect::Continuation, space0_before_e( move |a, s| parse_loc_expr(min_indent, a, s), min_indent, @@ -2028,9 +2028,9 @@ fn expect_help<'a>( fn if_expr_help<'a>( min_indent: u16, options: ExprParseOptions, -) -> impl Parser<'a, Expr<'a>, If<'a>> { +) -> impl Parser<'a, Expr<'a>, EIf<'a>> { move |arena: &'a Bump, state| { - let (_, _, state) = parser::keyword_e(keyword::IF, If::If).parse(arena, state)?; + let (_, _, state) = parser::keyword_e(keyword::IF, EIf::If).parse(arena, state)?; let mut branches = Vec::with_capacity_in(1, arena); @@ -2044,8 +2044,8 @@ fn if_expr_help<'a>( // try to parse another `if` // NOTE this drops spaces between the `else` and the `if` let optional_if = and!( - backtrackable(space0_e(min_indent, If::Space, If::IndentIf)), - parser::keyword_e(keyword::IF, If::If) + backtrackable(space0_e(min_indent, EIf::Space, EIf::IndentIf)), + parser::keyword_e(keyword::IF, EIf::If) ); match optional_if.parse(arena, state) { @@ -2058,12 +2058,12 @@ fn if_expr_help<'a>( }; let (_, else_branch, state) = space0_before_e( - specialize_ref(If::ElseBranch, move |arena, state| { + specialize_ref(EIf::ElseBranch, move |arena, state| { parse_loc_expr_with_options(min_indent, options, arena, state) }), min_indent, - If::Space, - If::IndentElseBranch, + EIf::Space, + EIf::IndentElseBranch, ) .parse(arena, state_final_else) .map_err(|(_, f, s)| (MadeProgress, f, s))?; @@ -2147,19 +2147,20 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> { } } -fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>> { +fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EList<'a>> { move |arena, state| { let (_, elements, state) = collection_trailing_sep_e!( - word1(b'[', List::Open), - specialize_ref(List::Expr, move |a, s| parse_loc_expr_no_multi_backpassing( - min_indent, a, s - )), - word1(b',', List::End), - word1(b']', List::End), + word1(b'[', EList::Open), + specialize_ref( + EList::Expr, + move |a, s| parse_loc_expr_no_multi_backpassing(min_indent, a, s) + ), + word1(b',', EList::End), + word1(b']', EList::End), min_indent, - List::Open, - List::Space, - List::IndentEnd, + EList::Open, + EList::Space, + EList::IndentEnd, Expr::SpaceBefore ) .parse(arena, state)?; @@ -2341,7 +2342,7 @@ fn string_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> { map!(crate::string_literal::parse(), Expr::Str) } -fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> { +fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> { map!( crate::number_literal::positive_number_literal(), |literal| { @@ -2364,7 +2365,7 @@ fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> { ) } -fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> { +fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> { map!(crate::number_literal::number_literal(), |literal| { use crate::number_literal::NumLiteral::*; diff --git a/compiler/parse/src/number_literal.rs b/compiler/parse/src/number_literal.rs index 2386f7803a..fc1d11e736 100644 --- a/compiler/parse/src/number_literal.rs +++ b/compiler/parse/src/number_literal.rs @@ -1,5 +1,5 @@ use crate::ast::Base; -use crate::parser::{Number, ParseResult, Parser, Progress, State}; +use crate::parser::{ENumber, ParseResult, Parser, Progress, State}; pub enum NumLiteral<'a> { Float(&'a str), @@ -11,7 +11,7 @@ pub enum NumLiteral<'a> { }, } -pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> { +pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> { move |_arena, state: State<'a>| { match state.bytes.get(0) { Some(first_byte) if (*first_byte as char).is_ascii_digit() => { @@ -19,13 +19,13 @@ pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> } _ => { // this is not a number at all - Err((Progress::NoProgress, Number::End, state)) + Err((Progress::NoProgress, ENumber::End, state)) } } } } -pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> { +pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> { move |_arena, state: State<'a>| { match state.bytes.get(0) { Some(first_byte) if *first_byte == b'-' => { @@ -37,7 +37,7 @@ pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> { } _ => { // this is not a number at all - Err((Progress::NoProgress, Number::End, state)) + Err((Progress::NoProgress, ENumber::End, state)) } } } @@ -47,7 +47,7 @@ fn parse_number_base<'a>( is_negated: bool, bytes: &'a [u8], state: State<'a>, -) -> ParseResult<'a, NumLiteral<'a>, Number> { +) -> ParseResult<'a, NumLiteral<'a>, ENumber> { match bytes.get(0..2) { Some(b"0b") => chomp_number_base(Base::Binary, is_negated, &bytes[2..], state), Some(b"0o") => chomp_number_base(Base::Octal, is_negated, &bytes[2..], state), @@ -61,13 +61,13 @@ fn chomp_number_base<'a>( is_negative: bool, bytes: &'a [u8], state: State<'a>, -) -> ParseResult<'a, NumLiteral<'a>, Number> { +) -> ParseResult<'a, NumLiteral<'a>, ENumber> { let (_is_float, chomped) = chomp_number(bytes); let string = unsafe { std::str::from_utf8_unchecked(&bytes[..chomped]) }; let new = state.advance_without_indenting_ee(chomped + 2 + is_negative as usize, |_, _| { - Number::LineTooLong + ENumber::LineTooLong })?; Ok(( @@ -85,24 +85,25 @@ fn chomp_number_dec<'a>( is_negative: bool, bytes: &'a [u8], state: State<'a>, -) -> ParseResult<'a, NumLiteral<'a>, Number> { +) -> ParseResult<'a, NumLiteral<'a>, ENumber> { let (is_float, chomped) = chomp_number(bytes); if is_negative && chomped == 0 { // we're probably actually looking at unary negation here - return Err((Progress::NoProgress, Number::End, state)); + return Err((Progress::NoProgress, ENumber::End, state)); } if !bytes.get(0).copied().unwrap_or_default().is_ascii_digit() { // we're probably actually looking at unary negation here - return Err((Progress::NoProgress, Number::End, state)); + return Err((Progress::NoProgress, ENumber::End, state)); } let string = unsafe { std::str::from_utf8_unchecked(&state.bytes[0..chomped + is_negative as usize]) }; - let new = state - .advance_without_indenting_ee(chomped + is_negative as usize, |_, _| Number::LineTooLong)?; + let new = state.advance_without_indenting_ee(chomped + is_negative as usize, |_, _| { + ENumber::LineTooLong + })?; Ok(( Progress::MadeProgress, diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 777bb67f76..c1e0187b29 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -186,7 +186,7 @@ pub enum SyntaxError<'a> { ArgumentsBeforeEquals(Region), NotYetImplemented(String), Todo, - Type(Type<'a>), + Type(EType<'a>), Pattern(EPattern<'a>), Expr(EExpr<'a>), Header(EHeader<'a>), @@ -258,7 +258,7 @@ pub enum ETypedIdent<'a> { HasType(Row, Col), IndentHasType(Row, Col), Name(Row, Col), - Type(Type<'a>, Row, Col), + Type(EType<'a>, Row, Col), IndentType(Row, Col), Identifier(Row, Col), } @@ -394,7 +394,7 @@ pub enum EExpr<'a> { DefMissingFinalExpr(Row, Col), DefMissingFinalExpr2(&'a EExpr<'a>, Row, Col), - Type(Type<'a>, Row, Col), + Type(EType<'a>, Row, Col), Pattern(&'a EPattern<'a>, Row, Col), IndentDefBody(Row, Col), IndentEquals(Row, Col), @@ -409,10 +409,10 @@ pub enum EExpr<'a> { BackpassComma(Row, Col), BackpassArrow(Row, Col), - When(When<'a>, Row, Col), - If(If<'a>, Row, Col), + When(EWhen<'a>, Row, Col), + If(EIf<'a>, Row, Col), - Expect(Expect<'a>, Row, Col), + Expect(EExpect<'a>, Row, Col), Lambda(ELambda<'a>, Row, Col), Underscore(Row, Col), @@ -420,15 +420,15 @@ pub enum EExpr<'a> { InParens(EInParens<'a>, Row, Col), Record(ERecord<'a>, Row, Col), Str(EString<'a>, Row, Col), - Number(Number, Row, Col), - List(List<'a>, Row, Col), + Number(ENumber, Row, Col), + List(EList<'a>, Row, Col), IndentStart(Row, Col), IndentEnd(Row, Col), } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Number { +pub enum ENumber { End, LineTooLong, } @@ -502,7 +502,7 @@ pub enum ELambda<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum List<'a> { +pub enum EList<'a> { Open(Row, Col), End(Row, Col), Space(BadInputError, Row, Col), @@ -514,7 +514,7 @@ pub enum List<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum When<'a> { +pub enum EWhen<'a> { Space(BadInputError, Row, Col), When(Row, Col), Is(Row, Col), @@ -538,7 +538,7 @@ pub enum When<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum If<'a> { +pub enum EIf<'a> { Space(BadInputError, Row, Col), If(Row, Col), Then(Row, Col), @@ -557,7 +557,7 @@ pub enum If<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Expect<'a> { +pub enum EExpect<'a> { Space(BadInputError, Row, Col), Expect(Row, Col), Condition(&'a EExpr<'a>, Row, Col), @@ -575,7 +575,7 @@ pub enum EPattern<'a> { Space(BadInputError, Row, Col), PInParens(PInParens<'a>, Row, Col), - NumLiteral(Number, Row, Col), + NumLiteral(ENumber, Row, Col), IndentStart(Row, Col), IndentEnd(Row, Col), @@ -614,11 +614,11 @@ pub enum PInParens<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Type<'a> { - TRecord(TRecord<'a>, Row, Col), - TTagUnion(TTagUnion<'a>, Row, Col), - TInParens(TInParens<'a>, Row, Col), - TApply(TApply, Row, Col), +pub enum EType<'a> { + TRecord(ETypeRecord<'a>, Row, Col), + TTagUnion(ETypeTagUnion<'a>, Row, Col), + TInParens(ETypeInParens<'a>, Row, Col), + TApply(ETypeApply, Row, Col), TBadTypeVariable(Row, Col), TWildcard(Row, Col), /// @@ -633,14 +633,14 @@ pub enum Type<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum TRecord<'a> { +pub enum ETypeRecord<'a> { End(Row, Col), Open(Row, Col), Field(Row, Col), Colon(Row, Col), Optional(Row, Col), - Type(&'a Type<'a>, Row, Col), + Type(&'a EType<'a>, Row, Col), Space(BadInputError, Row, Col), @@ -651,11 +651,11 @@ pub enum TRecord<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum TTagUnion<'a> { +pub enum ETypeTagUnion<'a> { End(Row, Col), Open(Row, Col), - Type(&'a Type<'a>, Row, Col), + Type(&'a EType<'a>, Row, Col), Space(BadInputError, Row, Col), @@ -664,11 +664,11 @@ pub enum TTagUnion<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum TInParens<'a> { +pub enum ETypeInParens<'a> { End(Row, Col), Open(Row, Col), /// - Type(&'a Type<'a>, Row, Col), + Type(&'a EType<'a>, Row, Col), /// Space(BadInputError, Row, Col), @@ -678,7 +678,7 @@ pub enum TInParens<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum TApply { +pub enum ETypeApply { /// StartNotUppercase(Row, Col), End(Row, Col), diff --git a/compiler/parse/src/type_annotation.rs b/compiler/parse/src/type_annotation.rs index cc9e362921..40628eb622 100644 --- a/compiler/parse/src/type_annotation.rs +++ b/compiler/parse/src/type_annotation.rs @@ -2,39 +2,43 @@ use crate::ast::{AssignedField, Collection, Tag, TypeAnnotation}; use crate::blankspace::{space0_around_ee, space0_before_e, space0_e}; use crate::keyword; use crate::parser::{ - allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, ParseResult, - Parser, + allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, EType, + ETypeApply, ETypeInParens, ETypeRecord, ETypeTagUnion, ParseResult, Parser, Progress::{self, *}, - State, TApply, TInParens, TRecord, TTagUnion, Type, + State, }; use bumpalo::collections::vec::Vec; use bumpalo::Bump; use roc_region::all::{Located, Region}; -pub fn located_help<'a>(min_indent: u16) -> impl Parser<'a, Located>, Type<'a>> { +pub fn located_help<'a>( + min_indent: u16, +) -> impl Parser<'a, Located>, EType<'a>> { expression(min_indent) } #[inline(always)] -fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TTagUnion<'a>> { +fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> { move |arena, state| { let (_, tags, state) = collection_trailing_sep_e!( - word1(b'[', TTagUnion::Open), + word1(b'[', ETypeTagUnion::Open), loc!(tag_type(min_indent)), - word1(b',', TTagUnion::End), - word1(b']', TTagUnion::End), + word1(b',', ETypeTagUnion::End), + word1(b']', ETypeTagUnion::End), min_indent, - TTagUnion::Open, - TTagUnion::Space, - TTagUnion::IndentEnd, + ETypeTagUnion::Open, + ETypeTagUnion::Space, + ETypeTagUnion::IndentEnd, Tag::SpaceBefore ) .parse(arena, state)?; // This could be an open tag union, e.g. `[ Foo, Bar ]a` - let (_, ext, state) = - optional(allocated(specialize_ref(TTagUnion::Type, term(min_indent)))) - .parse(arena, state)?; + let (_, ext, state) = optional(allocated(specialize_ref( + ETypeTagUnion::Type, + term(min_indent), + ))) + .parse(arena, state)?; let result = TypeAnnotation::TagUnion { tags: tags.items, @@ -46,18 +50,18 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TT } } -fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, Type<'a>> { - |_arena, state: State<'a>| Err((NoProgress, Type::TStart(state.line, state.column), state)) +fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, EType<'a>> { + |_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.line, state.column), state)) } -fn term<'a>(min_indent: u16) -> impl Parser<'a, Located>, Type<'a>> { +fn term<'a>(min_indent: u16) -> impl Parser<'a, Located>, EType<'a>> { map_with_arena!( and!( one_of!( loc_wildcard(), - specialize(Type::TInParens, loc_type_in_parens(min_indent)), - loc!(specialize(Type::TRecord, record_type(min_indent))), - loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))), + specialize(EType::TInParens, loc_type_in_parens(min_indent)), + loc!(specialize(EType::TRecord, record_type(min_indent))), + loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))), loc!(applied_type(min_indent)), loc!(parse_type_variable), fail_type_start(), @@ -67,14 +71,14 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located>, Typ map!( and!( skip_second!( - backtrackable(space0_e(min_indent, Type::TSpace, Type::TIndentEnd)), - crate::parser::keyword_e(keyword::AS, Type::TEnd) + backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentEnd)), + crate::parser::keyword_e(keyword::AS, EType::TEnd) ), space0_before_e( term(min_indent), min_indent, - Type::TSpace, - Type::TAsIndentStart + EType::TSpace, + EType::TAsIndentStart ) ), Some @@ -103,24 +107,26 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located>, Typ } /// The `*` type variable, e.g. in (List *) Wildcard, -fn loc_wildcard<'a>() -> impl Parser<'a, Located>, Type<'a>> { - map!(loc!(word1(b'*', Type::TWildcard)), |loc_val: Located<()>| { +fn loc_wildcard<'a>() -> impl Parser<'a, Located>, EType<'a>> { + map!(loc!(word1(b'*', EType::TWildcard)), |loc_val: Located< + (), + >| { loc_val.map(|_| TypeAnnotation::Wildcard) }) } -fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located>, Type<'a>> { +fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located>, EType<'a>> { use crate::ast::Spaceable; map_with_arena!( and!( - backtrackable(space0_e(min_indent, Type::TSpace, Type::TIndentStart)), + backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentStart)), one_of!( loc_wildcard(), - specialize(Type::TInParens, loc_type_in_parens(min_indent)), - loc!(specialize(Type::TRecord, record_type(min_indent))), - loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))), - loc!(specialize(Type::TApply, parse_concrete_type)), + specialize(EType::TInParens, loc_type_in_parens(min_indent)), + loc!(specialize(EType::TRecord, record_type(min_indent))), + loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))), + loc!(specialize(EType::TApply, parse_concrete_type)), loc!(parse_type_variable) ) ), @@ -137,28 +143,28 @@ fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located( min_indent: u16, -) -> impl Parser<'a, Located>, TInParens<'a>> { +) -> impl Parser<'a, Located>, ETypeInParens<'a>> { between!( - word1(b'(', TInParens::Open), + word1(b'(', ETypeInParens::Open), space0_around_ee( - move |arena, state| specialize_ref(TInParens::Type, expression(min_indent)) + move |arena, state| specialize_ref(ETypeInParens::Type, expression(min_indent)) .parse(arena, state), min_indent, - TInParens::Space, - TInParens::IndentOpen, - TInParens::IndentEnd, + ETypeInParens::Space, + ETypeInParens::IndentOpen, + ETypeInParens::IndentEnd, ), - word1(b')', TInParens::IndentEnd) + word1(b')', ETypeInParens::IndentEnd) ) } #[inline(always)] -fn tag_type<'a>(min_indent: u16) -> impl Parser<'a, Tag<'a>, TTagUnion<'a>> { +fn tag_type<'a>(min_indent: u16) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> { move |arena, state: State<'a>| { - let (_, name, state) = loc!(parse_tag_name(TTagUnion::End)).parse(arena, state)?; + let (_, name, state) = loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state)?; - let (_, args, state) = - specialize_ref(TTagUnion::Type, loc_applied_args_e(min_indent)).parse(arena, state)?; + let (_, args, state) = specialize_ref(ETypeTagUnion::Type, loc_applied_args_e(min_indent)) + .parse(arena, state)?; let result = if name.value.starts_with('@') { Tag::Private { @@ -190,7 +196,7 @@ where fn record_type_field<'a>( min_indent: u16, -) -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, TRecord<'a>> { +) -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, ETypeRecord<'a>> { use crate::ident::lowercase_ident; use crate::parser::Either::*; use AssignedField::*; @@ -201,30 +207,34 @@ fn record_type_field<'a>( let row = state.line; let col = state.column; let (progress, loc_label, state) = loc!(specialize( - move |_, _, _| TRecord::Field(row, col), + move |_, _, _| ETypeRecord::Field(row, col), lowercase_ident() )) .parse(arena, state)?; debug_assert_eq!(progress, MadeProgress); let (_, spaces, state) = - space0_e(min_indent, TRecord::Space, TRecord::IndentEnd).parse(arena, state)?; + space0_e(min_indent, ETypeRecord::Space, ETypeRecord::IndentEnd).parse(arena, state)?; // Having a value is optional; both `{ email }` and `{ email: blah }` work. // (This is true in both literals and types.) let (_, opt_loc_val, state) = optional(either!( - word1(b':', TRecord::Colon), - word1(b'?', TRecord::Optional) + word1(b':', ETypeRecord::Colon), + word1(b'?', ETypeRecord::Optional) )) .parse(arena, state)?; - let val_parser = specialize_ref(TRecord::Type, term(min_indent)); + let val_parser = specialize_ref(ETypeRecord::Type, term(min_indent)); match opt_loc_val { Some(First(_)) => { - let (_, loc_val, state) = - space0_before_e(val_parser, min_indent, TRecord::Space, TRecord::IndentColon) - .parse(arena, state)?; + let (_, loc_val, state) = space0_before_e( + val_parser, + min_indent, + ETypeRecord::Space, + ETypeRecord::IndentColon, + ) + .parse(arena, state)?; Ok(( MadeProgress, @@ -236,8 +246,8 @@ fn record_type_field<'a>( let (_, loc_val, state) = space0_before_e( val_parser, min_indent, - TRecord::Space, - TRecord::IndentOptional, + ETypeRecord::Space, + ETypeRecord::IndentOptional, ) .parse(arena, state)?; @@ -263,26 +273,26 @@ fn record_type_field<'a>( } #[inline(always)] -fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TRecord<'a>> { +fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> { use crate::type_annotation::TypeAnnotation::*; move |arena, state| { let (_, fields, state) = collection_trailing_sep_e!( // word1_check_indent!(b'{', TRecord::Open, min_indent, TRecord::IndentOpen), - word1(b'{', TRecord::Open), + word1(b'{', ETypeRecord::Open), loc!(record_type_field(min_indent)), - word1(b',', TRecord::End), + word1(b',', ETypeRecord::End), // word1_check_indent!(b'}', TRecord::End, min_indent, TRecord::IndentEnd), - word1(b'}', TRecord::End), + word1(b'}', ETypeRecord::End), min_indent, - TRecord::Open, - TRecord::Space, - TRecord::IndentEnd, + ETypeRecord::Open, + ETypeRecord::Space, + ETypeRecord::IndentEnd, AssignedField::SpaceBefore ) .parse(arena, state)?; - let field_term = specialize_ref(TRecord::Type, term(min_indent)); + let field_term = specialize_ref(ETypeRecord::Type, term(min_indent)); let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?; let result = Record { @@ -297,10 +307,10 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TReco } } -fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, Type<'a>> { +fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> { map!( and!( - specialize(Type::TApply, parse_concrete_type), + specialize(EType::TApply, parse_concrete_type), // Optionally parse space-separated arguments for the constructor, // e.g. `Str Float` in `Map Str Float` loc_applied_args_e(min_indent) @@ -324,33 +334,33 @@ fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, Type fn loc_applied_args_e<'a>( min_indent: u16, -) -> impl Parser<'a, Vec<'a, Located>>, Type<'a>> { +) -> impl Parser<'a, Vec<'a, Located>>, EType<'a>> { zero_or_more!(loc_applied_arg(min_indent)) } -fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located>, Type<'a>> { +fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located>, EType<'a>> { move |arena, state: State<'a>| { let (p1, first, state) = space0_before_e( term(min_indent), min_indent, - Type::TSpace, - Type::TIndentStart, + EType::TSpace, + EType::TIndentStart, ) .parse(arena, state)?; let (p2, rest, state) = zero_or_more!(skip_first!( - word1(b',', Type::TFunctionArgument), + word1(b',', EType::TFunctionArgument), one_of![ space0_around_ee( term(min_indent), min_indent, - Type::TSpace, - Type::TIndentStart, - Type::TIndentEnd + EType::TSpace, + EType::TIndentStart, + EType::TIndentEnd ), |_, state: State<'a>| Err(( NoProgress, - Type::TFunctionArgument(state.line, state.column), + EType::TFunctionArgument(state.line, state.column), state )) ] @@ -360,8 +370,8 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located // TODO this space0 is dropped, so newlines just before the function arrow when there // is only one argument are not seen by the formatter. Can we do better? let (p3, is_function, state) = optional(skip_first!( - space0_e(min_indent, Type::TSpace, Type::TIndentStart), - word2(b'-', b'>', Type::TStart) + space0_e(min_indent, EType::TSpace, EType::TIndentStart), + word2(b'-', b'>', EType::TStart) )) .parse(arena, state)?; @@ -369,8 +379,8 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located let (p4, return_type, state) = space0_before_e( term(min_indent), min_indent, - Type::TSpace, - Type::TIndentStart, + EType::TSpace, + EType::TIndentStart, ) .parse(arena, state)?; @@ -418,7 +428,7 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located fn parse_concrete_type<'a>( arena: &'a Bump, state: State<'a>, -) -> ParseResult<'a, TypeAnnotation<'a>, TApply> { +) -> ParseResult<'a, TypeAnnotation<'a>, ETypeApply> { let initial_bytes = state.bytes; match crate::ident::concrete_type().parse(arena, state) { @@ -428,7 +438,7 @@ fn parse_concrete_type<'a>( Ok((MadeProgress, answer, state)) } Err((NoProgress, _, state)) => { - Err((NoProgress, TApply::End(state.line, state.column), state)) + Err((NoProgress, ETypeApply::End(state.line, state.column), state)) } Err((MadeProgress, _, mut state)) => { // we made some progress, but ultimately failed. @@ -439,7 +449,7 @@ fn parse_concrete_type<'a>( unsafe { std::str::from_utf8_unchecked(&initial_bytes[..chomped + delta]) }; state = state.advance_without_indenting_ee(chomped, |r, c| { - TApply::Space(crate::parser::BadInputError::LineTooLong, r, c) + ETypeApply::Space(crate::parser::BadInputError::LineTooLong, r, c) })?; Ok((MadeProgress, TypeAnnotation::Malformed(parsed_str), state)) @@ -450,7 +460,7 @@ fn parse_concrete_type<'a>( fn parse_type_variable<'a>( arena: &'a Bump, state: State<'a>, -) -> ParseResult<'a, TypeAnnotation<'a>, Type<'a>> { +) -> ParseResult<'a, TypeAnnotation<'a>, EType<'a>> { match crate::ident::lowercase_ident().parse(arena, state) { Ok((_, name, state)) => { let answer = TypeAnnotation::BoundVariable(name); @@ -459,7 +469,7 @@ fn parse_type_variable<'a>( } Err((progress, _, state)) => Err(( progress, - Type::TBadTypeVariable(state.line, state.column), + EType::TBadTypeVariable(state.line, state.column), state, )), } diff --git a/compiler/reporting/src/error/parse.rs b/compiler/reporting/src/error/parse.rs index 2076ee81cc..163a2b118b 100644 --- a/compiler/reporting/src/error/parse.rs +++ b/compiler/reporting/src/error/parse.rs @@ -1019,16 +1019,16 @@ fn to_list_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, context: Context, - parse_problem: &roc_parse::parser::List<'a>, + parse_problem: &roc_parse::parser::EList<'a>, start_row: Row, start_col: Col, ) -> Report<'a> { - use roc_parse::parser::List; + use roc_parse::parser::EList; match *parse_problem { - List::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), + EList::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), - List::Expr(expr, row, col) => to_expr_report( + EList::Expr(expr, row, col) => to_expr_report( alloc, filename, Context::InNode(Node::ListElement, start_row, start_col, Box::new(context)), @@ -1037,7 +1037,7 @@ fn to_list_report<'a>( col, ), - List::Open(row, col) | List::End(row, col) => { + EList::Open(row, col) | EList::End(row, col) => { match what_is_next(alloc.src_lines, row, col) { Next::Other(Some(',')) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); @@ -1098,7 +1098,7 @@ fn to_list_report<'a>( } } - List::IndentOpen(row, col) | List::IndentEnd(row, col) => { + EList::IndentOpen(row, col) | EList::IndentEnd(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -1130,16 +1130,16 @@ fn to_if_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, context: Context, - parse_problem: &roc_parse::parser::If<'a>, + parse_problem: &roc_parse::parser::EIf<'a>, start_row: Row, start_col: Col, ) -> Report<'a> { - use roc_parse::parser::If; + use roc_parse::parser::EIf; match *parse_problem { - If::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), + EIf::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), - If::Condition(expr, row, col) => to_expr_report( + EIf::Condition(expr, row, col) => to_expr_report( alloc, filename, Context::InNode(Node::IfCondition, start_row, start_col, Box::new(context)), @@ -1148,7 +1148,7 @@ fn to_if_report<'a>( col, ), - If::ThenBranch(expr, row, col) => to_expr_report( + EIf::ThenBranch(expr, row, col) => to_expr_report( alloc, filename, Context::InNode(Node::IfThenBranch, start_row, start_col, Box::new(context)), @@ -1157,7 +1157,7 @@ fn to_if_report<'a>( col, ), - If::ElseBranch(expr, row, col) => to_expr_report( + EIf::ElseBranch(expr, row, col) => to_expr_report( alloc, filename, Context::InNode(Node::IfElseBranch, start_row, start_col, Box::new(context)), @@ -1166,10 +1166,10 @@ fn to_if_report<'a>( col, ), - If::If(_row, _col) => unreachable!("another branch would be taken"), - If::IndentIf(_row, _col) => unreachable!("another branch would be taken"), + EIf::If(_row, _col) => unreachable!("another branch would be taken"), + EIf::IndentIf(_row, _col) => unreachable!("another branch would be taken"), - If::Then(row, col) | If::IndentThenBranch(row, col) | If::IndentThenToken(row, col) => { + EIf::Then(row, col) | EIf::IndentThenBranch(row, col) | EIf::IndentThenToken(row, col) => { to_unfinished_if_report( alloc, filename, @@ -1185,7 +1185,7 @@ fn to_if_report<'a>( ) } - If::Else(row, col) | If::IndentElseBranch(row, col) | If::IndentElseToken(row, col) => { + EIf::Else(row, col) | EIf::IndentElseBranch(row, col) | EIf::IndentElseToken(row, col) => { to_unfinished_if_report( alloc, filename, @@ -1201,7 +1201,7 @@ fn to_if_report<'a>( ) } - If::IndentCondition(row, col) => to_unfinished_if_report( + EIf::IndentCondition(row, col) => to_unfinished_if_report( alloc, filename, row, @@ -1249,14 +1249,14 @@ fn to_when_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, context: Context, - parse_problem: &roc_parse::parser::When<'a>, + parse_problem: &roc_parse::parser::EWhen<'a>, start_row: Row, start_col: Col, ) -> Report<'a> { - use roc_parse::parser::When; + use roc_parse::parser::EWhen; match *parse_problem { - When::IfGuard(nested, row, col) => match what_is_next(alloc.src_lines, row, col) { + EWhen::IfGuard(nested, row, col) => match what_is_next(alloc.src_lines, row, col) { Next::Token("->") => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -1287,7 +1287,7 @@ fn to_when_report<'a>( col, ), }, - When::Arrow(row, col) => { + EWhen::Arrow(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -1310,9 +1310,9 @@ fn to_when_report<'a>( } } - When::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), + EWhen::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), - When::Branch(expr, row, col) => to_expr_report( + EWhen::Branch(expr, row, col) => to_expr_report( alloc, filename, Context::InNode(Node::WhenBranch, start_row, start_col, Box::new(context)), @@ -1321,7 +1321,7 @@ fn to_when_report<'a>( col, ), - When::Condition(expr, row, col) => to_expr_report( + EWhen::Condition(expr, row, col) => to_expr_report( alloc, filename, Context::InNode(Node::WhenCondition, start_row, start_col, Box::new(context)), @@ -1330,7 +1330,7 @@ fn to_when_report<'a>( col, ), - When::Bar(row, col) => to_unfinished_when_report( + EWhen::Bar(row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1344,10 +1344,10 @@ fn to_when_report<'a>( ]), ), - When::IfToken(_row, _col) => unreachable!("the if-token is optional"), - When::When(_row, _col) => unreachable!("another branch would be taken"), + EWhen::IfToken(_row, _col) => unreachable!("the if-token is optional"), + EWhen::When(_row, _col) => unreachable!("another branch would be taken"), - When::Is(row, col) | When::IndentIs(row, col) => to_unfinished_when_report( + EWhen::Is(row, col) | EWhen::IndentIs(row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1361,7 +1361,7 @@ fn to_when_report<'a>( ]), ), - When::IndentCondition(row, col) => to_unfinished_when_report( + EWhen::IndentCondition(row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1373,7 +1373,7 @@ fn to_when_report<'a>( ]), ), - When::IndentPattern(row, col) => to_unfinished_when_report( + EWhen::IndentPattern(row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1383,7 +1383,7 @@ fn to_when_report<'a>( alloc.concat(vec![alloc.reflow(r"I was expecting to see a pattern next")]), ), - When::IndentArrow(row, col) => to_unfinished_when_report( + EWhen::IndentArrow(row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1397,7 +1397,7 @@ fn to_when_report<'a>( ]), ), - When::IndentIfGuard(row, col) => to_unfinished_when_report( + EWhen::IndentIfGuard(row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1411,7 +1411,7 @@ fn to_when_report<'a>( ]), ), - When::IndentBranch(row, col) => to_unfinished_when_report( + EWhen::IndentBranch(row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1424,7 +1424,7 @@ fn to_when_report<'a>( ]), ), - When::PatternAlignment(indent, row, col) => to_unfinished_when_report( + EWhen::PatternAlignment(indent, row, col) => to_unfinished_when_report( alloc, filename, row, @@ -1437,7 +1437,7 @@ fn to_when_report<'a>( alloc.reflow(" spaces)"), ]), ), - When::Pattern(ref pat, row, col) => to_pattern_report(alloc, filename, pat, row, col), + EWhen::Pattern(ref pat, row, col) => to_pattern_report(alloc, filename, pat, row, col), } } @@ -2000,23 +2000,23 @@ fn to_pattern_in_parens_report<'a>( fn to_type_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, - parse_problem: &roc_parse::parser::Type<'a>, + parse_problem: &roc_parse::parser::EType<'a>, start_row: Row, start_col: Col, ) -> Report<'a> { - use roc_parse::parser::Type; + use roc_parse::parser::EType; match parse_problem { - Type::TRecord(record, row, col) => to_trecord_report(alloc, filename, record, *row, *col), - Type::TTagUnion(tag_union, row, col) => { + EType::TRecord(record, row, col) => to_trecord_report(alloc, filename, record, *row, *col), + EType::TTagUnion(tag_union, row, col) => { to_ttag_union_report(alloc, filename, tag_union, *row, *col) } - Type::TInParens(tinparens, row, col) => { + EType::TInParens(tinparens, row, col) => { to_tinparens_report(alloc, filename, tinparens, *row, *col) } - Type::TApply(tapply, row, col) => to_tapply_report(alloc, filename, tapply, *row, *col), + EType::TApply(tapply, row, col) => to_tapply_report(alloc, filename, tapply, *row, *col), - Type::TFunctionArgument(row, col) => match what_is_next(alloc.src_lines, *row, *col) { + EType::TFunctionArgument(row, col) => match what_is_next(alloc.src_lines, *row, *col) { Next::Other(Some(',')) => { let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let region = Region::from_row_col(*row, *col); @@ -2037,7 +2037,7 @@ fn to_type_report<'a>( _ => todo!(), }, - Type::TStart(row, col) => { + EType::TStart(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let region = Region::from_row_col(*row, *col); @@ -2061,7 +2061,7 @@ fn to_type_report<'a>( } } - Type::TIndentStart(row, col) => { + EType::TIndentStart(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let region = Region::from_row_col(*row, *col); @@ -2079,7 +2079,7 @@ fn to_type_report<'a>( } } - Type::TIndentEnd(row, col) => { + EType::TIndentEnd(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let region = Region::from_row_col(*row, *col); @@ -2097,7 +2097,7 @@ fn to_type_report<'a>( } } - Type::TAsIndentStart(row, col) => { + EType::TAsIndentStart(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let region = Region::from_row_col(*row, *col); @@ -2115,7 +2115,7 @@ fn to_type_report<'a>( } } - Type::TBadTypeVariable(row, col) => { + EType::TBadTypeVariable(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let region = Region::from_row_col(*row, *col); @@ -2139,14 +2139,14 @@ fn to_type_report<'a>( fn to_trecord_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, - parse_problem: &roc_parse::parser::TRecord<'a>, + parse_problem: &roc_parse::parser::ETypeRecord<'a>, start_row: Row, start_col: Col, ) -> Report<'a> { - use roc_parse::parser::TRecord; + use roc_parse::parser::ETypeRecord; match *parse_problem { - TRecord::Open(row, col) => match what_is_next(alloc.src_lines, row, col) { + ETypeRecord::Open(row, col) => match what_is_next(alloc.src_lines, row, col) { Next::Keyword(keyword) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = to_keyword_region(row, col, keyword); @@ -2191,7 +2191,7 @@ fn to_trecord_report<'a>( } }, - TRecord::End(row, col) => { + ETypeRecord::End(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -2237,7 +2237,7 @@ fn to_trecord_report<'a>( } } - TRecord::Field(row, col) => match what_is_next(alloc.src_lines, row, col) { + ETypeRecord::Field(row, col) => match what_is_next(alloc.src_lines, row, col) { Next::Keyword(keyword) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = to_keyword_region(row, col, keyword); @@ -2286,16 +2286,16 @@ fn to_trecord_report<'a>( } }, - TRecord::Colon(_, _) => { + ETypeRecord::Colon(_, _) => { unreachable!("because `{ foo }` is a valid field; the colon is not required") } - TRecord::Optional(_, _) => { + ETypeRecord::Optional(_, _) => { unreachable!("because `{ foo }` is a valid field; the question mark is not required") } - TRecord::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), + ETypeRecord::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), - TRecord::IndentOpen(row, col) => { + ETypeRecord::IndentOpen(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -2318,7 +2318,7 @@ fn to_trecord_report<'a>( } } - TRecord::IndentEnd(row, col) => { + ETypeRecord::IndentEnd(row, col) => { match next_line_starts_with_close_curly(alloc.src_lines, row) { Some((curly_row, curly_col)) => { let surroundings = @@ -2370,29 +2370,29 @@ fn to_trecord_report<'a>( } } - TRecord::IndentColon(_, _) => { + ETypeRecord::IndentColon(_, _) => { unreachable!("because `{ foo }` is a valid field; the colon is not required") } - TRecord::IndentOptional(_, _) => { + ETypeRecord::IndentOptional(_, _) => { unreachable!("because `{ foo }` is a valid field; the question mark is not required") } - TRecord::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), + ETypeRecord::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), } } fn to_ttag_union_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, - parse_problem: &roc_parse::parser::TTagUnion<'a>, + parse_problem: &roc_parse::parser::ETypeTagUnion<'a>, start_row: Row, start_col: Col, ) -> Report<'a> { - use roc_parse::parser::TTagUnion; + use roc_parse::parser::ETypeTagUnion; match *parse_problem { - TTagUnion::Open(row, col) => match what_is_next(alloc.src_lines, row, col) { + ETypeTagUnion::Open(row, col) => match what_is_next(alloc.src_lines, row, col) { Next::Keyword(keyword) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = to_keyword_region(row, col, keyword); @@ -2459,7 +2459,7 @@ fn to_ttag_union_report<'a>( } }, - TTagUnion::End(row, col) => { + ETypeTagUnion::End(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -2523,9 +2523,9 @@ fn to_ttag_union_report<'a>( } } - TTagUnion::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), + ETypeTagUnion::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), - TTagUnion::IndentOpen(row, col) => { + ETypeTagUnion::IndentOpen(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -2548,7 +2548,7 @@ fn to_ttag_union_report<'a>( } } - TTagUnion::IndentEnd(row, col) => { + ETypeTagUnion::IndentEnd(row, col) => { match next_line_starts_with_close_square_bracket(alloc.src_lines, row) { Some((curly_row, curly_col)) => { let surroundings = @@ -2600,21 +2600,21 @@ fn to_ttag_union_report<'a>( } } - TTagUnion::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), + ETypeTagUnion::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), } } fn to_tinparens_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, - parse_problem: &roc_parse::parser::TInParens<'a>, + parse_problem: &roc_parse::parser::ETypeInParens<'a>, start_row: Row, start_col: Col, ) -> Report<'a> { - use roc_parse::parser::TInParens; + use roc_parse::parser::ETypeInParens; match *parse_problem { - TInParens::Open(row, col) => { + ETypeInParens::Open(row, col) => { match what_is_next(alloc.src_lines, row, col) { Next::Keyword(keyword) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); @@ -2686,7 +2686,7 @@ fn to_tinparens_report<'a>( } } - TInParens::End(row, col) => { + ETypeInParens::End(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -2734,9 +2734,9 @@ fn to_tinparens_report<'a>( } } - TInParens::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), + ETypeInParens::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), - TInParens::IndentOpen(row, col) => { + ETypeInParens::IndentOpen(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -2760,7 +2760,7 @@ fn to_tinparens_report<'a>( } } - TInParens::IndentEnd(row, col) => { + ETypeInParens::IndentEnd(row, col) => { match next_line_starts_with_close_parenthesis(alloc.src_lines, row) { Some((curly_row, curly_col)) => { let surroundings = @@ -2812,21 +2812,21 @@ fn to_tinparens_report<'a>( } } - TInParens::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), + ETypeInParens::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), } } fn to_tapply_report<'a>( alloc: &'a RocDocAllocator<'a>, filename: PathBuf, - parse_problem: &roc_parse::parser::TApply, + parse_problem: &roc_parse::parser::ETypeApply, _start_row: Row, _start_col: Col, ) -> Report<'a> { - use roc_parse::parser::TApply; + use roc_parse::parser::ETypeApply; match *parse_problem { - TApply::DoubleDot(row, col) => { + ETypeApply::DoubleDot(row, col) => { let region = Region::from_row_col(row, col); let doc = alloc.stack(vec![ @@ -2842,7 +2842,7 @@ fn to_tapply_report<'a>( severity: Severity::RuntimeError, } } - TApply::TrailingDot(row, col) => { + ETypeApply::TrailingDot(row, col) => { let region = Region::from_row_col(row, col); let doc = alloc.stack(vec![ @@ -2864,7 +2864,7 @@ fn to_tapply_report<'a>( severity: Severity::RuntimeError, } } - TApply::StartIsNumber(row, col) => { + ETypeApply::StartIsNumber(row, col) => { let region = Region::from_row_col(row, col); let doc = alloc.stack(vec![ @@ -2886,7 +2886,7 @@ fn to_tapply_report<'a>( severity: Severity::RuntimeError, } } - TApply::StartNotUppercase(row, col) => { + ETypeApply::StartNotUppercase(row, col) => { let region = Region::from_row_col(row, col); let doc = alloc.stack(vec![ @@ -2909,7 +2909,7 @@ fn to_tapply_report<'a>( } } - TApply::End(row, col) => { + ETypeApply::End(row, col) => { let region = Region::from_row_col(row, col); let doc = alloc.stack(vec![ @@ -2927,7 +2927,7 @@ fn to_tapply_report<'a>( } } - TApply::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), + ETypeApply::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), } } From b77563867f775e6c506bc0bca08126074aa8496f Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 20:52:00 +0000 Subject: [PATCH 023/223] Enable some gen_primitive tests for wasm --- compiler/test_gen/src/gen_primitives.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/test_gen/src/gen_primitives.rs b/compiler/test_gen/src/gen_primitives.rs index 7dbde0b8ea..2ee5823a8a 100644 --- a/compiler/test_gen/src/gen_primitives.rs +++ b/compiler/test_gen/src/gen_primitives.rs @@ -85,7 +85,7 @@ fn branch_third_float() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn branch_first_int() { assert_evals_to!( indoc!( @@ -101,7 +101,7 @@ fn branch_first_int() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn branch_second_int() { assert_evals_to!( indoc!( @@ -134,7 +134,7 @@ fn branch_third_int() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn branch_store_variable() { assert_evals_to!( indoc!( @@ -504,7 +504,7 @@ fn gen_multiple_defs() { // } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn factorial() { assert_evals_to!( indoc!( From 86403b4a2f604f7077b591863522343d45e37abb Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 20:52:35 +0000 Subject: [PATCH 024/223] Enable some gen_compare tests for wasm --- compiler/test_gen/src/gen_compare.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/test_gen/src/gen_compare.rs b/compiler/test_gen/src/gen_compare.rs index e3f6845727..3dcc557e2d 100644 --- a/compiler/test_gen/src/gen_compare.rs +++ b/compiler/test_gen/src/gen_compare.rs @@ -1,19 +1,16 @@ -#![cfg(not(feature = "gen-wasm"))] - #[cfg(feature = "gen-llvm")] use crate::helpers::llvm::assert_evals_to; #[cfg(feature = "gen-dev")] use crate::helpers::dev::assert_evals_to; -// #[cfg(feature = "gen-wasm")] -// use crate::helpers::wasm::assert_evals_to; +#[cfg(feature = "gen-wasm")] +use crate::helpers::wasm::assert_evals_to; -// use crate::assert_wasm_evals_to as assert_evals_to; use indoc::indoc; #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn eq_i64() { assert_evals_to!( indoc!( @@ -30,7 +27,7 @@ fn eq_i64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn neq_i64() { assert_evals_to!( indoc!( @@ -47,7 +44,7 @@ fn neq_i64() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn eq_u64() { assert_evals_to!( indoc!( @@ -64,7 +61,7 @@ fn eq_u64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn neq_u64() { assert_evals_to!( indoc!( @@ -81,7 +78,7 @@ fn neq_u64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn eq_f64() { assert_evals_to!( indoc!( @@ -98,7 +95,7 @@ fn eq_f64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn neq_f64() { assert_evals_to!( indoc!( @@ -115,7 +112,7 @@ fn neq_f64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn eq_bool_tag() { assert_evals_to!( indoc!( @@ -132,7 +129,7 @@ fn eq_bool_tag() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn neq_bool_tag() { assert_evals_to!( indoc!( @@ -163,7 +160,7 @@ fn unit() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn newtype() { assert_evals_to!("Identity 42 == Identity 42", true, bool); assert_evals_to!("Identity 42 != Identity 42", false, bool); From 7f633c107f541dfb9337ea81dc7113bcedd37c9a Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 23:02:39 +0000 Subject: [PATCH 025/223] Fix a bug in our model of the Wasm VM stack --- .../gen_wasm/src/wasm_module/code_builder.rs | 18 ++++++++++++------ compiler/gen_wasm/src/wasm_module/opcodes.rs | 2 +- compiler/test_gen/src/gen_num.rs | 2 +- compiler/test_gen/src/helpers/wasm.rs | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index 559221bb0b..66b2544703 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -202,10 +202,10 @@ impl<'a> CodeBuilder<'a> { true } - fn add_insertion(&mut self, insert_at: usize, opcode: u8, immediate: u32) { + fn add_insertion(&mut self, insert_at: usize, opcode: OpCode, immediate: u32) { let start = self.insert_bytes.len(); - self.insert_bytes.push(opcode); + self.insert_bytes.push(opcode as u8); self.insert_bytes.encode_u32(immediate); self.insertions.push(Insertion { @@ -213,6 +213,8 @@ impl<'a> CodeBuilder<'a> { start, end: self.insert_bytes.len(), }); + + // println!("insert {:?} {} at byte offset {} ", opcode, immediate, insert_at); } /// Load a Symbol that is stored in the VM stack @@ -244,14 +246,14 @@ impl<'a> CodeBuilder<'a> { // Symbol is not on top of the stack. Find it. if let Some(found_index) = self.vm_stack.iter().rposition(|&s| s == symbol) { // Insert a local.set where the value was created - self.add_insertion(pushed_at, SETLOCAL as u8, next_local_id.0); + self.add_insertion(pushed_at, SETLOCAL, next_local_id.0); // Take the value out of the stack where local.set was inserted self.vm_stack.remove(found_index); // Insert a local.get at the current position self.get_local(next_local_id); - self.vm_stack.push(symbol); + self.set_top_symbol(symbol); // This Symbol is no longer stored in the VM stack, but in a local None @@ -267,11 +269,11 @@ impl<'a> CodeBuilder<'a> { Popped { pushed_at } => { // This Symbol is being used for a second time // Insert a local.tee where it was pushed, so we don't interfere with the first usage - self.add_insertion(pushed_at, TEELOCAL as u8, next_local_id.0); + self.add_insertion(pushed_at, TEELOCAL, next_local_id.0); // Insert a local.get at the current position self.get_local(next_local_id); - self.vm_stack.push(symbol); + self.set_top_symbol(symbol); // This symbol has been promoted to a Local // Tell the caller it no longer has a VirtualMachineSymbolState @@ -441,6 +443,8 @@ impl<'a> CodeBuilder<'a> { } self.code.push(opcode as u8); + + // println!("{:10}\t{:?}", format!("{:?}", opcode), &self.vm_stack); } fn inst_imm8(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u8) { @@ -529,6 +533,8 @@ impl<'a> CodeBuilder<'a> { } self.code.push(CALL as u8); + // println!("CALL \t{:?}", &self.vm_stack); + // Write the index of the function to be called. // Also make a RelocationEntry so the linker can see that this byte offset relates to a function by name. // Here we initialise the offset to an index of self.code. After completing the function, we'll add diff --git a/compiler/gen_wasm/src/wasm_module/opcodes.rs b/compiler/gen_wasm/src/wasm_module/opcodes.rs index 895cf1e5f7..cb8ef70b47 100644 --- a/compiler/gen_wasm/src/wasm_module/opcodes.rs +++ b/compiler/gen_wasm/src/wasm_module/opcodes.rs @@ -1,5 +1,5 @@ #[repr(u8)] -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub enum OpCode { UNREACHABLE = 0x00, NOP = 0x01, diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index adbeac667c..538b928fec 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -571,7 +571,7 @@ fn abs_min_int_overflow() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn gen_if_fn() { assert_evals_to!( indoc!( diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index b9ee9459aa..4f6945522d 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -127,7 +127,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( let src_hash = hash_state.finish(); // Filename contains a hash of the Roc test source code. Helpful when comparing across commits. - let dir = "/tmp/roc/compiler/gen_wasm/output"; + let dir = "/tmp/roc/gen_wasm"; std::fs::create_dir_all(dir).unwrap(); let path = format!("{}/test-{:016x}.wasm", dir, src_hash); From 78a7e45b8f4c92b53d37eaea4d58587039fdec11 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Thu, 11 Nov 2021 17:02:39 +0000 Subject: [PATCH 026/223] Fix a type error in Switch statement condition --- compiler/gen_wasm/src/backend.rs | 26 +++++++++++--- compiler/test_gen/src/gen_primitives.rs | 48 ++++++++++++------------- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 3b4da4a465..e4f3e200b2 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -303,7 +303,7 @@ impl<'a> WasmBackend<'a> { Stmt::Switch { cond_symbol, - cond_layout: _, + cond_layout, branches, default_branch, ret_layout: _, @@ -326,16 +326,32 @@ impl<'a> WasmBackend<'a> { self.start_block(BlockType::NoResult) } + let cond_type = WasmLayout::new(cond_layout).value_type(); + // then, we jump whenever the value under scrutiny is equal to the value of a branch for (i, (value, _, _)) in branches.iter().enumerate() { // put the cond_symbol on the top of the stack self.storage .load_symbols(&mut self.code_builder, &[*cond_symbol]); - self.code_builder.i32_const(*value as i32); - - // compare the 2 topmost values - self.code_builder.i32_eq(); + match cond_type { + ValueType::I32 => { + self.code_builder.i32_const(*value as i32); + self.code_builder.i32_eq(); + } + ValueType::I64 => { + self.code_builder.i64_const(*value as i64); + self.code_builder.i64_eq(); + } + ValueType::F32 => { + self.code_builder.f32_const(f32::from_bits(*value as u32)); + self.code_builder.f32_eq(); + } + ValueType::F64 => { + self.code_builder.f64_const(f64::from_bits(*value as u64)); + self.code_builder.f64_eq(); + } + } // "break" out of `i` surrounding blocks self.code_builder.br_if(i as u32); diff --git a/compiler/test_gen/src/gen_primitives.rs b/compiler/test_gen/src/gen_primitives.rs index 2ee5823a8a..de4c4f813d 100644 --- a/compiler/test_gen/src/gen_primitives.rs +++ b/compiler/test_gen/src/gen_primitives.rs @@ -221,7 +221,7 @@ fn gen_when_one_branch() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_large_when_int() { assert_evals_to!( indoc!( @@ -243,31 +243,31 @@ fn gen_large_when_int() { ); } -// #[test] -// #[cfg(any(feature = "gen-llvm"))] -// fn gen_large_when_float() { -// assert_evals_to!( -// indoc!( -// r#" -// foo = \num -> -// when num is -// 0.5 -> 200.1 -// -3.6 -> 111.2 # TODO adding more negative numbers reproduces parsing bugs here -// 3.6 -> 789.5 -// 1.7 -> 123.3 -// 2.8 -> 456.4 -// _ -> 1000.6 +#[test] +#[cfg(any(feature = "gen-wasm"))] +fn gen_large_when_float() { + assert_evals_to!( + indoc!( + r#" + foo = \num -> + when num is + 0.5 -> 200.1 + -3.6 -> 111.2 # TODO adding more negative numbers reproduces parsing bugs here + 3.6 -> 789.5 + 1.7 -> 123.3 + 2.8 -> 456.4 + _ -> 1000.6 -// foo -3.6 -// "# -// ), -// 111.2, -// f64 -// ); -// } + foo -3.6 + "# + ), + 111.2, + f64 + ); +} #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn or_pattern() { assert_evals_to!( indoc!( @@ -337,7 +337,7 @@ fn return_unnamed_fn() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_when_fn() { assert_evals_to!( indoc!( From 3a751aa3e87cfd2e1f18a7e3927d50611461acb5 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Fri, 12 Nov 2021 08:59:19 +0000 Subject: [PATCH 027/223] Cheap optimisation for boolean conditions in Switch statements --- compiler/gen_wasm/src/backend.rs | 40 +++++++++++++++++++------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index e4f3e200b2..d90abe2859 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -4,7 +4,7 @@ use code_builder::Align; use roc_collections::all::MutMap; use roc_module::symbol::Symbol; use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt}; -use roc_mono::layout::{Layout, LayoutIds}; +use roc_mono::layout::{Builtin, Layout, LayoutIds}; use crate::layout::WasmLayout; use crate::low_level::{build_call_low_level, LowlevelBuildResult}; @@ -326,6 +326,7 @@ impl<'a> WasmBackend<'a> { self.start_block(BlockType::NoResult) } + let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Int1)); let cond_type = WasmLayout::new(cond_layout).value_type(); // then, we jump whenever the value under scrutiny is equal to the value of a branch @@ -334,22 +335,29 @@ impl<'a> WasmBackend<'a> { self.storage .load_symbols(&mut self.code_builder, &[*cond_symbol]); - match cond_type { - ValueType::I32 => { - self.code_builder.i32_const(*value as i32); - self.code_builder.i32_eq(); + if is_bool { + // We already have a bool, don't need to compare against a const to get one + if *value == 0 { + self.code_builder.i32_eqz(); } - ValueType::I64 => { - self.code_builder.i64_const(*value as i64); - self.code_builder.i64_eq(); - } - ValueType::F32 => { - self.code_builder.f32_const(f32::from_bits(*value as u32)); - self.code_builder.f32_eq(); - } - ValueType::F64 => { - self.code_builder.f64_const(f64::from_bits(*value as u64)); - self.code_builder.f64_eq(); + } else { + match cond_type { + ValueType::I32 => { + self.code_builder.i32_const(*value as i32); + self.code_builder.i32_eq(); + } + ValueType::I64 => { + self.code_builder.i64_const(*value as i64); + self.code_builder.i64_eq(); + } + ValueType::F32 => { + self.code_builder.f32_const(f32::from_bits(*value as u32)); + self.code_builder.f32_eq(); + } + ValueType::F64 => { + self.code_builder.f64_const(f64::from_bits(*value as u64)); + self.code_builder.f64_eq(); + } } } From 4b3538dc5869173770f590b3b70ef8239d03d83b Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Fri, 12 Nov 2021 12:48:44 +0000 Subject: [PATCH 028/223] Simplify CodeBuilder::call --- .../gen_wasm/src/wasm_module/code_builder.rs | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index 66b2544703..e9be6ca6a5 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -520,27 +520,14 @@ impl<'a> CodeBuilder<'a> { n_args: usize, has_return_val: bool, ) { - let stack_depth = self.vm_stack.len(); - if n_args > stack_depth { - panic!( - "Trying to call to call function {:?} with {:?} values but only {:?} on the VM stack\n{:?}", - function_index, n_args, stack_depth, self - ); - } - self.vm_stack.truncate(stack_depth - n_args); - if has_return_val { - self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE); - } - self.code.push(CALL as u8); + self.inst(CALL, n_args, has_return_val); - // println!("CALL \t{:?}", &self.vm_stack); - - // Write the index of the function to be called. - // Also make a RelocationEntry so the linker can see that this byte offset relates to a function by name. - // Here we initialise the offset to an index of self.code. After completing the function, we'll add - // other factors to make it relative to the code section. (All insertions will be known then.) let offset = self.code.len() as u32; self.code.encode_padded_u32(function_index); + + // Make a RelocationEntry so the linker can see that this byte offset relates to a function by name. + // Here we initialise the offset to an index of self.code. After completing the function, we'll add + // other factors to make it relative to the code section. (All insertions will be known then.) self.relocations.push(RelocationEntry::Index { type_id: IndexRelocType::FunctionIndexLeb, offset, From daf6771bf5cb49592f98c102ef789c19e358db1b Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Fri, 12 Nov 2021 13:01:16 +0000 Subject: [PATCH 029/223] Shorten the name of the Symbol for temporary Wasm values --- compiler/gen_wasm/src/wasm_module/code_builder.rs | 2 +- compiler/module/src/symbol.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index e9be6ca6a5..71461111e6 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -439,7 +439,7 @@ impl<'a> CodeBuilder<'a> { let new_len = self.vm_stack.len() - pops as usize; self.vm_stack.truncate(new_len); if push { - self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE); + self.vm_stack.push(Symbol::WASM_TMP); } self.code.push(opcode as u8); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 882e79ef62..92345fbdf0 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -875,8 +875,8 @@ define_builtins! { // used by the dev backend to store the pointer to where to store large return types 23 RET_POINTER: "#ret_pointer" - // used in wasm dev backend to mark values in the VM stack that have no other Symbol - 24 WASM_ANONYMOUS_STACK_VALUE: "#wasm_anonymous_stack_value" + // used in wasm dev backend to mark temporary values in the VM stack + 24 WASM_TMP: "#wasm_tmp" } 1 NUM: "Num" => { 0 NUM_NUM: "Num" imported // the Num.Num type alias From 33109006c2eb7db6e3d5953e6326ab97750d3d6a Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Fri, 12 Nov 2021 13:23:09 +0000 Subject: [PATCH 030/223] Fix bugs in Ret statement --- compiler/gen_wasm/src/backend.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index d90abe2859..9093401626 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -294,9 +294,10 @@ impl<'a> WasmBackend<'a> { _ => { self.storage.load_symbols(&mut self.code_builder, &[*sym]); - self.code_builder.br(self.block_depth); // jump to end of function (for stack frame pop) } } + // jump to the "stack frame pop" code at the end of the function + self.code_builder.br(self.block_depth - 1); Ok(()) } @@ -321,7 +322,7 @@ impl<'a> WasmBackend<'a> { cond_storage, ); - // create (number_of_branches - 1) new blocks. + // create a block for each branch except the default for _ in 0..branches.len() { self.start_block(BlockType::NoResult) } From aca8e7670de5009a1673a987707d2b6c0942c287 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 12 Nov 2021 11:28:00 -0800 Subject: [PATCH 031/223] Add Joost Baas to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index aca22d319b..a44adf2dcc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -51,3 +51,4 @@ Eric Newbury Ayaz Hafiz Johannes Maas Takeshi Sato +Joost Baas From 196538cc586be523ad8dd795c04d8fd943a34787 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 01:00:20 +0100 Subject: [PATCH 032/223] fix valgrind error, finally --- compiler/gen_llvm/src/llvm/bitcode.rs | 4 ++-- compiler/gen_llvm/src/llvm/build_list.rs | 24 +++++++++++++---------- compiler/gen_llvm/src/llvm/refcounting.rs | 11 ----------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/bitcode.rs b/compiler/gen_llvm/src/llvm/bitcode.rs index 2afb1c7159..159c688580 100644 --- a/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/compiler/gen_llvm/src/llvm/bitcode.rs @@ -260,7 +260,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( .build_pointer_cast( argument_ptr.into_pointer_value(), basic_type, - "cast_ptr_to_tag", + "cast_ptr_to_tag_build_transform_caller_help", ) .into() } else { @@ -409,7 +409,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>( let value = if layout.is_passed_by_reference() { env.builder - .build_pointer_cast(value_ptr, value_type, "cast_ptr_to_tag") + .build_pointer_cast(value_ptr, value_type, "cast_ptr_to_tag_build_rc_wrapper") .into() } else { let value_cast = env diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index 154295d9cd..323960353d 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -17,7 +17,7 @@ use morphic_lib::UpdateMode; use roc_builtins::bitcode; use roc_mono::layout::{Builtin, Layout, LayoutIds}; -use super::build::load_roc_value; +use super::build::{load_roc_value, store_roc_value}; pub fn pass_update_mode<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -55,9 +55,13 @@ pub fn call_bitcode_fn_returns_list<'a, 'ctx, 'env>( fn pass_element_as_opaque<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, element: BasicValueEnum<'ctx>, + layout: Layout<'a>, ) -> BasicValueEnum<'ctx> { - let element_ptr = env.builder.build_alloca(element.get_type(), "element"); - env.builder.build_store(element_ptr, element); + let element_type = basic_type_from_layout(env, &layout); + let element_ptr = env + .builder + .build_alloca(element_type, "element_to_pass_as_opaque"); + store_roc_value(env, layout, element_ptr, element); env.builder.build_bitcast( element_ptr, @@ -108,7 +112,7 @@ pub fn list_single<'a, 'ctx, 'env>( env, &[ env.alignment_intvalue(element_layout), - pass_element_as_opaque(env, element), + pass_element_as_opaque(env, element, *element_layout), layout_width(env, element_layout), ], bitcode::LIST_SINGLE, @@ -130,7 +134,7 @@ pub fn list_repeat<'a, 'ctx, 'env>( &[ list_len.into(), env.alignment_intvalue(element_layout), - pass_element_as_opaque(env, element), + pass_element_as_opaque(env, element, *element_layout), layout_width(env, element_layout), inc_element_fn.as_global_value().as_pointer_value().into(), ], @@ -250,7 +254,7 @@ pub fn list_append<'a, 'ctx, 'env>( &[ pass_list_cc(env, original_wrapper.into()), env.alignment_intvalue(element_layout), - pass_element_as_opaque(env, element), + pass_element_as_opaque(env, element, *element_layout), layout_width(env, element_layout), pass_update_mode(env, update_mode), ], @@ -270,7 +274,7 @@ pub fn list_prepend<'a, 'ctx, 'env>( &[ pass_list_cc(env, original_wrapper.into()), env.alignment_intvalue(element_layout), - pass_element_as_opaque(env, element), + pass_element_as_opaque(env, element, *element_layout), layout_width(env, element_layout), ], bitcode::LIST_PREPEND, @@ -409,7 +413,7 @@ pub fn list_set<'a, 'ctx, 'env>( &[ bytes.into(), index.into(), - pass_element_as_opaque(env, element), + pass_element_as_opaque(env, element, *element_layout), layout_width(env, element_layout), dec_element_fn.as_global_value().as_pointer_value().into(), ], @@ -422,7 +426,7 @@ pub fn list_set<'a, 'ctx, 'env>( length.into(), env.alignment_intvalue(element_layout), index.into(), - pass_element_as_opaque(env, element), + pass_element_as_opaque(env, element, *element_layout), layout_width(env, element_layout), dec_element_fn.as_global_value().as_pointer_value().into(), ], @@ -598,7 +602,7 @@ pub fn list_contains<'a, 'ctx, 'env>( env, &[ pass_list_cc(env, list), - pass_element_as_opaque(env, element), + pass_element_as_opaque(env, element, *element_layout), layout_width(env, element_layout), eq_fn, ], diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 47f2ecf24c..1b6c6aa4d0 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -1724,17 +1724,6 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( if let Layout::RecursivePointer = field_layout { panic!("non-recursive tag unions cannot contain naked recursion pointers!"); } else if field_layout.contains_refcounted() { - // crazy hack: inlining this function when it decrements a list or string results - // in many, many valgrind errors in `--optimize` mode. We do not know why. - if let Layout::Builtin(Builtin::Str | Builtin::List(_)) = field_layout { - use inkwell::attributes::{Attribute, AttributeLoc}; - let kind_id = Attribute::get_named_enum_kind_id("noinline"); - debug_assert!(kind_id > 0); - let enum_attr = env.context.create_enum_attribute(kind_id, 1); - - fn_val.add_attribute(AttributeLoc::Function, enum_attr); - } - let field_ptr = env .builder .build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field") From a9216d11491205583dde1b3ad9daa4712af5c613 Mon Sep 17 00:00:00 2001 From: satotake Date: Sat, 13 Nov 2021 02:57:45 +0000 Subject: [PATCH 033/223] retry recursion --- compiler/can/src/builtins.rs | 115 +++++++++++++++-------------------- 1 file changed, 49 insertions(+), 66 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index ca6b74585d..1c018e5b4b 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -1820,11 +1820,7 @@ fn list_len(symbol: Symbol, var_store: &mut VarStore) -> Def { let len_var = var_store.fresh(); let list_var = var_store.fresh(); - let body = RunLowLevel { - op: LowLevel::ListLen, - args: vec![(list_var, Var(Symbol::ARG_1))], - ret_var: len_var, - }; + let body = run_low_level_list_len(Var(Symbol::ARG_1), list_var, len_var); defn( symbol, @@ -1835,6 +1831,14 @@ fn list_len(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +fn run_low_level_list_len(list_expr: Expr, list_var: Variable, int_var: Variable) -> Expr { + RunLowLevel { + op: LowLevel::ListLen, + args: vec![(list_var, list_expr)], + ret_var: int_var, + } +} + /// List.get : List elem, Int -> Result elem [ OutOfBounds ]* /// /// List.get : @@ -2048,11 +2052,16 @@ fn list_take_first_2(symbol: Symbol, var_store: &mut VarStore) -> Def { let sym_rec = Symbol::LIST_TAKE_3_TEMP; let int_var = var_store.fresh(); - let bool_var = var_store.fresh(); + let captured_var = var_store.fresh(); let clos_var = var_store.fresh(); let list_after = var_store.fresh(); - let one = || int(int_var, Variable::NATURAL, 1); + let rec_box = Box::new(( + clos_var, + no_region(Var(sym_rec)), + var_store.fresh(), + list_var, + )); let clos = Closure(ClosureData { function_type: clos_var, @@ -2061,67 +2070,42 @@ fn list_take_first_2(symbol: Symbol, var_store: &mut VarStore) -> Def { return_type: list_after, name: sym_rec, recursive: Recursive::Recursive, - captured_symbols: vec![], + captured_symbols: vec![(Symbol::ARG_2, captured_var)], arguments: vec![(list_after, no_region(Pattern::Identifier(Symbol::ARG_3)))], loc_body: { + let bool_var = var_store.fresh(); + let num_var = var_store.fresh(); + let n = |x| int(num_var, Variable::NATURAL, x); Box::new(no_region(If { - cond_var: var_store.fresh(), - branch_var: var_store.fresh(), + cond_var: bool_var, + branch_var: list_after, branches: vec![( no_region(RunLowLevel { op: LowLevel::NumLte, args: vec![ ( - int_var, - RunLowLevel { - op: LowLevel::ListLen, - args: vec![(list_after, Var(Symbol::ARG_3))], - ret_var: int_var, - }, + num_var, + run_low_level_list_len(Var(Symbol::ARG_3), list_after, num_var), ), - (int_var, Var(Symbol::ARG_2)), + (num_var, Var(Symbol::ARG_2)), + // (num_var, n(3)), ], ret_var: bool_var, }), no_region(Var(Symbol::ARG_3)), )], - final_else: Box::new(no_region(Call( - Box::new(( - clos_var, - no_region(Var(sym_rec)), - var_store.fresh(), - list_after, - )), - vec![( - list_after, - no_region(RunLowLevel { - // DropLast - op: LowLevel::ListDrop, - args: vec![ - (list_after, Var(Symbol::ARG_3)), - ( - int_var, - RunLowLevel { - ret_var: int_var, - op: LowLevel::NumSubWrap, - args: vec![ - ( - int_var, - RunLowLevel { - ret_var: int_var, - op: LowLevel::ListLen, - args: vec![(list_after, Var(Symbol::ARG_3))], - }, - ), - (int_var, one()), - ], - }, - ), - ], - ret_var: list_after, - }), - )], - CalledVia::Space, + // final_else: Box::new(no_region(Call( + // rec_box.clone(), + // vec![( + // list_after, + // no_region(run_list_drop_last(Var(Symbol::ARG_3), list_after, var_store)), + // )], + // CalledVia::Space, + // ))), + final_else: Box::new(no_region(run_list_drop_last( + Var(Symbol::ARG_3), + list_after, + var_store, ))), })) }, @@ -2135,12 +2119,7 @@ fn list_take_first_2(symbol: Symbol, var_store: &mut VarStore) -> Def { pattern_vars: Default::default(), }; let body = Call( - Box::new(( - clos_var, - no_region(Var(sym_rec)), - var_store.fresh(), - list_var, - )), + rec_box, vec![(list_var, no_region(Var(Symbol::ARG_1)))], CalledVia::Space, ); @@ -2367,19 +2346,17 @@ fn list_drop_first(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -/// List.dropLast: List elem -> List elem -fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def { - let list_var = var_store.fresh(); +fn run_list_drop_last(list_expr: Expr, list_var: Variable, var_store: &mut VarStore) -> Expr { let index_var = var_store.fresh(); let arg_var = var_store.fresh(); let len_var = Variable::NAT; let num_var = len_var; let num_precision_var = Variable::NATURAL; - let body = RunLowLevel { + return RunLowLevel { op: LowLevel::ListDropAt, args: vec![ - (list_var, Var(Symbol::ARG_1)), + (list_var, list_expr.clone()), ( index_var, // Num.sub (List.len list) 1 @@ -2391,7 +2368,7 @@ fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def { // List.len list RunLowLevel { op: LowLevel::ListLen, - args: vec![(list_var, Var(Symbol::ARG_1))], + args: vec![(list_var, list_expr)], ret_var: len_var, }, ), @@ -2403,6 +2380,12 @@ fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def { ], ret_var: list_var, }; +} + +/// List.dropLast: List elem -> List elem +fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def { + let list_var = var_store.fresh(); + let body = run_list_drop_last(Var(Symbol::ARG_1), list_var, var_store); defn( symbol, From 8f8b2463eaadb04d61964ca00919ba983b653c6d Mon Sep 17 00:00:00 2001 From: satotake Date: Sat, 13 Nov 2021 03:38:58 +0000 Subject: [PATCH 034/223] reset --- compiler/builtins/src/std.rs | 14 --- compiler/can/src/builtins.rs | 193 ++--------------------------- compiler/module/src/symbol.rs | 4 - compiler/solve/tests/solve_expr.rs | 24 ---- compiler/test_gen/src/gen_list.rs | 35 ------ 5 files changed, 11 insertions(+), 259 deletions(-) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 0a1317842c..5d054ad831 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -985,13 +985,6 @@ pub fn types() -> MutMap { Box::new(list_type(flex(TVAR1))), ); - // takeFirst2 : List elem, Nat -> List elem - add_top_level_function_type!( - Symbol::LIST_TAKE_FIRST_2, - vec![list_type(flex(TVAR1)), nat_type()], - Box::new(list_type(flex(TVAR1))), - ); - // takeLast : List elem, Nat -> List elem add_top_level_function_type!( Symbol::LIST_TAKE_LAST, @@ -999,13 +992,6 @@ pub fn types() -> MutMap { Box::new(list_type(flex(TVAR1))), ); - // takeLast2 : List elem, Nat -> List elem - add_top_level_function_type!( - Symbol::LIST_TAKE_LAST_2, - vec![list_type(flex(TVAR1)), nat_type()], - Box::new(list_type(flex(TVAR1))), - ); - // sublist : List elem, { start : Nat, len : Nat } -> List elem add_top_level_function_type!( Symbol::LIST_SUBLIST, diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index e3ae09f614..ddabf11685 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -94,8 +94,6 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option LIST_MAP4 => list_map4, LIST_TAKE_FIRST => list_take_first, LIST_TAKE_LAST => list_take_last, - LIST_TAKE_FIRST_2 => list_take_first_2, - LIST_TAKE_LAST_2 => list_take_last_2, LIST_SUBLIST => list_sublist, LIST_DROP => list_drop, LIST_DROP_AT => list_drop_at, @@ -1821,7 +1819,11 @@ fn list_len(symbol: Symbol, var_store: &mut VarStore) -> Def { let len_var = var_store.fresh(); let list_var = var_store.fresh(); - let body = run_low_level_list_len(Var(Symbol::ARG_1), list_var, len_var); + let body = RunLowLevel { + op: LowLevel::ListLen, + args: vec![(list_var, Var(Symbol::ARG_1))], + ret_var: len_var, + }; defn( symbol, @@ -1832,14 +1834,6 @@ fn list_len(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -fn run_low_level_list_len(list_expr: Expr, list_var: Variable, int_var: Variable) -> Expr { - RunLowLevel { - op: LowLevel::ListLen, - args: vec![(list_var, list_expr)], - ret_var: int_var, - } -} - /// List.get : List elem, Int -> Result elem [ OutOfBounds ]* /// /// List.get : @@ -2045,95 +2039,6 @@ fn list_take_first(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -/// List.takeFirst2 : List elem, Nat -> List elem -fn list_take_first_2(symbol: Symbol, var_store: &mut VarStore) -> Def { - let list_var = var_store.fresh(); - let len_var = var_store.fresh(); - - let sym_rec = Symbol::LIST_TAKE_3_TEMP; - - let int_var = var_store.fresh(); - let captured_var = var_store.fresh(); - let clos_var = var_store.fresh(); - let list_after = var_store.fresh(); - - let rec_box = Box::new(( - clos_var, - no_region(Var(sym_rec)), - var_store.fresh(), - list_var, - )); - - let clos = Closure(ClosureData { - function_type: clos_var, - closure_type: var_store.fresh(), - closure_ext_var: var_store.fresh(), - return_type: list_after, - name: sym_rec, - recursive: Recursive::Recursive, - captured_symbols: vec![(Symbol::ARG_2, captured_var)], - arguments: vec![(list_after, no_region(Pattern::Identifier(Symbol::ARG_3)))], - loc_body: { - let bool_var = var_store.fresh(); - let num_var = var_store.fresh(); - let n = |x| int(num_var, Variable::NATURAL, x); - Box::new(no_region(If { - cond_var: bool_var, - branch_var: list_after, - branches: vec![( - no_region(RunLowLevel { - op: LowLevel::NumLte, - args: vec![ - ( - num_var, - run_low_level_list_len(Var(Symbol::ARG_3), list_after, num_var), - ), - (num_var, Var(Symbol::ARG_2)), - // (num_var, n(3)), - ], - ret_var: bool_var, - }), - no_region(Var(Symbol::ARG_3)), - )], - // final_else: Box::new(no_region(Call( - // rec_box.clone(), - // vec![( - // list_after, - // no_region(run_list_drop_last(Var(Symbol::ARG_3), list_after, var_store)), - // )], - // CalledVia::Space, - // ))), - final_else: Box::new(no_region(run_list_drop_last( - Var(Symbol::ARG_3), - list_after, - var_store, - ))), - })) - }, - }); - - let def_rec = Def { - annotation: None, - expr_var: int_var, - loc_expr: no_region(clos), - loc_pattern: no_region(Pattern::Identifier(sym_rec)), - pattern_vars: Default::default(), - }; - let body = Call( - rec_box, - vec![(list_var, no_region(Var(Symbol::ARG_1)))], - CalledVia::Space, - ); - - defn( - symbol, - vec![(list_var, Symbol::ARG_1), (len_var, Symbol::ARG_2)], - var_store, - LetRec(vec![def_rec], Box::new(no_region(body)), list_var), - list_var, - ) -} - /// List.takeLast : List elem, Nat -> List elem fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); @@ -2157,78 +2062,6 @@ fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -/// List.takeLast2 : List elem, Nat -> List elem -fn list_take_last_2(symbol: Symbol, var_store: &mut VarStore) -> Def { - let list_var = var_store.fresh(); - let len_var = var_store.fresh(); - - let sym_list = Symbol::ARG_1; - let sym_len = Symbol::ARG_2; - - let drop_len = Symbol::LIST_TAKE_2_TEMP; - - let bool_var = var_store.fresh(); - let int_var = var_store.fresh(); - - let zero = || int(int_var, Variable::NATURAL, 0); - - let def_drop_len = Def { - annotation: None, - expr_var: int_var, - loc_expr: no_region(RunLowLevel { - op: LowLevel::NumSubWrap, - args: vec![ - ( - int_var, - RunLowLevel { - op: LowLevel::ListLen, - args: vec![(list_var, Var(sym_list))], - ret_var: int_var, - }, - ), - (int_var, Var(sym_len)), - ], - ret_var: int_var, - }), - loc_pattern: no_region(Pattern::Identifier(drop_len)), - pattern_vars: Default::default(), - }; - - let get_larger = If { - cond_var: bool_var, - branch_var: int_var, - branches: vec![( - no_region(RunLowLevel { - op: LowLevel::NumGte, - args: vec![(int_var, Var(drop_len)), (int_var, zero())], - ret_var: bool_var, - }), - no_region(Var(drop_len)), - )], - final_else: Box::new(no_region(zero())), - }; - - let body_drop = RunLowLevel { - op: LowLevel::ListDrop, - args: vec![(list_var, Var(sym_list)), (int_var, get_larger)], - ret_var: list_var, - }; - - let body = LetNonRec( - Box::new(def_drop_len), - Box::new(no_region(body_drop)), - list_var, - ); - - defn( - symbol, - vec![(list_var, sym_list), (len_var, sym_len)], - var_store, - body, - list_var, - ) -} - /// List.sublist : List elem, { start : Nat, len : Nat } -> List elem fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); @@ -2347,17 +2180,19 @@ fn list_drop_first(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -fn run_list_drop_last(list_expr: Expr, list_var: Variable, var_store: &mut VarStore) -> Expr { +/// List.dropLast: List elem -> List elem +fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def { + let list_var = var_store.fresh(); let index_var = var_store.fresh(); let arg_var = var_store.fresh(); let len_var = Variable::NAT; let num_var = len_var; let num_precision_var = Variable::NATURAL; - return RunLowLevel { + let body = RunLowLevel { op: LowLevel::ListDropAt, args: vec![ - (list_var, list_expr.clone()), + (list_var, Var(Symbol::ARG_1)), ( index_var, // Num.sub (List.len list) 1 @@ -2369,7 +2204,7 @@ fn run_list_drop_last(list_expr: Expr, list_var: Variable, var_store: &mut VarSt // List.len list RunLowLevel { op: LowLevel::ListLen, - args: vec![(list_var, list_expr)], + args: vec![(list_var, Var(Symbol::ARG_1))], ret_var: len_var, }, ), @@ -2381,12 +2216,6 @@ fn run_list_drop_last(list_expr: Expr, list_var: Variable, var_store: &mut VarSt ], ret_var: list_var, }; -} - -/// List.dropLast: List elem -> List elem -fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def { - let list_var = var_store.fresh(); - let body = run_list_drop_last(Var(Symbol::ARG_1), list_var, var_store); defn( symbol, diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 4e2d1acdb5..92345fbdf0 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1071,10 +1071,6 @@ define_builtins! { 47 LIST_FIND: "find" 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" - 50 LIST_TAKE_FIRST_2: "takeFirst2" - 51 LIST_TAKE_LAST_2: "takeLast2" - 52 LIST_TAKE_2_TEMP: "#take2" - 53 LIST_TAKE_3_TEMP: "#take3" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index bd59a6a7e3..dcf74d79bb 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3769,18 +3769,6 @@ mod solve_expr { ); } - #[test] - fn list_take_first_2() { - infer_eq_without_problem( - indoc!( - r#" - List.takeFirst2 - "# - ), - "List a, Nat -> List a", - ); - } - #[test] fn list_take_last() { infer_eq_without_problem( @@ -3793,18 +3781,6 @@ mod solve_expr { ); } - #[test] - fn list_take_last_2() { - infer_eq_without_problem( - indoc!( - r#" - List.takeLast2 - "# - ), - "List a, Nat -> List a", - ); - } - #[test] fn list_sublist() { infer_eq_without_problem( diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 46a5adee99..5e0f737e72 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -187,16 +187,6 @@ fn list_take_first() { ); } -#[test] -#[cfg(any(feature = "gen-llvm"))] -fn list_take_first_2() { - assert_evals_to!( - "List.takeFirst2 [1, 2, 3] 2", - RocList::from_slice(&[1, 2]), - RocList - ); -} - #[test] #[cfg(any(feature = "gen-llvm"))] fn list_take_last() { @@ -218,31 +208,6 @@ fn list_take_last() { ); } -#[test] -#[cfg(any(feature = "gen-llvm"))] -fn list_take_last_2() { - assert_evals_to!( - "List.takeLast2 [1, 2, 3] 2", - RocList::from_slice(&[2, 3]), - RocList - ); - assert_evals_to!( - "List.takeLast2 [1, 2, 3] 0", - RocList::from_slice(&[]), - RocList - ); - assert_evals_to!( - "List.takeLast2 [] 1", - RocList::from_slice(&[]), - RocList - ); - assert_evals_to!( - "List.takeLast2 [1,2] 5", - RocList::from_slice(&[1, 2]), - RocList - ); -} - #[test] #[cfg(any(feature = "gen-llvm"))] fn list_sublist() { From 98d2c57edf3a966849bcc0477f40efd1ffdcbcf6 Mon Sep 17 00:00:00 2001 From: satotake Date: Sat, 13 Nov 2021 04:55:18 +0000 Subject: [PATCH 035/223] move List.sublist to backend --- compiler/builtins/bitcode/src/list.zig | 39 ++++++++++++++++++++++++ compiler/builtins/bitcode/src/main.zig | 1 + compiler/builtins/src/bitcode.rs | 1 + compiler/can/src/builtins.rs | 33 +++----------------- compiler/gen_llvm/src/llvm/build.rs | 23 +++++++++++++- compiler/gen_llvm/src/llvm/build_list.rs | 27 ++++++++++++++++ compiler/gen_wasm/src/low_level.rs | 7 +++-- compiler/module/src/low_level.rs | 2 ++ compiler/mono/src/borrow.rs | 1 + compiler/mono/src/low_level.rs | 1 + 10 files changed, 102 insertions(+), 33 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index 906ffa4456..bcdbfb0c5c 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -888,6 +888,45 @@ pub fn listTakeFirst( } } + +pub fn listSublist( + list: RocList, + alignment: u32, + element_width: usize, + rec: extern struct { len: usize, start: usize }, + dec: Dec, +) callconv(.C) RocList { + const start = rec.start; + const len = rec.len; + if (list.bytes) |source_ptr| { + const size = list.len(); + + if (start >= size) { + return RocList.empty(); + } + + const keep_len = std.math.min(len, size - start); + const drop_len = std.math.max(start, 0); + + var i: usize = 0; + while (i < drop_len) : (i += 1) { + const element = source_ptr + i * element_width; + dec(element); + } + + const output = RocList.allocate(alignment, keep_len, element_width); + const target_ptr = output.bytes orelse unreachable; + + @memcpy(target_ptr, source_ptr + start * element_width, keep_len * element_width); + + utils.decref(list.bytes, size * element_width, alignment); + + return output; + } else { + return RocList.empty(); + } +} + pub fn listTakeLast( list: RocList, alignment: u32, diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index 57b31d14e5..a3e3ffd19a 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -47,6 +47,7 @@ comptime { exportListFn(list.listConcat, "concat"); exportListFn(list.listTakeFirst, "take_first"); exportListFn(list.listTakeLast, "take_last"); + exportListFn(list.listSublist, "sublist"); exportListFn(list.listDrop, "drop"); exportListFn(list.listDropAt, "drop_at"); exportListFn(list.listSet, "set"); diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index cb45e67ac1..5aa5c4a526 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -185,6 +185,7 @@ pub const LIST_APPEND: &str = "roc_builtins.list.append"; pub const LIST_PREPEND: &str = "roc_builtins.list.prepend"; pub const LIST_TAKE_FIRST: &str = "roc_builtins.list.take_first"; pub const LIST_TAKE_LAST: &str = "roc_builtins.list.take_last"; +pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist"; pub const LIST_DROP: &str = "roc_builtins.list.drop"; pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at"; pub const LIST_SWAP: &str = "roc_builtins.list.swap"; diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index ddabf11685..45b4b1fa98 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2070,34 +2070,9 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { let sym_list = Symbol::ARG_1; let sym_rec = Symbol::ARG_2; - let start_var = var_store.fresh(); - let len_var = var_store.fresh(); - - let get_start = Access { - record_var: rec_var, - ext_var: var_store.fresh(), - field_var: var_store.fresh(), - loc_expr: Box::new(no_region(Var(sym_rec))), - field: "start".into(), - }; - - let get_len = Access { - record_var: rec_var, - ext_var: var_store.fresh(), - field_var: var_store.fresh(), - loc_expr: Box::new(no_region(Var(sym_rec))), - field: "len".into(), - }; - - let body_drop = RunLowLevel { - op: LowLevel::ListDrop, - args: vec![(list_var, Var(sym_list)), (start_var, get_start)], - ret_var: list_var, - }; - - let body_take = RunLowLevel { - op: LowLevel::ListTakeFirst, - args: vec![(list_var, body_drop), (len_var, get_len)], + let body = RunLowLevel { + op: LowLevel::ListSublist, + args: vec![(list_var, Var(sym_list)), (rec_var, Var(sym_rec))], ret_var: list_var, }; @@ -2105,7 +2080,7 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { symbol, vec![(list_var, sym_list), (rec_var, sym_rec)], var_store, - body_take, + body, list_var, ) } diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index f8a16ea1c6..bd593e3e16 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -12,7 +12,7 @@ use crate::llvm::build_list::{ list_contains, list_drop, list_drop_at, list_find_trivial_not_found, list_find_unsafe, list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, - list_reverse, list_set, list_single, list_sort_with, list_swap, list_take_first, + list_reverse, list_set, list_single, list_sort_with, list_sublist, list_swap, list_take_first, list_take_last, }; use crate::llvm::build_str::{ @@ -5210,6 +5210,27 @@ fn run_low_level<'a, 'ctx, 'env>( _ => unreachable!("Invalid layout {:?} in List.takeLast", list_layout), } } + ListSublist => { + // List.sublist : List elem, { start : Nat, len : Nat } -> List elem + debug_assert_eq!(args.len(), 2); + + let (list, list_layout) = load_symbol_and_layout(scope, &args[0]); + let original_wrapper = list.into_struct_value(); + + let rec = load_symbol(scope, &args[1]); + + match list_layout { + Layout::Builtin(Builtin::EmptyList) => empty_list(env), + Layout::Builtin(Builtin::List(element_layout)) => list_sublist( + env, + layout_ids, + original_wrapper, + rec.into_struct_value(), + element_layout, + ), + _ => unreachable!("Invalid layout {:?} in List.sublist", list_layout), + } + } ListDrop => { // List.drop : List elem, Nat -> List elem debug_assert_eq!(args.len(), 2); diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index 7112c4b19a..a6a95a9ef6 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -338,6 +338,33 @@ pub fn list_take_last<'a, 'ctx, 'env>( ) } +/// List.sublist : List elem, { start : Nat, len : Nat } -> List elem +pub fn list_sublist<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout_ids: &mut LayoutIds<'a>, + original_wrapper: StructValue<'ctx>, + len_and_start: StructValue<'ctx>, + element_layout: &Layout<'a>, +) -> BasicValueEnum<'ctx> { + let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout); + call_bitcode_fn_returns_list( + env, + &[ + pass_list_cc(env, original_wrapper.into()), + env.alignment_intvalue(element_layout), + layout_width(env, element_layout), + complex_bitcast( + env.builder, + len_and_start.into(), + env.str_list_c_abi().into(), + "to_i128", + ), + dec_element_fn.as_global_value().as_pointer_value().into(), + ], + bitcode::LIST_SUBLIST, + ) +} + /// List.drop : List elem, Nat -> List elem pub fn list_drop<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 48eafa1621..ffb8ce1af8 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -34,9 +34,10 @@ pub fn build_call_low_level<'a>( | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListTakeFirst - | ListTakeLast | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize - | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys - | DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { + | ListTakeLast | ListSublist | ListDrop | ListDropAt | ListSwap | ListAny + | ListFindUnsafe | DictSize | DictEmpty | DictInsert | DictRemove | DictContains + | DictGetUnsafe | DictKeys | DictValues | DictUnion | DictIntersection | DictDifference + | DictWalk | SetFromList => { return NotImplemented; } diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index 8ac9bdd2c0..920e217fd9 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -45,6 +45,7 @@ pub enum LowLevel { ListSortWith, ListTakeFirst, ListTakeLast, + ListSublist, ListDrop, ListDropAt, ListSwap, @@ -138,6 +139,7 @@ macro_rules! first_order { | ListSet | ListTakeFirst | ListTakeLast + | ListSublist | ListDrop | ListDropAt | ListSingle diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 965aa5698a..9b7989a144 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -968,6 +968,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] { ListAppend => arena.alloc_slice_copy(&[owned, owned]), ListTakeFirst => arena.alloc_slice_copy(&[owned, irrelevant]), ListTakeLast => arena.alloc_slice_copy(&[owned, irrelevant]), + ListSublist => arena.alloc_slice_copy(&[owned, irrelevant]), ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]), ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]), ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]), diff --git a/compiler/mono/src/low_level.rs b/compiler/mono/src/low_level.rs index 2a31addd74..8d26fb187f 100644 --- a/compiler/mono/src/low_level.rs +++ b/compiler/mono/src/low_level.rs @@ -102,6 +102,7 @@ enum FirstOrder { ListSet, ListTakeFirst, ListTakeLast, + ListSublist, ListDrop, ListDropAt, ListSingle, From 2e073d57eaeb23c6b7c731178796eab8ad6e320d Mon Sep 17 00:00:00 2001 From: satotake Date: Sat, 13 Nov 2021 05:12:18 +0000 Subject: [PATCH 036/223] destruct record at high level --- compiler/builtins/bitcode/src/list.zig | 11 +++++------ compiler/can/src/builtins.rs | 25 +++++++++++++++++++++++- compiler/gen_llvm/src/llvm/build.rs | 11 ++++++++--- compiler/gen_llvm/src/llvm/build_list.rs | 11 ++++------- compiler/mono/src/borrow.rs | 2 +- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index bcdbfb0c5c..adf5f7f2bc 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -893,11 +893,10 @@ pub fn listSublist( list: RocList, alignment: u32, element_width: usize, - rec: extern struct { len: usize, start: usize }, + start: usize, + len: usize, dec: Dec, ) callconv(.C) RocList { - const start = rec.start; - const len = rec.len; if (list.bytes) |source_ptr| { const size = list.len(); @@ -922,9 +921,9 @@ pub fn listSublist( utils.decref(list.bytes, size * element_width, alignment); return output; - } else { - return RocList.empty(); - } + } + + return RocList.empty(); } pub fn listTakeLast( diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 45b4b1fa98..27c1f38735 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2070,9 +2070,32 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { let sym_list = Symbol::ARG_1; let sym_rec = Symbol::ARG_2; + let start_var = var_store.fresh(); + let len_var = var_store.fresh(); + + let get_start = Access { + record_var: rec_var, + ext_var: var_store.fresh(), + field_var: var_store.fresh(), + loc_expr: Box::new(no_region(Var(sym_rec))), + field: "start".into(), + }; + + let get_len = Access { + record_var: rec_var, + ext_var: var_store.fresh(), + field_var: var_store.fresh(), + loc_expr: Box::new(no_region(Var(sym_rec))), + field: "len".into(), + }; + let body = RunLowLevel { op: LowLevel::ListSublist, - args: vec![(list_var, Var(sym_list)), (rec_var, Var(sym_rec))], + args: vec![ + (list_var, Var(sym_list)), + (start_var, get_start), + (len_var, get_len), + ], ret_var: list_var, }; diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index bd593e3e16..e6a82e6ff6 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -5212,12 +5212,16 @@ fn run_low_level<'a, 'ctx, 'env>( } ListSublist => { // List.sublist : List elem, { start : Nat, len : Nat } -> List elem - debug_assert_eq!(args.len(), 2); + // + // As a low-level, record is destructed + // List.sublist : List elem, start : Nat, len : Nat -> List elem + debug_assert_eq!(args.len(), 3); let (list, list_layout) = load_symbol_and_layout(scope, &args[0]); let original_wrapper = list.into_struct_value(); - let rec = load_symbol(scope, &args[1]); + let start = load_symbol(scope, &args[1]); + let len = load_symbol(scope, &args[2]); match list_layout { Layout::Builtin(Builtin::EmptyList) => empty_list(env), @@ -5225,7 +5229,8 @@ fn run_low_level<'a, 'ctx, 'env>( env, layout_ids, original_wrapper, - rec.into_struct_value(), + start.into_int_value(), + len.into_int_value(), element_layout, ), _ => unreachable!("Invalid layout {:?} in List.sublist", list_layout), diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index a6a95a9ef6..6695e93b83 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -343,7 +343,8 @@ pub fn list_sublist<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, original_wrapper: StructValue<'ctx>, - len_and_start: StructValue<'ctx>, + start: IntValue<'ctx>, + len: IntValue<'ctx>, element_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout); @@ -353,12 +354,8 @@ pub fn list_sublist<'a, 'ctx, 'env>( pass_list_cc(env, original_wrapper.into()), env.alignment_intvalue(element_layout), layout_width(env, element_layout), - complex_bitcast( - env.builder, - len_and_start.into(), - env.str_list_c_abi().into(), - "to_i128", - ), + start.into(), + len.into(), dec_element_fn.as_global_value().as_pointer_value().into(), ], bitcode::LIST_SUBLIST, diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 9b7989a144..f1724b10fa 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -968,7 +968,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] { ListAppend => arena.alloc_slice_copy(&[owned, owned]), ListTakeFirst => arena.alloc_slice_copy(&[owned, irrelevant]), ListTakeLast => arena.alloc_slice_copy(&[owned, irrelevant]), - ListSublist => arena.alloc_slice_copy(&[owned, irrelevant]), + ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]), ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]), ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]), ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]), From 9ec2bc7946c6618fa099a98c0708d0c349235aad Mon Sep 17 00:00:00 2001 From: satotake Date: Sat, 13 Nov 2021 06:03:18 +0000 Subject: [PATCH 037/223] Remove `takeFirst` and `takeLast` from backend --- compiler/builtins/bitcode/src/list.zig | 55 ------------------------ compiler/builtins/bitcode/src/main.zig | 2 - compiler/builtins/src/bitcode.rs | 2 - compiler/can/src/builtins.rs | 36 +++++++++++++++- compiler/gen_llvm/src/llvm/build.rs | 44 +------------------ compiler/gen_llvm/src/llvm/build_list.rs | 41 ------------------ compiler/gen_wasm/src/low_level.rs | 9 ++-- compiler/module/src/low_level.rs | 4 -- compiler/mono/src/borrow.rs | 2 - compiler/mono/src/low_level.rs | 2 - 10 files changed, 39 insertions(+), 158 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index adf5f7f2bc..d284369a65 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -862,33 +862,6 @@ pub fn listSwap( return newList; } -pub fn listTakeFirst( - list: RocList, - alignment: u32, - element_width: usize, - take_count: usize, -) callconv(.C) RocList { - if (list.bytes) |source_ptr| { - if (take_count == 0) { - return RocList.empty(); - } - const in_len = list.len(); - const out_len = std.math.min(take_count, in_len); - - const output = RocList.allocate(alignment, out_len, element_width); - const target_ptr = output.bytes orelse unreachable; - - @memcpy(target_ptr, source_ptr, out_len * element_width); - - utils.decref(list.bytes, in_len * element_width, alignment); - - return output; - } else { - return RocList.empty(); - } -} - - pub fn listSublist( list: RocList, alignment: u32, @@ -926,34 +899,6 @@ pub fn listSublist( return RocList.empty(); } -pub fn listTakeLast( - list: RocList, - alignment: u32, - element_width: usize, - take_count: usize, - dec: Dec, -) callconv(.C) RocList { - if (take_count == 0) { - return RocList.empty(); - } - if (list.bytes) |source_ptr| { - const size = list.len(); - if (size <= take_count) { - return list; - } - const drop_count = size - take_count; - return listDrop( - list, - alignment, - element_width, - drop_count, - dec, - ); - } else { - return RocList.empty(); - } -} - pub fn listDrop( list: RocList, alignment: u32, diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index a3e3ffd19a..374aaa7bc5 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -45,8 +45,6 @@ comptime { exportListFn(list.listReverse, "reverse"); exportListFn(list.listSortWith, "sort_with"); exportListFn(list.listConcat, "concat"); - exportListFn(list.listTakeFirst, "take_first"); - exportListFn(list.listTakeLast, "take_last"); exportListFn(list.listSublist, "sublist"); exportListFn(list.listDrop, "drop"); exportListFn(list.listDropAt, "drop_at"); diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 5aa5c4a526..f8ad6f920f 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -183,8 +183,6 @@ pub const LIST_CONTAINS: &str = "roc_builtins.list.contains"; pub const LIST_REPEAT: &str = "roc_builtins.list.repeat"; pub const LIST_APPEND: &str = "roc_builtins.list.append"; pub const LIST_PREPEND: &str = "roc_builtins.list.prepend"; -pub const LIST_TAKE_FIRST: &str = "roc_builtins.list.take_first"; -pub const LIST_TAKE_LAST: &str = "roc_builtins.list.take_last"; pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist"; pub const LIST_DROP: &str = "roc_builtins.list.drop"; pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at"; diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 27c1f38735..0c558f57cb 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2020,11 +2020,13 @@ fn list_swap(symbol: Symbol, var_store: &mut VarStore) -> Def { fn list_take_first(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); let len_var = var_store.fresh(); + let zero = int(len_var, Variable::NATURAL, 0); let body = RunLowLevel { - op: LowLevel::ListTakeFirst, + op: LowLevel::ListSublist, args: vec![ (list_var, Var(Symbol::ARG_1)), + (len_var, zero), (len_var, Var(Symbol::ARG_2)), ], ret_var: list_var, @@ -2044,10 +2046,40 @@ fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); let len_var = var_store.fresh(); + let zero = int(len_var, Variable::NATURAL, 0); + let bool_var = var_store.fresh(); + + let get_list_len = RunLowLevel { + op: LowLevel::ListLen, + args: vec![(list_var, Var(Symbol::ARG_1))], + ret_var: len_var, + }; + + let get_sub = RunLowLevel { + op: LowLevel::NumSubWrap, + args: vec![(len_var, get_list_len), (len_var, Var(Symbol::ARG_2))], + ret_var: len_var, + }; + + let get_start = If { + cond_var: bool_var, + branch_var: len_var, + branches: vec![( + no_region(RunLowLevel { + op: LowLevel::NumGt, + args: vec![(len_var, get_sub.clone()), (len_var, zero.clone())], + ret_var: bool_var, + }), + no_region(get_sub), + )], + final_else: Box::new(no_region(zero)), + }; + let body = RunLowLevel { - op: LowLevel::ListTakeLast, + op: LowLevel::ListSublist, args: vec![ (list_var, Var(Symbol::ARG_1)), + (len_var, get_start), (len_var, Var(Symbol::ARG_2)), ], ret_var: list_var, diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index e6a82e6ff6..dc0499ae67 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -12,8 +12,7 @@ use crate::llvm::build_list::{ list_contains, list_drop, list_drop_at, list_find_trivial_not_found, list_find_unsafe, list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, - list_reverse, list_set, list_single, list_sort_with, list_sublist, list_swap, list_take_first, - list_take_last, + list_reverse, list_set, list_single, list_sort_with, list_sublist, list_swap, }; use crate::llvm::build_str::{ empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, @@ -5169,47 +5168,6 @@ fn run_low_level<'a, 'ctx, 'env>( _ => unreachable!("Invalid layout {:?} in List.swap", list_layout), } } - ListTakeFirst => { - // List.takeFirst : List elem, Nat -> List elem - debug_assert_eq!(args.len(), 2); - - let (list, list_layout) = load_symbol_and_layout(scope, &args[0]); - let original_wrapper = list.into_struct_value(); - - let count = load_symbol(scope, &args[1]); - - match list_layout { - Layout::Builtin(Builtin::EmptyList) => empty_list(env), - Layout::Builtin(Builtin::List(element_layout)) => list_take_first( - env, - original_wrapper, - count.into_int_value(), - element_layout, - ), - _ => unreachable!("Invalid layout {:?} in List.takeFirst", list_layout), - } - } - ListTakeLast => { - // List.takeLast : List elem, Nat -> List elem - debug_assert_eq!(args.len(), 2); - - let (list, list_layout) = load_symbol_and_layout(scope, &args[0]); - let original_wrapper = list.into_struct_value(); - - let count = load_symbol(scope, &args[1]); - - match list_layout { - Layout::Builtin(Builtin::EmptyList) => empty_list(env), - Layout::Builtin(Builtin::List(element_layout)) => list_take_last( - env, - layout_ids, - original_wrapper, - count.into_int_value(), - element_layout, - ), - _ => unreachable!("Invalid layout {:?} in List.takeLast", list_layout), - } - } ListSublist => { // List.sublist : List elem, { start : Nat, len : Nat } -> List elem // diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index 6695e93b83..e78fa2f765 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -297,47 +297,6 @@ pub fn list_swap<'a, 'ctx, 'env>( ) } -/// List.takeFirst : List elem, Nat -> List elem -pub fn list_take_first<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - original_wrapper: StructValue<'ctx>, - count: IntValue<'ctx>, - element_layout: &Layout<'a>, -) -> BasicValueEnum<'ctx> { - call_bitcode_fn_returns_list( - env, - &[ - pass_list_cc(env, original_wrapper.into()), - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), - count.into(), - ], - bitcode::LIST_TAKE_FIRST, - ) -} - -/// List.takeLast : List elem, Nat -> List elem -pub fn list_take_last<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - layout_ids: &mut LayoutIds<'a>, - original_wrapper: StructValue<'ctx>, - count: IntValue<'ctx>, - element_layout: &Layout<'a>, -) -> BasicValueEnum<'ctx> { - let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout); - call_bitcode_fn_returns_list( - env, - &[ - pass_list_cc(env, original_wrapper.into()), - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), - count.into(), - dec_element_fn.as_global_value().as_pointer_value().into(), - ], - bitcode::LIST_TAKE_LAST, - ) -} - /// List.sublist : List elem, { start : Nat, len : Nat } -> List elem pub fn list_sublist<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index ffb8ce1af8..2cf05a7a08 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -33,11 +33,10 @@ pub fn build_call_low_level<'a>( | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil - | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListTakeFirst - | ListTakeLast | ListSublist | ListDrop | ListDropAt | ListSwap | ListAny - | ListFindUnsafe | DictSize | DictEmpty | DictInsert | DictRemove | DictContains - | DictGetUnsafe | DictKeys | DictValues | DictUnion | DictIntersection | DictDifference - | DictWalk | SetFromList => { + | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListSublist + | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize | DictEmpty + | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues + | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { return NotImplemented; } diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index 920e217fd9..dd9a4f020b 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -43,8 +43,6 @@ pub enum LowLevel { ListKeepOks, ListKeepErrs, ListSortWith, - ListTakeFirst, - ListTakeLast, ListSublist, ListDrop, ListDropAt, @@ -137,8 +135,6 @@ macro_rules! first_order { | ListLen | ListGetUnsafe | ListSet - | ListTakeFirst - | ListTakeLast | ListSublist | ListDrop | ListDropAt diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index f1724b10fa..045dfb38cb 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -966,8 +966,6 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] { // TODO when we have lists with capacity (if ever) // List.append should own its first argument ListAppend => arena.alloc_slice_copy(&[owned, owned]), - ListTakeFirst => arena.alloc_slice_copy(&[owned, irrelevant]), - ListTakeLast => arena.alloc_slice_copy(&[owned, irrelevant]), ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]), ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]), ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]), diff --git a/compiler/mono/src/low_level.rs b/compiler/mono/src/low_level.rs index 8d26fb187f..2139ea59aa 100644 --- a/compiler/mono/src/low_level.rs +++ b/compiler/mono/src/low_level.rs @@ -100,8 +100,6 @@ enum FirstOrder { ListLen, ListGetUnsafe, ListSet, - ListTakeFirst, - ListTakeLast, ListSublist, ListDrop, ListDropAt, From f587be5169eb7f2b521617d4243aac4d43d9dbbb Mon Sep 17 00:00:00 2001 From: satotake Date: Sat, 13 Nov 2021 06:06:24 +0000 Subject: [PATCH 038/223] zig fmt --- compiler/builtins/bitcode/src/list.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index d284369a65..7dda2126c5 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -894,7 +894,7 @@ pub fn listSublist( utils.decref(list.bytes, size * element_width, alignment); return output; - } + } return RocList.empty(); } From 10eab4b785b080e1e591ef8288de7a078f31f263 Mon Sep 17 00:00:00 2001 From: Theo Felippe Date: Sat, 13 Nov 2021 08:29:40 +0000 Subject: [PATCH 039/223] implemented Result.isErr --- compiler/builtins/src/std.rs | 7 +++ compiler/can/src/builtins.rs | 78 +++++++++++++++++++++++++++++ compiler/module/src/symbol.rs | 1 + compiler/test_gen/src/gen_result.rs | 30 +++++++++++ 4 files changed, 116 insertions(+) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 5d054ad831..dab48890e3 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -1381,6 +1381,13 @@ pub fn types() -> MutMap { Box::new(bool_type()), ); + // isErr : Result * * -> bool + add_top_level_function_type!( + Symbol::RESULT_IS_ERR, + vec![result_type(flex(TVAR1), flex(TVAR3))], + Box::new(bool_type()), + ); + types } diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index ddabf11685..c718f22b5f 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -193,6 +193,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option RESULT_AFTER => result_after, RESULT_WITH_DEFAULT => result_with_default, RESULT_IS_OK => result_is_ok, + RESULT_IS_ERR => result_is_err, } } @@ -3992,6 +3993,83 @@ fn result_with_default(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +fn result_is_err(symbol: Symbol, var_store: &mut VarStore) -> Def { + let ret_var = var_store.fresh(); + let result_var = var_store.fresh(); + + let mut branches = vec![]; + + { + // ok branch + let tag_name = TagName::Global("Ok".into()); + + let pattern = Pattern::AppliedTag { + whole_var: result_var, + ext_var: var_store.fresh(), + tag_name, + arguments: vec![(var_store.fresh(), no_region(Pattern::Underscore))], + }; + + let false_expr = Tag { + variant_var: var_store.fresh(), + ext_var: var_store.fresh(), + name: TagName::Global("False".into()), + arguments: vec![], + }; + + let branch = WhenBranch { + patterns: vec![no_region(pattern)], + value: no_region(false_expr), + guard: None, + }; + + branches.push(branch); + } + + { + // err branch + let tag_name = TagName::Global("Err".into()); + + let pattern = Pattern::AppliedTag { + whole_var: result_var, + ext_var: var_store.fresh(), + tag_name, + arguments: vec![(var_store.fresh(), no_region(Pattern::Underscore))], + }; + + let true_expr = Tag { + variant_var: var_store.fresh(), + ext_var: var_store.fresh(), + name: TagName::Global("True".into()), + arguments: vec![], + }; + + let branch = WhenBranch { + patterns: vec![no_region(pattern)], + value: no_region(true_expr), + guard: None, + }; + + branches.push(branch); + } + + let body = When { + cond_var: result_var, + expr_var: ret_var, + region: Region::zero(), + loc_cond: Box::new(no_region(Var(Symbol::ARG_1))), + branches, + }; + + defn( + symbol, + vec![(result_var, Symbol::ARG_1)], + var_store, + body, + ret_var, + ) +} + fn result_is_ok(symbol: Symbol, var_store: &mut VarStore) -> Def { let ret_var = var_store.fresh(); let result_var = var_store.fresh(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 92345fbdf0..2233003ca0 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1079,6 +1079,7 @@ define_builtins! { 3 RESULT_WITH_DEFAULT: "withDefault" 4 RESULT_AFTER: "after" 5 RESULT_IS_OK: "isOk" + 6 RESULT_IS_ERR: "isErr" } 6 DICT: "Dict" => { 0 DICT_DICT: "Dict" imported // the Dict.Dict type alias diff --git a/compiler/test_gen/src/gen_result.rs b/compiler/test_gen/src/gen_result.rs index bfb0634326..4b86af9e83 100644 --- a/compiler/test_gen/src/gen_result.rs +++ b/compiler/test_gen/src/gen_result.rs @@ -189,3 +189,33 @@ fn is_ok() { bool ); } + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn is_err() { + assert_evals_to!( + indoc!( + r#" + result : Result I64 {} + result = Ok 2 + + Result.isErr result + "# + ), + false, + bool + ); + + assert_evals_to!( + indoc!( + r#" + result : Result I64 {} + result = Err {} + + Result.isErr result + "# + ), + true, + bool + ); +} From 030a504bd225d56b3ee6f09254db5960e80456bf Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 13 Nov 2021 14:39:15 +0100 Subject: [PATCH 040/223] valgrind flag --- cli/src/build.rs | 5 +++++ cli/src/lib.rs | 10 ++++++++++ cli/tests/cli_run.rs | 10 +++++++++- compiler/build/src/link.rs | 13 +++++++++++++ linker/src/lib.rs | 3 ++- 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/cli/src/build.rs b/cli/src/build.rs index 82b8242bc7..97af317837 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -55,6 +55,7 @@ pub fn build_file<'a>( link_type: LinkType, surgically_link: bool, precompiled: bool, + target_valgrind: bool, ) -> Result> { let compilation_start = SystemTime::now(); let ptr_bytes = target.pointer_width().unwrap().bytes() as u32; @@ -116,6 +117,7 @@ pub fn build_file<'a>( .keys() .map(|x| x.as_str(&loaded.interns).to_string()) .collect(), + target_valgrind ); // TODO try to move as much of this linking as possible to the precompiled @@ -288,6 +290,7 @@ fn spawn_rebuild_thread( binary_path: PathBuf, target: &Triple, exported_symbols: Vec, + target_valgrind: bool ) -> std::thread::JoinHandle { let thread_local_target = target.clone(); std::thread::spawn(move || { @@ -299,6 +302,7 @@ fn spawn_rebuild_thread( &thread_local_target, host_input_path.as_path(), exported_symbols, + target_valgrind, ) .unwrap(); } else { @@ -307,6 +311,7 @@ fn spawn_rebuild_thread( &thread_local_target, host_input_path.as_path(), None, + target_valgrind ); } } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 543f24981a..2958abbd64 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -33,6 +33,7 @@ pub const FLAG_BACKEND: &str = "backend"; pub const FLAG_TIME: &str = "time"; pub const FLAG_LINK: &str = "roc-linker"; pub const FLAG_PRECOMPILED: &str = "precompiled-host"; +pub const FLAG_VALGRIND: &str = "valgrind"; pub const ROC_FILE: &str = "ROC_FILE"; pub const BACKEND: &str = "BACKEND"; pub const DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES"; @@ -100,6 +101,12 @@ pub fn build_app<'a>() -> App<'a> { .about("Assumes the host has been precompiled and skips recompiling the host.") .required(false), ) + .arg( + Arg::new(FLAG_VALGRIND) + .long(FLAG_VALGRIND) + .about("Some assembly instructions are not supported by valgrind, this flag prevents those from being output when building the host.") + .required(false), + ) ) .subcommand(App::new(CMD_REPL) .about("Launch the interactive Read Eval Print Loop (REPL)") @@ -258,6 +265,7 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result { }; let surgically_link = matches.is_present(FLAG_LINK); let precompiled = matches.is_present(FLAG_PRECOMPILED); + if surgically_link && !roc_linker::supported(&link_type, &target) { panic!( "Link type, {:?}, with target, {}, not supported by roc linker", @@ -287,6 +295,7 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result { }); let src_dir = path.parent().unwrap().canonicalize().unwrap(); + let target_valgrind = matches.is_present(FLAG_VALGRIND); let res_binary_path = build_file( &arena, &target, @@ -298,6 +307,7 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result { link_type, surgically_link, precompiled, + target_valgrind ); match res_binary_path { diff --git a/cli/tests/cli_run.rs b/cli/tests/cli_run.rs index 3251e3b48b..a8975d2ff0 100644 --- a/cli/tests/cli_run.rs +++ b/cli/tests/cli_run.rs @@ -53,7 +53,15 @@ mod cli_run { expected_ending: &str, use_valgrind: bool, ) { - let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags].concat()); + + let mut all_flags = vec![]; + all_flags.extend_from_slice(flags); + + if use_valgrind { + all_flags.extend_from_slice(&["--valgrind"]); + } + + let compile_out = run_roc(&[&["build", file.to_str().unwrap()], &all_flags[..]].concat()); if !compile_out.stderr.is_empty() { panic!("{}", compile_out.stderr); } diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index d5285b3602..484178415b 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -86,6 +86,7 @@ pub fn build_zig_host_native( target: &str, opt_level: OptLevel, shared_lib_path: Option<&Path>, + target_valgrind: bool, ) -> Output { let mut command = Command::new("zig"); command @@ -118,6 +119,14 @@ pub fn build_zig_host_native( "-target", target, ]); + + if target_valgrind { + command.args(&[ + "-mcpu", + "x86_64" + ]); + } + if matches!(opt_level, OptLevel::Optimize) { command.args(&["-O", "ReleaseSafe"]); } @@ -339,6 +348,7 @@ pub fn rebuild_host( target: &Triple, host_input_path: &Path, shared_lib_path: Option<&Path>, + target_valgrind: bool, ) { let c_host_src = host_input_path.with_file_name("host.c"); let c_host_dest = host_input_path.with_file_name("c_host.o"); @@ -394,6 +404,7 @@ pub fn rebuild_host( "native", opt_level, shared_lib_path, + target_valgrind, ) } Architecture::X86_32(_) => { @@ -407,6 +418,7 @@ pub fn rebuild_host( "i386-linux-musl", opt_level, shared_lib_path, + target_valgrind ) } @@ -421,6 +433,7 @@ pub fn rebuild_host( target_triple_str(target), opt_level, shared_lib_path, + target_valgrind ) } _ => panic!("Unsupported architecture {:?}", target.architecture), diff --git a/linker/src/lib.rs b/linker/src/lib.rs index 769ba7011e..58f801115f 100644 --- a/linker/src/lib.rs +++ b/linker/src/lib.rs @@ -142,10 +142,11 @@ pub fn build_and_preprocess_host( target: &Triple, host_input_path: &Path, exposed_to_host: Vec, + target_valgrind: bool, ) -> io::Result<()> { let dummy_lib = host_input_path.with_file_name("libapp.so"); generate_dynamic_lib(target, exposed_to_host, &dummy_lib)?; - rebuild_host(opt_level, target, host_input_path, Some(&dummy_lib)); + rebuild_host(opt_level, target, host_input_path, Some(&dummy_lib), target_valgrind); let dynhost = host_input_path.with_file_name("dynhost"); let metadata = host_input_path.with_file_name("metadata"); let prehost = host_input_path.with_file_name("preprocessedhost"); From e2f7606f251e71f39a5a92522c9aec75fa7ed159 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 15:42:47 +0100 Subject: [PATCH 041/223] shrink higher order with indirection --- Cargo.lock | 1 + compiler/gen_dev/src/lib.rs | 2 +- compiler/gen_llvm/src/llvm/build.rs | 51 ++++++++------------- compiler/mono/Cargo.toml | 1 + compiler/mono/src/alias_analysis.rs | 8 ++-- compiler/mono/src/borrow.rs | 8 ++-- compiler/mono/src/inc_dec.rs | 14 +++--- compiler/mono/src/ir.rs | 69 ++++++++++++++++++----------- compiler/mono/src/layout.rs | 8 ++++ 9 files changed, 90 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c987c0452..1a9b7a966b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3467,6 +3467,7 @@ dependencies = [ "roc_std", "roc_types", "roc_unify", + "static_assertions", "ven_graph", "ven_pretty", ] diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index e17abf1362..817a000649 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -785,7 +785,7 @@ where match call_type { CallType::ByName { .. } => {} CallType::LowLevel { .. } => {} - CallType::HigherOrderLowLevel { .. } => {} + CallType::HigherOrder { .. } => {} CallType::Foreign { .. } => {} } } diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index f8a16ea1c6..0ce8640365 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -55,8 +55,8 @@ use roc_collections::all::{ImMap, MutMap, MutSet}; use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::{ - BranchInfo, CallType, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc, OptLevel, - ProcLayout, + BranchInfo, CallType, EntryPoint, HigherOrderLowLevel, JoinPointId, ListLiteralElement, + ModifyRc, OptLevel, ProcLayout, }; use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, UnionLayout}; use target_lexicon::{Architecture, OperatingSystem, Triple}; @@ -936,33 +936,12 @@ pub fn build_exp_call<'a, 'ctx, 'env>( ) } - CallType::HigherOrderLowLevel { - op, - function_owns_closure_data, - specialization_id, - function_name, - function_env, - arg_layouts, - ret_layout, - .. - } => { - let bytes = specialization_id.to_bytes(); + CallType::HigherOrder(higher_order) => { + let bytes = higher_order.specialization_id.to_bytes(); let callee_var = CalleeSpecVar(&bytes); let func_spec = func_spec_solutions.callee_spec(callee_var).unwrap(); - run_higher_order_low_level( - env, - layout_ids, - scope, - layout, - *op, - func_spec, - arg_layouts, - ret_layout, - *function_owns_closure_data, - *function_name, - function_env, - ) + run_higher_order_low_level(env, layout_ids, scope, layout, func_spec, higher_order) } CallType::Foreign { @@ -4418,16 +4397,24 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( layout_ids: &mut LayoutIds<'a>, scope: &Scope<'a, 'ctx>, return_layout: &Layout<'a>, - op: roc_mono::low_level::HigherOrder, func_spec: FuncSpec, - argument_layouts: &[Layout<'a>], - result_layout: &Layout<'a>, - function_owns_closure_data: bool, - function_name: Symbol, - function_env: &Symbol, + higher_order: &HigherOrderLowLevel<'a>, ) -> BasicValueEnum<'ctx> { use roc_mono::low_level::HigherOrder::*; + let HigherOrderLowLevel { + op, + arg_layouts: argument_layouts, + ret_layout: result_layout, + function_owns_closure_data, + function_name, + function_env, + .. + } = higher_order; + + let function_owns_closure_data = *function_owns_closure_data; + let function_name = *function_name; + // macros because functions cause lifetime issues related to the `env` or `layout_ids` macro_rules! function_details { () => {{ diff --git a/compiler/mono/Cargo.toml b/compiler/mono/Cargo.toml index 6075ecb44c..02045363d6 100644 --- a/compiler/mono/Cargo.toml +++ b/compiler/mono/Cargo.toml @@ -20,3 +20,4 @@ morphic_lib = { path = "../../vendor/morphic_lib" } bumpalo = { version = "3.8.0", features = ["collections"] } hashbrown = { version = "0.11.2", features = [ "bumpalo" ] } ven_graph = { path = "../../vendor/pathfinding" } +static_assertions = "1.1.0" diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index bd90890392..048b860565 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -10,8 +10,8 @@ use roc_module::symbol::Symbol; use std::convert::TryFrom; use crate::ir::{ - Call, CallType, Expr, HostExposedLayouts, ListLiteralElement, Literal, ModifyRc, OptLevel, - Proc, Stmt, + Call, CallType, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement, Literal, + ModifyRc, OptLevel, Proc, Stmt, }; use crate::layout::{Builtin, Layout, ListLayout, RawFunctionLayout, UnionLayout}; @@ -688,7 +688,7 @@ fn call_spec( *update_mode, call.arguments, ), - HigherOrderLowLevel { + HigherOrder(HigherOrderLowLevel { specialization_id, closure_env_layout, update_mode, @@ -698,7 +698,7 @@ fn call_spec( function_name, function_env, .. - } => { + }) => { use crate::low_level::HigherOrder::*; let array = specialization_id.to_bytes(); diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 965aa5698a..f7bcd2a59f 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -1,4 +1,4 @@ -use crate::ir::{Expr, JoinPointId, Param, Proc, ProcLayout, Stmt}; +use crate::ir::{Expr, HigherOrderLowLevel, JoinPointId, Param, Proc, ProcLayout, Stmt}; use crate::layout::Layout; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -593,14 +593,14 @@ impl<'a> BorrowInfState<'a> { self.own_args_using_bools(arguments, ps); } - HigherOrderLowLevel { + HigherOrder(HigherOrderLowLevel { op, arg_layouts, ret_layout, function_name, function_env, .. - } => { + }) => { use crate::low_level::HigherOrder::*; let closure_layout = ProcLayout { @@ -1046,7 +1046,7 @@ fn call_info_call<'a>(call: &crate::ir::Call<'a>, info: &mut CallInfo<'a>) { } Foreign { .. } => {} LowLevel { .. } => {} - HigherOrderLowLevel { .. } => {} + HigherOrder(_) => {} } } diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index d377795253..c180432907 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -1,5 +1,7 @@ use crate::borrow::{ParamMap, BORROWED, OWNED}; -use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, ProcLayout, Stmt}; +use crate::ir::{ + CallType, Expr, HigherOrderLowLevel, JoinPointId, ModifyRc, Param, Proc, ProcLayout, Stmt, +}; use crate::layout::Layout; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -463,7 +465,7 @@ impl<'a> Context<'a> { &*self.arena.alloc(Stmt::Let(z, v, l, b)) } - HigherOrderLowLevel { + HigherOrder(HigherOrderLowLevel { op, closure_env_layout, specialization_id, @@ -473,7 +475,7 @@ impl<'a> Context<'a> { function_name, function_env, .. - } => { + }) => { // setup use crate::low_level::HigherOrder::*; @@ -481,7 +483,7 @@ impl<'a> Context<'a> { ($borrows:expr) => { Expr::Call(crate::ir::Call { call_type: if let Some(OWNED) = $borrows.map(|p| p.borrow) { - HigherOrderLowLevel { + let higher_order = HigherOrderLowLevel { op: *op, closure_env_layout: *closure_env_layout, function_owns_closure_data: true, @@ -491,7 +493,9 @@ impl<'a> Context<'a> { function_env: *function_env, arg_layouts, ret_layout: *ret_layout, - } + }; + + CallType::HigherOrder(self.arena.alloc(higher_order)) } else { call_type }, diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index c0c02f3466..470a82fc6f 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -24,6 +24,16 @@ use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder}; pub const PRETTY_PRINT_IR_SYMBOLS: bool = false; +// if your changes cause this number to go down, great! +// please change it to the lower number. +// if it went up, maybe check that the change is really required +static_assertions::assert_eq_size!([u8; 3 * 8], Literal); +static_assertions::assert_eq_size!([u8; 13 * 8], Expr); +static_assertions::assert_eq_size!([u8; 22 * 8], Stmt); +static_assertions::assert_eq_size!([u8; 7 * 8], ProcLayout); +static_assertions::assert_eq_size!([u8; 12 * 8], Call); +static_assertions::assert_eq_size!([u8; 10 * 8], CallType); + macro_rules! return_on_layout_error { ($env:expr, $layout_result:expr) => { match $layout_result { @@ -1072,11 +1082,11 @@ impl<'a> Call<'a> { .text(format!("lowlevel {:?} ", lowlevel)) .append(alloc.intersperse(it, " ")) } - HigherOrderLowLevel { op: lowlevel, .. } => { + HigherOrder(higher_order) => { let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s)); alloc - .text(format!("lowlevel {:?} ", lowlevel)) + .text(format!("lowlevel {:?} ", higher_order.op)) .append(alloc.intersperse(it, " ")) } Foreign { @@ -1130,31 +1140,34 @@ pub enum CallType<'a> { op: LowLevel, update_mode: UpdateModeId, }, - HigherOrderLowLevel { - op: crate::low_level::HigherOrder, - /// the layout of the closure argument, if any - closure_env_layout: Option>, + HigherOrder(&'a HigherOrderLowLevel<'a>), +} - /// name of the top-level function that is passed as an argument - /// e.g. in `List.map xs Num.abs` this would be `Num.abs` - function_name: Symbol, +#[derive(Clone, Debug, PartialEq)] +pub struct HigherOrderLowLevel<'a> { + pub op: crate::low_level::HigherOrder, + /// the layout of the closure argument, if any + pub closure_env_layout: Option>, - /// Symbol of the environment captured by the function argument - function_env: Symbol, + /// name of the top-level function that is passed as an argument + /// e.g. in `List.map xs Num.abs` this would be `Num.abs` + pub function_name: Symbol, - /// does the function argument need to own the closure data - function_owns_closure_data: bool, + /// Symbol of the environment captured by the function argument + pub function_env: Symbol, - /// specialization id of the function argument, used for name generation - specialization_id: CallSpecId, + /// does the function argument need to own the closure data + pub function_owns_closure_data: bool, - /// update mode of the higher order lowlevel itself - update_mode: UpdateModeId, + /// specialization id of the function argument, used for name generation + pub specialization_id: CallSpecId, - /// function layout, used for name generation - arg_layouts: &'a [Layout<'a>], - ret_layout: Layout<'a>, - }, + /// update mode of the higher order lowlevel itself + pub update_mode: UpdateModeId, + + /// function layout, used for name generation + pub arg_layouts: &'a [Layout<'a>], + pub ret_layout: Layout<'a>, } #[derive(Clone, Debug, PartialEq)] @@ -3986,8 +3999,8 @@ pub fn with_hole<'a>( lambda_set, op, closure_data_symbol, - |(top_level_function, closure_data, closure_env_layout, specialization_id, update_mode)| self::Call { - call_type: CallType::HigherOrderLowLevel { + |(top_level_function, closure_data, closure_env_layout, specialization_id, update_mode)| { + let higher_order = HigherOrderLowLevel { op: crate::low_level::HigherOrder::$ho { $($x,)* }, closure_env_layout, specialization_id, @@ -3997,8 +4010,12 @@ pub fn with_hole<'a>( function_name: top_level_function, arg_layouts, ret_layout, - }, - arguments: arena.alloc([$($x,)* top_level_function, closure_data]), + }; + + self::Call { + call_type: CallType::HigherOrder(arena.alloc(higher_order)), + arguments: arena.alloc([$($x,)* top_level_function, closure_data]), + } }, layout, assigned, @@ -5475,7 +5492,7 @@ fn substitute_in_call<'a>( }), CallType::Foreign { .. } => None, CallType::LowLevel { .. } => None, - CallType::HigherOrderLowLevel { .. } => None, + CallType::HigherOrder { .. } => None, }; let mut did_change = false; diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 673da22e32..075a4b66d9 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -12,6 +12,14 @@ use std::collections::hash_map::Entry; use std::collections::HashMap; use ven_pretty::{DocAllocator, DocBuilder}; +// if your changes cause this number to go down, great! +// please change it to the lower number. +// if it went up, maybe check that the change is really required +static_assertions::assert_eq_size!([u8; 3 * 8], Builtin); +static_assertions::assert_eq_size!([u8; 5 * 8], Layout); +static_assertions::assert_eq_size!([u8; 4 * 8], UnionLayout); +static_assertions::assert_eq_size!([u8; 3 * 8], LambdaSet); + pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::() * 8) as usize; const GENERATE_NULLABLE: bool = true; From 13713ee6ad91f62e732fa890d2b4805b6a91dcea Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 15:43:49 +0100 Subject: [PATCH 042/223] pass layout by reference --- compiler/mono/src/ir.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 470a82fc6f..b759e83006 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1134,7 +1134,7 @@ pub enum CallType<'a> { }, Foreign { foreign_symbol: ForeignSymbol, - ret_layout: Layout<'a>, + ret_layout: &'a Layout<'a>, }, LowLevel { op: LowLevel, @@ -3947,7 +3947,7 @@ pub fn with_hole<'a>( let call = self::Call { call_type: CallType::Foreign { foreign_symbol, - ret_layout: layout, + ret_layout: env.arena.alloc(layout), }, arguments: arg_symbols, }; From 83953b0bbac51be0727d9f91f0dfcfc004352fbd Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 15:59:19 +0100 Subject: [PATCH 043/223] shrink Call --- compiler/gen_llvm/src/llvm/build.rs | 4 +-- compiler/mono/src/alias_analysis.rs | 14 ++++---- compiler/mono/src/borrow.rs | 4 +-- compiler/mono/src/inc_dec.rs | 2 +- compiler/mono/src/ir.rs | 54 ++++++++++++++--------------- 5 files changed, 39 insertions(+), 39 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 0ce8640365..54852a42a9 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -672,7 +672,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>( top_level: ProcLayout<'a>, ) -> (&'static str, FunctionValue<'ctx>) { let it = top_level.arguments.iter().copied(); - let bytes = roc_mono::alias_analysis::func_name_bytes_help(symbol, it, top_level.result); + let bytes = roc_mono::alias_analysis::func_name_bytes_help(symbol, it, &top_level.result); let func_name = FuncName(&bytes); let func_solutions = mod_solutions.func_solutions(func_name).unwrap(); @@ -4150,7 +4150,7 @@ pub fn build_proc<'a, 'ctx, 'env>( let bytes = roc_mono::alias_analysis::func_name_bytes_help( symbol, it, - top_level.result, + &top_level.result, ); let func_name = FuncName(&bytes); let func_solutions = mod_solutions.func_solutions(func_name).unwrap(); diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 048b860565..0d6620b0be 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -24,7 +24,7 @@ pub const STATIC_LIST_NAME: ConstName = ConstName(b"THIS IS A STATIC LIST"); const ENTRY_POINT_NAME: &[u8] = b"mainForHost"; pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] { - func_name_bytes_help(proc.name, proc.args.iter().map(|x| x.0), proc.ret_layout) + func_name_bytes_help(proc.name, proc.args.iter().map(|x| x.0), &proc.ret_layout) } const DEBUG: bool = false; @@ -53,7 +53,7 @@ impl TagUnionId { pub fn func_name_bytes_help<'a, I>( symbol: Symbol, argument_layouts: I, - return_layout: Layout<'a>, + return_layout: &Layout<'a>, ) -> [u8; SIZE] where I: Iterator>, @@ -162,13 +162,13 @@ where match layout { RawFunctionLayout::Function(_, _, _) => { let it = top_level.arguments.iter().copied(); - let bytes = func_name_bytes_help(*symbol, it, top_level.result); + let bytes = func_name_bytes_help(*symbol, it, &top_level.result); host_exposed_functions.push((bytes, top_level.arguments)); } RawFunctionLayout::ZeroArgumentThunk(_) => { let it = std::iter::once(Layout::Struct(&[])); - let bytes = func_name_bytes_help(*symbol, it, top_level.result); + let bytes = func_name_bytes_help(*symbol, it, &top_level.result); host_exposed_functions.push((bytes, top_level.arguments)); } @@ -196,7 +196,7 @@ where let roc_main_bytes = func_name_bytes_help( entry_point.symbol, entry_point.layout.arguments.iter().copied(), - entry_point.layout.result, + &entry_point.layout.result, ); let roc_main = FuncName(&roc_main_bytes); @@ -660,7 +660,7 @@ fn call_spec( let arg_value_id = build_tuple_value(builder, env, block, call.arguments)?; let it = arg_layouts.iter().copied(); - let bytes = func_name_bytes_help(*symbol, it, *ret_layout); + let bytes = func_name_bytes_help(*symbol, it, ret_layout); let name = FuncName(&bytes); let module = MOD_APP; builder.add_call(block, spec_var, module, name, arg_value_id) @@ -708,7 +708,7 @@ fn call_spec( let update_mode_var = UpdateModeVar(&mode); let it = arg_layouts.iter().copied(); - let bytes = func_name_bytes_help(*function_name, it, *ret_layout); + let bytes = func_name_bytes_help(*function_name, it, ret_layout); let name = FuncName(&bytes); let module = MOD_APP; diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index f7bcd2a59f..0b6d6531c1 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -560,7 +560,7 @@ impl<'a> BorrowInfState<'a> { arg_layouts, .. } => { - let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); + let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout); // get the borrow signature of the applied function let ps = param_map @@ -795,7 +795,7 @@ impl<'a> BorrowInfState<'a> { Stmt::Ret(z), ) = (v, b) { - let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); + let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout); if self.current_proc == *g && x == *z { // anonymous functions (for which the ps may not be known) diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index c180432907..63604bf205 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -667,7 +667,7 @@ impl<'a> Context<'a> { arg_layouts, .. } => { - let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); + let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout); // get the borrow signature let ps = self diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index b759e83006..7e225772f5 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -28,11 +28,11 @@ pub const PRETTY_PRINT_IR_SYMBOLS: bool = false; // please change it to the lower number. // if it went up, maybe check that the change is really required static_assertions::assert_eq_size!([u8; 3 * 8], Literal); -static_assertions::assert_eq_size!([u8; 13 * 8], Expr); +static_assertions::assert_eq_size!([u8; 11 * 8], Expr); static_assertions::assert_eq_size!([u8; 22 * 8], Stmt); static_assertions::assert_eq_size!([u8; 7 * 8], ProcLayout); -static_assertions::assert_eq_size!([u8; 12 * 8], Call); -static_assertions::assert_eq_size!([u8; 10 * 8], CallType); +static_assertions::assert_eq_size!([u8; 8 * 8], Call); +static_assertions::assert_eq_size!([u8; 6 * 8], CallType); macro_rules! return_on_layout_error { ($env:expr, $layout_result:expr) => { @@ -1128,7 +1128,7 @@ impl UpdateModeId { pub enum CallType<'a> { ByName { name: Symbol, - ret_layout: Layout<'a>, + ret_layout: &'a Layout<'a>, arg_layouts: &'a [Layout<'a>], specialization_id: CallSpecId, }, @@ -2027,7 +2027,7 @@ fn specialize_external<'a>( Symbol::ARG_CLOSURE, argument_symbols.into_bump_slice(), argument_layouts, - *return_layout, + return_layout, assigned, hole, ); @@ -3871,7 +3871,7 @@ pub fn with_hole<'a>( closure_data_symbol, arg_symbols, arg_layouts, - *ret_layout, + ret_layout, assigned, hole, ); @@ -3898,7 +3898,7 @@ pub fn with_hole<'a>( closure_data_symbol, arg_symbols, arg_layouts, - *ret_layout, + ret_layout, assigned, hole, ); @@ -6107,7 +6107,7 @@ fn force_thunk<'a>( let call = self::Call { call_type: CallType::ByName { name: thunk_name, - ret_layout: layout, + ret_layout: env.arena.alloc(layout), arg_layouts: &[], specialization_id: env.next_call_specialization_id(), }, @@ -6472,7 +6472,7 @@ fn call_by_name<'a>( closure_data_symbol, arg_symbols, arg_layouts, - *ret_layout, + ret_layout, assigned, hole, ); @@ -6596,7 +6596,7 @@ fn call_by_name_help<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: *ret_layout, + ret_layout: ret_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6637,7 +6637,7 @@ fn call_by_name_help<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: *ret_layout, + ret_layout: ret_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6691,7 +6691,7 @@ fn call_by_name_help<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: *ret_layout, + ret_layout: ret_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6939,7 +6939,7 @@ fn call_specialized_proc<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: function_layout.result, + ret_layout: env.arena.alloc(function_layout.result), arg_layouts: function_layout.arguments, specialization_id: env.next_call_specialization_id(), }, @@ -6982,7 +6982,7 @@ fn call_specialized_proc<'a>( closure_data_symbol, field_symbols, argument_layouts.into_bump_slice(), - function_layout.result, + env.arena.alloc(function_layout.result), assigned, hole, ); @@ -7012,7 +7012,7 @@ fn call_specialized_proc<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: function_layout.result, + ret_layout: env.arena.alloc(function_layout.result), arg_layouts: function_layout.arguments, specialization_id: env.next_call_specialization_id(), }, @@ -8096,7 +8096,7 @@ fn match_on_lambda_set<'a>( closure_data_symbol: Symbol, argument_symbols: &'a [Symbol], argument_layouts: &'a [Layout<'a>], - return_layout: Layout<'a>, + return_layout: &'a Layout<'a>, assigned: Symbol, hole: &'a Stmt<'a>, ) -> Stmt<'a> { @@ -8193,7 +8193,7 @@ fn union_lambda_set_to_switch<'a>( closure_data_symbol: Symbol, argument_symbols: &'a [Symbol], argument_layouts: &'a [Layout<'a>], - return_layout: Layout<'a>, + return_layout: &'a Layout<'a>, assigned: Symbol, hole: &'a Stmt<'a>, ) -> Stmt<'a> { @@ -8237,12 +8237,12 @@ fn union_lambda_set_to_switch<'a>( cond_layout: closure_tag_id_layout, branches: branches.into_bump_slice(), default_branch, - ret_layout: return_layout, + ret_layout: *return_layout, }; let param = Param { symbol: assigned, - layout: return_layout, + layout: *return_layout, borrow: false, }; @@ -8264,7 +8264,7 @@ fn union_lambda_set_branch<'a>( closure_data_layout: Layout<'a>, argument_symbols_slice: &'a [Symbol], argument_layouts_slice: &'a [Layout<'a>], - return_layout: Layout<'a>, + return_layout: &'a Layout<'a>, ) -> Stmt<'a> { let result_symbol = env.unique_symbol(); @@ -8293,7 +8293,7 @@ fn union_lambda_set_branch_help<'a>( closure_data_layout: Layout<'a>, argument_symbols_slice: &'a [Symbol], argument_layouts_slice: &'a [Layout<'a>], - return_layout: Layout<'a>, + return_layout: &'a Layout<'a>, assigned: Symbol, hole: &'a Stmt<'a>, ) -> Stmt<'a> { @@ -8339,7 +8339,7 @@ fn union_lambda_set_branch_help<'a>( arguments: argument_symbols, }; - build_call(env, call, assigned, return_layout, hole) + build_call(env, call, assigned, *return_layout, hole) } #[allow(clippy::too_many_arguments)] @@ -8351,7 +8351,7 @@ fn enum_lambda_set_to_switch<'a>( closure_data_symbol: Symbol, argument_symbols: &'a [Symbol], argument_layouts: &'a [Layout<'a>], - return_layout: Layout<'a>, + return_layout: &'a Layout<'a>, assigned: Symbol, hole: &'a Stmt<'a>, ) -> Stmt<'a> { @@ -8388,12 +8388,12 @@ fn enum_lambda_set_to_switch<'a>( cond_layout: closure_tag_id_layout, branches: branches.into_bump_slice(), default_branch, - ret_layout: return_layout, + ret_layout: *return_layout, }; let param = Param { symbol: assigned, - layout: return_layout, + layout: *return_layout, borrow: false, }; @@ -8414,7 +8414,7 @@ fn enum_lambda_set_branch<'a>( closure_data_layout: Layout<'a>, argument_symbols_slice: &'a [Symbol], argument_layouts_slice: &'a [Layout<'a>], - return_layout: Layout<'a>, + return_layout: &'a Layout<'a>, ) -> Stmt<'a> { let result_symbol = env.unique_symbol(); @@ -8455,7 +8455,7 @@ fn enum_lambda_set_branch<'a>( }, arguments: argument_symbols, }; - build_call(env, call, assigned, return_layout, env.arena.alloc(hole)) + build_call(env, call, assigned, *return_layout, env.arena.alloc(hole)) } #[allow(clippy::too_many_arguments)] From f522d28a0063f3f48d72b707f66b86ee99f215a4 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 16:04:23 +0100 Subject: [PATCH 044/223] clippy --- compiler/gen_llvm/src/llvm/build.rs | 38 ++++++++++++++--------------- compiler/mono/src/ir.rs | 6 ++--- compiler/parse/tests/test_parse.rs | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 54852a42a9..c26ed82ebe 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -4473,7 +4473,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match op { ListMap { xs } => { // List.map : List before, (before -> after) -> List after - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); @@ -4501,8 +4501,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } } ListMap2 { xs, ys } => { - let (list1, list1_layout) = load_symbol_and_layout(scope, &xs); - let (list2, list2_layout) = load_symbol_and_layout(scope, &ys); + let (list1, list1_layout) = load_symbol_and_layout(scope, xs); + let (list2, list2_layout) = load_symbol_and_layout(scope, ys); let (function, closure, closure_layout) = function_details!(); @@ -4541,9 +4541,9 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } } ListMap3 { xs, ys, zs } => { - let (list1, list1_layout) = load_symbol_and_layout(scope, &xs); - let (list2, list2_layout) = load_symbol_and_layout(scope, &ys); - let (list3, list3_layout) = load_symbol_and_layout(scope, &zs); + let (list1, list1_layout) = load_symbol_and_layout(scope, xs); + let (list2, list2_layout) = load_symbol_and_layout(scope, ys); + let (list3, list3_layout) = load_symbol_and_layout(scope, zs); let (function, closure, closure_layout) = function_details!(); @@ -4587,10 +4587,10 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } } ListMap4 { xs, ys, zs, ws } => { - let (list1, list1_layout) = load_symbol_and_layout(scope, &xs); - let (list2, list2_layout) = load_symbol_and_layout(scope, &ys); - let (list3, list3_layout) = load_symbol_and_layout(scope, &zs); - let (list4, list4_layout) = load_symbol_and_layout(scope, &ws); + let (list1, list1_layout) = load_symbol_and_layout(scope, xs); + let (list2, list2_layout) = load_symbol_and_layout(scope, ys); + let (list3, list3_layout) = load_symbol_and_layout(scope, zs); + let (list4, list4_layout) = load_symbol_and_layout(scope, ws); let (function, closure, closure_layout) = function_details!(); @@ -4649,7 +4649,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } ListMapWithIndex { xs } => { // List.mapWithIndex : List before, (Nat, before -> after) -> List after - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); @@ -4678,7 +4678,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } ListKeepIf { xs } => { // List.keepIf : List elem, (elem -> Bool) -> List elem - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); @@ -4704,7 +4704,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } ListKeepOks { xs } => { // List.keepOks : List before, (before -> Result after *) -> List after - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); @@ -4744,7 +4744,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } ListKeepErrs { xs } => { // List.keepErrs : List before, (before -> Result * after) -> List after - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); @@ -4793,7 +4793,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } ListSortWith { xs } => { // List.sortWith : List a, (a, a -> Ordering) -> List a - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); @@ -4831,7 +4831,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } } ListAny { xs } => { - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); match list_layout { @@ -4855,7 +4855,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } } ListFindUnsafe { xs } => { - let (list, list_layout) = load_symbol_and_layout(scope, &xs); + let (list, list_layout) = load_symbol_and_layout(scope, xs); let (function, closure, closure_layout) = function_details!(); @@ -4886,8 +4886,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( } } DictWalk { xs, state } => { - let (dict, dict_layout) = load_symbol_and_layout(scope, &xs); - let (default, default_layout) = load_symbol_and_layout(scope, &state); + let (dict, dict_layout) = load_symbol_and_layout(scope, xs); + let (default, default_layout) = load_symbol_and_layout(scope, state); let (function, closure, closure_layout) = function_details!(); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 7e225772f5..def0d503a0 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -6596,7 +6596,7 @@ fn call_by_name_help<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: ret_layout, + ret_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6637,7 +6637,7 @@ fn call_by_name_help<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: ret_layout, + ret_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6691,7 +6691,7 @@ fn call_by_name_help<'a>( let call = self::Call { call_type: CallType::ByName { name: proc_name, - ret_layout: ret_layout, + ret_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index cf699dd62b..e1919a0567 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -444,7 +444,7 @@ mod test_parse { #[quickcheck] fn all_f64_values_parse(num: f64) { let string = num.to_string(); - if string.contains(".") { + if string.contains('.') { assert_parses_to(&string, Float(&string)); } else if num.is_nan() { assert_parses_to(&string, Expr::GlobalTag(&string)); From d18c09a21db0b33ad16e059191a73d266331e752 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 16:04:50 +0100 Subject: [PATCH 045/223] misc other clippy things --- cli/tests/cli_run.rs | 26 +++++++++++------------- docs/tests/insert_syntax_highlighting.rs | 12 ++++------- editor/src/editor/mvc/ed_model.rs | 12 ++++------- editor/src/editor/mvc/ed_update.rs | 2 +- 4 files changed, 21 insertions(+), 31 deletions(-) diff --git a/cli/tests/cli_run.rs b/cli/tests/cli_run.rs index 3251e3b48b..2a4d92ccb3 100644 --- a/cli/tests/cli_run.rs +++ b/cli/tests/cli_run.rs @@ -111,20 +111,18 @@ mod cli_run { } valgrind_out + } else if let Some(input_file) = input_file { + run_cmd( + file.with_file_name(executable_filename).to_str().unwrap(), + stdin, + &[input_file.to_str().unwrap()], + ) } else { - if let Some(input_file) = input_file { - run_cmd( - file.with_file_name(executable_filename).to_str().unwrap(), - stdin, - &[input_file.to_str().unwrap()], - ) - } else { - run_cmd( - file.with_file_name(executable_filename).to_str().unwrap(), - stdin, - &[], - ) - } + run_cmd( + file.with_file_name(executable_filename).to_str().unwrap(), + stdin, + &[], + ) }; if !&out.stdout.ends_with(expected_ending) { panic!( @@ -796,7 +794,7 @@ fn read_wasi_stdout(wasi_env: wasmer_wasi::WasiEnv) -> String { let mut buf = String::new(); stdout.read_to_string(&mut buf).unwrap(); - return buf; + buf } _ => todo!(), } diff --git a/docs/tests/insert_syntax_highlighting.rs b/docs/tests/insert_syntax_highlighting.rs index 1c33d8ba71..9812d76441 100644 --- a/docs/tests/insert_syntax_highlighting.rs +++ b/docs/tests/insert_syntax_highlighting.rs @@ -73,19 +73,15 @@ main = "Hello, world!" PathBuf::from([Uuid::new_v4().to_string(), ".roc".to_string()].join("")); let temp_file_full_path = temp_dir.path().join(temp_file_path_buf); - let mut file = File::create(temp_file_full_path.clone()).expect(&format!( - "Failed to create temporary file for path {:?}", - temp_file_full_path - )); + let mut file = File::create(temp_file_full_path.clone()).unwrap_or_else(|_| panic!("Failed to create temporary file for path {:?}", + temp_file_full_path)); let mut full_code_str = HELLO_WORLD.to_owned(); full_code_str.push_str("\n\n"); full_code_str.push_str(code_str); - writeln!(file, "{}", full_code_str).expect(&format!( - "Failed to write {:?} to file: {:?}", - HELLO_WORLD, file - )); + writeln!(file, "{}", full_code_str).unwrap_or_else(|_| panic!("Failed to write {:?} to file: {:?}", + HELLO_WORLD, file)); load_module(&temp_file_full_path) } diff --git a/editor/src/editor/mvc/ed_model.rs b/editor/src/editor/mvc/ed_model.rs index db0d92433b..85b91a4933 100644 --- a/editor/src/editor/mvc/ed_model.rs +++ b/editor/src/editor/mvc/ed_model.rs @@ -290,14 +290,10 @@ pub mod test_ed_model { PathBuf::from([Uuid::new_v4().to_string(), ".roc".to_string()].join("")); let temp_file_full_path = temp_dir.path().join(temp_file_path_buf); - let mut file = File::create(temp_file_full_path.clone()).expect(&format!( - "Failed to create temporary file for path {:?}", - temp_file_full_path - )); - writeln!(file, "{}", clean_code_str).expect(&format!( - "Failed to write {:?} to file: {:?}", - clean_code_str, file - )); + let mut file = File::create(temp_file_full_path.clone()).unwrap_or_else(|_| panic!("Failed to create temporary file for path {:?}", + temp_file_full_path)); + writeln!(file, "{}", clean_code_str).unwrap_or_else(|_| panic!("Failed to write {:?} to file: {:?}", + clean_code_str, file)); let loaded_module = load_module(&temp_file_full_path); diff --git a/editor/src/editor/mvc/ed_update.rs b/editor/src/editor/mvc/ed_update.rs index e44d22166e..fba3cd346b 100644 --- a/editor/src/editor/mvc/ed_update.rs +++ b/editor/src/editor/mvc/ed_update.rs @@ -1453,7 +1453,7 @@ pub mod test_ed_update { // add newlines like the editor's formatting would add them fn add_nls(lines: Vec) -> Vec { - let mut new_lines = lines.clone(); + let mut new_lines = lines; new_lines.append(&mut vec!["".to_owned(), "".to_owned()]); From f3cfd4d552c0c684c0d2476e52b75fc711cc9bd7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 16:25:59 +0100 Subject: [PATCH 046/223] fix formatting --- cli_utils/Cargo.lock | 25 ++---------------------- docs/tests/insert_syntax_highlighting.rs | 12 ++++++++---- editor/src/editor/mvc/ed_model.rs | 12 ++++++++---- 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/cli_utils/Cargo.lock b/cli_utils/Cargo.lock index f41f503d27..177699b420 100644 --- a/cli_utils/Cargo.lock +++ b/cli_utils/Cargo.lock @@ -2398,8 +2398,6 @@ name = "roc_build" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "libloading 0.7.1", "roc_builtins", @@ -2440,8 +2438,6 @@ name = "roc_can" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "roc_builtins", "roc_collections", "roc_module", @@ -2459,8 +2455,6 @@ dependencies = [ "bumpalo", "clap 3.0.0-beta.5", "const_format", - "im", - "im-rc", "inkwell 0.1.0", "libloading 0.7.1", "mimalloc", @@ -2562,8 +2556,6 @@ dependencies = [ "fs_extra", "futures", "glyph_brush", - "im", - "im-rc", "libc", "log", "nonempty", @@ -2599,8 +2591,6 @@ name = "roc_fmt" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "roc_collections", "roc_module", "roc_parse", @@ -2612,8 +2602,6 @@ name = "roc_gen_dev" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "object 0.26.2", "roc_builtins", "roc_collections", @@ -2632,20 +2620,13 @@ name = "roc_gen_llvm" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "morphic_lib", "roc_builtins", "roc_collections", "roc_module", "roc_mono", - "roc_problem", - "roc_region", - "roc_solve", "roc_std", - "roc_types", - "roc_unify", "target-lexicon", ] @@ -2654,6 +2635,7 @@ name = "roc_gen_wasm" version = "0.1.0" dependencies = [ "bumpalo", + "roc_builtins", "roc_collections", "roc_module", "roc_mono", @@ -2726,7 +2708,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "hashbrown 0.11.2", - "linked-hash-map", "morphic_lib", "roc_can", "roc_collections", @@ -2737,7 +2718,7 @@ dependencies = [ "roc_std", "roc_types", "roc_unify", - "ven_ena", + "static_assertions", "ven_graph", "ven_pretty", ] @@ -2773,8 +2754,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "distance", - "im", - "im-rc", "roc_can", "roc_collections", "roc_module", diff --git a/docs/tests/insert_syntax_highlighting.rs b/docs/tests/insert_syntax_highlighting.rs index 9812d76441..e211786673 100644 --- a/docs/tests/insert_syntax_highlighting.rs +++ b/docs/tests/insert_syntax_highlighting.rs @@ -73,15 +73,19 @@ main = "Hello, world!" PathBuf::from([Uuid::new_v4().to_string(), ".roc".to_string()].join("")); let temp_file_full_path = temp_dir.path().join(temp_file_path_buf); - let mut file = File::create(temp_file_full_path.clone()).unwrap_or_else(|_| panic!("Failed to create temporary file for path {:?}", - temp_file_full_path)); + let mut file = File::create(temp_file_full_path.clone()).unwrap_or_else(|_| { + panic!( + "Failed to create temporary file for path {:?}", + temp_file_full_path + ) + }); let mut full_code_str = HELLO_WORLD.to_owned(); full_code_str.push_str("\n\n"); full_code_str.push_str(code_str); - writeln!(file, "{}", full_code_str).unwrap_or_else(|_| panic!("Failed to write {:?} to file: {:?}", - HELLO_WORLD, file)); + writeln!(file, "{}", full_code_str) + .unwrap_or_else(|_| panic!("Failed to write {:?} to file: {:?}", HELLO_WORLD, file)); load_module(&temp_file_full_path) } diff --git a/editor/src/editor/mvc/ed_model.rs b/editor/src/editor/mvc/ed_model.rs index 85b91a4933..8749fb5f99 100644 --- a/editor/src/editor/mvc/ed_model.rs +++ b/editor/src/editor/mvc/ed_model.rs @@ -290,10 +290,14 @@ pub mod test_ed_model { PathBuf::from([Uuid::new_v4().to_string(), ".roc".to_string()].join("")); let temp_file_full_path = temp_dir.path().join(temp_file_path_buf); - let mut file = File::create(temp_file_full_path.clone()).unwrap_or_else(|_| panic!("Failed to create temporary file for path {:?}", - temp_file_full_path)); - writeln!(file, "{}", clean_code_str).unwrap_or_else(|_| panic!("Failed to write {:?} to file: {:?}", - clean_code_str, file)); + let mut file = File::create(temp_file_full_path.clone()).unwrap_or_else(|_| { + panic!( + "Failed to create temporary file for path {:?}", + temp_file_full_path + ) + }); + writeln!(file, "{}", clean_code_str) + .unwrap_or_else(|_| panic!("Failed to write {:?} to file: {:?}", clean_code_str, file)); let loaded_module = load_module(&temp_file_full_path); From a4ca6a31a643bacea790daa47a348625688887c8 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 08:17:59 -0800 Subject: [PATCH 047/223] Use Collection in Expr::Record and related places --- ast/src/lang/core/expr/expr_to_expr2.rs | 10 +++---- cli/src/repl/eval.rs | 27 +++++-------------- compiler/can/src/expr.rs | 10 +++---- compiler/can/src/operator.rs | 27 ++++++++----------- compiler/can/src/pattern.rs | 2 +- compiler/fmt/src/expr.rs | 26 ++++++++---------- compiler/parse/src/ast.rs | 24 +++++++++++------ compiler/parse/src/expr.rs | 26 ++++++++++-------- compiler/parse/src/pattern.rs | 5 +--- compiler/parse/tests/test_parse.rs | 36 +++++++++++++------------ 10 files changed, 86 insertions(+), 107 deletions(-) diff --git a/ast/src/lang/core/expr/expr_to_expr2.rs b/ast/src/lang/core/expr/expr_to_expr2.rs index d9eaf2cf18..00fa759f65 100644 --- a/ast/src/lang/core/expr/expr_to_expr2.rs +++ b/ast/src/lang/core/expr/expr_to_expr2.rs @@ -185,13 +185,12 @@ pub fn expr_to_expr2<'a>( RecordUpdate { fields, update: loc_update, - final_comments: _, } => { let (can_update, update_out) = expr_to_expr2(env, scope, &loc_update.value, loc_update.region); if let Expr2::Var(symbol) = &can_update { - match canonicalize_fields(env, scope, fields) { + match canonicalize_fields(env, scope, fields.items) { Ok((can_fields, mut output)) => { output.references.union_mut(update_out.references); @@ -236,14 +235,11 @@ pub fn expr_to_expr2<'a>( } } - Record { - fields, - final_comments: _, - } => { + Record(fields) => { if fields.is_empty() { (Expr2::EmptyRecord, Output::default()) } else { - match canonicalize_fields(env, scope, fields) { + match canonicalize_fields(env, scope, fields.items) { Ok((can_fields, output)) => ( Expr2::Record { record_var: env.var_store.fresh(), diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index 307b097419..b56200dc6f 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -7,7 +7,7 @@ use roc_module::operator::CalledVia; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::ProcLayout; use roc_mono::layout::{union_sorted_tags_help, Builtin, Layout, UnionLayout, UnionVariant}; -use roc_parse::ast::{AssignedField, Expr, StrLiteral}; +use roc_parse::ast::{AssignedField, Collection, Expr, StrLiteral}; use roc_region::all::{Located, Region}; use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable}; @@ -621,10 +621,7 @@ fn struct_to_ast<'a>( let output = env.arena.alloc([loc_field]); - Expr::Record { - fields: output, - final_comments: &[], - } + Expr::Record(Collection::with_items(output)) } else { debug_assert_eq!(sorted_fields.len(), field_layouts.len()); @@ -658,10 +655,7 @@ fn struct_to_ast<'a>( let output = output.into_bump_slice(); - Expr::Record { - fields: output, - final_comments: &[], - } + Expr::Record(Collection::with_items(output)) } } @@ -735,10 +729,7 @@ fn bool_to_ast<'a>(env: &Env<'a, '_>, value: bool, content: &Content) -> Expr<'a region: Region::zero(), }; - Expr::Record { - fields: arena.alloc([loc_assigned_field]), - final_comments: arena.alloc([]), - } + Expr::Record(Collection::with_items(arena.alloc([loc_assigned_field]))) } FlatType::TagUnion(tags, _) if tags.len() == 1 => { let (tag_name, payload_vars) = unpack_single_element_tag_union(env.subs, *tags); @@ -850,10 +841,7 @@ fn byte_to_ast<'a>(env: &Env<'a, '_>, value: u8, content: &Content) -> Expr<'a> region: Region::zero(), }; - Expr::Record { - fields: arena.alloc([loc_assigned_field]), - final_comments: &[], - } + Expr::Record(Collection::with_items(arena.alloc([loc_assigned_field]))) } FlatType::TagUnion(tags, _) if tags.len() == 1 => { let (tag_name, payload_vars) = unpack_single_element_tag_union(env.subs, *tags); @@ -972,10 +960,7 @@ fn num_to_ast<'a>(env: &Env<'a, '_>, num_expr: Expr<'a>, content: &Content) -> E region: Region::zero(), }; - Expr::Record { - fields: arena.alloc([loc_assigned_field]), - final_comments: arena.alloc([]), - } + Expr::Record(Collection::with_items(arena.alloc([loc_assigned_field]))) } FlatType::TagUnion(tags, _) => { // This was a single-tag union that got unwrapped at runtime. diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 4e96b58e51..768bba827e 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -228,14 +228,11 @@ pub fn canonicalize_expr<'a>( (answer, Output::default()) } - ast::Expr::Record { - fields, - final_comments: _, - } => { + ast::Expr::Record(fields) => { if fields.is_empty() { (EmptyRecord, Output::default()) } else { - match canonicalize_fields(env, var_store, scope, region, fields) { + match canonicalize_fields(env, var_store, scope, region, fields.items) { Ok((can_fields, output)) => ( Record { record_var: var_store.fresh(), @@ -261,12 +258,11 @@ pub fn canonicalize_expr<'a>( ast::Expr::RecordUpdate { fields, update: loc_update, - final_comments: _, } => { let (can_update, update_out) = canonicalize_expr(env, var_store, scope, loc_update.region, &loc_update.value); if let Var(symbol) = &can_update.value { - match canonicalize_fields(env, var_store, scope, region, fields) { + match canonicalize_fields(env, var_store, scope, region, fields.items) { Ok((can_fields, mut output)) => { output.references = output.references.union(update_out.references); diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index 36b790764d..4faecdf9bf 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -6,7 +6,7 @@ use roc_module::ident::ModuleName; use roc_module::operator::BinOp::Pizza; use roc_module::operator::{BinOp, CalledVia}; use roc_parse::ast::Expr::{self, *}; -use roc_parse::ast::{AssignedField, Def, WhenBranch}; +use roc_parse::ast::{AssignedField, Collection, Def, WhenBranch}; use roc_region::all::{Located, Region}; // BinOp precedence logic adapted from Gluon by Markus Westerlind @@ -164,10 +164,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a value, }) } - Record { - fields, - final_comments, - } => { + Record(fields) => { let mut new_fields = Vec::with_capacity_in(fields.len(), arena); for field in fields.iter() { @@ -183,18 +180,14 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a arena.alloc(Located { region: loc_expr.region, - value: Record { - fields: new_fields, - final_comments, - }, + value: Record(Collection { + items: new_fields, + final_comments: fields.final_comments, + }), }) } - RecordUpdate { - fields, - update, - final_comments, - } => { + RecordUpdate { fields, update } => { // NOTE the `update` field is always a `Var { .. }` and does not need to be desugared let mut new_fields = Vec::with_capacity_in(fields.len(), arena); @@ -213,8 +206,10 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a region: loc_expr.region, value: RecordUpdate { update: *update, - fields: new_fields, - final_comments, + fields: Collection { + items: new_fields, + final_comments: fields.final_comments, + }, }, }) } diff --git a/compiler/can/src/pattern.rs b/compiler/can/src/pattern.rs index adc853bd69..01f0c55862 100644 --- a/compiler/can/src/pattern.rs +++ b/compiler/can/src/pattern.rs @@ -246,7 +246,7 @@ pub fn canonicalize_pattern<'a>( let mut destructs = Vec::with_capacity(patterns.len()); let mut opt_erroneous = None; - for loc_pattern in *patterns { + for loc_pattern in patterns.iter() { match loc_pattern.value { Identifier(label) => { match scope.introduce( diff --git a/compiler/fmt/src/expr.rs b/compiler/fmt/src/expr.rs index 49a0f5f937..fd4d43e821 100644 --- a/compiler/fmt/src/expr.rs +++ b/compiler/fmt/src/expr.rs @@ -5,7 +5,9 @@ use crate::spaces::{add_spaces, fmt_comments_only, fmt_spaces, newline, NewlineA use bumpalo::collections::String; use roc_module::operator::{self, BinOp}; use roc_parse::ast::StrSegment; -use roc_parse::ast::{AssignedField, Base, CommentOrNewline, Expr, Pattern, WhenBranch}; +use roc_parse::ast::{ + AssignedField, Base, Collection, CommentOrNewline, Expr, Pattern, WhenBranch, +}; use roc_region::all::Located; impl<'a> Formattable<'a> for Expr<'a> { @@ -98,7 +100,7 @@ impl<'a> Formattable<'a> for Expr<'a> { .any(|loc_pattern| loc_pattern.is_multiline()) } - Record { fields, .. } => fields.iter().any(|loc_field| loc_field.is_multiline()), + Record(fields) => fields.iter().any(|loc_field| loc_field.is_multiline()), RecordUpdate { fields, .. } => fields.iter().any(|loc_field| loc_field.is_multiline()), } } @@ -250,18 +252,11 @@ impl<'a> Formattable<'a> for Expr<'a> { buf.push_str(string); } - Record { - fields, - final_comments, - } => { - fmt_record(buf, None, fields, final_comments, indent); + Record(fields) => { + fmt_record(buf, None, *fields, indent); } - RecordUpdate { - fields, - update, - final_comments, - } => { - fmt_record(buf, Some(*update), fields, final_comments, indent); + RecordUpdate { update, fields } => { + fmt_record(buf, Some(*update), *fields, indent); } Closure(loc_patterns, loc_ret) => { fmt_closure(buf, loc_patterns, loc_ret, indent); @@ -917,10 +912,11 @@ fn fmt_backpassing<'a>( fn fmt_record<'a>( buf: &mut String<'a>, update: Option<&'a Located>>, - loc_fields: &[Located>>], - final_comments: &'a [CommentOrNewline<'a>], + fields: Collection<'a, Located>>>, indent: u16, ) { + let loc_fields = fields.items; + let final_comments = fields.final_comments; if loc_fields.is_empty() && final_comments.iter().all(|c| c.is_newline()) { buf.push_str("{}"); } else { diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 6d31884d56..02fd3acb03 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -25,6 +25,18 @@ impl<'a, T> Collection<'a, T> { final_comments: &[], } } + + pub fn iter(&self) -> impl Iterator { + self.items.iter() + } + + pub fn len(&self) -> usize { + self.items.len() + } + + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } } #[derive(Clone, Debug, PartialEq)] @@ -122,14 +134,10 @@ pub enum Expr<'a> { RecordUpdate { update: &'a Loc>, - fields: &'a [Loc>>], - final_comments: &'a &'a [CommentOrNewline<'a>], + fields: Collection<'a, Loc>>>, }, - Record { - fields: &'a [Loc>>], - final_comments: &'a [CommentOrNewline<'a>], - }, + Record(Collection<'a, Loc>>>), // Lookups Var { @@ -257,7 +265,6 @@ pub enum TypeAnnotation<'a> { /// The row type variable in an open record, e.g. the `r` in `{ name: Str }r`. /// This is None if it's a closed record annotation like `{ name: Str }`. ext: Option<&'a Loc>>, - // final_comments: &'a [CommentOrNewline<'a>], }, /// A tag union, e.g. `[ @@ -357,10 +364,11 @@ pub enum Pattern<'a> { GlobalTag(&'a str), PrivateTag(&'a str), Apply(&'a Loc>, &'a [Loc>]), + /// This is Loc rather than Loc so we can record comments /// around the destructured names, e.g. { x ### x does stuff ###, y } /// In practice, these patterns will always be Identifier - RecordDestructure(&'a [Loc>]), + RecordDestructure(Collection<'a, Loc>>), /// A required field pattern, e.g. { x: Just 0 } -> ... /// Can only occur inside of a RecordDestructure diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index ad3b94f7f6..d2f7b24487 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -1,4 +1,6 @@ -use crate::ast::{AssignedField, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation}; +use crate::ast::{ + AssignedField, Collection, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation, +}; use crate::blankspace::{space0_after_e, space0_around_ee, space0_before_e, space0_e}; use crate::ident::{lowercase_ident, parse_ident, Ident}; use crate::keyword; @@ -1446,10 +1448,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result expr_to_pattern_help(arena, sub_expr), - Expr::Record { - fields, - final_comments: _, - } => { + Expr::Record(fields) => { let mut loc_patterns = Vec::with_capacity_in(fields.len(), arena); for loc_assigned_field in fields.iter() { @@ -1459,7 +1458,10 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result Ok(Pattern::FloatLiteral(string)), @@ -2312,13 +2314,15 @@ fn record_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EExpr<' let mut value = match opt_update { Some(update) => Expr::RecordUpdate { update: &*arena.alloc(update), - fields: loc_assigned_fields_with_comments.value.0.into_bump_slice(), - final_comments: arena.alloc(loc_assigned_fields_with_comments.value.1), + fields: Collection { + items: loc_assigned_fields_with_comments.value.0.into_bump_slice(), + final_comments: arena.alloc(loc_assigned_fields_with_comments.value.1), + }, }, - None => Expr::Record { - fields: loc_assigned_fields_with_comments.value.0.into_bump_slice(), + None => Expr::Record(Collection { + items: loc_assigned_fields_with_comments.value.0.into_bump_slice(), final_comments: loc_assigned_fields_with_comments.value.1, - }, + }), }; // there can be field access, e.g. `{ x : 4 }.x` diff --git a/compiler/parse/src/pattern.rs b/compiler/parse/src/pattern.rs index a855537d4f..6f1dfa3351 100644 --- a/compiler/parse/src/pattern.rs +++ b/compiler/parse/src/pattern.rs @@ -331,10 +331,7 @@ fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRec ) .parse(arena, state)?; - // TODO - let _unused = fields.final_comments; - - let result = Pattern::RecordDestructure(fields.items); + let result = Pattern::RecordDestructure(fields); Ok((MadeProgress, result, state)) } diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index cf699dd62b..4e35c1b007 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -460,10 +460,7 @@ mod test_parse { #[test] fn empty_record() { let arena = Bump::new(); - let expected = Record { - fields: &[], - final_comments: &[], - }; + let expected = Record(Collection::empty()); let actual = parse_expr_with(&arena, "{}"); assert_eq!(Ok(expected), actual); @@ -493,8 +490,7 @@ mod test_parse { let update_target = Located::new(0, 0, 2, 13, var); let expected = RecordUpdate { update: &*arena.alloc(update_target), - fields, - final_comments: &(&[] as &[_]), + fields: Collection::with_items(fields), }; let actual = parse_expr_with(&arena, "{ Foo.Bar.baz & x: 5, y: 0 }"); @@ -526,10 +522,7 @@ mod test_parse { Located::new(0, 0, 1, 26, label1), Located::new(0, 0, 28, 32, label2), ]; - let expected = Record { - fields, - final_comments: &[], - }; + let expected = Record(Collection::with_items(fields)); let actual = parse_expr_with(&arena, "{x : if True then 1 else 2, y: 3 }"); assert_eq!(Ok(expected), actual); @@ -1897,7 +1890,13 @@ mod test_parse { Located::new(1, 1, 5, 7, Identifier("y")) ]; let def1 = Def::Body( - arena.alloc(Located::new(1, 1, 0, 8, RecordDestructure(&fields))), + arena.alloc(Located::new( + 1, + 1, + 0, + 8, + RecordDestructure(Collection::with_items(&fields)), + )), arena.alloc(Located::new(1, 1, 11, 12, Num("5"))), ); let loc_def1 = &*arena.alloc(Located::new(1, 1, 0, 12, def1)); @@ -2028,10 +2027,7 @@ mod test_parse { let inner_backpassing = { let identifier_z = Located::new(2, 2, 0, 1, Identifier("z")); - let empty_record = Record { - fields: &[], - final_comments: &[], - }; + let empty_record = Record(Collection::empty()); let loc_empty_record = Located::new(2, 2, 5, 7, empty_record); let var_x = Var { @@ -2950,7 +2946,10 @@ mod test_parse { let arena = Bump::new(); let newlines = &[Newline]; let identifiers1 = &[Located::new(1, 1, 3, 4, Identifier("y"))]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(RecordDestructure(identifiers1)), newlines); + let pattern1 = Pattern::SpaceBefore( + arena.alloc(RecordDestructure(Collection::with_items(identifiers1))), + newlines, + ); let loc_pattern1 = Located::new(1, 1, 1, 6, pattern1); let expr1 = Num("2"); let loc_expr1 = Located::new(1, 1, 10, 11, expr1); @@ -2964,7 +2963,10 @@ mod test_parse { Located::new(2, 2, 3, 4, Identifier("z")), Located::new(2, 2, 6, 7, Identifier("w")), ]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(RecordDestructure(identifiers2)), newlines); + let pattern2 = Pattern::SpaceBefore( + arena.alloc(RecordDestructure(Collection::with_items(identifiers2))), + newlines, + ); let loc_pattern2 = Located::new(2, 2, 1, 9, pattern2); let expr2 = Num("4"); let loc_expr2 = Located::new(2, 2, 13, 14, expr2); From d63405d82483fa87bc7c0b1187c7a19c798599b1 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 08:35:38 -0800 Subject: [PATCH 048/223] Make Expr::List use a Collection --- ast/src/lang/core/expr/expr_to_expr2.rs | 2 +- cli/src/repl/eval.rs | 15 ++-------- compiler/can/src/expr.rs | 4 +-- compiler/can/src/operator.rs | 11 +++----- compiler/fmt/src/expr.rs | 18 ++++-------- compiler/parse/src/ast.rs | 5 +--- compiler/parse/src/expr.rs | 4 +-- compiler/parse/tests/test_parse.rs | 37 ++++++++----------------- 8 files changed, 29 insertions(+), 67 deletions(-) diff --git a/ast/src/lang/core/expr/expr_to_expr2.rs b/ast/src/lang/core/expr/expr_to_expr2.rs index 00fa759f65..d1589a83b6 100644 --- a/ast/src/lang/core/expr/expr_to_expr2.rs +++ b/ast/src/lang/core/expr/expr_to_expr2.rs @@ -132,7 +132,7 @@ pub fn expr_to_expr2<'a>( Str(literal) => flatten_str_literal(env, scope, literal), - List { items, .. } => { + List(items) => { let mut output = Output::default(); let output_ref = &mut output; diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index b56200dc6f..1abb0f2f07 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -133,10 +133,7 @@ fn jit_to_ast_help<'a>( ), Layout::Builtin(Builtin::EmptyList) => { Ok(run_jit_function!(lib, main_fn_name, &'static str, |_| { - Expr::List { - items: &[], - final_comments: &[], - } + Expr::List(Collection::empty()) })) } Layout::Builtin(Builtin::List(elem_layout)) => Ok(run_jit_function!( @@ -431,10 +428,7 @@ fn ptr_to_ast<'a>( num_to_ast(env, number_literal_to_ast(env.arena, num), content) } - Layout::Builtin(Builtin::EmptyList) => Expr::List { - items: &[], - final_comments: &[], - }, + Layout::Builtin(Builtin::EmptyList) => Expr::List(Collection::empty()), Layout::Builtin(Builtin::List(elem_layout)) => { // Turn the (ptr, len) wrapper struct into actual ptr and len values. let len = unsafe { *(ptr.offset(env.ptr_bytes as isize) as *const usize) }; @@ -522,10 +516,7 @@ fn list_to_ast<'a>( let output = output.into_bump_slice(); - Expr::List { - items: output, - final_comments: &[], - } + Expr::List(Collection::with_items(output)) } fn single_tag_union_to_ast<'a>( diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 768bba827e..098ad7926b 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -303,9 +303,7 @@ pub fn canonicalize_expr<'a>( } } ast::Expr::Str(literal) => flatten_str_literal(env, var_store, scope, literal), - ast::Expr::List { - items: loc_elems, .. - } => { + ast::Expr::List(loc_elems) => { if loc_elems.is_empty() { ( List { diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index 4faecdf9bf..98e8a1cba1 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -144,20 +144,17 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a arena.alloc(Located { region, value }) } - List { - items, - final_comments, - } => { + List(items) => { let mut new_items = Vec::with_capacity_in(items.len(), arena); for item in items.iter() { new_items.push(desugar_expr(arena, item)); } let new_items = new_items.into_bump_slice(); - let value: Expr<'a> = List { + let value: Expr<'a> = List(Collection { items: new_items, - final_comments, - }; + final_comments: items.final_comments, + }); arena.alloc(Located { region: loc_expr.region, diff --git a/compiler/fmt/src/expr.rs b/compiler/fmt/src/expr.rs index fd4d43e821..5e028c10ac 100644 --- a/compiler/fmt/src/expr.rs +++ b/compiler/fmt/src/expr.rs @@ -41,7 +41,7 @@ impl<'a> Formattable<'a> for Expr<'a> { // These expressions always have newlines Defs(_, _) | When(_, _) => true, - List { items, .. } => items.iter().any(|loc_expr| loc_expr.is_multiline()), + List(items) => items.iter().any(|loc_expr| loc_expr.is_multiline()), Str(literal) => { use roc_parse::ast::StrLiteral::*; @@ -290,11 +290,8 @@ impl<'a> Formattable<'a> for Expr<'a> { fmt_if(buf, branches, final_else, self.is_multiline(), indent); } When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent), - List { - items, - final_comments, - } => { - fmt_list(buf, items, final_comments, indent); + List(items) => { + fmt_list(buf, *items, indent); } BinOps(lefts, right) => fmt_bin_ops(buf, lefts, right, false, parens, indent), UnaryOp(sub_expr, unary_op) => { @@ -411,12 +408,9 @@ fn fmt_bin_ops<'a>( loc_right_side.format_with_options(buf, apply_needs_parens, Newlines::Yes, indent); } -fn fmt_list<'a>( - buf: &mut String<'a>, - loc_items: &[&Located>], - final_comments: &'a [CommentOrNewline<'a>], - indent: u16, -) { +fn fmt_list<'a>(buf: &mut String<'a>, items: Collection<'a, &Located>>, indent: u16) { + let loc_items = items.items; + let final_comments = items.final_comments; if loc_items.is_empty() && final_comments.iter().all(|c| c.is_newline()) { buf.push_str("[]"); } else { diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 02fd3acb03..d9661f2f37 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -127,10 +127,7 @@ pub enum Expr<'a> { AccessorFunction(&'a str), // Collection Literals - List { - items: &'a [&'a Loc>], - final_comments: &'a [CommentOrNewline<'a>], - }, + List(Collection<'a, &'a Loc>>), RecordUpdate { update: &'a Loc>, diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index d2f7b24487..ad14d0dfe4 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -2173,10 +2173,10 @@ fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EList<'a> allocated.push(parsed_elem); } - let expr = Expr::List { + let expr = Expr::List(Collection { items: allocated.into_bump_slice(), final_comments: elements.final_comments, - }; + }); Ok((MadeProgress, expr, state)) } diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 4e35c1b007..25d10eb092 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -1166,10 +1166,7 @@ mod test_parse { #[test] fn empty_list() { let arena = Bump::new(); - let expected = List { - items: &[], - final_comments: &[], - }; + let expected = List(Collection::empty()); let actual = parse_expr_with(&arena, "[]"); assert_eq!(Ok(expected), actual); @@ -1179,10 +1176,7 @@ mod test_parse { fn spaces_inside_empty_list() { // This is a regression test! let arena = Bump::new(); - let expected = List { - items: &[], - final_comments: &[], - }; + let expected = List(Collection::empty()); let actual = parse_expr_with(&arena, "[ ]"); assert_eq!(Ok(expected), actual); @@ -1191,10 +1185,10 @@ mod test_parse { #[test] fn newline_inside_empty_list() { let arena = Bump::new(); - let expected = List { + let expected = List(Collection { items: &[], final_comments: &[Newline], - }; + }); let actual = parse_expr_with(&arena, "[\n]"); assert_eq!(Ok(expected), actual); @@ -1203,10 +1197,10 @@ mod test_parse { #[test] fn comment_inside_empty_list() { let arena = Bump::new(); - let expected = List { + let expected = List(Collection { items: &[], final_comments: &[LineComment("comment")], - }; + }); let actual = parse_expr_with(&arena, "[#comment\n]"); assert_eq!(Ok(expected), actual); @@ -1216,10 +1210,7 @@ mod test_parse { fn packed_singleton_list() { let arena = Bump::new(); let items = &[&*arena.alloc(Located::new(0, 0, 1, 2, Num("1")))]; - let expected = List { - items, - final_comments: &[], - }; + let expected = List(Collection::with_items(items)); let actual = parse_expr_with(&arena, "[1]"); assert_eq!(Ok(expected), actual); @@ -1229,10 +1220,7 @@ mod test_parse { fn spaced_singleton_list() { let arena = Bump::new(); let items = &[&*arena.alloc(Located::new(0, 0, 2, 3, Num("1")))]; - let expected = List { - items, - final_comments: &[], - }; + let expected = List(Collection::with_items(items)); let actual = parse_expr_with(&arena, "[ 1 ]"); assert_eq!(Ok(expected), actual); @@ -1247,10 +1235,7 @@ mod test_parse { )); let item = Expr::SpaceBefore(item, arena.alloc([Newline])); let items = [&*arena.alloc(Located::new(1, 1, 0, 1, item))]; - let expected = List { - items: &items, - final_comments: &[], - }; + let expected = List(Collection::with_items(&items)); let actual = parse_expr_with(&arena, "[\n1\n]"); assert_eq!(Ok(expected), actual); @@ -2111,8 +2096,8 @@ mod test_parse { let apply = Expr::Apply( arena.alloc(Located::new(0, 0, 8, 17, var_list_map2)), bumpalo::vec![ in &arena; - &*arena.alloc(Located::new(0, 0, 18, 20, Expr::List{ items: &[], final_comments: &[] })), - &*arena.alloc(Located::new(0, 0, 21, 23, Expr::List{ items: &[], final_comments: &[] })), + &*arena.alloc(Located::new(0, 0, 18, 20, Expr::List(Collection::empty()))), + &*arena.alloc(Located::new(0, 0, 21, 23, Expr::List(Collection::empty()))), ] .into_bump_slice(), CalledVia::Space, From 1fabc64fdf77dd413cdd3012ee7ffcae419aa593 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 10:20:10 -0800 Subject: [PATCH 049/223] Use Collection in Expr::TagUnion --- ast/src/lang/core/types.rs | 2 +- compiler/can/src/annotation.rs | 2 +- compiler/fmt/src/annotation.rs | 49 ++++++++------------------- compiler/load/src/docs.rs | 8 ++--- compiler/parse/src/ast.rs | 3 +- compiler/parse/src/type_annotation.rs | 6 +--- 6 files changed, 21 insertions(+), 49 deletions(-) diff --git a/ast/src/lang/core/types.rs b/ast/src/lang/core/types.rs index 3cb2a03f8f..8cb34c1089 100644 --- a/ast/src/lang/core/types.rs +++ b/ast/src/lang/core/types.rs @@ -428,7 +428,7 @@ pub fn to_type2<'a>( Type2::Record(field_types, ext_type) } TagUnion { tags, ext, .. } => { - let tag_types_vec = can_tags(env, scope, references, tags, region); + let tag_types_vec = can_tags(env, scope, references, tags.items, region); let tag_types = PoolVec::with_capacity(tag_types_vec.len() as u32, env.pool); diff --git a/compiler/can/src/annotation.rs b/compiler/can/src/annotation.rs index 17e0441542..a649bb850c 100644 --- a/compiler/can/src/annotation.rs +++ b/compiler/can/src/annotation.rs @@ -417,7 +417,7 @@ fn can_annotation_help( TagUnion { tags, ext, .. } => { let tag_types = can_tags( env, - tags, + tags.items, region, scope, var_store, diff --git a/compiler/fmt/src/annotation.rs b/compiler/fmt/src/annotation.rs index 4e73d91b7e..41170c7f48 100644 --- a/compiler/fmt/src/annotation.rs +++ b/compiler/fmt/src/annotation.rs @@ -1,6 +1,6 @@ use crate::spaces::{fmt_comments_only, fmt_spaces, newline, NewlineAt, INDENT}; use bumpalo::collections::String; -use roc_parse::ast::{AssignedField, Collection, Expr, Tag, TypeAnnotation}; +use roc_parse::ast::{AssignedField, Expr, Tag, TypeAnnotation}; use roc_region::all::Located; /// Does an AST node need parens around it? @@ -81,9 +81,9 @@ where } macro_rules! format_sequence { - ($buf: expr, $indent:expr, $start:expr, $end:expr, $items:expr, $final_comments:expr, $newline:expr, $t:ident) => { - let is_multiline = - $items.iter().any(|item| item.value.is_multiline()) || !$final_comments.is_empty(); + ($buf: expr, $indent:expr, $start:expr, $end:expr, $items:expr, $newline:expr, $t:ident) => { + let is_multiline = $items.iter().any(|item| item.value.is_multiline()) + || !$items.final_comments.is_empty(); if is_multiline { let braces_indent = $indent + INDENT; @@ -138,7 +138,12 @@ macro_rules! format_sequence { } } } - fmt_comments_only($buf, $final_comments.iter(), NewlineAt::Top, item_indent); + fmt_comments_only( + $buf, + $items.final_comments.iter(), + NewlineAt::Top, + item_indent, + ); newline($buf, braces_indent); $buf.push($end); } else { @@ -192,11 +197,7 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> { fields.items.iter().any(|field| field.value.is_multiline()) } - TagUnion { - tags, - ext, - final_comments: _, - } => { + TagUnion { tags, ext } => { match ext { Some(ann) if ann.value.is_multiline() => return true, _ => {} @@ -279,36 +280,16 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> { BoundVariable(v) => buf.push_str(v), Wildcard => buf.push('*'), - TagUnion { - tags, - ext, - final_comments, - } => { - format_sequence!(buf, indent, '[', ']', tags, final_comments, newlines, Tag); + TagUnion { tags, ext } => { + format_sequence!(buf, indent, '[', ']', tags, newlines, Tag); if let Some(loc_ext_ann) = *ext { loc_ext_ann.value.format(buf, indent); } } - Record { - fields: - Collection { - items, - final_comments, - }, - ext, - } => { - format_sequence!( - buf, - indent, - '{', - '}', - items, - final_comments, - newlines, - AssignedField - ); + Record { fields, ext } => { + format_sequence!(buf, indent, '{', '}', fields, newlines, AssignedField); if let Some(loc_ext_ann) = *ext { loc_ext_ann.value.format(buf, indent); diff --git a/compiler/load/src/docs.rs b/compiler/load/src/docs.rs index 0cbc74ea83..edadfbcd5b 100644 --- a/compiler/load/src/docs.rs +++ b/compiler/load/src/docs.rs @@ -235,16 +235,12 @@ fn generate_entry_doc<'a>( fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) -> TypeAnnotation { match type_annotation { - ast::TypeAnnotation::TagUnion { - tags, - ext, - final_comments: _, - } => { + ast::TypeAnnotation::TagUnion { tags, ext } => { let mut tags_to_render: Vec = Vec::new(); let mut any_tags_are_private = false; - for tag in tags { + for tag in tags.iter() { match tag_to_doc(in_func_type_ann, tag.value) { None => { any_tags_are_private = true; diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index d9661f2f37..797c360018 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -266,11 +266,10 @@ pub enum TypeAnnotation<'a> { /// A tag union, e.g. `[ TagUnion { - tags: &'a [Loc>], /// The row type variable in an open tag union, e.g. the `a` in `[ Foo, Bar ]a`. /// This is None if it's a closed tag union like `[ Foo, Bar]`. ext: Option<&'a Loc>>, - final_comments: &'a [CommentOrNewline<'a>], + tags: Collection<'a, Loc>>, }, /// The `*` type variable, e.g. in (List *) diff --git a/compiler/parse/src/type_annotation.rs b/compiler/parse/src/type_annotation.rs index 40628eb622..29065c5ed6 100644 --- a/compiler/parse/src/type_annotation.rs +++ b/compiler/parse/src/type_annotation.rs @@ -40,11 +40,7 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ET ))) .parse(arena, state)?; - let result = TypeAnnotation::TagUnion { - tags: tags.items, - ext, - final_comments: tags.final_comments, - }; + let result = TypeAnnotation::TagUnion { tags, ext }; Ok((MadeProgress, result, state)) } From 8d7c252fce4fd33ec54e447b848edc4c62e72b82 Mon Sep 17 00:00:00 2001 From: Theo Felippe Date: Sat, 13 Nov 2021 18:02:58 +0000 Subject: [PATCH 050/223] implemented Str.trimRight --- compiler/builtins/bitcode/src/main.zig | 1 + compiler/builtins/bitcode/src/str.zig | 107 ++++++++++++++++++++++++ compiler/builtins/src/bitcode.rs | 1 + compiler/builtins/src/std.rs | 7 ++ compiler/can/src/builtins.rs | 6 ++ compiler/gen_llvm/src/llvm/build.rs | 7 ++ compiler/gen_llvm/src/llvm/build_str.rs | 10 +++ compiler/gen_wasm/src/low_level.rs | 2 +- compiler/module/src/low_level.rs | 2 + compiler/module/src/symbol.rs | 1 + compiler/mono/src/borrow.rs | 1 + compiler/test_gen/src/gen_str.rs | 93 ++++++++++++++++++++ 12 files changed, 237 insertions(+), 1 deletion(-) diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index 374aaa7bc5..c270263b37 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -127,6 +127,7 @@ comptime { exportStrFn(str.repeat, "repeat"); exportStrFn(str.strTrim, "trim"); exportStrFn(str.strTrimLeft, "trim_left"); + exportStrFn(str.strTrimRight, "trim_right"); inline for (INTEGERS) |T| { str.exportFromInt(T, ROC_BUILTINS ++ "." ++ STR ++ ".from_int."); diff --git a/compiler/builtins/bitcode/src/str.zig b/compiler/builtins/bitcode/src/str.zig index 8eb369b308..474b716faf 100644 --- a/compiler/builtins/bitcode/src/str.zig +++ b/compiler/builtins/bitcode/src/str.zig @@ -1584,6 +1584,42 @@ pub fn strTrimLeft(string: RocStr) callconv(.C) RocStr { return RocStr.empty(); } +pub fn strTrimRight(string: RocStr) callconv(.C) RocStr { + if (string.str_bytes) |bytes_ptr| { + const leading_bytes = countLeadingWhitespaceBytes(string); + const trailing_bytes = countTrailingWhitespaceBytes(string); + const original_len = string.len(); + + if (original_len == trailing_bytes) { + string.deinit(); + return RocStr.empty(); + } + + const new_len = original_len - trailing_bytes; + + const small_or_shared = new_len <= SMALL_STR_MAX_LENGTH or !string.isRefcountOne(); + if (small_or_shared) { + return RocStr.init(string.asU8ptr(), new_len); + } + + // nonempty, large, and unique: + + var i: usize = 0; + while (i < new_len) : (i += 1) { + const dest = bytes_ptr + i; + const source = dest; + @memcpy(dest, source, 1); + } + + var new_string = string; + new_string.str_len = new_len; + + return new_string; + } + + return RocStr.empty(); +} + fn countLeadingWhitespaceBytes(string: RocStr) usize { var byte_count: usize = 0; @@ -1820,6 +1856,77 @@ test "strTrimLeft: small to small" { try expect(trimmed.isSmallStr()); } +test "strTrimRight: empty" { + const trimmedEmpty = strTrimRight(RocStr.empty()); + try expect(trimmedEmpty.eq(RocStr.empty())); +} + +test "strTrimRight: blank" { + const original_bytes = " "; + const original = RocStr.init(original_bytes, original_bytes.len); + defer original.deinit(); + + const trimmed = strTrimRight(original); + + try expect(trimmed.eq(RocStr.empty())); +} + +test "strTrimRight: large to large" { + const original_bytes = " hello giant world "; + const original = RocStr.init(original_bytes, original_bytes.len); + defer original.deinit(); + + try expect(!original.isSmallStr()); + + const expected_bytes = " hello giant world"; + const expected = RocStr.init(expected_bytes, expected_bytes.len); + defer expected.deinit(); + + try expect(!expected.isSmallStr()); + + const trimmed = strTrimRight(original); + + try expect(trimmed.eq(expected)); +} + +test "strTrimRight: large to small" { + const original_bytes = " hello world "; + const original = RocStr.init(original_bytes, original_bytes.len); + defer original.deinit(); + + try expect(!original.isSmallStr()); + + const expected_bytes = " hello world"; + const expected = RocStr.init(expected_bytes, expected_bytes.len); + defer expected.deinit(); + + try expect(expected.isSmallStr()); + + const trimmed = strTrimRight(original); + + try expect(trimmed.eq(expected)); + try expect(trimmed.isSmallStr()); +} + +test "strTrimRight: small to small" { + const original_bytes = " hello world "; + const original = RocStr.init(original_bytes, original_bytes.len); + defer original.deinit(); + + try expect(original.isSmallStr()); + + const expected_bytes = " hello world"; + const expected = RocStr.init(expected_bytes, expected_bytes.len); + defer expected.deinit(); + + try expect(expected.isSmallStr()); + + const trimmed = strTrimRight(original); + + try expect(trimmed.eq(expected)); + try expect(trimmed.isSmallStr()); +} + test "ReverseUtf8View: hello world" { const original_bytes = "hello world"; const expected_bytes = "dlrow olleh"; diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index f8ad6f920f..5197afebbf 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -149,6 +149,7 @@ pub const STR_FROM_UTF8_RANGE: &str = "roc_builtins.str.from_utf8_range"; pub const STR_REPEAT: &str = "roc_builtins.str.repeat"; pub const STR_TRIM: &str = "roc_builtins.str.trim"; pub const STR_TRIM_LEFT: &str = "roc_builtins.str.trim_left"; +pub const STR_TRIM_RIGHT: &str = "roc_builtins.str.trim_right"; pub const DICT_HASH: &str = "roc_builtins.dict.hash"; pub const DICT_HASH_STR: &str = "roc_builtins.dict.hash_str"; diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index dab48890e3..0f8d1fe154 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -639,6 +639,13 @@ pub fn types() -> MutMap { Box::new(str_type()) ); + // trimRight : Str -> Str + add_top_level_function_type!( + Symbol::STR_TRIM_RIGHT, + vec![str_type()], + Box::new(str_type()) + ); + // trim : Str -> Str add_top_level_function_type!(Symbol::STR_TRIM, vec![str_type()], Box::new(str_type())); diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 25c4e9b1d7..924e0f6567 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -69,6 +69,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option STR_REPEAT => str_repeat, STR_TRIM => str_trim, STR_TRIM_LEFT => str_trim_left, + STR_TRIM_RIGHT => str_trim_right, LIST_LEN => list_len, LIST_GET => list_get, LIST_SET => list_set, @@ -1295,6 +1296,11 @@ fn str_trim_left(symbol: Symbol, var_store: &mut VarStore) -> Def { lowlevel_1(symbol, LowLevel::StrTrimLeft, var_store) } +/// Str.trimRight : Str -> Str +fn str_trim_right(symbol: Symbol, var_store: &mut VarStore) -> Def { + lowlevel_1(symbol, LowLevel::StrTrimRight, var_store) +} + /// Str.repeat : Str, Nat -> Str fn str_repeat(symbol: Symbol, var_store: &mut VarStore) -> Def { let str_var = var_store.fresh(); diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index dc0499ae67..39c94f1a12 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -18,6 +18,7 @@ use crate::llvm::build_str::{ empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, str_from_utf8, str_from_utf8_range, str_join_with, str_number_of_bytes, str_repeat, str_split, str_starts_with, str_starts_with_code_point, str_to_utf8, str_trim, str_trim_left, + str_trim_right, }; use crate::llvm::compare::{generic_eq, generic_neq}; use crate::llvm::convert::{ @@ -5070,6 +5071,12 @@ fn run_low_level<'a, 'ctx, 'env>( str_trim_left(env, scope, args[0]) } + StrTrimRight => { + // Str.trim : Str -> Str + debug_assert_eq!(args.len(), 1); + + str_trim_right(env, scope, args[0]) + } ListLen => { // List.len : List * -> Int debug_assert_eq!(args.len(), 1); diff --git a/compiler/gen_llvm/src/llvm/build_str.rs b/compiler/gen_llvm/src/llvm/build_str.rs index e9bd164b0a..975d979866 100644 --- a/compiler/gen_llvm/src/llvm/build_str.rs +++ b/compiler/gen_llvm/src/llvm/build_str.rs @@ -269,6 +269,16 @@ pub fn str_trim_left<'a, 'ctx, 'env>( call_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_LEFT) } +/// Str.trimRight : Str -> Str +pub fn str_trim_right<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + scope: &Scope<'a, 'ctx>, + str_symbol: Symbol, +) -> BasicValueEnum<'ctx> { + let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol); + call_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_RIGHT) +} + /// Str.fromInt : Int -> Str pub fn str_from_int<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 2cf05a7a08..c44387e1dd 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -28,7 +28,7 @@ pub fn build_call_low_level<'a>( match lowlevel { StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt - | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft + | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft | StrTrimRight | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim | ListLen | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index dd9a4f020b..bc8d2706d0 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -19,6 +19,7 @@ pub enum LowLevel { StrFromFloat, StrTrim, StrTrimLeft, + StrTrimRight, ListLen, ListGetUnsafe, ListSet, @@ -131,6 +132,7 @@ macro_rules! first_order { | StrRepeat | StrTrim | StrTrimLeft + | StrTrimRight | StrFromFloat | ListLen | ListGetUnsafe diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 2233003ca0..44bf51012a 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1019,6 +1019,7 @@ define_builtins! { 19 STR_REPEAT: "repeat" 20 STR_TRIM: "trim" 21 STR_TRIM_LEFT: "trimLeft" + 22 STR_TRIM_RIGHT: "trimRight" } 4 LIST: "List" => { 0 LIST_LIST: "List" imported // the List.List type alias diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 045dfb38cb..889272bcf8 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -941,6 +941,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] { StrConcat => arena.alloc_slice_copy(&[owned, borrowed]), StrTrim => arena.alloc_slice_copy(&[owned]), StrTrimLeft => arena.alloc_slice_copy(&[owned]), + StrTrimRight => arena.alloc_slice_copy(&[owned]), StrSplit => arena.alloc_slice_copy(&[borrowed, borrowed]), ListSingle => arena.alloc_slice_copy(&[irrelevant]), ListRepeat => arena.alloc_slice_copy(&[irrelevant, borrowed]), diff --git a/compiler/test_gen/src/gen_str.rs b/compiler/test_gen/src/gen_str.rs index d5949996ee..691ae32971 100644 --- a/compiler/test_gen/src/gen_str.rs +++ b/compiler/test_gen/src/gen_str.rs @@ -1244,3 +1244,96 @@ fn str_trim_left_small_to_small_shared() { (RocStr, RocStr) ); } + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn str_trim_right_small_blank_string() { + assert_evals_to!(indoc!(r#"Str.trimRight " ""#), RocStr::from(""), RocStr); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn str_trim_right_small_to_small() { + assert_evals_to!( + indoc!(r#"Str.trimRight " hello world ""#), + RocStr::from(" hello world"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn str_trim_right_large_to_large_unique() { + assert_evals_to!( + indoc!(r#"Str.trimRight (Str.concat " hello world from a large string" " ")"#), + RocStr::from(" hello world from a large string"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn str_trim_right_large_to_small_unique() { + assert_evals_to!( + indoc!(r#"Str.trimRight (Str.concat " hello world" " ")"#), + RocStr::from(" hello world"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn str_trim_right_large_to_large_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world world " + + { trimmed: Str.trimRight original, original: original } + "# + ), + ( + RocStr::from(" hello world world "), + RocStr::from(" hello world world"), + ), + (RocStr, RocStr) + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn str_trim_right_large_to_small_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world " + + { trimmed: Str.trimRight original, original: original } + "# + ), + ( + RocStr::from(" hello world "), + RocStr::from(" hello world"), + ), + (RocStr, RocStr) + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn str_trim_right_small_to_small_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world " + + { trimmed: Str.trimRight original, original: original } + "# + ), + (RocStr::from(" hello world "), RocStr::from(" hello world"),), + (RocStr, RocStr) + ); +} From ed3ce2962cf2bffafe06d5c3785178e3acc58700 Mon Sep 17 00:00:00 2001 From: Theo Felippe Date: Sat, 13 Nov 2021 18:09:18 +0000 Subject: [PATCH 051/223] removed unused const --- compiler/builtins/bitcode/src/str.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/builtins/bitcode/src/str.zig b/compiler/builtins/bitcode/src/str.zig index 474b716faf..26972282dc 100644 --- a/compiler/builtins/bitcode/src/str.zig +++ b/compiler/builtins/bitcode/src/str.zig @@ -1586,7 +1586,6 @@ pub fn strTrimLeft(string: RocStr) callconv(.C) RocStr { pub fn strTrimRight(string: RocStr) callconv(.C) RocStr { if (string.str_bytes) |bytes_ptr| { - const leading_bytes = countLeadingWhitespaceBytes(string); const trailing_bytes = countTrailingWhitespaceBytes(string); const original_len = string.len(); From 277681fd0647bcaae740a8cc4a5b00289141a6d1 Mon Sep 17 00:00:00 2001 From: Theo Felippe Date: Sat, 13 Nov 2021 18:12:14 +0000 Subject: [PATCH 052/223] fixed formatting --- compiler/gen_wasm/src/low_level.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index c44387e1dd..7dfbcf3b96 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -28,15 +28,15 @@ pub fn build_call_low_level<'a>( match lowlevel { StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt - | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft | StrTrimRight - | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim | ListLen - | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat - | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 - | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil - | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListSublist - | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize | DictEmpty - | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues - | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { + | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft + | StrTrimRight | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim + | ListLen | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse + | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap + | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk + | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith + | ListSublist | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize + | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys + | DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { return NotImplemented; } From f8b4ce0317763843ab6ff430ad29095a6a9a6c05 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 13 Nov 2021 19:31:07 +0100 Subject: [PATCH 053/223] shrink tag id sizes in layouts --- compiler/gen_llvm/src/llvm/build.rs | 16 ++++---- compiler/mono/src/alias_analysis.rs | 4 +- compiler/mono/src/decision_tree.rs | 28 +++++++------- compiler/mono/src/exhaustive.rs | 12 ++++-- compiler/mono/src/ir.rs | 58 ++++++++++++++--------------- compiler/mono/src/layout.rs | 47 +++++++++++------------ compiler/mono/src/reset_reuse.rs | 8 ++-- 7 files changed, 90 insertions(+), 83 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 901563a5b2..e7e1021beb 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -57,7 +57,7 @@ use roc_mono::ir::{ BranchInfo, CallType, EntryPoint, HigherOrderLowLevel, JoinPointId, ListLiteralElement, ModifyRc, OptLevel, ProcLayout, }; -use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, UnionLayout}; +use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout}; use target_lexicon::{Architecture, OperatingSystem, Triple}; /// This is for Inkwell's FunctionValue::verify - we want to know the verification @@ -1270,9 +1270,9 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( other_tags, } => { debug_assert!(argument.is_pointer_value()); - debug_assert_ne!(*tag_id as i64, *nullable_id); + debug_assert_ne!(*tag_id, *nullable_id); - let tag_index = if (*tag_id as i64) < *nullable_id { + let tag_index = if *tag_id < *nullable_id { *tag_id } else { tag_id - 1 @@ -1420,7 +1420,7 @@ pub fn build_tag<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, scope: &Scope<'a, 'ctx>, union_layout: &UnionLayout<'a>, - tag_id: u8, + tag_id: TagIdIntType, arguments: &[Symbol], reuse_allocation: Option>, parent: FunctionValue<'ctx>, @@ -1539,7 +1539,7 @@ pub fn build_tag<'a, 'ctx, 'env>( env, scope, union_layout, - tag_id, + tag_id as _, arguments, tag_field_layouts, tags, @@ -1553,7 +1553,7 @@ pub fn build_tag<'a, 'ctx, 'env>( } => { let tag_field_layouts = { use std::cmp::Ordering::*; - match tag_id.cmp(&(*nullable_id as u8)) { + match tag_id.cmp(&(*nullable_id as _)) { Equal => { let layout = Layout::Union(*union_layout); @@ -1571,7 +1571,7 @@ pub fn build_tag<'a, 'ctx, 'env>( env, scope, union_layout, - tag_id, + tag_id as _, arguments, tag_field_layouts, tags, @@ -1638,7 +1638,7 @@ pub fn build_tag<'a, 'ctx, 'env>( let tag_struct_type = block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes); - if tag_id == *nullable_id as u8 { + if tag_id == *nullable_id as _ { let output_type = tag_struct_type.ptr_type(AddressSpace::Generic); return output_type.const_null().into(); diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 0d6620b0be..6acb90d50d 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -1477,14 +1477,14 @@ fn expr_spec<'a>( } UnionLayout::Recursive(_) => builder.add_make_tuple(block, &[cell_id, data_id])?, UnionLayout::NullableWrapped { nullable_id, .. } => { - if *tag_id == *nullable_id as u8 { + if *tag_id == *nullable_id as _ { data_id } else { builder.add_make_tuple(block, &[cell_id, data_id])? } } UnionLayout::NullableUnwrapped { nullable_id, .. } => { - if *tag_id == *nullable_id as u8 { + if *tag_id == *nullable_id as _ { data_id } else { builder.add_make_tuple(block, &[cell_id, data_id])? diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 16b3ea0a84..8d5b9a99db 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -3,7 +3,7 @@ use crate::ir::{ BranchInfo, DestructType, Env, Expr, FloatPrecision, IntPrecision, JoinPointId, Literal, Param, Pattern, Procs, Stmt, }; -use crate::layout::{Builtin, Layout, LayoutCache, UnionLayout}; +use crate::layout::{Builtin, Layout, LayoutCache, TagIdIntType, UnionLayout}; use roc_collections::all::{MutMap, MutSet}; use roc_module::ident::TagName; use roc_module::low_level::LowLevel; @@ -81,7 +81,7 @@ enum GuardedTest<'a> { #[allow(clippy::enum_variant_names)] enum Test<'a> { IsCtor { - tag_id: u8, + tag_id: TagIdIntType, tag_name: TagName, union: crate::exhaustive::Union, arguments: Vec<(Pattern<'a>, Layout<'a>)>, @@ -92,7 +92,7 @@ enum Test<'a> { IsStr(Box), IsBit(bool), IsByte { - tag_id: u8, + tag_id: TagIdIntType, num_alts: usize, }, } @@ -562,7 +562,7 @@ fn test_at_path<'a>( }, BitLiteral { value, .. } => IsBit(*value), EnumLiteral { tag_id, union, .. } => IsByte { - tag_id: *tag_id, + tag_id: *tag_id as _, num_alts: union.alternatives.len(), }, IntLiteral(v, precision) => IsInt(*v, *precision), @@ -864,7 +864,7 @@ fn to_relevant_branch_help<'a>( EnumLiteral { tag_id, .. } => match test { IsByte { tag_id: test_id, .. - } if tag_id == *test_id => { + } if tag_id == *test_id as _ => { start.extend(end); Some(Branch { goal: branch.goal, @@ -1171,7 +1171,7 @@ pub fn optimize_when<'a>( #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct PathInstruction { index: u64, - tag_id: u8, + tag_id: TagIdIntType, } fn path_to_expr_help<'a>( @@ -1198,7 +1198,7 @@ fn path_to_expr_help<'a>( union_layout: *union_layout, }; - let inner_layout = union_layout.layout_at(*tag_id as u8, index as usize); + let inner_layout = union_layout.layout_at(*tag_id as TagIdIntType, index as usize); symbol = env.unique_symbol(); stores.push((symbol, inner_layout, inner_expr)); @@ -1317,7 +1317,9 @@ fn test_to_equality<'a>( Test::IsByte { tag_id: test_byte, .. } => { - let lhs = Expr::Literal(Literal::Byte(test_byte)); + debug_assert!(test_byte <= (u8::MAX as u16)); + + let lhs = Expr::Literal(Literal::Byte(test_byte as u8)); let lhs_symbol = env.unique_symbol(); stores.push((lhs_symbol, Layout::Builtin(Builtin::Int8), lhs)); @@ -1504,13 +1506,13 @@ enum ConstructorKnown<'a> { Both { scrutinee: Symbol, layout: Layout<'a>, - pass: u8, - fail: u8, + pass: TagIdIntType, + fail: TagIdIntType, }, OnlyPass { scrutinee: Symbol, layout: Layout<'a>, - tag_id: u8, + tag_id: TagIdIntType, }, Neither, } @@ -1530,7 +1532,7 @@ impl<'a> ConstructorKnown<'a> { layout: *cond_layout, scrutinee: cond_symbol, pass: *tag_id, - fail: (*tag_id == 0) as u8, + fail: (*tag_id == 0) as _, } } else { ConstructorKnown::OnlyPass { @@ -1774,7 +1776,7 @@ fn decide_to_branching<'a>( BranchInfo::Constructor { scrutinee: inner_cond_symbol, layout: inner_cond_layout, - tag_id: tag_id_sum as u8, + tag_id: tag_id_sum as u8 as _, } } else { BranchInfo::None diff --git a/compiler/mono/src/exhaustive.rs b/compiler/mono/src/exhaustive.rs index 77c28d64a1..e1b2847eea 100644 --- a/compiler/mono/src/exhaustive.rs +++ b/compiler/mono/src/exhaustive.rs @@ -1,4 +1,4 @@ -use crate::ir::DestructType; +use crate::{ir::DestructType, layout::TagIdIntType}; use roc_collections::all::{Index, MutMap}; use roc_module::ident::{Lowercase, TagName}; use roc_region::all::{Located, Region}; @@ -35,7 +35,7 @@ pub enum RenderAs { } #[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] -pub struct TagId(pub u8); +pub struct TagId(pub TagIdIntType); #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Ctor { @@ -71,8 +71,12 @@ fn simplify(pattern: &crate::ir::Pattern) -> Pattern { StrLiteral(v) => Literal(Literal::Str(v.clone())), // To make sure these are exhaustive, we have to "fake" a union here - BitLiteral { value, union, .. } => Ctor(union.clone(), TagId(*value as u8), vec![]), - EnumLiteral { tag_id, union, .. } => Ctor(union.clone(), TagId(*tag_id), vec![]), + BitLiteral { value, union, .. } => { + Ctor(union.clone(), TagId(*value as TagIdIntType), vec![]) + } + EnumLiteral { tag_id, union, .. } => { + Ctor(union.clone(), TagId(*tag_id as TagIdIntType), vec![]) + } Underscore => Anything, Identifier(_) => Anything, diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index def0d503a0..2e1b02d0f0 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -4,7 +4,7 @@ use self::InProgressProc::*; use crate::exhaustive::{Ctor, Guard, RenderAs, TagId}; use crate::layout::{ Builtin, ClosureRepresentation, LambdaSet, Layout, LayoutCache, LayoutProblem, - RawFunctionLayout, UnionLayout, WrappedVariant, + RawFunctionLayout, TagIdIntType, UnionLayout, WrappedVariant, }; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -28,9 +28,9 @@ pub const PRETTY_PRINT_IR_SYMBOLS: bool = false; // please change it to the lower number. // if it went up, maybe check that the change is really required static_assertions::assert_eq_size!([u8; 3 * 8], Literal); -static_assertions::assert_eq_size!([u8; 11 * 8], Expr); -static_assertions::assert_eq_size!([u8; 22 * 8], Stmt); -static_assertions::assert_eq_size!([u8; 7 * 8], ProcLayout); +static_assertions::assert_eq_size!([u8; 10 * 8], Expr); +static_assertions::assert_eq_size!([u8; 19 * 8], Stmt); +static_assertions::assert_eq_size!([u8; 6 * 8], ProcLayout); static_assertions::assert_eq_size!([u8; 8 * 8], Call); static_assertions::assert_eq_size!([u8; 6 * 8], CallType); @@ -932,7 +932,7 @@ pub enum BranchInfo<'a> { Constructor { scrutinee: Symbol, layout: Layout<'a>, - tag_id: u8, + tag_id: TagIdIntType, }, } @@ -1180,7 +1180,7 @@ pub enum Expr<'a> { Tag { tag_layout: UnionLayout<'a>, tag_name: TagName, - tag_id: u8, + tag_id: TagIdIntType, arguments: &'a [Symbol], }, Struct(&'a [Symbol]), @@ -1198,7 +1198,7 @@ pub enum Expr<'a> { UnionAtIndex { structure: Symbol, - tag_id: u8, + tag_id: TagIdIntType, union_layout: UnionLayout<'a>, index: u64, }, @@ -1215,7 +1215,7 @@ pub enum Expr<'a> { // normal Tag fields tag_layout: UnionLayout<'a>, tag_name: TagName, - tag_id: u8, + tag_id: TagIdIntType, arguments: &'a [Symbol], }, Reset(Symbol), @@ -4406,7 +4406,7 @@ fn convert_tag_union<'a>( let tag = Expr::Tag { tag_layout: union_layout, tag_name, - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: field_symbols, }; @@ -4429,7 +4429,7 @@ fn convert_tag_union<'a>( let tag = Expr::Tag { tag_layout: union_layout, tag_name, - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: field_symbols, }; @@ -4454,7 +4454,7 @@ fn convert_tag_union<'a>( let tag = Expr::Tag { tag_layout: union_layout, tag_name, - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: field_symbols, }; @@ -4481,7 +4481,7 @@ fn convert_tag_union<'a>( let tag = Expr::Tag { tag_layout: union_layout, tag_name, - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: field_symbols, }; @@ -4499,7 +4499,7 @@ fn convert_tag_union<'a>( let tag = Expr::Tag { tag_layout: union_layout, tag_name, - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: field_symbols, }; @@ -5811,7 +5811,7 @@ fn store_tag_pattern<'a>( structure: Symbol, union_layout: UnionLayout<'a>, arguments: &[(Pattern<'a>, Layout<'a>)], - tag_id: u8, + tag_id: TagIdIntType, mut stmt: Stmt<'a>, ) -> StorePattern<'a> { use Pattern::*; @@ -7055,7 +7055,7 @@ pub enum Pattern<'a> { }, AppliedTag { tag_name: TagName, - tag_id: u8, + tag_id: TagIdIntType, arguments: Vec<'a, (Pattern<'a>, Layout<'a>)>, layout: UnionLayout<'a>, union: crate::exhaustive::Union, @@ -7242,7 +7242,7 @@ fn from_can_pattern_help<'a>( let mut ctors = std::vec::Vec::with_capacity(tag_names.len()); for (i, tag_name) in tag_names.into_iter().enumerate() { ctors.push(Ctor { - tag_id: TagId(i as u8), + tag_id: TagId(i as _), name: tag_name, arity: 0, }) @@ -7333,7 +7333,7 @@ fn from_can_pattern_help<'a>( for (i, (tag_name, args)) in tags.iter().enumerate() { ctors.push(Ctor { - tag_id: TagId(i as u8), + tag_id: TagId(i as _), name: tag_name.clone(), arity: args.len(), }) @@ -7370,7 +7370,7 @@ fn from_can_pattern_help<'a>( Pattern::AppliedTag { tag_name: tag_name.clone(), - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: mono_args, union, layout, @@ -7384,7 +7384,7 @@ fn from_can_pattern_help<'a>( for (i, (tag_name, args)) in tags.iter().enumerate() { ctors.push(Ctor { - tag_id: TagId(i as u8), + tag_id: TagId(i as _), name: tag_name.clone(), // don't include tag discriminant in arity arity: args.len() - 1, @@ -7415,7 +7415,7 @@ fn from_can_pattern_help<'a>( Pattern::AppliedTag { tag_name: tag_name.clone(), - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: mono_args, union, layout, @@ -7429,7 +7429,7 @@ fn from_can_pattern_help<'a>( debug_assert_eq!(&w_tag_name, tag_name); ctors.push(Ctor { - tag_id: TagId(0_u8), + tag_id: TagId(0 as TagIdIntType), name: tag_name.clone(), arity: fields.len(), }); @@ -7458,7 +7458,7 @@ fn from_can_pattern_help<'a>( Pattern::AppliedTag { tag_name: tag_name.clone(), - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: mono_args, union, layout, @@ -7476,7 +7476,7 @@ fn from_can_pattern_help<'a>( for (tag_name, args) in tags.iter() { if i == nullable_id as usize { ctors.push(Ctor { - tag_id: TagId(i as u8), + tag_id: TagId(i as _), name: nullable_name.clone(), // don't include tag discriminant in arity arity: 0, @@ -7486,7 +7486,7 @@ fn from_can_pattern_help<'a>( } ctors.push(Ctor { - tag_id: TagId(i as u8), + tag_id: TagId(i as _), name: tag_name.clone(), // don't include tag discriminant in arity arity: args.len() - 1, @@ -7497,7 +7497,7 @@ fn from_can_pattern_help<'a>( if i == nullable_id as usize { ctors.push(Ctor { - tag_id: TagId(i as u8), + tag_id: TagId(i as _), name: nullable_name.clone(), // don't include tag discriminant in arity arity: 0, @@ -7531,7 +7531,7 @@ fn from_can_pattern_help<'a>( Pattern::AppliedTag { tag_name: tag_name.clone(), - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: mono_args, union, layout, @@ -7547,13 +7547,13 @@ fn from_can_pattern_help<'a>( debug_assert!(!other_fields.is_empty()); ctors.push(Ctor { - tag_id: TagId(nullable_id as u8), + tag_id: TagId(nullable_id as _), name: nullable_name.clone(), arity: 0, }); ctors.push(Ctor { - tag_id: TagId(!nullable_id as u8), + tag_id: TagId(!nullable_id as _), name: nullable_name.clone(), // FIXME drop tag arity: other_fields.len() - 1, @@ -7587,7 +7587,7 @@ fn from_can_pattern_help<'a>( Pattern::AppliedTag { tag_name: tag_name.clone(), - tag_id: tag_id as u8, + tag_id: tag_id as _, arguments: mono_args, union, layout, diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 075a4b66d9..f1c89bc390 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -16,11 +16,12 @@ use ven_pretty::{DocAllocator, DocBuilder}; // please change it to the lower number. // if it went up, maybe check that the change is really required static_assertions::assert_eq_size!([u8; 3 * 8], Builtin); -static_assertions::assert_eq_size!([u8; 5 * 8], Layout); -static_assertions::assert_eq_size!([u8; 4 * 8], UnionLayout); +static_assertions::assert_eq_size!([u8; 4 * 8], Layout); +static_assertions::assert_eq_size!([u8; 3 * 8], UnionLayout); static_assertions::assert_eq_size!([u8; 3 * 8], LambdaSet); -pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::() * 8) as usize; +pub type TagIdIntType = u16; +pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::() * 8) as usize; const GENERATE_NULLABLE: bool = true; /// If a (Num *) gets translated to a Layout, this is the numeric type it defaults to. @@ -217,7 +218,7 @@ pub enum UnionLayout<'a> { /// e.g. `FingerTree a : [ Empty, Single a, More (Some a) (FingerTree (Tuple a)) (Some a) ]` /// see also: https://youtu.be/ip92VMpf_-A?t=164 NullableWrapped { - nullable_id: i64, + nullable_id: u16, other_tags: &'a [&'a [Layout<'a>]], }, /// A recursive tag union where the non-nullable variant does NOT store the tag id @@ -255,7 +256,7 @@ impl<'a> UnionLayout<'a> { } } - pub fn layout_at(self, tag_id: u8, index: usize) -> Layout<'a> { + pub fn layout_at(self, tag_id: TagIdIntType, index: usize) -> Layout<'a> { let result = match self { UnionLayout::NonRecursive(tag_layouts) => { let field_layouts = tag_layouts[tag_id as usize]; @@ -273,9 +274,9 @@ impl<'a> UnionLayout<'a> { nullable_id, other_tags, } => { - debug_assert_ne!(nullable_id, tag_id as i64); + debug_assert_ne!(nullable_id, tag_id); - let tag_index = if (tag_id as i64) < nullable_id { + let tag_index = if tag_id < nullable_id { tag_id } else { tag_id - 1 @@ -378,12 +379,12 @@ impl<'a> UnionLayout<'a> { } } - pub fn tag_is_null(&self, tag_id: u8) -> bool { + pub fn tag_is_null(&self, tag_id: TagIdIntType) -> bool { match self { UnionLayout::NonRecursive(_) | UnionLayout::NonNullableUnwrapped(_) | UnionLayout::Recursive(_) => false, - UnionLayout::NullableWrapped { nullable_id, .. } => *nullable_id == tag_id as i64, + UnionLayout::NullableWrapped { nullable_id, .. } => *nullable_id == tag_id, UnionLayout::NullableUnwrapped { nullable_id, .. } => *nullable_id == (tag_id != 0), } } @@ -439,7 +440,7 @@ pub enum ClosureRepresentation<'a> { Union { alphabetic_order_fields: &'a [Layout<'a>], tag_name: TagName, - tag_id: u8, + tag_id: TagIdIntType, union_layout: UnionLayout<'a>, }, /// The closure is represented as a struct. The layouts are sorted @@ -497,7 +498,7 @@ impl<'a> LambdaSet<'a> { .unwrap(); ClosureRepresentation::Union { - tag_id: index as u8, + tag_id: index as TagIdIntType, alphabetic_order_fields: fields, tag_name: TagName::Closure(function_symbol), union_layout: *union, @@ -1483,7 +1484,7 @@ fn layout_from_flat_type<'a>( if GENERATE_NULLABLE { for (index, (_name, variables)) in tags_vec.iter().enumerate() { if variables.is_empty() { - nullable = Some(index as i64); + nullable = Some(index as TagIdIntType); break; } } @@ -1491,7 +1492,7 @@ fn layout_from_flat_type<'a>( env.insert_seen(rec_var); for (index, (_name, variables)) in tags_vec.into_iter().enumerate() { - if matches!(nullable, Some(i) if i == index as i64) { + if matches!(nullable, Some(i) if i == index as TagIdIntType) { // don't add the nullable case continue; } @@ -1641,7 +1642,7 @@ pub enum WrappedVariant<'a> { sorted_tag_layouts: Vec<'a, (TagName, &'a [Layout<'a>])>, }, NullableWrapped { - nullable_id: i64, + nullable_id: TagIdIntType, nullable_name: TagName, sorted_tag_layouts: Vec<'a, (TagName, &'a [Layout<'a>])>, }, @@ -1658,7 +1659,7 @@ pub enum WrappedVariant<'a> { } impl<'a> WrappedVariant<'a> { - pub fn tag_name_to_id(&self, tag_name: &TagName) -> (u8, &'a [Layout<'a>]) { + pub fn tag_name_to_id(&self, tag_name: &TagName) -> (TagIdIntType, &'a [Layout<'a>]) { use WrappedVariant::*; match self { @@ -1670,7 +1671,7 @@ impl<'a> WrappedVariant<'a> { .expect("tag name is not in its own type"); debug_assert!(tag_id < 256); - (tag_id as u8, *argument_layouts) + (tag_id as TagIdIntType, *argument_layouts) } NullableWrapped { nullable_id, @@ -1680,7 +1681,7 @@ impl<'a> WrappedVariant<'a> { // assumption: the nullable_name is not included in sorted_tag_layouts if tag_name == nullable_name { - (*nullable_id as u8, &[] as &[_]) + (*nullable_id as TagIdIntType, &[] as &[_]) } else { let (mut tag_id, (_, argument_layouts)) = sorted_tag_layouts .iter() @@ -1693,7 +1694,7 @@ impl<'a> WrappedVariant<'a> { } debug_assert!(tag_id < 256); - (tag_id as u8, *argument_layouts) + (tag_id as TagIdIntType, *argument_layouts) } } NullableUnwrapped { @@ -1703,11 +1704,11 @@ impl<'a> WrappedVariant<'a> { other_fields, } => { if tag_name == nullable_name { - (*nullable_id as u8, &[] as &[_]) + (*nullable_id as TagIdIntType, &[] as &[_]) } else { debug_assert_eq!(other_name, tag_name); - (!*nullable_id as u8, *other_fields) + (!*nullable_id as TagIdIntType, *other_fields) } } NonNullableUnwrapped { fields, .. } => (0, fields), @@ -1863,14 +1864,14 @@ fn union_sorted_tags_help_new<'a>( let mut answer = Vec::with_capacity_in(tags_vec.len(), arena); let mut has_any_arguments = false; - let mut nullable: Option<(i64, TagName)> = None; + let mut nullable: Option<(TagIdIntType, TagName)> = None; // only recursive tag unions can be nullable let is_recursive = opt_rec_var.is_some(); if is_recursive && GENERATE_NULLABLE { for (index, (name, variables)) in tags_vec.iter().enumerate() { if variables.is_empty() { - nullable = Some((index as i64, (*name).clone())); + nullable = Some((index as TagIdIntType, (*name).clone())); break; } } @@ -2081,7 +2082,7 @@ pub fn union_sorted_tags_help<'a>( if is_recursive && GENERATE_NULLABLE { for (index, (name, variables)) in tags_vec.iter().enumerate() { if variables.is_empty() { - nullable = Some((index as i64, name.clone())); + nullable = Some((index as TagIdIntType, name.clone())); break; } } diff --git a/compiler/mono/src/reset_reuse.rs b/compiler/mono/src/reset_reuse.rs index 64fde943c5..cf8ecff9cf 100644 --- a/compiler/mono/src/reset_reuse.rs +++ b/compiler/mono/src/reset_reuse.rs @@ -1,6 +1,6 @@ use crate::inc_dec::{collect_stmt, occurring_variables_expr, JPLiveVarMap, LiveVarSet}; use crate::ir::{BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt}; -use crate::layout::{Layout, UnionLayout}; +use crate::layout::{Layout, TagIdIntType, UnionLayout}; use bumpalo::collections::Vec; use bumpalo::Bump; use roc_collections::all::MutSet; @@ -27,17 +27,17 @@ pub fn insert_reset_reuse<'a, 'i>( #[derive(Debug)] struct CtorInfo<'a> { - id: u8, + id: TagIdIntType, layout: UnionLayout<'a>, } -fn may_reuse(tag_layout: UnionLayout, tag_id: u8, other: &CtorInfo) -> bool { +fn may_reuse(tag_layout: UnionLayout, tag_id: TagIdIntType, other: &CtorInfo) -> bool { if tag_layout != other.layout { return false; } // we should not get here if the tag we matched on is represented as NULL - debug_assert!(!tag_layout.tag_is_null(other.id)); + debug_assert!(!tag_layout.tag_is_null(other.id as _)); // furthermore, we can only use the memory if the tag we're creating is non-NULL !tag_layout.tag_is_null(tag_id) From 9bf16749463105e746ab4b04c056edfaec0f560f Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Sat, 13 Nov 2021 16:06:12 -0800 Subject: [PATCH 054/223] Shrink Collection to make parse_expr_size test pass --- compiler/can/src/operator.rs | 51 +++------ compiler/fmt/src/annotation.rs | 4 +- compiler/fmt/src/expr.rs | 6 +- compiler/parse/src/ast.rs | 143 +++++++++++++++++++------- compiler/parse/src/expr.rs | 44 +++----- compiler/parse/src/parser.rs | 8 +- compiler/parse/src/type_annotation.rs | 10 +- compiler/parse/tests/test_parse.rs | 14 ++- 8 files changed, 155 insertions(+), 125 deletions(-) diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index 98e8a1cba1..c11242d71c 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -6,7 +6,7 @@ use roc_module::ident::ModuleName; use roc_module::operator::BinOp::Pizza; use roc_module::operator::{BinOp, CalledVia}; use roc_parse::ast::Expr::{self, *}; -use roc_parse::ast::{AssignedField, Collection, Def, WhenBranch}; +use roc_parse::ast::{AssignedField, Def, WhenBranch}; use roc_region::all::{Located, Region}; // BinOp precedence logic adapted from Gluon by Markus Westerlind @@ -151,62 +151,39 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a new_items.push(desugar_expr(arena, item)); } let new_items = new_items.into_bump_slice(); - let value: Expr<'a> = List(Collection { - items: new_items, - final_comments: items.final_comments, - }); + let value: Expr<'a> = List(items.replace_items(new_items)); arena.alloc(Located { region: loc_expr.region, value, }) } - Record(fields) => { - let mut new_fields = Vec::with_capacity_in(fields.len(), arena); - - for field in fields.iter() { + Record(fields) => arena.alloc(Located { + region: loc_expr.region, + value: Record(fields.map_items(arena, |field| { let value = desugar_field(arena, &field.value); - - new_fields.push(Located { + Located { value, region: field.region, - }); - } - - let new_fields = new_fields.into_bump_slice(); - - arena.alloc(Located { - region: loc_expr.region, - value: Record(Collection { - items: new_fields, - final_comments: fields.final_comments, - }), - }) - } + } + })), + }), RecordUpdate { fields, update } => { // NOTE the `update` field is always a `Var { .. }` and does not need to be desugared - let mut new_fields = Vec::with_capacity_in(fields.len(), arena); - - for field in fields.iter() { + let new_fields = fields.map_items(arena, |field| { let value = desugar_field(arena, &field.value); - - new_fields.push(Located { + Located { value, region: field.region, - }); - } - - let new_fields = new_fields.into_bump_slice(); + } + }); arena.alloc(Located { region: loc_expr.region, value: RecordUpdate { update: *update, - fields: Collection { - items: new_fields, - final_comments: fields.final_comments, - }, + fields: new_fields, }, }) } diff --git a/compiler/fmt/src/annotation.rs b/compiler/fmt/src/annotation.rs index 41170c7f48..c74636dfa9 100644 --- a/compiler/fmt/src/annotation.rs +++ b/compiler/fmt/src/annotation.rs @@ -83,7 +83,7 @@ where macro_rules! format_sequence { ($buf: expr, $indent:expr, $start:expr, $end:expr, $items:expr, $newline:expr, $t:ident) => { let is_multiline = $items.iter().any(|item| item.value.is_multiline()) - || !$items.final_comments.is_empty(); + || !$items.final_comments().is_empty(); if is_multiline { let braces_indent = $indent + INDENT; @@ -140,7 +140,7 @@ macro_rules! format_sequence { } fmt_comments_only( $buf, - $items.final_comments.iter(), + $items.final_comments().iter(), NewlineAt::Top, item_indent, ); diff --git a/compiler/fmt/src/expr.rs b/compiler/fmt/src/expr.rs index 5e028c10ac..f82fd61a1f 100644 --- a/compiler/fmt/src/expr.rs +++ b/compiler/fmt/src/expr.rs @@ -408,9 +408,9 @@ fn fmt_bin_ops<'a>( loc_right_side.format_with_options(buf, apply_needs_parens, Newlines::Yes, indent); } -fn fmt_list<'a>(buf: &mut String<'a>, items: Collection<'a, &Located>>, indent: u16) { +fn fmt_list<'a>(buf: &mut String<'a>, items: Collection<'a, &'a Located>>, indent: u16) { let loc_items = items.items; - let final_comments = items.final_comments; + let final_comments = items.final_comments(); if loc_items.is_empty() && final_comments.iter().all(|c| c.is_newline()) { buf.push_str("[]"); } else { @@ -910,7 +910,7 @@ fn fmt_record<'a>( indent: u16, ) { let loc_fields = fields.items; - let final_comments = fields.final_comments; + let final_comments = fields.final_comments(); if loc_fields.is_empty() && final_comments.iter().all(|c| c.is_newline()) { buf.push_str("{}"); } else { diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 797c360018..61ce017865 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -1,44 +1,10 @@ use crate::header::{AppHeader, ImportsEntry, InterfaceHeader, PlatformHeader, TypedIdent}; use crate::ident::Ident; -use bumpalo::collections::String; +use bumpalo::collections::{String, Vec}; use bumpalo::Bump; use roc_module::operator::{BinOp, CalledVia, UnaryOp}; use roc_region::all::{Loc, Position, Region}; -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Collection<'a, T> { - pub items: &'a [T], - pub final_comments: &'a [CommentOrNewline<'a>], -} - -impl<'a, T> Collection<'a, T> { - pub fn empty() -> Collection<'a, T> { - Collection { - items: &[], - final_comments: &[], - } - } - - pub fn with_items(items: &'a [T]) -> Collection<'a, T> { - Collection { - items, - final_comments: &[], - } - } - - pub fn iter(&self) -> impl Iterator { - self.items.iter() - } - - pub fn len(&self) -> usize { - self.items.len() - } - - pub fn is_empty(&self) -> bool { - self.items.is_empty() - } -} - #[derive(Clone, Debug, PartialEq)] pub enum Module<'a> { Interface { header: InterfaceHeader<'a> }, @@ -523,6 +489,113 @@ impl<'a> Pattern<'a> { } } } +#[derive(Copy, Clone, Debug)] +pub struct Collection<'a, T> { + pub items: &'a [T], + // Use a pointer to a slice (rather than just a slice), in order to avoid bloating + // Ast variants. The final_comments field is rarely accessed in the hot path, so + // this shouldn't matter much for perf. + // Use an Option, so it's possible to initialize without allocating. + final_comments: Option<&'a &'a [CommentOrNewline<'a>]>, +} + +impl<'a, T> Collection<'a, T> { + pub fn empty() -> Collection<'a, T> { + Collection { + items: &[], + final_comments: None, + } + } + + pub fn with_items(items: &'a [T]) -> Collection<'a, T> { + Collection { + items, + final_comments: None, + } + } + + pub fn with_items_and_comments( + arena: &'a Bump, + items: &'a [T], + comments: &'a [CommentOrNewline<'a>], + ) -> Collection<'a, T> { + Collection { + items, + final_comments: if comments.is_empty() { + None + } else { + Some(arena.alloc(comments)) + }, + } + } + + pub fn replace_items(&self, new_items: &'a [V]) -> Collection<'a, V> { + Collection { + items: new_items, + final_comments: self.final_comments, + } + } + + pub fn ptrify_items(&self, arena: &'a Bump) -> Collection<'a, &'a T> { + let mut allocated = Vec::with_capacity_in(self.len(), arena); + + for parsed_elem in self.items { + allocated.push(parsed_elem); + } + + self.replace_items(allocated.into_bump_slice()) + } + + pub fn map_items(&self, arena: &'a Bump, f: impl Fn(&'a T) -> V) -> Collection<'a, V> { + let mut allocated = Vec::with_capacity_in(self.len(), arena); + + for parsed_elem in self.items { + allocated.push(f(parsed_elem)); + } + + self.replace_items(allocated.into_bump_slice()) + } + + pub fn map_items_result( + &self, + arena: &'a Bump, + f: impl Fn(&T) -> Result, + ) -> Result, E> { + let mut allocated = Vec::with_capacity_in(self.len(), arena); + + for parsed_elem in self.items { + allocated.push(f(parsed_elem)?); + } + + Ok(self.replace_items(allocated.into_bump_slice())) + } + + pub fn final_comments(&self) -> &'a [CommentOrNewline<'a>] { + if let Some(final_comments) = self.final_comments { + *final_comments + } else { + &[] + } + } + + pub fn iter(&self) -> impl Iterator { + self.items.iter() + } + + pub fn len(&self) -> usize { + self.items.len() + } + + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } +} + +impl<'a, T: PartialEq> PartialEq for Collection<'a, T> { + fn eq(&self, other: &Self) -> bool { + self.items == other.items && self.final_comments() == other.final_comments() + } +} pub trait Spaceable<'a> { fn before(&'a self, _: &'a [CommentOrNewline<'a>]) -> Self; diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index ad14d0dfe4..90eaeb268f 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -1449,19 +1449,13 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result expr_to_pattern_help(arena, sub_expr), Expr::Record(fields) => { - let mut loc_patterns = Vec::with_capacity_in(fields.len(), arena); - - for loc_assigned_field in fields.iter() { + let patterns = fields.map_items_result(arena, |loc_assigned_field| { let region = loc_assigned_field.region; let value = assigned_expr_field_to_pattern_help(arena, &loc_assigned_field.value)?; + Ok(Located { region, value }) + })?; - loc_patterns.push(Located { region, value }); - } - - Ok(Pattern::RecordDestructure(Collection { - items: loc_patterns.into_bump_slice(), - final_comments: fields.final_comments, - })) + Ok(Pattern::RecordDestructure(patterns)) } Expr::Float(string) => Ok(Pattern::FloatLiteral(string)), @@ -2167,16 +2161,8 @@ fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EList<'a> ) .parse(arena, state)?; - let mut allocated = Vec::with_capacity_in(elements.items.len(), arena); - - for parsed_elem in elements.items { - allocated.push(parsed_elem); - } - - let expr = Expr::List(Collection { - items: allocated.into_bump_slice(), - final_comments: elements.final_comments, - }); + let elements = elements.ptrify_items(arena); + let expr = Expr::List(elements); Ok((MadeProgress, expr, state)) } @@ -2314,15 +2300,17 @@ fn record_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EExpr<' let mut value = match opt_update { Some(update) => Expr::RecordUpdate { update: &*arena.alloc(update), - fields: Collection { - items: loc_assigned_fields_with_comments.value.0.into_bump_slice(), - final_comments: arena.alloc(loc_assigned_fields_with_comments.value.1), - }, + fields: Collection::with_items_and_comments( + arena, + loc_assigned_fields_with_comments.value.0.into_bump_slice(), + arena.alloc(loc_assigned_fields_with_comments.value.1), + ), }, - None => Expr::Record(Collection { - items: loc_assigned_fields_with_comments.value.0.into_bump_slice(), - final_comments: loc_assigned_fields_with_comments.value.1, - }), + None => Expr::Record(Collection::with_items_and_comments( + arena, + loc_assigned_fields_with_comments.value.0.into_bump_slice(), + loc_assigned_fields_with_comments.value.1, + )), }; // there can be field access, e.g. `{ x : 4 }.x` diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index c1e0187b29..07b9800359 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -1300,10 +1300,10 @@ macro_rules! collection_trailing_sep_e { } } - let collection = $crate::ast::Collection { - items: parsed_elems.into_bump_slice(), - final_comments, - }; + let collection = $crate::ast::Collection::with_items_and_comments( + arena, + parsed_elems.into_bump_slice(), + final_comments); Ok((MadeProgress, collection, state)) } diff --git a/compiler/parse/src/type_annotation.rs b/compiler/parse/src/type_annotation.rs index 29065c5ed6..64b6c69fb0 100644 --- a/compiler/parse/src/type_annotation.rs +++ b/compiler/parse/src/type_annotation.rs @@ -1,4 +1,4 @@ -use crate::ast::{AssignedField, Collection, Tag, TypeAnnotation}; +use crate::ast::{AssignedField, Tag, TypeAnnotation}; use crate::blankspace::{space0_around_ee, space0_before_e, space0_e}; use crate::keyword; use crate::parser::{ @@ -291,13 +291,7 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, EType let field_term = specialize_ref(ETypeRecord::Type, term(min_indent)); let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?; - let result = Record { - fields: Collection { - items: fields.items, - final_comments: fields.final_comments, - }, - ext, - }; + let result = Record { fields, ext }; Ok((MadeProgress, result, state)) } diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 25d10eb092..c49820045b 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -1185,10 +1185,7 @@ mod test_parse { #[test] fn newline_inside_empty_list() { let arena = Bump::new(); - let expected = List(Collection { - items: &[], - final_comments: &[Newline], - }); + let expected = List(Collection::with_items_and_comments(&arena, &[], &[Newline])); let actual = parse_expr_with(&arena, "[\n]"); assert_eq!(Ok(expected), actual); @@ -1197,10 +1194,11 @@ mod test_parse { #[test] fn comment_inside_empty_list() { let arena = Bump::new(); - let expected = List(Collection { - items: &[], - final_comments: &[LineComment("comment")], - }); + let expected = List(Collection::with_items_and_comments( + &arena, + &[], + &[LineComment("comment")], + )); let actual = parse_expr_with(&arena, "[#comment\n]"); assert_eq!(Ok(expected), actual); From 3ff3695758f02ef9b5ff2c770bda232d9c4036b7 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Sat, 13 Nov 2021 16:24:35 -0800 Subject: [PATCH 055/223] Add a manual Debug formatter for Collection to make debugging nicer --- compiler/parse/src/ast.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 61ce017865..4b79be508e 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + use crate::header::{AppHeader, ImportsEntry, InterfaceHeader, PlatformHeader, TypedIdent}; use crate::ident::Ident; use bumpalo::collections::{String, Vec}; @@ -489,7 +491,7 @@ impl<'a> Pattern<'a> { } } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct Collection<'a, T> { pub items: &'a [T], // Use a pointer to a slice (rather than just a slice), in order to avoid bloating @@ -597,6 +599,19 @@ impl<'a, T: PartialEq> PartialEq for Collection<'a, T> { } } +impl<'a, T: Debug> Debug for Collection<'a, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.final_comments().is_empty() { + f.debug_list().entries(self.items.iter()).finish() + } else { + f.debug_struct("Collection") + .field("items", &self.items) + .field("final_comments", &self.final_comments()) + .finish() + } + } +} + pub trait Spaceable<'a> { fn before(&'a self, _: &'a [CommentOrNewline<'a>]) -> Self; fn after(&'a self, _: &'a [CommentOrNewline<'a>]) -> Self; From a7f9b341329f4ae9d9d60013e0b285fc6cff2906 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 14 Nov 2021 02:06:57 +0100 Subject: [PATCH 056/223] clippy --- compiler/mono/src/ir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 2e1b02d0f0..8c563e1237 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -7429,7 +7429,7 @@ fn from_can_pattern_help<'a>( debug_assert_eq!(&w_tag_name, tag_name); ctors.push(Ctor { - tag_id: TagId(0 as TagIdIntType), + tag_id: TagId(0), name: tag_name.clone(), arity: fields.len(), }); From 39263b0ab118846cbcb4c463375b699f24a187a1 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 14 Nov 2021 09:08:19 +0000 Subject: [PATCH 057/223] Shorter name: VmSymbolState --- compiler/gen_wasm/src/storage.rs | 8 ++++---- compiler/gen_wasm/src/wasm_module/code_builder.rs | 12 ++++++------ compiler/gen_wasm/src/wasm_module/mod.rs | 4 +--- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/gen_wasm/src/storage.rs b/compiler/gen_wasm/src/storage.rs index f99beea619..f552d59c59 100644 --- a/compiler/gen_wasm/src/storage.rs +++ b/compiler/gen_wasm/src/storage.rs @@ -5,7 +5,7 @@ use roc_collections::all::MutMap; use roc_module::symbol::Symbol; use crate::layout::WasmLayout; -use crate::wasm_module::{CodeBuilder, LocalId, ValueType, VirtualMachineSymbolState}; +use crate::wasm_module::{CodeBuilder, LocalId, ValueType, VmSymbolState}; use crate::{copy_memory, round_up_to_alignment, CopyMemoryConfig, PTR_SIZE, PTR_TYPE}; pub enum StoredValueKind { @@ -33,7 +33,7 @@ impl StackMemoryLocation { pub enum StoredValue { /// A value stored implicitly in the VM stack (primitives only) VirtualMachineStack { - vm_state: VirtualMachineSymbolState, + vm_state: VmSymbolState, value_type: ValueType, size: u32, }, @@ -126,7 +126,7 @@ impl<'a> Storage<'a> { } } _ => StoredValue::VirtualMachineStack { - vm_state: VirtualMachineSymbolState::NotYetPushed, + vm_state: VmSymbolState::NotYetPushed, value_type: *value_type, size: *size, }, @@ -422,7 +422,7 @@ impl<'a> Storage<'a> { } = storage { let local_id = self.get_next_local_id(); - if vm_state != VirtualMachineSymbolState::NotYetPushed { + if vm_state != VmSymbolState::NotYetPushed { code_builder.load_symbol(symbol, vm_state, local_id); code_builder.set_local(local_id); } diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index 71461111e6..1fe64dc6be 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -73,7 +73,7 @@ impl From for Align { } #[derive(Debug, Clone, PartialEq, Copy)] -pub enum VirtualMachineSymbolState { +pub enum VmSymbolState { /// Value doesn't exist yet NotYetPushed, @@ -169,7 +169,7 @@ impl<'a> CodeBuilder<'a> { /// Set the Symbol that is at the top of the VM stack right now /// We will use this later when we need to load the Symbol - pub fn set_top_symbol(&mut self, sym: Symbol) -> VirtualMachineSymbolState { + pub fn set_top_symbol(&mut self, sym: Symbol) -> VmSymbolState { let len = self.vm_stack.len(); let pushed_at = self.code.len(); @@ -182,7 +182,7 @@ impl<'a> CodeBuilder<'a> { self.vm_stack[len - 1] = sym; - VirtualMachineSymbolState::Pushed { pushed_at } + VmSymbolState::Pushed { pushed_at } } /// Verify if a sequence of symbols is at the top of the stack @@ -227,10 +227,10 @@ impl<'a> CodeBuilder<'a> { pub fn load_symbol( &mut self, symbol: Symbol, - vm_state: VirtualMachineSymbolState, + vm_state: VmSymbolState, next_local_id: LocalId, - ) -> Option { - use VirtualMachineSymbolState::*; + ) -> Option { + use VmSymbolState::*; match vm_state { NotYetPushed => panic!("Symbol {:?} has no value yet. Nothing to load.", symbol), diff --git a/compiler/gen_wasm/src/wasm_module/mod.rs b/compiler/gen_wasm/src/wasm_module/mod.rs index b925bfafd7..2a404e9b48 100644 --- a/compiler/gen_wasm/src/wasm_module/mod.rs +++ b/compiler/gen_wasm/src/wasm_module/mod.rs @@ -4,8 +4,6 @@ pub mod opcodes; pub mod sections; pub mod serialize; -pub use code_builder::{ - Align, BlockType, CodeBuilder, LocalId, ValueType, VirtualMachineSymbolState, -}; +pub use code_builder::{Align, BlockType, CodeBuilder, LocalId, ValueType, VmSymbolState}; pub use linking::{LinkingSubSection, SymInfo}; pub use sections::{ConstExpr, Export, ExportType, Global, GlobalType, Signature, WasmModule}; From a2abf9c3d20b46dc0e985acc17927defaa25b953 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 14 Nov 2021 10:59:32 +0000 Subject: [PATCH 058/223] More accurate model of the Wasm VM's stack machine, with control flow blocks --- .../gen_wasm/src/wasm_module/code_builder.rs | 267 +++++++++++++----- compiler/gen_wasm/src/wasm_module/opcodes.rs | 2 +- compiler/test_gen/src/gen_primitives.rs | 2 +- 3 files changed, 205 insertions(+), 66 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index 1fe64dc6be..ed2a850576 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -1,7 +1,6 @@ use bumpalo::collections::vec::Vec; use bumpalo::Bump; use core::panic; -use std::fmt::Debug; use roc_module::symbol::Symbol; @@ -10,6 +9,13 @@ use super::opcodes::{OpCode, OpCode::*}; use super::serialize::{SerialBuffer, Serialize}; use crate::{round_up_to_alignment, FRAME_ALIGNMENT_BYTES, STACK_POINTER_GLOBAL_ID}; +const ENABLE_DEBUG_LOG: bool = true; +macro_rules! log_instruction { + ($($x: expr),+) => { + if ENABLE_DEBUG_LOG { println!($($x,)*); } + }; +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LocalId(pub u32); @@ -29,6 +35,7 @@ impl Serialize for ValueType { } } +#[derive(PartialEq, Eq, Debug)] pub enum BlockType { NoResult, Value(ValueType), @@ -43,6 +50,24 @@ impl BlockType { } } +/// A control block in our model of the VM +/// Child blocks cannot "see" values from their parent block +struct VmBlock<'a> { + /// opcode indicating what kind of block this is + opcode: OpCode, + /// the stack of values for this block + value_stack: Vec<'a, Symbol>, + /// whether this block pushes a result value to its parent + has_result: bool, +} + +impl std::fmt::Debug for VmBlock<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let result = if self.has_result { "Result" } else { "NoResult" }; + f.write_fmt(format_args!("{:?} {}", self.opcode, result)) + } +} + /// Wasm memory alignment. (Rust representation matches Wasm encoding) #[repr(u8)] #[derive(Clone, Copy, Debug)] @@ -113,6 +138,8 @@ macro_rules! instruction_memargs { #[derive(Debug)] pub struct CodeBuilder<'a> { + arena: &'a Bump, + /// The main container for the instructions code: Vec<'a, u8>, @@ -135,8 +162,8 @@ pub struct CodeBuilder<'a> { inner_length: Vec<'a, u8>, /// Our simulation model of the Wasm stack machine - /// Keeps track of where Symbol values are in the VM stack - vm_stack: Vec<'a, Symbol>, + /// Nested blocks of instructions. A child block can't "see" the stack of its parent block + vm_block_stack: Vec<'a, VmBlock<'a>>, /// Linker info to help combine the Roc module with builtin & platform modules, /// e.g. to modify call instructions when function indices change @@ -146,13 +173,22 @@ pub struct CodeBuilder<'a> { #[allow(clippy::new_without_default)] impl<'a> CodeBuilder<'a> { pub fn new(arena: &'a Bump) -> Self { + let mut vm_block_stack = Vec::with_capacity_in(8, arena); + let function_block = VmBlock { + opcode: BLOCK, + has_result: true, + value_stack: Vec::with_capacity_in(8, arena), + }; + vm_block_stack.push(function_block); + CodeBuilder { + arena, code: Vec::with_capacity_in(1024, arena), insertions: Vec::with_capacity_in(32, arena), insert_bytes: Vec::with_capacity_in(64, arena), preamble: Vec::with_capacity_in(32, arena), inner_length: Vec::with_capacity_in(5, arena), - vm_stack: Vec::with_capacity_in(32, arena), + vm_block_stack, relocations: Vec::with_capacity_in(32, arena), } } @@ -167,35 +203,39 @@ impl<'a> CodeBuilder<'a> { ***********************************************************/ + fn current_stack(&self) -> &Vec<'a, Symbol> { + let block = self.vm_block_stack.last().unwrap(); + &block.value_stack + } + + fn current_stack_mut(&mut self) -> &mut Vec<'a, Symbol> { + let block = self.vm_block_stack.last_mut().unwrap(); + &mut block.value_stack + } + /// Set the Symbol that is at the top of the VM stack right now /// We will use this later when we need to load the Symbol pub fn set_top_symbol(&mut self, sym: Symbol) -> VmSymbolState { - let len = self.vm_stack.len(); + let current_stack = &mut self.vm_block_stack.last_mut().unwrap().value_stack; let pushed_at = self.code.len(); - - if len == 0 { - panic!( - "trying to set symbol with nothing on stack, code = {:?}", - self.code - ); - } - - self.vm_stack[len - 1] = sym; + let top_symbol: &mut Symbol = current_stack.last_mut().unwrap(); + *top_symbol = sym; VmSymbolState::Pushed { pushed_at } } /// Verify if a sequence of symbols is at the top of the stack pub fn verify_stack_match(&self, symbols: &[Symbol]) -> bool { + let current_stack = self.current_stack(); let n_symbols = symbols.len(); - let stack_depth = self.vm_stack.len(); + let stack_depth = current_stack.len(); if n_symbols > stack_depth { return false; } let offset = stack_depth - n_symbols; for (i, sym) in symbols.iter().enumerate() { - if self.vm_stack[offset + i] != *sym { + if current_stack[offset + i] != *sym { return false; } } @@ -214,7 +254,12 @@ impl<'a> CodeBuilder<'a> { end: self.insert_bytes.len(), }); - // println!("insert {:?} {} at byte offset {} ", opcode, immediate, insert_at); + log_instruction!( + "**insert {:?} {} at byte offset {}**", + opcode, + immediate, + insert_at + ); } /// Load a Symbol that is stored in the VM stack @@ -233,35 +278,47 @@ impl<'a> CodeBuilder<'a> { use VmSymbolState::*; match vm_state { - NotYetPushed => panic!("Symbol {:?} has no value yet. Nothing to load.", symbol), + NotYetPushed => unreachable!("Symbol {:?} has no value yet. Nothing to load.", symbol), Pushed { pushed_at } => { - let &top = self.vm_stack.last().unwrap(); - if top == symbol { - // We're lucky, the symbol is already on top of the VM stack - // No code to generate! (This reduces code size by up to 25% in tests.) - // Just let the caller know what happened - Some(Popped { pushed_at }) - } else { - // Symbol is not on top of the stack. Find it. - if let Some(found_index) = self.vm_stack.iter().rposition(|&s| s == symbol) { - // Insert a local.set where the value was created - self.add_insertion(pushed_at, SETLOCAL, next_local_id.0); + match self.current_stack().last() { + Some(top_symbol) if *top_symbol == symbol => { + // We're lucky, the symbol is already on top of the current block's stack. + // No code to generate! (This reduces code size by up to 25% in tests.) + // Just let the caller know what happened + Some(Popped { pushed_at }) + } + _ => { + // Symbol is not on top of the stack. + // We should have saved it to a local, so go back and do that now. - // Take the value out of the stack where local.set was inserted - self.vm_stack.remove(found_index); + // It should still be on the stack in the block where it was assigned. Remove it. + let mut found = false; + for block in self.vm_block_stack.iter_mut() { + if let Some(found_index) = + block.value_stack.iter().position(|&s| s == symbol) + { + block.value_stack.remove(found_index); + found = true; + } + } - // Insert a local.get at the current position + // Go back to the code position where it was pushed, and save it to a local + if found { + self.add_insertion(pushed_at, SETLOCAL, next_local_id.0); + } else { + if ENABLE_DEBUG_LOG { + println!("{:?} has been popped implicitly. Leaving it on the stack.", symbol); + } + self.add_insertion(pushed_at, TEELOCAL, next_local_id.0); + } + + // Recover the value again at the current position self.get_local(next_local_id); self.set_top_symbol(symbol); // This Symbol is no longer stored in the VM stack, but in a local None - } else { - panic!( - "{:?} has state {:?} but not found in VM stack", - symbol, vm_state - ); } } } @@ -284,7 +341,7 @@ impl<'a> CodeBuilder<'a> { /********************************************************** - FINALIZE AND SERIALIZE + FUNCTION HEADER ***********************************************************/ @@ -377,6 +434,12 @@ impl<'a> CodeBuilder<'a> { self.insertions.sort_by_key(|ins| ins.at); } + /********************************************************** + + SERIALIZE + + ***********************************************************/ + /// Serialize all byte vectors in the right order /// Also update relocation offsets relative to the base offset (code section body start) pub fn serialize_with_relocs( @@ -435,33 +498,68 @@ impl<'a> CodeBuilder<'a> { /// Base method for generating instructions /// Emits the opcode and simulates VM stack push/pop - fn inst(&mut self, opcode: OpCode, pops: usize, push: bool) { - let new_len = self.vm_stack.len() - pops as usize; - self.vm_stack.truncate(new_len); + fn inst_base(&mut self, opcode: OpCode, pops: usize, push: bool) { + let current_stack = self.current_stack_mut(); + let new_len = current_stack.len() - pops as usize; + current_stack.truncate(new_len); if push { - self.vm_stack.push(Symbol::WASM_TMP); + current_stack.push(Symbol::WASM_TMP); } - self.code.push(opcode as u8); - - // println!("{:10}\t{:?}", format!("{:?}", opcode), &self.vm_stack); } - fn inst_imm8(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u8) { - self.inst(opcode, pops, push); - self.code.push(immediate); + /// Plain instruction without any immediates + fn inst(&mut self, opcode: OpCode, pops: usize, push: bool) { + self.inst_base(opcode, pops, push); + log_instruction!( + "{:10}\t\t{:?}", + format!("{:?}", opcode), + self.current_stack() + ); } - // public for use in test code - pub fn inst_imm32(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u32) { - self.inst(opcode, pops, push); + /// Block instruction + fn inst_block(&mut self, opcode: OpCode, pops: usize, block_type: BlockType) { + self.inst_base(opcode, pops, false); + self.code.push(block_type.as_byte()); + + // Start a new block with a fresh value stack + self.vm_block_stack.push(VmBlock { + opcode, + value_stack: Vec::with_capacity_in(8, self.arena), + has_result: block_type != BlockType::NoResult, + }); + + log_instruction!( + "{:10} {:?}\t{:?}", + format!("{:?}", opcode), + block_type, + &self.vm_block_stack + ); + } + + fn inst_imm32(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u32) { + self.inst_base(opcode, pops, push); self.code.encode_u32(immediate); + log_instruction!( + "{:10}\t{}\t{:?}", + format!("{:?}", opcode), + immediate, + self.current_stack() + ); } fn inst_mem(&mut self, opcode: OpCode, pops: usize, push: bool, align: Align, offset: u32) { - self.inst(opcode, pops, push); + self.inst_base(opcode, pops, push); self.code.push(align as u8); self.code.encode_u32(offset); + log_instruction!( + "{:10} {:?} {}\t{:?}", + format!("{:?}", opcode), + align, + offset, + self.current_stack() + ); } /// Insert a linker relocation for a memory address @@ -488,22 +586,38 @@ impl<'a> CodeBuilder<'a> { instruction_no_args!(nop, NOP, 0, false); pub fn block(&mut self, ty: BlockType) { - self.inst_imm8(BLOCK, 0, false, ty.as_byte()); + self.inst_block(BLOCK, 0, ty); } pub fn loop_(&mut self, ty: BlockType) { - self.inst_imm8(LOOP, 0, false, ty.as_byte()); + self.inst_block(LOOP, 0, ty); } pub fn if_(&mut self, ty: BlockType) { - self.inst_imm8(IF, 1, false, ty.as_byte()); + self.inst_block(IF, 1, ty); + } + pub fn else_(&mut self) { + // Reuse the 'then' block but clear its value stack + self.current_stack_mut().clear(); + self.inst(ELSE, 0, false); } - instruction_no_args!(else_, ELSE, 0, false); - instruction_no_args!(end, END, 0, false); + pub fn end(&mut self) { + self.inst_base(END, 0, false); + let ended_block = self.vm_block_stack.pop().unwrap(); + if ended_block.has_result { + let result = ended_block.value_stack.last().unwrap(); + self.current_stack_mut().push(*result) + } + + log_instruction!("END \t\t{:?}", &self.vm_block_stack); + } pub fn br(&mut self, levels: u32) { self.inst_imm32(BR, 0, false, levels); } pub fn br_if(&mut self, levels: u32) { + // In dynamic execution, br_if can pop 2 values if condition is true and the target block has a result. + // But our stack model is for *static* analysis and we need it to be correct at the next instruction, + // where the branch was not taken. So we only pop 1 value, the condition. self.inst_imm32(BRIF, 1, false, levels); } #[allow(dead_code)] @@ -520,7 +634,7 @@ impl<'a> CodeBuilder<'a> { n_args: usize, has_return_val: bool, ) { - self.inst(CALL, n_args, has_return_val); + self.inst_base(CALL, n_args, has_return_val); let offset = self.code.len() as u32; self.code.encode_padded_u32(function_index); @@ -533,6 +647,13 @@ impl<'a> CodeBuilder<'a> { offset, symbol_index, }); + + log_instruction!( + "{:10}\t{}\t{:?}", + format!("{:?}", CALL), + function_index, + self.current_stack() + ); } #[allow(dead_code)] @@ -584,26 +705,44 @@ impl<'a> CodeBuilder<'a> { instruction_memargs!(i64_store32, I64STORE32, 2, false); pub fn memory_size(&mut self) { - self.inst_imm8(CURRENTMEMORY, 0, true, 0); + self.inst(CURRENTMEMORY, 0, true); + self.code.push(0); } pub fn memory_grow(&mut self) { - self.inst_imm8(GROWMEMORY, 1, true, 0); + self.inst(GROWMEMORY, 1, true); + self.code.push(0); + } + + fn log_const(&self, opcode: OpCode, x: T) + where + T: std::fmt::Debug + std::fmt::Display, + { + log_instruction!( + "{:10}\t{}\t{:?}", + format!("{:?}", opcode), + x, + self.current_stack() + ); } pub fn i32_const(&mut self, x: i32) { - self.inst(I32CONST, 0, true); + self.inst_base(I32CONST, 0, true); self.code.encode_i32(x); + self.log_const(I32CONST, x); } pub fn i64_const(&mut self, x: i64) { - self.inst(I64CONST, 0, true); + self.inst_base(I64CONST, 0, true); self.code.encode_i64(x); + self.log_const(I64CONST, x); } pub fn f32_const(&mut self, x: f32) { - self.inst(F32CONST, 0, true); + self.inst_base(F32CONST, 0, true); self.code.encode_f32(x); + self.log_const(F32CONST, x); } pub fn f64_const(&mut self, x: f64) { - self.inst(F64CONST, 0, true); + self.inst_base(F64CONST, 0, true); self.code.encode_f64(x); + self.log_const(F64CONST, x); } // TODO: Consider creating unified methods for numerical ops like 'eq' and 'add', diff --git a/compiler/gen_wasm/src/wasm_module/opcodes.rs b/compiler/gen_wasm/src/wasm_module/opcodes.rs index cb8ef70b47..868b77375d 100644 --- a/compiler/gen_wasm/src/wasm_module/opcodes.rs +++ b/compiler/gen_wasm/src/wasm_module/opcodes.rs @@ -1,5 +1,5 @@ #[repr(u8)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum OpCode { UNREACHABLE = 0x00, NOP = 0x01, diff --git a/compiler/test_gen/src/gen_primitives.rs b/compiler/test_gen/src/gen_primitives.rs index de4c4f813d..7928fc109e 100644 --- a/compiler/test_gen/src/gen_primitives.rs +++ b/compiler/test_gen/src/gen_primitives.rs @@ -385,7 +385,7 @@ fn gen_basic_def() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_multiple_defs() { assert_evals_to!( indoc!( From f121d6f599ccfbd8948f266c8efc58a3e44f6ace Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 14 Nov 2021 13:21:56 +0000 Subject: [PATCH 059/223] Fix formatting --- compiler/gen_wasm/src/wasm_module/code_builder.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index ed2a850576..660f612bdf 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -63,8 +63,11 @@ struct VmBlock<'a> { impl std::fmt::Debug for VmBlock<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let result = if self.has_result { "Result" } else { "NoResult" }; - f.write_fmt(format_args!("{:?} {}", self.opcode, result)) + f.write_fmt(format_args!("{:?} {}", self.opcode, if self.has_result { + "Result" + } else { + "NoResult" + })) } } @@ -308,7 +311,10 @@ impl<'a> CodeBuilder<'a> { self.add_insertion(pushed_at, SETLOCAL, next_local_id.0); } else { if ENABLE_DEBUG_LOG { - println!("{:?} has been popped implicitly. Leaving it on the stack.", symbol); + println!( + "{:?} has been popped implicitly. Leaving it on the stack.", + symbol + ); } self.add_insertion(pushed_at, TEELOCAL, next_local_id.0); } From d34f5050cb65ee5abae0ed9c9623508dbc51e47d Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 14 Nov 2021 13:35:25 +0000 Subject: [PATCH 060/223] formatting --- compiler/gen_wasm/src/wasm_module/code_builder.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index 660f612bdf..5468784926 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -63,11 +63,15 @@ struct VmBlock<'a> { impl std::fmt::Debug for VmBlock<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("{:?} {}", self.opcode, if self.has_result { - "Result" - } else { - "NoResult" - })) + f.write_fmt(format_args!( + "{:?} {}", + self.opcode, + if self.has_result { + "Result" + } else { + "NoResult" + } + )) } } From 5b64eb6983f995a7914c4448b41a2826efeb74a1 Mon Sep 17 00:00:00 2001 From: satotake Date: Sun, 14 Nov 2021 13:35:39 +0000 Subject: [PATCH 061/223] refacotr `List.drop` --- compiler/can/src/builtins.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 25c4e9b1d7..9f15173254 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2144,20 +2144,33 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { /// List.drop : List elem, Nat -> List elem fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); - let index_var = var_store.fresh(); + let len_var = var_store.fresh(); + + let get_list_len = RunLowLevel { + op: LowLevel::ListLen, + args: vec![(list_var, Var(Symbol::ARG_1))], + ret_var: len_var, + }; + + let get_len = RunLowLevel { + op: LowLevel::NumSubWrap, + args: vec![(len_var, get_list_len), (len_var, Var(Symbol::ARG_2))], + ret_var: len_var, + }; let body = RunLowLevel { - op: LowLevel::ListDrop, + op: LowLevel::ListSublist, args: vec![ (list_var, Var(Symbol::ARG_1)), - (index_var, Var(Symbol::ARG_2)), + (len_var, Var(Symbol::ARG_2)), + (len_var, get_len), ], ret_var: list_var, }; defn( symbol, - vec![(list_var, Symbol::ARG_1), (index_var, Symbol::ARG_2)], + vec![(list_var, Symbol::ARG_1), (len_var, Symbol::ARG_2)], var_store, body, list_var, From a436893b381886c727b5201a4e2a3939e2d7de7b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 14 Nov 2021 16:50:54 +0000 Subject: [PATCH 062/223] Update nixpkgs sources Signed-off-by: Matthias Beyer --- nix/sources.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nix/sources.json b/nix/sources.json index ed41deee13..51fc580d86 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -17,10 +17,10 @@ "homepage": "", "owner": "NixOS", "repo": "nixpkgs", - "rev": "51acb65b302551ac7993b437cc6863fe9fa8ae50", - "sha256": "0si8s2ji4prp614q3050x4sp282wxgp0mm5q50slcf5f75jw5yhh", + "rev": "5cb226a06c49f7a2d02863d0b5786a310599df6b", + "sha256": "0dzz207swwm5m0dyibhxg5psccrcqfh1lzkmzzfns27wc4ria6z3", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/51acb65b302551ac7993b437cc6863fe9fa8ae50.tar.gz", + "url": "https://github.com/NixOS/nixpkgs/archive/5cb226a06c49f7a2d02863d0b5786a310599df6b.tar.gz", "url_template": "https://github.com///archive/.tar.gz" } } From c10f403c941ba4360853b8a68c78c11f524d1c28 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Wed, 10 Nov 2021 19:28:04 -0800 Subject: [PATCH 063/223] Allow trailing comments in exposes decl --- compiler/load/src/file.rs | 4 +-- compiler/parse/src/header.rs | 9 ++++-- compiler/parse/src/module.rs | 12 ++++---- compiler/parse/src/parser.rs | 1 + compiler/parse/tests/test_parse.rs | 45 ++++++++++++++++++++++++++---- 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 0d20be6415..745574b9a7 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3886,7 +3886,7 @@ fn exposed_from_import<'a>(entry: &ImportsEntry<'a>) -> (QualifiedModuleName<'a> Module(module_name, exposes) => { let mut exposed = Vec::with_capacity(exposes.len()); - for loc_entry in exposes { + for loc_entry in exposes.iter() { exposed.push(ident_from_exposed(&loc_entry.value)); } @@ -3901,7 +3901,7 @@ fn exposed_from_import<'a>(entry: &ImportsEntry<'a>) -> (QualifiedModuleName<'a> Package(package_name, module_name, exposes) => { let mut exposed = Vec::with_capacity(exposes.len()); - for loc_entry in exposes { + for loc_entry in exposes.iter() { exposed.push(ident_from_exposed(&loc_entry.value)); } diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index 42c35cd0dc..c5d3696630 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -177,7 +177,7 @@ pub struct Effects<'a> { pub entries: &'a [Loc>], } -#[derive(Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum ExposesEntry<'a, T> { /// e.g. `Task` Exposed(T), @@ -199,13 +199,16 @@ impl<'a, T> Spaceable<'a> for ExposesEntry<'a, T> { #[derive(Clone, Debug, PartialEq)] pub enum ImportsEntry<'a> { /// e.g. `Task` or `Task.{ Task, after }` - Module(ModuleName<'a>, Vec<'a, Loc>>), + Module( + ModuleName<'a>, + Collection<'a, Loc>>, + ), /// e.g. `base.Task` or `base.Task.{ after }` or `base.{ Task.{ Task, after } }` Package( &'a str, ModuleName<'a>, - Vec<'a, Loc>>, + Collection<'a, Loc>>, ), // Spaces diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index eec34ecbcb..e33c7daf1d 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -768,7 +768,7 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> { type Temp<'a> = ( (Option<&'a str>, ModuleName<'a>), - Option>>>, + Option>>>, ); map_with_arena!( @@ -785,19 +785,21 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> { // e.g. `.{ Task, after}` maybe!(skip_first!( word1(b'.', EImports::ExposingDot), - collection_e!( + collection_trailing_sep_e!( word1(b'{', EImports::SetStart), exposes_entry(EImports::Identifier), word1(b',', EImports::SetEnd), word1(b'}', EImports::SetEnd), min_indent, + EImports::Open, EImports::Space, - EImports::IndentSetEnd + EImports::IndentSetEnd, + ExposesEntry::SpaceBefore ) )) ), - |arena, ((opt_shortname, module_name), opt_values): Temp<'a>| { - let exposed_values = opt_values.unwrap_or_else(|| Vec::new_in(arena)); + |_arena, ((opt_shortname, module_name), opt_values): Temp<'a>| { + let exposed_values = opt_values.unwrap_or_else(|| Collection::empty()); match opt_shortname { Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values), diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 07b9800359..ece23b6c2b 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -315,6 +315,7 @@ pub enum EEffects<'a> { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EImports { + Open(Row, Col), Imports(Row, Col), IndentImports(Row, Col), IndentListStart(Row, Col), diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index c49820045b..041123c9e7 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3166,7 +3166,7 @@ mod test_parse { let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); let arena = Bump::new(); let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); - let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena)); + let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Collection::empty()); let loc_import = Located::new(2, 2, 14, 25, import); let imports = bumpalo::vec![in &arena; loc_import]; let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort")); @@ -3222,10 +3222,39 @@ mod test_parse { let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); let arena = Bump::new(); let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); - let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena)); - let loc_import = Located::new(2, 2, 14, 25, import); + let import = ImportsEntry::Package( + "foo", + ModuleName::new("Bar"), + Collection::with_items_and_comments( + &arena, + arena.alloc([ + Located::new( + 3, + 3, + 8, + 11, + ExposesEntry::SpaceBefore( + arena.alloc(ExposesEntry::Exposed("Baz")), + arena.alloc([Newline]), + ), + ), + Located::new( + 4, + 4, + 8, + 17, + ExposesEntry::SpaceBefore( + arena.alloc(ExposesEntry::Exposed("FourtyTwo")), + arena.alloc([Newline]), + ), + ), + ]), + arena.alloc([Newline, LineComment(" I'm a happy comment")]), + ), + ); + let loc_import = Located::new(2, 6, 14, 5, import); let imports = bumpalo::vec![in &arena; loc_import]; - let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort")); + let provide_entry = Located::new(7, 7, 15, 24, Exposed("quicksort")); let provides = bumpalo::vec![in &arena; provide_entry]; let module_name = StrLiteral::PlainLine("quicksort"); @@ -3235,7 +3264,7 @@ mod test_parse { packages, imports, provides, - to: Located::new(3, 3, 30, 34, To::ExistingPackage("base")), + to: Located::new(7, 7, 30, 34, To::ExistingPackage("base")), after_app_keyword: &[], before_packages: newlines, after_packages: &[], @@ -3253,7 +3282,11 @@ mod test_parse { r#" app "quicksort" packages { base: "./platform", } - imports [ foo.Bar.Baz ] + imports [ foo.Bar.{ + Baz, + FourtyTwo, + # I'm a happy comment + } ] provides [ quicksort ] to base "# ); From 23c75d269988890f911deae2e3eb58fde7763094 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Wed, 10 Nov 2021 19:39:02 -0800 Subject: [PATCH 064/223] Allow trailing comments in imports decl --- compiler/fmt/src/module.rs | 8 ++++---- compiler/load/src/file.rs | 6 +++--- compiler/parse/src/header.rs | 10 +++++----- compiler/parse/src/module.rs | 12 +++++++----- compiler/parse/tests/test_parse.rs | 16 ++++++++-------- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/compiler/fmt/src/module.rs b/compiler/fmt/src/module.rs index 6ceca3d28c..e0ba55a451 100644 --- a/compiler/fmt/src/module.rs +++ b/compiler/fmt/src/module.rs @@ -1,6 +1,6 @@ use crate::spaces::{fmt_spaces, INDENT}; use bumpalo::collections::{String, Vec}; -use roc_parse::ast::Module; +use roc_parse::ast::{Collection, Module}; use roc_parse::header::{AppHeader, ExposesEntry, ImportsEntry, InterfaceHeader, PlatformHeader}; use roc_region::all::Located; @@ -64,7 +64,7 @@ pub fn fmt_interface_header<'a>(buf: &mut String<'a>, header: &'a InterfaceHeade fmt_spaces(buf, header.after_imports.iter(), indent); } - fmt_imports(buf, &header.imports, indent); + fmt_imports(buf, header.imports, indent); } pub fn fmt_app_header<'a>(buf: &mut String<'a>, header: &'a AppHeader<'a>) { @@ -76,7 +76,7 @@ pub fn fmt_app_header<'a>(buf: &mut String<'a>, header: &'a AppHeader<'a>) { buf.push_str("imports"); fmt_spaces(buf, header.before_imports.iter(), indent); - fmt_imports(buf, &header.imports, indent); + fmt_imports(buf, header.imports, indent); fmt_spaces(buf, header.after_imports.iter(), indent); } @@ -86,7 +86,7 @@ pub fn fmt_platform_header<'a>(_buf: &mut String<'a>, _header: &'a PlatformHeade fn fmt_imports<'a>( buf: &mut String<'a>, - loc_entries: &'a Vec<'a, Located>>, + loc_entries: Collection<'a, Located>>, indent: u16, ) { buf.push('['); diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 745574b9a7..2a4bd23738 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2609,7 +2609,7 @@ fn parse_header<'a>( header_src, packages: &[], exposes: header.exposes.into_bump_slice(), - imports: header.imports.into_bump_slice(), + imports: header.imports.items, to_platform: None, }; @@ -2643,7 +2643,7 @@ fn parse_header<'a>( header_src, packages, exposes: header.provides.into_bump_slice(), - imports: header.imports.into_bump_slice(), + imports: header.imports.items, to_platform: Some(header.to.value.clone()), }; @@ -3421,7 +3421,7 @@ fn fabricate_pkg_config_module<'a>( packages: &[], provides, requires: arena.alloc([header.requires.signature.clone()]), - imports: header.imports.clone().into_bump_slice(), + imports: header.imports.items, }; send_header_two( diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index c5d3696630..d0c76d22c5 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -38,7 +38,7 @@ pub enum PackageOrPath<'a> { Path(StrLiteral<'a>), } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct ModuleName<'a>(&'a str); impl<'a> From> for &'a str { @@ -61,7 +61,7 @@ impl<'a> ModuleName<'a> { pub struct InterfaceHeader<'a> { pub name: Loc>, pub exposes: Vec<'a, Loc>>, - pub imports: Vec<'a, Loc>>, + pub imports: Collection<'a, Loc>>, // Potential comments and newlines - these will typically all be empty. pub before_header: &'a [CommentOrNewline<'a>], @@ -82,7 +82,7 @@ pub enum To<'a> { pub struct AppHeader<'a> { pub name: Loc>, pub packages: Collection<'a, Loc>>, - pub imports: Vec<'a, Loc>>, + pub imports: Collection<'a, Loc>>, pub provides: Vec<'a, Loc>>, pub to: Loc>, @@ -147,7 +147,7 @@ pub struct PlatformHeader<'a> { pub requires: PlatformRequires<'a>, pub exposes: Vec<'a, Loc>>>, pub packages: Collection<'a, Loc>>, - pub imports: Vec<'a, Loc>>, + pub imports: Collection<'a, Loc>>, pub provides: Vec<'a, Loc>>, pub effects: Effects<'a>, @@ -196,7 +196,7 @@ impl<'a, T> Spaceable<'a> for ExposesEntry<'a, T> { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum ImportsEntry<'a> { /// e.g. `Task` or `Task.{ Task, after }` Module( diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index e33c7daf1d..56f22610d9 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -220,11 +220,11 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> { #[allow(clippy::type_complexity)] let opt_imports: Option<( (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), - Vec<'a, Located>>, + Collection<'a, Located>>, )> = opt_imports; let ((before_imports, after_imports), imports) = - opt_imports.unwrap_or_else(|| ((&[] as _, &[] as _), Vec::new_in(arena))); + opt_imports.unwrap_or_else(|| ((&[] as _, &[] as _), Collection::empty())); let provides: ProvidesTo<'a> = provides; // rustc must be told the type here let header = AppHeader { @@ -631,7 +631,7 @@ fn imports<'a>() -> impl Parser< 'a, ( (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), - Vec<'a, Located>>, + Collection<'a, Located>>, ), EImports, > { @@ -646,14 +646,16 @@ fn imports<'a>() -> impl Parser< EImports::IndentImports, EImports::IndentListStart ), - collection_e!( + collection_trailing_sep_e!( word1(b'[', EImports::ListStart), loc!(imports_entry()), word1(b',', EImports::ListEnd), word1(b']', EImports::ListEnd), min_indent, + EImports::Open, EImports::Space, - EImports::IndentListEnd + EImports::IndentListEnd, + ImportsEntry::SpaceBefore ) ) } diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 041123c9e7..5782b1d239 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3077,7 +3077,7 @@ mod test_parse { fn empty_app_header() { let arena = Bump::new(); let packages = Collection::empty(); - let imports = Vec::new_in(&arena); + let imports = Collection::empty(); let provides = Vec::new_in(&arena); let module_name = StrLiteral::PlainLine("test-app"); let header = AppHeader { @@ -3117,7 +3117,7 @@ mod test_parse { let arena = Bump::new(); let packages = Collection::empty(); - let imports = Vec::new_in(&arena); + let imports = Collection::empty(); let provides = Vec::new_in(&arena); let module_name = StrLiteral::PlainLine("test-app"); let header = AppHeader { @@ -3168,7 +3168,7 @@ mod test_parse { let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Collection::empty()); let loc_import = Located::new(2, 2, 14, 25, import); - let imports = bumpalo::vec![in &arena; loc_import]; + let imports = Collection::with_items(arena.alloc([loc_import])); let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort")); let provides = bumpalo::vec![in &arena; provide_entry]; let module_name = StrLiteral::PlainLine("quicksort"); @@ -3253,7 +3253,7 @@ mod test_parse { ), ); let loc_import = Located::new(2, 6, 14, 5, import); - let imports = bumpalo::vec![in &arena; loc_import]; + let imports = Collection::with_items(arena.alloc([loc_import])); let provide_entry = Located::new(7, 7, 15, 24, Exposed("quicksort")); let provides = bumpalo::vec![in &arena; provide_entry]; let module_name = StrLiteral::PlainLine("quicksort"); @@ -3342,7 +3342,7 @@ mod test_parse { requires, exposes: Vec::new_in(&arena), packages: Collection::empty(), - imports: Vec::new_in(&arena), + imports: Collection::empty(), provides: Vec::new_in(&arena), effects, after_platform_keyword: &[], @@ -3385,7 +3385,7 @@ mod test_parse { let loc_pkg_entry = Located::new(3, 3, 15, 27, pkg_entry); let arena = Bump::new(); let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); - let imports = Vec::new_in(&arena); + let imports = Collection::empty(); let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost")); let provides = bumpalo::vec![in &arena; provide_entry]; let effects = Effects { @@ -3466,7 +3466,7 @@ mod test_parse { fn empty_interface_header() { let arena = Bump::new(); let exposes = Vec::new_in(&arena); - let imports = Vec::new_in(&arena); + let imports = Collection::empty(); let module_name = ModuleName::new("Foo"); let header = InterfaceHeader { before_header: &[], @@ -3498,7 +3498,7 @@ mod test_parse { fn nested_module() { let arena = Bump::new(); let exposes = Vec::new_in(&arena); - let imports = Vec::new_in(&arena); + let imports = Collection::empty(); let module_name = ModuleName::new("Foo.Bar.Baz"); let header = InterfaceHeader { before_header: &[], From d67b6c50b106fe74da7add5f567c8743ee42a440 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Wed, 10 Nov 2021 20:20:55 -0800 Subject: [PATCH 065/223] Allow trailing comments in provides decl --- compiler/parse/src/module.rs | 15 ++++++++++----- compiler/parse/src/parser.rs | 1 + compiler/parse/tests/test_parse.rs | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index 56f22610d9..004a17a6f8 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -270,7 +270,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> { let (_, ((before_imports, after_imports), imports), state) = specialize(EHeader::Imports, imports()).parse(arena, state)?; - let (_, ((before_provides, after_provides), provides), state) = + let (_, ((before_provides, after_provides), (provides, provides_final_comments)), state) = specialize(EHeader::Provides, provides_without_to()).parse(arena, state)?; let (_, effects, state) = specialize(EHeader::Effects, effects()).parse(arena, state)?; @@ -342,7 +342,7 @@ fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> { ) ), |( - ((before_provides_keyword, after_provides_keyword), entries), + ((before_provides_keyword, after_provides_keyword), (entries, final_comments)), ((before_to_keyword, after_to_keyword), to), )| { ProvidesTo { @@ -362,7 +362,10 @@ fn provides_without_to<'a>() -> impl Parser< 'a, ( (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), - Vec<'a, Located>>, + ( + Vec<'a, Located>>, + &'a [CommentOrNewline<'a>], + ), ), EProvides<'a>, > { @@ -376,14 +379,16 @@ fn provides_without_to<'a>() -> impl Parser< EProvides::IndentProvides, EProvides::IndentListStart ), - collection_e!( + collection_trailing_sep_e!( word1(b'[', EProvides::ListStart), exposes_entry(EProvides::Identifier), word1(b',', EProvides::ListEnd), word1(b']', EProvides::ListEnd), min_indent, + EProvides::Open, EProvides::Space, - EProvides::IndentListEnd + EProvides::IndentListEnd, + ExposesEntry::SpaceBefore ) ) } diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index ece23b6c2b..4b0270e74a 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -214,6 +214,7 @@ pub enum EHeader<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub enum EProvides<'a> { Provides(Row, Col), + Open(Row, Col), To(Row, Col), IndentProvides(Row, Col), IndentTo(Row, Col), diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 5782b1d239..4d3fd5e2ba 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3264,7 +3264,7 @@ mod test_parse { packages, imports, provides, - to: Located::new(7, 7, 30, 34, To::ExistingPackage("base")), + to: Located::new(7, 7, 31, 35, To::ExistingPackage("base")), after_app_keyword: &[], before_packages: newlines, after_packages: &[], @@ -3287,7 +3287,7 @@ mod test_parse { FourtyTwo, # I'm a happy comment } ] - provides [ quicksort ] to base + provides [ quicksort, ] to base "# ); From df89fe7dd686960cf76506fc57a5527c72edc27b Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 10:58:45 -0800 Subject: [PATCH 066/223] Make provides a Collection --- compiler/load/src/file.rs | 4 ++-- compiler/parse/src/header.rs | 4 ++-- compiler/parse/src/module.rs | 11 ++++------- compiler/parse/tests/test_parse.rs | 12 ++++++------ 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 2a4bd23738..11c30c2dc7 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2642,7 +2642,7 @@ fn parse_header<'a>( opt_shorthand, header_src, packages, - exposes: header.provides.into_bump_slice(), + exposes: header.provides.items, imports: header.imports.items, to_platform: Some(header.to.value.clone()), }; @@ -3410,7 +3410,7 @@ fn fabricate_pkg_config_module<'a>( module_timing: ModuleTiming, ) -> (ModuleId, Msg<'a>) { let provides: &'a [Located>] = - header.provides.clone().into_bump_slice(); + header.provides.items; let info = PlatformHeaderInfo { filename, diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index d0c76d22c5..37475ebce1 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -83,7 +83,7 @@ pub struct AppHeader<'a> { pub name: Loc>, pub packages: Collection<'a, Loc>>, pub imports: Collection<'a, Loc>>, - pub provides: Vec<'a, Loc>>, + pub provides: Collection<'a, Loc>>, pub to: Loc>, // Potential comments and newlines - these will typically all be empty. @@ -148,7 +148,7 @@ pub struct PlatformHeader<'a> { pub exposes: Vec<'a, Loc>>>, pub packages: Collection<'a, Loc>>, pub imports: Collection<'a, Loc>>, - pub provides: Vec<'a, Loc>>, + pub provides: Collection<'a, Loc>>, pub effects: Effects<'a>, // Potential comments and newlines - these will typically all be empty. diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index 004a17a6f8..4a31995e91 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -270,7 +270,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> { let (_, ((before_imports, after_imports), imports), state) = specialize(EHeader::Imports, imports()).parse(arena, state)?; - let (_, ((before_provides, after_provides), (provides, provides_final_comments)), state) = + let (_, ((before_provides, after_provides), provides), state) = specialize(EHeader::Provides, provides_without_to()).parse(arena, state)?; let (_, effects, state) = specialize(EHeader::Effects, effects()).parse(arena, state)?; @@ -303,7 +303,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> { #[derive(Debug)] struct ProvidesTo<'a> { - entries: Vec<'a, Located>>, + entries: Collection<'a, Located>>, to: Located>, before_provides_keyword: &'a [CommentOrNewline<'a>], @@ -342,7 +342,7 @@ fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> { ) ), |( - ((before_provides_keyword, after_provides_keyword), (entries, final_comments)), + ((before_provides_keyword, after_provides_keyword), entries), ((before_to_keyword, after_to_keyword), to), )| { ProvidesTo { @@ -362,10 +362,7 @@ fn provides_without_to<'a>() -> impl Parser< 'a, ( (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), - ( - Vec<'a, Located>>, - &'a [CommentOrNewline<'a>], - ), + Collection<'a, Located>>, ), EProvides<'a>, > { diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 4d3fd5e2ba..b3b3779bd4 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3078,7 +3078,7 @@ mod test_parse { let arena = Bump::new(); let packages = Collection::empty(); let imports = Collection::empty(); - let provides = Vec::new_in(&arena); + let provides = Collection::empty(); let module_name = StrLiteral::PlainLine("test-app"); let header = AppHeader { name: Located::new(0, 0, 4, 14, module_name), @@ -3118,7 +3118,7 @@ mod test_parse { let arena = Bump::new(); let packages = Collection::empty(); let imports = Collection::empty(); - let provides = Vec::new_in(&arena); + let provides = Collection::empty(); let module_name = StrLiteral::PlainLine("test-app"); let header = AppHeader { before_header: &[], @@ -3170,7 +3170,7 @@ mod test_parse { let loc_import = Located::new(2, 2, 14, 25, import); let imports = Collection::with_items(arena.alloc([loc_import])); let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort")); - let provides = bumpalo::vec![in &arena; provide_entry]; + let provides = Collection::with_items(arena.alloc([provide_entry])); let module_name = StrLiteral::PlainLine("quicksort"); let header = AppHeader { @@ -3255,7 +3255,7 @@ mod test_parse { let loc_import = Located::new(2, 6, 14, 5, import); let imports = Collection::with_items(arena.alloc([loc_import])); let provide_entry = Located::new(7, 7, 15, 24, Exposed("quicksort")); - let provides = bumpalo::vec![in &arena; provide_entry]; + let provides = Collection::with_items(arena.alloc([provide_entry])); let module_name = StrLiteral::PlainLine("quicksort"); let header = AppHeader { @@ -3343,7 +3343,7 @@ mod test_parse { exposes: Vec::new_in(&arena), packages: Collection::empty(), imports: Collection::empty(), - provides: Vec::new_in(&arena), + provides: Collection::empty(), effects, after_platform_keyword: &[], before_requires: &[], @@ -3387,7 +3387,7 @@ mod test_parse { let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); let imports = Collection::empty(); let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost")); - let provides = bumpalo::vec![in &arena; provide_entry]; + let provides = Collection::with_items(arena.alloc([provide_entry])); let effects = Effects { effect_type_name: "Effect", effect_shortname: "fx", From 71cc8d4c4b7b8fb3e5fe28833e95826c179c783d Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 11:09:52 -0800 Subject: [PATCH 067/223] Convert requires_rigids to collection_trailing_sep_e --- compiler/load/src/file.rs | 3 +-- compiler/parse/src/header.rs | 4 ++-- compiler/parse/src/module.rs | 8 +++++--- compiler/parse/src/parser.rs | 1 + compiler/parse/tests/test_parse.rs | 10 ++++++++-- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 11c30c2dc7..eb77687428 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3409,8 +3409,7 @@ fn fabricate_pkg_config_module<'a>( header_src: &'a str, module_timing: ModuleTiming, ) -> (ModuleId, Msg<'a>) { - let provides: &'a [Located>] = - header.provides.items; + let provides: &'a [Located>] = header.provides.items; let info = PlatformHeaderInfo { filename, diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index 37475ebce1..f7ec7139b9 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -117,7 +117,7 @@ pub struct PackageHeader<'a> { pub after_imports: &'a [CommentOrNewline<'a>], } -#[derive(Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum PlatformRigid<'a> { Entry { rigid: &'a str, alias: &'a str }, @@ -137,7 +137,7 @@ impl<'a> Spaceable<'a> for PlatformRigid<'a> { #[derive(Clone, Debug, PartialEq)] pub struct PlatformRequires<'a> { - pub rigids: Vec<'a, Loc>>, + pub rigids: Collection<'a, Loc>>, pub signature: Loc>, } diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index 4a31995e91..e6a8d9a6e3 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -444,15 +444,17 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a #[inline(always)] fn requires_rigids<'a>( min_indent: u16, -) -> impl Parser<'a, Vec<'a, Located>>, ERequires<'a>> { - collection_e!( +) -> impl Parser<'a, Collection<'a, Located>>, ERequires<'a>> { + collection_trailing_sep_e!( word1(b'{', ERequires::ListStart), specialize(|_, r, c| ERequires::Rigid(r, c), loc!(requires_rigid())), word1(b',', ERequires::ListEnd), word1(b'}', ERequires::ListEnd), min_indent, + ERequires::Open, ERequires::Space, - ERequires::IndentListEnd + ERequires::IndentListEnd, + PlatformRigid::SpaceBefore ) } diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 4b0270e74a..1c176893d5 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -243,6 +243,7 @@ pub enum EExposes { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ERequires<'a> { Requires(Row, Col), + Open(Row, Col), IndentRequires(Row, Col), IndentListStart(Row, Col), IndentListEnd(Row, Col), diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index b3b3779bd4..5a194088f5 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3318,7 +3318,7 @@ mod test_parse { let region2 = Region::new(0, 0, 45, 47); PlatformRequires { - rigids: Vec::new_in(&arena), + rigids: Collection::empty(), signature: Located::at( region1, TypedIdent::Entry { @@ -3403,7 +3403,13 @@ mod test_parse { let region3 = Region::new(1, 1, 14, 26); PlatformRequires { - rigids: bumpalo::vec![ in &arena; Located::at(region3, PlatformRigid::Entry { alias: "Model", rigid: "model" }) ], + rigids: Collection::with_items(arena.alloc([Located::at( + region3, + PlatformRigid::Entry { + alias: "Model", + rigid: "model", + }, + )])), signature: Located::at( region1, TypedIdent::Entry { From c4e70ca7aa6b268c014439a414f27449f5cb300d Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 11:12:17 -0800 Subject: [PATCH 068/223] Convert exposes_values to ccollection_trailing_sep_e --- compiler/fmt/src/module.rs | 4 ++-- compiler/load/src/file.rs | 2 +- compiler/parse/src/header.rs | 2 +- compiler/parse/src/module.rs | 8 +++++--- compiler/parse/src/parser.rs | 1 + compiler/parse/tests/test_parse.rs | 4 ++-- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/fmt/src/module.rs b/compiler/fmt/src/module.rs index e0ba55a451..17522326c2 100644 --- a/compiler/fmt/src/module.rs +++ b/compiler/fmt/src/module.rs @@ -1,5 +1,5 @@ use crate::spaces::{fmt_spaces, INDENT}; -use bumpalo::collections::{String, Vec}; +use bumpalo::collections::String; use roc_parse::ast::{Collection, Module}; use roc_parse::header::{AppHeader, ExposesEntry, ImportsEntry, InterfaceHeader, PlatformHeader}; use roc_region::all::Located; @@ -112,7 +112,7 @@ fn fmt_imports<'a>( fn fmt_exposes<'a>( buf: &mut String<'a>, - loc_entries: &'a Vec<'a, Located>>, + loc_entries: &'a Collection<'a, Located>>, indent: u16, ) { buf.push('['); diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index eb77687428..89e610ef0b 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2608,7 +2608,7 @@ fn parse_header<'a>( opt_shorthand, header_src, packages: &[], - exposes: header.exposes.into_bump_slice(), + exposes: header.exposes.items, imports: header.imports.items, to_platform: None, }; diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index f7ec7139b9..f40c0d6780 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -60,7 +60,7 @@ impl<'a> ModuleName<'a> { #[derive(Clone, Debug, PartialEq)] pub struct InterfaceHeader<'a> { pub name: Loc>, - pub exposes: Vec<'a, Loc>>, + pub exposes: Collection<'a, Loc>>, pub imports: Collection<'a, Loc>>, // Potential comments and newlines - these will typically all be empty. diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index e6a8d9a6e3..00583fbb5a 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -491,7 +491,7 @@ fn exposes_values<'a>() -> impl Parser< 'a, ( (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), - Vec<'a, Located>>, + Collection<'a, Located>>, ), EExposes, > { @@ -506,14 +506,16 @@ fn exposes_values<'a>() -> impl Parser< EExposes::IndentExposes, EExposes::IndentListStart ), - collection_e!( + collection_trailing_sep_e!( word1(b'[', EExposes::ListStart), exposes_entry(EExposes::Identifier), word1(b',', EExposes::ListEnd), word1(b']', EExposes::ListEnd), min_indent, + EExposes::Open, EExposes::Space, - EExposes::IndentListEnd + EExposes::IndentListEnd, + ExposesEntry::SpaceBefore ) ) } diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 1c176893d5..73a32128f7 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -231,6 +231,7 @@ pub enum EProvides<'a> { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EExposes { Exposes(Row, Col), + Open(Row, Col), IndentExposes(Row, Col), IndentListStart(Row, Col), IndentListEnd(Row, Col), diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 5a194088f5..db54abf04f 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3471,7 +3471,7 @@ mod test_parse { #[test] fn empty_interface_header() { let arena = Bump::new(); - let exposes = Vec::new_in(&arena); + let exposes = Collection::empty(); let imports = Collection::empty(); let module_name = ModuleName::new("Foo"); let header = InterfaceHeader { @@ -3503,7 +3503,7 @@ mod test_parse { #[test] fn nested_module() { let arena = Bump::new(); - let exposes = Vec::new_in(&arena); + let exposes = Collection::empty(); let imports = Collection::empty(); let module_name = ModuleName::new("Foo.Bar.Baz"); let header = InterfaceHeader { From 8c8bc910fd1c32d8f986298974cee4cd9dc612a9 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 11:13:54 -0800 Subject: [PATCH 069/223] Convert exposes_modules to collection_trailing_sep_e --- compiler/load/src/file.rs | 2 +- compiler/parse/src/header.rs | 2 +- compiler/parse/src/module.rs | 8 +++++--- compiler/parse/tests/test_parse.rs | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 89e610ef0b..c733460053 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3466,7 +3466,7 @@ fn fabricate_effects_module<'a>( { let mut module_ids = (*module_ids).lock(); - for exposed in header.exposes { + for exposed in header.exposes.iter() { if let ExposesEntry::Exposed(module_name) = exposed.value { module_ids.get_or_insert(&PQModuleName::Qualified( shorthand, diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index f40c0d6780..20e680ca2f 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -145,7 +145,7 @@ pub struct PlatformRequires<'a> { pub struct PlatformHeader<'a> { pub name: Loc>, pub requires: PlatformRequires<'a>, - pub exposes: Vec<'a, Loc>>>, + pub exposes: Collection<'a, Loc>>>, pub packages: Collection<'a, Loc>>, pub imports: Collection<'a, Loc>>, pub provides: Collection<'a, Loc>>, diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index 00583fbb5a..f6a8a60148 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -545,7 +545,7 @@ fn exposes_modules<'a>() -> impl Parser< 'a, ( (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), - Vec<'a, Located>>>, + Collection<'a, Located>>>, ), EExposes, > { @@ -560,14 +560,16 @@ fn exposes_modules<'a>() -> impl Parser< EExposes::IndentExposes, EExposes::IndentListStart ), - collection_e!( + collection_trailing_sep_e!( word1(b'[', EExposes::ListStart), exposes_module(EExposes::Identifier), word1(b',', EExposes::ListEnd), word1(b']', EExposes::ListEnd), min_indent, + EExposes::Open, EExposes::Space, - EExposes::IndentListEnd + EExposes::IndentListEnd, + ExposesEntry::SpaceBefore ) ) } diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index db54abf04f..5032dcc010 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3340,7 +3340,7 @@ mod test_parse { before_header: &[], name: Located::new(0, 0, 9, 23, pkg_name), requires, - exposes: Vec::new_in(&arena), + exposes: Collection::empty(), packages: Collection::empty(), imports: Collection::empty(), provides: Collection::empty(), @@ -3431,7 +3431,7 @@ mod test_parse { before_header: &[], name: Located::new(0, 0, 9, 19, pkg_name), requires, - exposes: Vec::new_in(&arena), + exposes: Collection::empty(), packages, imports, provides, From 6c82b1789a17ac75cf0bf3c8f457fd0395df1110 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 11:15:56 -0800 Subject: [PATCH 070/223] Convert effects to collection_trailing_sep_e --- compiler/parse/src/header.rs | 2 +- compiler/parse/src/module.rs | 8 +++++--- compiler/parse/src/parser.rs | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index 20e680ca2f..b1fbcc23eb 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -227,7 +227,7 @@ impl<'a> ExposesEntry<'a, &'a str> { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum TypedIdent<'a> { /// e.g. /// diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index f6a8a60148..7a194fe073 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -697,14 +697,16 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> { space0_e(min_indent, EEffects::Space, EEffects::IndentListStart) ) .parse(arena, state)?; - let (_, entries, state) = collection_e!( + let (_, entries, state) = collection_trailing_sep_e!( word1(b'{', EEffects::ListStart), specialize(EEffects::TypedIdent, loc!(typed_ident())), word1(b',', EEffects::ListEnd), word1(b'}', EEffects::ListEnd), min_indent, + EEffects::Open, EEffects::Space, - EEffects::IndentListEnd + EEffects::IndentListEnd, + TypedIdent::SpaceBefore ) .parse(arena, state)?; @@ -716,7 +718,7 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> { spaces_after_type_name, effect_shortname: type_shortname, effect_type_name: type_name, - entries: entries.into_bump_slice(), + entries: entries.items, }, state, )) diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 73a32128f7..9baa462522 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -305,6 +305,7 @@ pub enum EPackageEntry<'a> { pub enum EEffects<'a> { Space(BadInputError, Row, Col), Effects(Row, Col), + Open(Row, Col), IndentEffects(Row, Col), ListStart(Row, Col), ListEnd(Row, Col), From fb960d98b81b20488f8b8077aa04ebea4273623e Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 11:16:17 -0800 Subject: [PATCH 071/223] Remove unused macros --- compiler/parse/src/parser.rs | 77 ------------------------------------ 1 file changed, 77 deletions(-) diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 9baa462522..76e1480387 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -1188,83 +1188,6 @@ macro_rules! collection { }; } -#[macro_export] -macro_rules! collection_e { - ($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $space_problem:expr, $indent_problem:expr) => { - skip_first!( - $opening_brace, - skip_first!( - // We specifically allow space characters inside here, so that - // `[ ]` can be successfully parsed as an empty list, and then - // changed by the formatter back into `[]`. - // - // We don't allow newlines or comments in the middle of empty - // roc_collections because those are normally stored in an Expr, - // and there's no Expr in which to store them in an empty collection! - // - // We could change the AST to add extra storage specifically to - // support empty literals containing newlines or comments, but this - // does not seem worth even the tiniest regression in compiler performance. - zero_or_more!($crate::parser::word1(b' ', |row, col| $space_problem( - crate::parser::BadInputError::LineTooLong, - row, - col - ))), - skip_second!( - $crate::parser::sep_by0( - $delimiter, - $crate::blankspace::space0_around_ee( - $elem, - $min_indent, - $space_problem, - $indent_problem, - $indent_problem - ) - ), - $closing_brace - ) - ) - ) - }; -} - -/// Parse zero or more elements between two braces (e.g. square braces). -/// Elements can be optionally surrounded by spaces, and are separated by a -/// delimiter (e.g comma-separated) with optionally a trailing delimiter. -/// Braces and delimiters get discarded. -#[macro_export] -macro_rules! collection_trailing_sep { - ($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr) => { - skip_first!( - $opening_brace, - skip_first!( - // We specifically allow space characters inside here, so that - // `[ ]` can be successfully parsed as an empty list, and then - // changed by the formatter back into `[]`. - // - // We don't allow newlines or comments in the middle of empty - // roc_collections because those are normally stored in an Expr, - // and there's no Expr in which to store them in an empty collection! - // - // We could change the AST to add extra storage specifically to - // support empty literals containing newlines or comments, but this - // does not seem worth even the tiniest regression in compiler performance. - zero_or_more!($crate::parser::ascii_char(b' ')), - skip_second!( - and!( - $crate::parser::trailing_sep_by0( - $delimiter, - $crate::blankspace::space0_around($elem, $min_indent) - ), - $crate::blankspace::space0($min_indent) - ), - $closing_brace - ) - ) - ) - }; -} - #[macro_export] macro_rules! collection_trailing_sep_e { ($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $open_problem:expr, $space_problem:expr, $indent_problem:expr, $space_before:expr) => { From cb55f66b5b8add272a39c6804188902f55c55c57 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 14 Nov 2021 19:39:03 +0100 Subject: [PATCH 072/223] pass slice instead of vector --- compiler/mono/src/decision_tree.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 16b3ea0a84..d949172117 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -422,7 +422,7 @@ fn gather_edges<'a>( // TODO remove clone let all_edges = relevant_tests .into_iter() - .map(|t| edges_for(path, branches.clone(), t)) + .map(|t| edges_for(path, &branches, t)) .collect(); let fallbacks = if check { @@ -583,7 +583,7 @@ fn test_at_path<'a>( // understanding: if the test is successful, where could we go? fn edges_for<'a>( path: &[PathInstruction], - branches: Vec>, + branches: &[Branch<'a>], test: GuardedTest<'a>, ) -> (GuardedTest<'a>, Vec>) { let mut new_branches = Vec::new(); From 6fab6e20f5d461d16accb081fe740cd02e627906 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Sun, 14 Nov 2021 10:40:09 -0800 Subject: [PATCH 073/223] Fix clippy --- compiler/load/src/file.rs | 4 ++-- compiler/parse/src/module.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index c733460053..17a370d49a 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3236,7 +3236,7 @@ fn send_header_two<'a>( let extra = HeaderFor::PkgConfig { config_shorthand: shorthand, - platform_main_type: requires[0].value.clone(), + platform_main_type: requires[0].value, main_for_host, }; @@ -3419,7 +3419,7 @@ fn fabricate_pkg_config_module<'a>( app_module_id, packages: &[], provides, - requires: arena.alloc([header.requires.signature.clone()]), + requires: arena.alloc([header.requires.signature]), imports: header.imports.items, }; diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index 7a194fe073..f0d2200e49 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -811,7 +811,7 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> { )) ), |_arena, ((opt_shortname, module_name), opt_values): Temp<'a>| { - let exposed_values = opt_values.unwrap_or_else(|| Collection::empty()); + let exposed_values = opt_values.unwrap_or_else(Collection::empty); match opt_shortname { Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values), From d29265759b6a0e4b84660ae1142c7d85c88145b7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 14 Nov 2021 19:49:02 +0100 Subject: [PATCH 074/223] simplify edge counting --- compiler/mono/src/decision_tree.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index d949172117..c033449cb0 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -419,7 +419,6 @@ fn gather_edges<'a>( let check = guarded_tests_are_complete(&relevant_tests); - // TODO remove clone let all_edges = relevant_tests .into_iter() .map(|t| edges_for(path, &branches, t)) @@ -1055,9 +1054,19 @@ fn small_defaults(branches: &[Branch], path: &[PathInstruction]) -> usize { } fn small_branching_factor(branches: &[Branch], path: &[PathInstruction]) -> usize { - let (edges, fallback) = gather_edges(branches.to_vec(), path); + // a specialized version of gather_edges that just counts the number of options - edges.len() + (if fallback.is_empty() { 0 } else { 1 }) + let relevant_tests = tests_at_path(path, branches); + + let check = guarded_tests_are_complete(&relevant_tests); + + let fallbacks = if check { + false + } else { + branches.iter().any(|b| is_irrelevant_to(path, b)) + }; + + relevant_tests.len() + (if !fallbacks { 0 } else { 1 }) } #[derive(Clone, Debug, PartialEq)] From 29d355c4d6e8bf624bf304c809ffc85c1fdac8b9 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 14 Nov 2021 19:06:04 +0000 Subject: [PATCH 075/223] Implement Expr::StructAtIndex for wasm dev backend --- compiler/gen_wasm/src/backend.rs | 27 +++++++++++- compiler/gen_wasm/src/storage.rs | 61 ++++++++++++++++++++++++++++ compiler/test_gen/src/gen_records.rs | 22 +++++----- 3 files changed, 97 insertions(+), 13 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 9093401626..aaffcecac9 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -22,8 +22,8 @@ use crate::wasm_module::{ LocalId, Signature, SymInfo, ValueType, }; use crate::{ - copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_TYPE, - STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME, + copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_SIZE, + PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME, }; /// The memory address where the constants data will be loaded during module instantiation. @@ -540,6 +540,29 @@ impl<'a> WasmBackend<'a> { Expr::Struct(fields) => self.create_struct(sym, layout, fields), + Expr::StructAtIndex { + index, + field_layouts, + structure, + } => { + if let StoredValue::StackMemory { location, .. } = self.storage.get(structure) { + let (local_id, mut offset) = + location.local_and_offset(self.storage.stack_frame_pointer); + for field in field_layouts.iter().take(*index as usize) { + offset += field.stack_size(PTR_SIZE); + } + self.storage.copy_value_from_memory( + &mut self.code_builder, + *sym, + local_id, + offset, + ); + } else { + unreachable!("Unexpected storage for {:?}", structure) + } + Ok(()) + } + x => Err(format!("Expression is not yet implemented {:?}", x)), } } diff --git a/compiler/gen_wasm/src/storage.rs b/compiler/gen_wasm/src/storage.rs index f552d59c59..fbec6ff61a 100644 --- a/compiler/gen_wasm/src/storage.rs +++ b/compiler/gen_wasm/src/storage.rs @@ -319,6 +319,67 @@ impl<'a> Storage<'a> { } } + /// Generate code to copy a StoredValue from an arbitrary memory location + /// (defined by a pointer and offset). + pub fn copy_value_from_memory( + &mut self, + code_builder: &mut CodeBuilder, + to_symbol: Symbol, + from_ptr: LocalId, + from_offset: u32, + ) -> u32 { + let to_storage = self.get(&to_symbol).to_owned(); + match to_storage { + StoredValue::StackMemory { + location, + size, + alignment_bytes, + } => { + let (to_ptr, to_offset) = location.local_and_offset(self.stack_frame_pointer); + copy_memory( + code_builder, + CopyMemoryConfig { + from_ptr, + from_offset, + to_ptr, + to_offset, + size, + alignment_bytes, + }, + ); + size + } + + StoredValue::VirtualMachineStack { + value_type, size, .. + } + | StoredValue::Local { + value_type, size, .. + } => { + use crate::wasm_module::Align::*; + + code_builder.get_local(from_ptr); + match (value_type, size) { + (ValueType::I64, 8) => code_builder.i64_load(Bytes8, from_offset), + (ValueType::I32, 4) => code_builder.i32_load(Bytes4, from_offset), + (ValueType::I32, 2) => code_builder.i32_load16_s(Bytes2, from_offset), + (ValueType::I32, 1) => code_builder.i32_load8_s(Bytes1, from_offset), + (ValueType::F32, 4) => code_builder.f32_load(Bytes4, from_offset), + (ValueType::F64, 8) => code_builder.f64_load(Bytes8, from_offset), + _ => { + panic!("Cannot store {:?} with alignment of {:?}", value_type, size); + } + }; + + if let StoredValue::Local { local_id, .. } = to_storage { + code_builder.set_local(local_id); + } + + size + } + } + } + /// Generate code to copy from one StoredValue to another /// Copies the _entire_ value. For struct fields etc., see `copy_value_to_memory` pub fn clone_value( diff --git a/compiler/test_gen/src/gen_records.rs b/compiler/test_gen/src/gen_records.rs index 927daf0e18..1c6274e20b 100644 --- a/compiler/test_gen/src/gen_records.rs +++ b/compiler/test_gen/src/gen_records.rs @@ -11,7 +11,7 @@ use crate::helpers::wasm::assert_evals_to; use indoc::indoc; #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn basic_record() { assert_evals_to!( indoc!( @@ -45,7 +45,7 @@ fn basic_record() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn f64_record() { assert_evals_to!( indoc!( @@ -137,7 +137,7 @@ fn fn_record() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn def_record() { assert_evals_to!( indoc!( @@ -192,7 +192,7 @@ fn when_on_record() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn when_record_with_guard_pattern() { assert_evals_to!( indoc!( @@ -207,7 +207,7 @@ fn when_record_with_guard_pattern() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn let_with_record_pattern() { assert_evals_to!( indoc!( @@ -223,7 +223,7 @@ fn let_with_record_pattern() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn record_guard_pattern() { assert_evals_to!( indoc!( @@ -239,7 +239,7 @@ fn record_guard_pattern() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn twice_record_access() { assert_evals_to!( indoc!( @@ -254,7 +254,7 @@ fn twice_record_access() { ); } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] fn empty_record() { assert_evals_to!( indoc!( @@ -873,7 +873,7 @@ fn update_single_element_record() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn booleans_in_record() { assert_evals_to!( indoc!("{ x: 1 == 1, y: 1 == 1 }"), @@ -908,7 +908,7 @@ fn alignment_in_record() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn blue_and_present() { assert_evals_to!( indoc!( @@ -927,7 +927,7 @@ fn blue_and_present() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn blue_and_absent() { assert_evals_to!( indoc!( From b9e97400d7859fcb6d14dd26ef87f5260646a0b9 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 14 Nov 2021 21:08:05 +0000 Subject: [PATCH 076/223] Inline lowlevel wrapper functions --- compiler/gen_wasm/src/backend.rs | 63 ++++++++------ compiler/gen_wasm/src/low_level.rs | 130 ++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 26 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index aaffcecac9..261a5c5693 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -2,12 +2,13 @@ use bumpalo::{self, collections::Vec}; use code_builder::Align; use roc_collections::all::MutMap; +use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt}; use roc_mono::layout::{Builtin, Layout, LayoutIds}; use crate::layout::WasmLayout; -use crate::low_level::{build_call_low_level, LowlevelBuildResult}; +use crate::low_level::{decode_low_level, symbol_to_lowlevel, LowlevelBuildResult}; use crate::storage::{Storage, StoredValue, StoredValueKind}; use crate::wasm_module::linking::{ DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_BINDING_WEAK, @@ -469,6 +470,11 @@ impl<'a> WasmBackend<'a> { arguments, }) => match call_type { CallType::ByName { name: func_sym, .. } => { + // If this function is just a lowlevel wrapper, then inline it + if let Some(lowlevel) = symbol_to_lowlevel(*func_sym) { + return self.build_low_level(lowlevel, arguments, wasm_layout); + } + let mut wasm_args_tmp: Vec; let (wasm_args, has_return_val) = match wasm_layout { WasmLayout::StackMemory { .. } => { @@ -511,30 +517,9 @@ impl<'a> WasmBackend<'a> { } CallType::LowLevel { op: lowlevel, .. } => { - let return_layout = WasmLayout::new(layout); - self.storage.load_symbols(&mut self.code_builder, arguments); - - let build_result = build_call_low_level( - &mut self.code_builder, - &mut self.storage, - lowlevel, - arguments, - &return_layout, - ); - use LowlevelBuildResult::*; - - match build_result { - Done => Ok(()), - BuiltinCall(name) => { - self.call_imported_builtin(name, arguments, &return_layout); - Ok(()) - } - NotImplemented => Err(format!( - "Low level operation {:?} is not yet implemented", - lowlevel - )), - } + self.build_low_level(*lowlevel, arguments, wasm_layout) } + x => Err(format!("the call type, {:?}, is not yet implemented", x)), }, @@ -567,6 +552,36 @@ impl<'a> WasmBackend<'a> { } } + fn build_low_level( + &mut self, + lowlevel: LowLevel, + arguments: &'a [Symbol], + return_layout: WasmLayout, + ) -> Result<(), String> { + self.storage.load_symbols(&mut self.code_builder, arguments); + + let build_result = decode_low_level( + &mut self.code_builder, + &mut self.storage, + lowlevel, + arguments, + &return_layout, + ); + use LowlevelBuildResult::*; + + match build_result { + Done => Ok(()), + BuiltinCall(name) => { + self.call_imported_builtin(name, arguments, &return_layout); + Ok(()) + } + NotImplemented => Err(format!( + "Low level operation {:?} is not yet implemented", + lowlevel + )), + } + } + fn load_literal( &mut self, lit: &Literal<'a>, diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 7dfbcf3b96..dc3e164f4e 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -15,10 +15,10 @@ pub enum LowlevelBuildResult { NotImplemented, } -pub fn build_call_low_level<'a>( +pub fn decode_low_level<'a>( code_builder: &mut CodeBuilder<'a>, storage: &mut Storage<'a>, - lowlevel: &LowLevel, + lowlevel: LowLevel, args: &'a [Symbol], ret_layout: &WasmLayout, ) -> LowlevelBuildResult { @@ -129,6 +129,9 @@ pub fn build_call_low_level<'a>( NumIsMultipleOf => return NotImplemented, NumAbs => match ret_layout.value_type() { I32 => { + let arg_storage = storage.get(&args[0]).to_owned(); + storage.ensure_value_has_local(code_builder, args[0], arg_storage); + storage.load_symbols(code_builder, args); code_builder.i32_const(0); storage.load_symbols(code_builder, args); code_builder.i32_sub(); @@ -138,6 +141,9 @@ pub fn build_call_low_level<'a>( code_builder.select(); } I64 => { + let arg_storage = storage.get(&args[0]).to_owned(); + storage.ensure_value_has_local(code_builder, args[0], arg_storage); + storage.load_symbols(code_builder, args); code_builder.i64_const(0); storage.load_symbols(code_builder, args); code_builder.i64_sub(); @@ -358,3 +364,123 @@ fn float_width_from_layout(wasm_layout: &WasmLayout) -> FloatWidth { FloatWidth::F64 } } + +pub fn symbol_to_lowlevel(symbol: Symbol) -> Option { + use LowLevel::*; + + match symbol { + Symbol::STR_CONCAT => Some(StrConcat), + Symbol::STR_JOIN_WITH => Some(StrJoinWith), + Symbol::STR_IS_EMPTY => Some(StrIsEmpty), + Symbol::STR_STARTS_WITH => Some(StrStartsWith), + Symbol::STR_STARTS_WITH_CODE_PT => Some(StrStartsWithCodePt), + Symbol::STR_ENDS_WITH => Some(StrEndsWith), + Symbol::STR_SPLIT => Some(StrSplit), + Symbol::STR_COUNT_GRAPHEMES => Some(StrCountGraphemes), + Symbol::STR_FROM_INT => Some(StrFromInt), + Symbol::STR_FROM_UTF8 => Some(StrFromUtf8), + Symbol::STR_FROM_UTF8_RANGE => Some(StrFromUtf8Range), + Symbol::STR_TO_UTF8 => Some(StrToUtf8), + Symbol::STR_REPEAT => Some(StrRepeat), + Symbol::STR_FROM_FLOAT => Some(StrFromFloat), + Symbol::STR_TRIM => Some(StrTrim), + Symbol::STR_TRIM_LEFT => Some(StrTrimLeft), + Symbol::STR_TRIM_RIGHT => Some(StrTrimRight), + Symbol::LIST_LEN => Some(ListLen), + Symbol::LIST_GET => Some(ListGetUnsafe), // ?? + Symbol::LIST_SET => Some(ListSet), + Symbol::LIST_SINGLE => Some(ListSingle), + Symbol::LIST_REPEAT => Some(ListRepeat), + Symbol::LIST_REVERSE => Some(ListReverse), + Symbol::LIST_CONCAT => Some(ListConcat), + Symbol::LIST_CONTAINS => Some(ListContains), + Symbol::LIST_APPEND => Some(ListAppend), + Symbol::LIST_PREPEND => Some(ListPrepend), + Symbol::LIST_JOIN => Some(ListJoin), + Symbol::LIST_RANGE => Some(ListRange), + Symbol::LIST_MAP => Some(ListMap), + Symbol::LIST_MAP2 => Some(ListMap2), + Symbol::LIST_MAP3 => Some(ListMap3), + Symbol::LIST_MAP4 => Some(ListMap4), + Symbol::LIST_MAP_WITH_INDEX => Some(ListMapWithIndex), + Symbol::LIST_KEEP_IF => Some(ListKeepIf), + Symbol::LIST_WALK => Some(ListWalk), + Symbol::LIST_WALK_UNTIL => Some(ListWalkUntil), + Symbol::LIST_WALK_BACKWARDS => Some(ListWalkBackwards), + Symbol::LIST_KEEP_OKS => Some(ListKeepOks), + Symbol::LIST_KEEP_ERRS => Some(ListKeepErrs), + Symbol::LIST_SORT_WITH => Some(ListSortWith), + Symbol::LIST_SUBLIST => Some(ListSublist), + + Symbol::LIST_DROP => Some(ListDrop), + Symbol::LIST_DROP_AT => Some(ListDropAt), + Symbol::LIST_SWAP => Some(ListSwap), + Symbol::LIST_ANY => Some(ListAny), + Symbol::LIST_FIND => Some(ListFindUnsafe), // ?? + Symbol::DICT_LEN => Some(DictSize), + Symbol::DICT_EMPTY => Some(DictEmpty), + Symbol::DICT_INSERT => Some(DictInsert), + Symbol::DICT_REMOVE => Some(DictRemove), + Symbol::DICT_CONTAINS => Some(DictContains), + Symbol::DICT_GET => Some(DictGetUnsafe), // ?? + Symbol::DICT_KEYS => Some(DictKeys), + Symbol::DICT_VALUES => Some(DictValues), + Symbol::DICT_UNION => Some(DictUnion), + Symbol::DICT_INTERSECTION => Some(DictIntersection), + Symbol::DICT_DIFFERENCE => Some(DictDifference), + Symbol::DICT_WALK => Some(DictWalk), + Symbol::SET_FROM_LIST => Some(SetFromList), + + Symbol::NUM_ADD => Some(NumAdd), + Symbol::NUM_ADD_WRAP => Some(NumAddWrap), + Symbol::NUM_ADD_CHECKED => Some(NumAddChecked), + Symbol::NUM_SUB => Some(NumSub), + Symbol::NUM_SUB_WRAP => Some(NumSubWrap), + Symbol::NUM_SUB_CHECKED => Some(NumSubChecked), + Symbol::NUM_MUL => Some(NumMul), + Symbol::NUM_MUL_WRAP => Some(NumMulWrap), + Symbol::NUM_MUL_CHECKED => Some(NumMulChecked), + Symbol::NUM_GT => Some(NumGt), + Symbol::NUM_GTE => Some(NumGte), + Symbol::NUM_LT => Some(NumLt), + Symbol::NUM_LTE => Some(NumLte), + Symbol::NUM_COMPARE => Some(NumCompare), + Symbol::NUM_DIV_FLOAT => Some(NumDivUnchecked), // ?? + Symbol::NUM_DIV_CEIL => Some(NumDivCeilUnchecked), + Symbol::NUM_REM => Some(NumRemUnchecked), + Symbol::NUM_IS_MULTIPLE_OF => Some(NumIsMultipleOf), + Symbol::NUM_ABS => Some(NumAbs), + Symbol::NUM_NEG => Some(NumNeg), + Symbol::NUM_SIN => Some(NumSin), + Symbol::NUM_COS => Some(NumCos), + Symbol::NUM_SQRT => Some(NumSqrtUnchecked), + Symbol::NUM_LOG => Some(NumLogUnchecked), + Symbol::NUM_ROUND => Some(NumRound), + Symbol::NUM_TO_FLOAT => Some(NumToFloat), + Symbol::NUM_POW => Some(NumPow), + Symbol::NUM_CEILING => Some(NumCeiling), + Symbol::NUM_POW_INT => Some(NumPowInt), + Symbol::NUM_FLOOR => Some(NumFloor), + // => Some(NumIsFinite), + Symbol::NUM_ATAN => Some(NumAtan), + Symbol::NUM_ACOS => Some(NumAcos), + Symbol::NUM_ASIN => Some(NumAsin), + Symbol::NUM_BYTES_TO_U16 => Some(NumBytesToU16), + Symbol::NUM_BYTES_TO_U32 => Some(NumBytesToU32), + Symbol::NUM_BITWISE_AND => Some(NumBitwiseAnd), + Symbol::NUM_BITWISE_XOR => Some(NumBitwiseXor), + Symbol::NUM_BITWISE_OR => Some(NumBitwiseOr), + Symbol::NUM_SHIFT_LEFT => Some(NumShiftLeftBy), + Symbol::NUM_SHIFT_RIGHT => Some(NumShiftRightBy), + Symbol::NUM_SHIFT_RIGHT_ZERO_FILL => Some(NumShiftRightZfBy), + Symbol::NUM_INT_CAST => Some(NumIntCast), + Symbol::BOOL_EQ => Some(Eq), + Symbol::BOOL_NEQ => Some(NotEq), + Symbol::BOOL_AND => Some(And), + Symbol::BOOL_OR => Some(Or), + Symbol::BOOL_NOT => Some(Not), + // => Some(Hash), + // => Some(ExpectTrue), + _ => None, + } +} From 2c0aac2a6a28c94b882d2aaad3c8585ed13e142a Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 14 Nov 2021 22:20:06 +0100 Subject: [PATCH 077/223] remove solved type hash instance --- compiler/mono/src/ir.rs | 26 +---- compiler/types/src/solved_types.rs | 147 +---------------------------- 2 files changed, 8 insertions(+), 165 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index c0c02f3466..892fd3fab7 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -206,7 +206,7 @@ impl<'a> Default for CapturedSymbols<'a> { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct PendingSpecialization<'a> { solved_type: SolvedType, host_exposed_aliases: BumpMap, @@ -1819,27 +1819,11 @@ fn specialize_externals_others_need<'a>( layout_cache: &mut LayoutCache<'a>, ) { for (symbol, solved_types) in externals_others_need.specs.iter() { - // de-duplicate by the Hash instance (set only deduplicates by Eq instance) - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - - let mut seen_hashes = Vec::with_capacity_in(solved_types.len(), env.arena); - - let hash_the_thing = |x: &SolvedType| { - let mut hasher = DefaultHasher::new(); - x.hash(&mut hasher); - hasher.finish() - }; - for solved_type in solved_types { - let hash = hash_the_thing(solved_type); - - if seen_hashes.iter().any(|h| *h == hash) { - // we've seen this one already - continue; - } - - seen_hashes.push(hash); + // historical note: we used to deduplicate with a hash here, + // but the cost of that hash is very high. So for now we make + // duplicate specializations, and the insertion into a hash map + // below will deduplicate them. let name = *symbol; diff --git a/compiler/types/src/solved_types.rs b/compiler/types/src/solved_types.rs index a1768f6e7f..5173dc43af 100644 --- a/compiler/types/src/solved_types.rs +++ b/compiler/types/src/solved_types.rs @@ -4,7 +4,6 @@ use roc_collections::all::{ImMap, MutSet, SendMap}; use roc_module::ident::{Lowercase, TagName}; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; -use std::hash::{Hash, Hasher}; /// A marker that a given Subs has been solved. /// The only way to obtain a Solved is by running the solver on it. @@ -25,151 +24,11 @@ impl Solved { } } -/// A custom hash instance, that treats flex vars specially, so that -/// -/// `Foo 100 200 100` hashes to the same as `Foo 300 100 300` -/// -/// i.e., we can rename the flex variables, so long as it happens consistently. -/// this is important so we don't generate the same PartialProc twice. -impl Hash for SolvedType { - fn hash(&self, state: &mut H) { - hash_solved_type_help(self, &mut Vec::new(), state); - } -} - -impl PartialEq for SolvedType { - fn eq(&self, other: &Self) -> bool { - use std::collections::hash_map::DefaultHasher; - - let mut state = DefaultHasher::new(); - hash_solved_type_help(self, &mut Vec::new(), &mut state); - let hash1 = state.finish(); - - let mut state = DefaultHasher::new(); - hash_solved_type_help(other, &mut Vec::new(), &mut state); - let hash2 = state.finish(); - - hash1 == hash2 - } -} - -fn hash_solved_type_help( - initial: &SolvedType, - flex_vars: &mut Vec, - state: &mut H, -) { - use SolvedType::*; - - let mut stack = Vec::with_capacity(63); - - stack.push(initial); - - while let Some(solved_type) = stack.pop() { - match solved_type { - Flex(var_id) => { - var_id_hash_help(*var_id, flex_vars, state); - } - Wildcard => "wildcard".hash(state), - EmptyRecord => "empty_record".hash(state), - EmptyTagUnion => "empty_tag_union".hash(state), - Error => "error".hash(state), - Func(arguments, closure, result) => { - stack.extend(arguments); - - stack.push(closure); - stack.push(result); - } - Apply(name, arguments) => { - name.hash(state); - stack.extend(arguments); - } - Rigid(name) => name.hash(state), - Erroneous(problem) => problem.hash(state), - - Record { fields, ext } => { - for (name, x) in fields { - name.hash(state); - "record_field".hash(state); - stack.push(x.as_inner()); - } - stack.push(ext); - } - - TagUnion(tags, ext) => { - for (name, arguments) in tags { - name.hash(state); - stack.extend(arguments); - } - stack.push(ext); - } - - FunctionOrTagUnion(_, _, ext) => { - stack.push(ext); - } - - RecursiveTagUnion(rec, tags, ext) => { - var_id_hash_help(*rec, flex_vars, state); - for (name, arguments) in tags { - name.hash(state); - stack.extend(arguments); - } - stack.push(ext); - } - - Alias(name, arguments, solved_lambda_sets, actual) => { - name.hash(state); - for (name, x) in arguments { - name.hash(state); - stack.push(x); - } - - for set in solved_lambda_sets { - stack.push(&set.0); - } - - stack.push(actual); - } - - HostExposedAlias { - name, - arguments, - lambda_set_variables: solved_lambda_sets, - actual, - actual_var, - } => { - name.hash(state); - for (name, x) in arguments { - name.hash(state); - stack.push(x); - } - - for set in solved_lambda_sets { - stack.push(&set.0); - } - - stack.push(actual); - var_id_hash_help(*actual_var, flex_vars, state); - } - } - } -} - -fn var_id_hash_help(var_id: VarId, flex_vars: &mut Vec, state: &mut H) { - let opt_index = flex_vars.iter().position(|x| *x == var_id); - match opt_index { - Some(index) => index.hash(state), - None => { - flex_vars.len().hash(state); - flex_vars.push(var_id); - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct SolvedLambdaSet(pub SolvedType); /// This is a fully solved type, with no Variables remaining in it. -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone)] pub enum SolvedType { /// A function. The types of its arguments, then the type of its return value. Func(Vec, Box, Box), @@ -531,7 +390,7 @@ impl SolvedType { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct BuiltinAlias { pub region: Region, pub vars: Vec>, From a384042c59eba9ad269e61e8cfff7376eaa5958c Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Sun, 14 Nov 2021 13:25:17 -0800 Subject: [PATCH 078/223] add handling for ListEnd errors --- compiler/reporting/src/error/parse.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/reporting/src/error/parse.rs b/compiler/reporting/src/error/parse.rs index 163a2b118b..505e41a736 100644 --- a/compiler/reporting/src/error/parse.rs +++ b/compiler/reporting/src/error/parse.rs @@ -3093,6 +3093,7 @@ fn to_provides_report<'a>( use roc_parse::parser::EProvides; match *parse_problem { + EProvides::ListEnd(row, col) | // TODO: give this its own error message EProvides::Identifier(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); @@ -3158,6 +3159,7 @@ fn to_exposes_report<'a>( use roc_parse::parser::EExposes; match *parse_problem { + EExposes::ListEnd(row, col) | // TODO: give this its own error message EExposes::Identifier(row, col) => { let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let region = Region::from_row_col(row, col); From 8ebd09b616cdbe7d2e599bac82c567784618ebb3 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 14 Nov 2021 22:28:21 +0100 Subject: [PATCH 079/223] make fewer intermediate pending specializations --- compiler/mono/src/ir.rs | 48 +++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 892fd3fab7..4b1ab497f3 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -550,8 +550,6 @@ impl<'a> Procs<'a> { // if we've already specialized this one, no further work is needed. if !already_specialized { - let pending = PendingSpecialization::from_var(env.arena, env.subs, annotation); - if self.is_module_thunk(symbol) { debug_assert!(layout.arguments.is_empty()); } @@ -559,6 +557,8 @@ impl<'a> Procs<'a> { match &mut self.pending_specializations { Some(pending_specializations) => { // register the pending specialization, so this gets code genned later + let pending = + PendingSpecialization::from_var(env.arena, env.subs, annotation); add_pending(pending_specializations, symbol, layout, pending); match self.partial_procs.symbol_to_id(symbol) { @@ -626,12 +626,13 @@ impl<'a> Procs<'a> { self.partial_procs.insert(symbol, partial_proc) }; - match specialize( + match specialize_variable( env, self, symbol, layout_cache, - pending, + annotation, + BumpMap::new_in(env.arena), partial_proc_id, ) { Ok((proc, layout)) => { @@ -6617,8 +6618,6 @@ fn call_by_name_help<'a>( assign_to_symbols(env, procs, layout_cache, iter, result) } } else { - let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); - // When requested (that is, when procs.pending_specializations is `Some`), // store a pending specialization rather than specializing immediately. // @@ -6639,6 +6638,7 @@ fn call_by_name_help<'a>( debug_assert!(!env.is_imported_symbol(proc_name)); // register the pending specialization, so this gets code genned later + let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); add_pending( pending_specializations, proc_name, @@ -6673,17 +6673,6 @@ fn call_by_name_help<'a>( None => { let opt_partial_proc = procs.partial_procs.symbol_to_id(proc_name); - /* - debug_assert_eq!( - argument_layouts.len(), - field_symbols.len(), - "Function {:?} is called with {} arguments, but the layout expects {}", - proc_name, - field_symbols.len(), - argument_layouts.len(), - ); - */ - let field_symbols = field_symbols.into_bump_slice(); match opt_partial_proc { @@ -6695,8 +6684,15 @@ fn call_by_name_help<'a>( .specialized .insert((proc_name, top_level_layout), InProgress); - match specialize(env, procs, proc_name, layout_cache, pending, partial_proc) - { + match specialize_variable( + env, + procs, + proc_name, + layout_cache, + fn_var, + BumpMap::new_in(env.arena), + partial_proc, + ) { Ok((proc, layout)) => { // now we just call our freshly-specialized function call_specialized_proc( @@ -6774,8 +6770,6 @@ fn call_by_name_module_thunk<'a>( if already_specialized { force_thunk(env, proc_name, inner_layout, assigned, hole) } else { - let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); - // When requested (that is, when procs.pending_specializations is `Some`), // store a pending specialization rather than specializing immediately. // @@ -6796,6 +6790,7 @@ fn call_by_name_module_thunk<'a>( debug_assert!(!env.is_imported_symbol(proc_name)); // register the pending specialization, so this gets code genned later + let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); add_pending( pending_specializations, proc_name, @@ -6817,8 +6812,15 @@ fn call_by_name_module_thunk<'a>( .specialized .insert((proc_name, top_level_layout), InProgress); - match specialize(env, procs, proc_name, layout_cache, pending, partial_proc) - { + match specialize_variable( + env, + procs, + proc_name, + layout_cache, + fn_var, + BumpMap::new_in(env.arena), + partial_proc, + ) { Ok((proc, raw_layout)) => { debug_assert!( raw_layout.is_zero_argument_thunk(), From 00793eb0d84a758978fc496afb9102d3ad3a46b5 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 00:06:13 +0000 Subject: [PATCH 080/223] Fix inexhaustive pattern matches in low_level --- compiler/module/src/low_level.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index bc8d2706d0..c37226d388 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -242,8 +242,8 @@ impl LowLevel { use LowLevel::*; match self { - first_order!() => false, higher_order!() => true, + _ => false, } } @@ -251,7 +251,6 @@ impl LowLevel { use LowLevel::*; match self { - first_order!() => unreachable!(), ListMap => 1, ListMap2 => 2, ListMap3 => 3, @@ -267,6 +266,7 @@ impl LowLevel { ListAny => 1, ListFindUnsafe => 1, DictWalk => 2, + _ => unreachable!(), } } } From 79bd9ccf715a7c876b2c3bfe223ecc30c7697e2b Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 00:27:04 +0000 Subject: [PATCH 081/223] Symbol-to-lowlevel mapping for both dev backends --- compiler/gen_dev/src/lib.rs | 104 +++----------- compiler/gen_wasm/src/backend.rs | 4 +- compiler/gen_wasm/src/low_level.rs | 120 ---------------- compiler/module/src/low_level.rs | 221 ++++++++++++++++------------- 4 files changed, 140 insertions(+), 309 deletions(-) diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index e17abf1362..7890a45675 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -227,97 +227,27 @@ where ret_layout, .. } => { - // For most builtins instead of calling a function, we can just inline the low level. - match *func_sym { - Symbol::NUM_ABS => self.build_run_low_level( + // If this function is just a lowlevel wrapper, then inline it + if let Some(lowlevel) = LowLevel::from_wrapper_symbol(*func_sym) { + return self.build_run_low_level( sym, - &LowLevel::NumAbs, + &lowlevel, arguments, arg_layouts, ret_layout, - ), - Symbol::NUM_ADD => self.build_run_low_level( - sym, - &LowLevel::NumAdd, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::NUM_ACOS => self.build_run_low_level( - sym, - &LowLevel::NumAcos, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::NUM_ASIN => self.build_run_low_level( - sym, - &LowLevel::NumAsin, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::NUM_ATAN => self.build_run_low_level( - sym, - &LowLevel::NumAtan, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::NUM_MUL => self.build_run_low_level( - sym, - &LowLevel::NumMul, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::NUM_POW_INT => self.build_run_low_level( - sym, - &LowLevel::NumPowInt, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::NUM_SUB => self.build_run_low_level( - sym, - &LowLevel::NumSub, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::NUM_ROUND => self.build_run_low_level( - sym, - &LowLevel::NumRound, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::BOOL_EQ => self.build_run_low_level( - sym, - &LowLevel::Eq, - arguments, - arg_layouts, - ret_layout, - ), - Symbol::STR_CONCAT => self.build_run_low_level( - sym, - &LowLevel::StrConcat, - arguments, - arg_layouts, - ret_layout, - ), - x if x - .module_string(&self.env().interns) - .starts_with(ModuleName::APP) => - { - let fn_name = LayoutIds::default() - .get(*func_sym, layout) - .to_symbol_string(*func_sym, &self.env().interns); - // Now that the arguments are needed, load them if they are literals. - self.load_literal_symbols(arguments)?; - self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout) - } - x => Err(format!("the function, {:?}, is not yet implemented", x)), + ); + } else if func_sym + .module_string(&self.env().interns) + .starts_with(ModuleName::APP) + { + let fn_name = LayoutIds::default() + .get(*func_sym, layout) + .to_symbol_string(*func_sym, &self.env().interns); + // Now that the arguments are needed, load them if they are literals. + self.load_literal_symbols(arguments)?; + self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout) + } else { + Err(format!("the function, {:?}, is not yet implemented", func_sym)) } } diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 261a5c5693..7ba303ed13 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -8,7 +8,7 @@ use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt}; use roc_mono::layout::{Builtin, Layout, LayoutIds}; use crate::layout::WasmLayout; -use crate::low_level::{decode_low_level, symbol_to_lowlevel, LowlevelBuildResult}; +use crate::low_level::{decode_low_level, LowlevelBuildResult}; use crate::storage::{Storage, StoredValue, StoredValueKind}; use crate::wasm_module::linking::{ DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_BINDING_WEAK, @@ -471,7 +471,7 @@ impl<'a> WasmBackend<'a> { }) => match call_type { CallType::ByName { name: func_sym, .. } => { // If this function is just a lowlevel wrapper, then inline it - if let Some(lowlevel) = symbol_to_lowlevel(*func_sym) { + if let Some(lowlevel) = LowLevel::from_wrapper_symbol(*func_sym) { return self.build_low_level(lowlevel, arguments, wasm_layout); } diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index dc3e164f4e..ac680e0b18 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -364,123 +364,3 @@ fn float_width_from_layout(wasm_layout: &WasmLayout) -> FloatWidth { FloatWidth::F64 } } - -pub fn symbol_to_lowlevel(symbol: Symbol) -> Option { - use LowLevel::*; - - match symbol { - Symbol::STR_CONCAT => Some(StrConcat), - Symbol::STR_JOIN_WITH => Some(StrJoinWith), - Symbol::STR_IS_EMPTY => Some(StrIsEmpty), - Symbol::STR_STARTS_WITH => Some(StrStartsWith), - Symbol::STR_STARTS_WITH_CODE_PT => Some(StrStartsWithCodePt), - Symbol::STR_ENDS_WITH => Some(StrEndsWith), - Symbol::STR_SPLIT => Some(StrSplit), - Symbol::STR_COUNT_GRAPHEMES => Some(StrCountGraphemes), - Symbol::STR_FROM_INT => Some(StrFromInt), - Symbol::STR_FROM_UTF8 => Some(StrFromUtf8), - Symbol::STR_FROM_UTF8_RANGE => Some(StrFromUtf8Range), - Symbol::STR_TO_UTF8 => Some(StrToUtf8), - Symbol::STR_REPEAT => Some(StrRepeat), - Symbol::STR_FROM_FLOAT => Some(StrFromFloat), - Symbol::STR_TRIM => Some(StrTrim), - Symbol::STR_TRIM_LEFT => Some(StrTrimLeft), - Symbol::STR_TRIM_RIGHT => Some(StrTrimRight), - Symbol::LIST_LEN => Some(ListLen), - Symbol::LIST_GET => Some(ListGetUnsafe), // ?? - Symbol::LIST_SET => Some(ListSet), - Symbol::LIST_SINGLE => Some(ListSingle), - Symbol::LIST_REPEAT => Some(ListRepeat), - Symbol::LIST_REVERSE => Some(ListReverse), - Symbol::LIST_CONCAT => Some(ListConcat), - Symbol::LIST_CONTAINS => Some(ListContains), - Symbol::LIST_APPEND => Some(ListAppend), - Symbol::LIST_PREPEND => Some(ListPrepend), - Symbol::LIST_JOIN => Some(ListJoin), - Symbol::LIST_RANGE => Some(ListRange), - Symbol::LIST_MAP => Some(ListMap), - Symbol::LIST_MAP2 => Some(ListMap2), - Symbol::LIST_MAP3 => Some(ListMap3), - Symbol::LIST_MAP4 => Some(ListMap4), - Symbol::LIST_MAP_WITH_INDEX => Some(ListMapWithIndex), - Symbol::LIST_KEEP_IF => Some(ListKeepIf), - Symbol::LIST_WALK => Some(ListWalk), - Symbol::LIST_WALK_UNTIL => Some(ListWalkUntil), - Symbol::LIST_WALK_BACKWARDS => Some(ListWalkBackwards), - Symbol::LIST_KEEP_OKS => Some(ListKeepOks), - Symbol::LIST_KEEP_ERRS => Some(ListKeepErrs), - Symbol::LIST_SORT_WITH => Some(ListSortWith), - Symbol::LIST_SUBLIST => Some(ListSublist), - - Symbol::LIST_DROP => Some(ListDrop), - Symbol::LIST_DROP_AT => Some(ListDropAt), - Symbol::LIST_SWAP => Some(ListSwap), - Symbol::LIST_ANY => Some(ListAny), - Symbol::LIST_FIND => Some(ListFindUnsafe), // ?? - Symbol::DICT_LEN => Some(DictSize), - Symbol::DICT_EMPTY => Some(DictEmpty), - Symbol::DICT_INSERT => Some(DictInsert), - Symbol::DICT_REMOVE => Some(DictRemove), - Symbol::DICT_CONTAINS => Some(DictContains), - Symbol::DICT_GET => Some(DictGetUnsafe), // ?? - Symbol::DICT_KEYS => Some(DictKeys), - Symbol::DICT_VALUES => Some(DictValues), - Symbol::DICT_UNION => Some(DictUnion), - Symbol::DICT_INTERSECTION => Some(DictIntersection), - Symbol::DICT_DIFFERENCE => Some(DictDifference), - Symbol::DICT_WALK => Some(DictWalk), - Symbol::SET_FROM_LIST => Some(SetFromList), - - Symbol::NUM_ADD => Some(NumAdd), - Symbol::NUM_ADD_WRAP => Some(NumAddWrap), - Symbol::NUM_ADD_CHECKED => Some(NumAddChecked), - Symbol::NUM_SUB => Some(NumSub), - Symbol::NUM_SUB_WRAP => Some(NumSubWrap), - Symbol::NUM_SUB_CHECKED => Some(NumSubChecked), - Symbol::NUM_MUL => Some(NumMul), - Symbol::NUM_MUL_WRAP => Some(NumMulWrap), - Symbol::NUM_MUL_CHECKED => Some(NumMulChecked), - Symbol::NUM_GT => Some(NumGt), - Symbol::NUM_GTE => Some(NumGte), - Symbol::NUM_LT => Some(NumLt), - Symbol::NUM_LTE => Some(NumLte), - Symbol::NUM_COMPARE => Some(NumCompare), - Symbol::NUM_DIV_FLOAT => Some(NumDivUnchecked), // ?? - Symbol::NUM_DIV_CEIL => Some(NumDivCeilUnchecked), - Symbol::NUM_REM => Some(NumRemUnchecked), - Symbol::NUM_IS_MULTIPLE_OF => Some(NumIsMultipleOf), - Symbol::NUM_ABS => Some(NumAbs), - Symbol::NUM_NEG => Some(NumNeg), - Symbol::NUM_SIN => Some(NumSin), - Symbol::NUM_COS => Some(NumCos), - Symbol::NUM_SQRT => Some(NumSqrtUnchecked), - Symbol::NUM_LOG => Some(NumLogUnchecked), - Symbol::NUM_ROUND => Some(NumRound), - Symbol::NUM_TO_FLOAT => Some(NumToFloat), - Symbol::NUM_POW => Some(NumPow), - Symbol::NUM_CEILING => Some(NumCeiling), - Symbol::NUM_POW_INT => Some(NumPowInt), - Symbol::NUM_FLOOR => Some(NumFloor), - // => Some(NumIsFinite), - Symbol::NUM_ATAN => Some(NumAtan), - Symbol::NUM_ACOS => Some(NumAcos), - Symbol::NUM_ASIN => Some(NumAsin), - Symbol::NUM_BYTES_TO_U16 => Some(NumBytesToU16), - Symbol::NUM_BYTES_TO_U32 => Some(NumBytesToU32), - Symbol::NUM_BITWISE_AND => Some(NumBitwiseAnd), - Symbol::NUM_BITWISE_XOR => Some(NumBitwiseXor), - Symbol::NUM_BITWISE_OR => Some(NumBitwiseOr), - Symbol::NUM_SHIFT_LEFT => Some(NumShiftLeftBy), - Symbol::NUM_SHIFT_RIGHT => Some(NumShiftRightBy), - Symbol::NUM_SHIFT_RIGHT_ZERO_FILL => Some(NumShiftRightZfBy), - Symbol::NUM_INT_CAST => Some(NumIntCast), - Symbol::BOOL_EQ => Some(Eq), - Symbol::BOOL_NEQ => Some(NotEq), - Symbol::BOOL_AND => Some(And), - Symbol::BOOL_OR => Some(Or), - Symbol::BOOL_NOT => Some(Not), - // => Some(Hash), - // => Some(ExpectTrue), - _ => None, - } -} diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index c37226d388..b4e4133348 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -1,3 +1,5 @@ +use crate::symbol::Symbol; + /// Low-level operations that get translated directly into e.g. LLVM instructions. /// These are always wrapped when exposed to end users, and can only make it /// into an Expr when added directly by can::builtins @@ -115,106 +117,6 @@ pub enum LowLevel { ExpectTrue, } -macro_rules! first_order { - () => { - StrConcat - | StrJoinWith - | StrIsEmpty - | StrStartsWith - | StrStartsWithCodePt - | StrEndsWith - | StrSplit - | StrCountGraphemes - | StrFromInt - | StrFromUtf8 - | StrFromUtf8Range - | StrToUtf8 - | StrRepeat - | StrTrim - | StrTrimLeft - | StrTrimRight - | StrFromFloat - | ListLen - | ListGetUnsafe - | ListSet - | ListSublist - | ListDrop - | ListDropAt - | ListSingle - | ListRepeat - | ListReverse - | ListConcat - | ListContains - | ListAppend - | ListPrepend - | ListJoin - | ListRange - | ListSwap - | DictSize - | DictEmpty - | DictInsert - | DictRemove - | DictContains - | DictGetUnsafe - | DictKeys - | DictValues - | DictUnion - | DictIntersection - | DictDifference - | SetFromList - | NumAdd - | NumAddWrap - | NumAddChecked - | NumSub - | NumSubWrap - | NumSubChecked - | NumMul - | NumMulWrap - | NumMulChecked - | NumGt - | NumGte - | NumLt - | NumLte - | NumCompare - | NumDivUnchecked - | NumDivCeilUnchecked - | NumRemUnchecked - | NumIsMultipleOf - | NumAbs - | NumNeg - | NumSin - | NumCos - | NumSqrtUnchecked - | NumLogUnchecked - | NumRound - | NumToFloat - | NumPow - | NumCeiling - | NumPowInt - | NumFloor - | NumIsFinite - | NumAtan - | NumAcos - | NumAsin - | NumBitwiseAnd - | NumBitwiseXor - | NumBitwiseOr - | NumShiftLeftBy - | NumShiftRightBy - | NumBytesToU16 - | NumBytesToU32 - | NumShiftRightZfBy - | NumIntCast - | Eq - | NotEq - | And - | Or - | Not - | Hash - | ExpectTrue - }; -} - macro_rules! higher_order { () => { ListMap @@ -269,4 +171,123 @@ impl LowLevel { _ => unreachable!(), } } + + /// Used in dev backends to optimise away the wrapper functions + pub fn from_wrapper_symbol(symbol: Symbol) -> Option { + use LowLevel::*; + + match symbol { + Symbol::STR_CONCAT => Some(StrConcat), + Symbol::STR_JOIN_WITH => Some(StrJoinWith), + Symbol::STR_IS_EMPTY => Some(StrIsEmpty), + Symbol::STR_STARTS_WITH => Some(StrStartsWith), + Symbol::STR_STARTS_WITH_CODE_PT => Some(StrStartsWithCodePt), + Symbol::STR_ENDS_WITH => Some(StrEndsWith), + Symbol::STR_SPLIT => Some(StrSplit), + Symbol::STR_COUNT_GRAPHEMES => Some(StrCountGraphemes), + Symbol::STR_FROM_INT => Some(StrFromInt), + Symbol::STR_FROM_UTF8 => Some(StrFromUtf8), + Symbol::STR_FROM_UTF8_RANGE => Some(StrFromUtf8Range), + Symbol::STR_TO_UTF8 => Some(StrToUtf8), + Symbol::STR_REPEAT => Some(StrRepeat), + Symbol::STR_FROM_FLOAT => Some(StrFromFloat), + Symbol::STR_TRIM => Some(StrTrim), + Symbol::STR_TRIM_LEFT => Some(StrTrimLeft), + Symbol::STR_TRIM_RIGHT => Some(StrTrimRight), + Symbol::LIST_LEN => Some(ListLen), + Symbol::LIST_GET => Some(ListGetUnsafe), + Symbol::LIST_SET => Some(ListSet), + Symbol::LIST_SINGLE => Some(ListSingle), + Symbol::LIST_REPEAT => Some(ListRepeat), + Symbol::LIST_REVERSE => Some(ListReverse), + Symbol::LIST_CONCAT => Some(ListConcat), + Symbol::LIST_CONTAINS => Some(ListContains), + Symbol::LIST_APPEND => Some(ListAppend), + Symbol::LIST_PREPEND => Some(ListPrepend), + Symbol::LIST_JOIN => Some(ListJoin), + Symbol::LIST_RANGE => Some(ListRange), + Symbol::LIST_MAP => Some(ListMap), + Symbol::LIST_MAP2 => Some(ListMap2), + Symbol::LIST_MAP3 => Some(ListMap3), + Symbol::LIST_MAP4 => Some(ListMap4), + Symbol::LIST_MAP_WITH_INDEX => Some(ListMapWithIndex), + Symbol::LIST_KEEP_IF => Some(ListKeepIf), + Symbol::LIST_WALK => Some(ListWalk), + Symbol::LIST_WALK_UNTIL => Some(ListWalkUntil), + Symbol::LIST_WALK_BACKWARDS => Some(ListWalkBackwards), + Symbol::LIST_KEEP_OKS => Some(ListKeepOks), + Symbol::LIST_KEEP_ERRS => Some(ListKeepErrs), + Symbol::LIST_SORT_WITH => Some(ListSortWith), + Symbol::LIST_SUBLIST => Some(ListSublist), + Symbol::LIST_DROP => Some(ListDrop), + Symbol::LIST_DROP_AT => Some(ListDropAt), + Symbol::LIST_SWAP => Some(ListSwap), + Symbol::LIST_ANY => Some(ListAny), + Symbol::LIST_FIND => Some(ListFindUnsafe), + Symbol::DICT_LEN => Some(DictSize), + Symbol::DICT_EMPTY => Some(DictEmpty), + Symbol::DICT_INSERT => Some(DictInsert), + Symbol::DICT_REMOVE => Some(DictRemove), + Symbol::DICT_CONTAINS => Some(DictContains), + Symbol::DICT_GET => Some(DictGetUnsafe), + Symbol::DICT_KEYS => Some(DictKeys), + Symbol::DICT_VALUES => Some(DictValues), + Symbol::DICT_UNION => Some(DictUnion), + Symbol::DICT_INTERSECTION => Some(DictIntersection), + Symbol::DICT_DIFFERENCE => Some(DictDifference), + Symbol::DICT_WALK => Some(DictWalk), + Symbol::SET_FROM_LIST => Some(SetFromList), + Symbol::NUM_ADD => Some(NumAdd), + Symbol::NUM_ADD_WRAP => Some(NumAddWrap), + Symbol::NUM_ADD_CHECKED => Some(NumAddChecked), + Symbol::NUM_SUB => Some(NumSub), + Symbol::NUM_SUB_WRAP => Some(NumSubWrap), + Symbol::NUM_SUB_CHECKED => Some(NumSubChecked), + Symbol::NUM_MUL => Some(NumMul), + Symbol::NUM_MUL_WRAP => Some(NumMulWrap), + Symbol::NUM_MUL_CHECKED => Some(NumMulChecked), + Symbol::NUM_GT => Some(NumGt), + Symbol::NUM_GTE => Some(NumGte), + Symbol::NUM_LT => Some(NumLt), + Symbol::NUM_LTE => Some(NumLte), + Symbol::NUM_COMPARE => Some(NumCompare), + Symbol::NUM_DIV_FLOAT => Some(NumDivUnchecked), + Symbol::NUM_DIV_CEIL => Some(NumDivCeilUnchecked), + Symbol::NUM_REM => Some(NumRemUnchecked), + Symbol::NUM_IS_MULTIPLE_OF => Some(NumIsMultipleOf), + Symbol::NUM_ABS => Some(NumAbs), + Symbol::NUM_NEG => Some(NumNeg), + Symbol::NUM_SIN => Some(NumSin), + Symbol::NUM_COS => Some(NumCos), + Symbol::NUM_SQRT => Some(NumSqrtUnchecked), + Symbol::NUM_LOG => Some(NumLogUnchecked), + Symbol::NUM_ROUND => Some(NumRound), + Symbol::NUM_TO_FLOAT => Some(NumToFloat), + Symbol::NUM_POW => Some(NumPow), + Symbol::NUM_CEILING => Some(NumCeiling), + Symbol::NUM_POW_INT => Some(NumPowInt), + Symbol::NUM_FLOOR => Some(NumFloor), + // => Some(NumIsFinite), + Symbol::NUM_ATAN => Some(NumAtan), + Symbol::NUM_ACOS => Some(NumAcos), + Symbol::NUM_ASIN => Some(NumAsin), + Symbol::NUM_BYTES_TO_U16 => Some(NumBytesToU16), + Symbol::NUM_BYTES_TO_U32 => Some(NumBytesToU32), + Symbol::NUM_BITWISE_AND => Some(NumBitwiseAnd), + Symbol::NUM_BITWISE_XOR => Some(NumBitwiseXor), + Symbol::NUM_BITWISE_OR => Some(NumBitwiseOr), + Symbol::NUM_SHIFT_LEFT => Some(NumShiftLeftBy), + Symbol::NUM_SHIFT_RIGHT => Some(NumShiftRightBy), + Symbol::NUM_SHIFT_RIGHT_ZERO_FILL => Some(NumShiftRightZfBy), + Symbol::NUM_INT_CAST => Some(NumIntCast), + Symbol::BOOL_EQ => Some(Eq), + Symbol::BOOL_NEQ => Some(NotEq), + Symbol::BOOL_AND => Some(And), + Symbol::BOOL_OR => Some(Or), + Symbol::BOOL_NOT => Some(Not), + // => Some(Hash), + // => Some(ExpectTrue), + _ => None, + } + } } From 64ad486c103ba6b415ffc94b65a8e3af89798ad0 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 13:05:06 -0800 Subject: [PATCH 082/223] automatically export snapshot tests --- .../pass/add_var_with_spaces.expr.result-ast | 1 + .../pass/add_var_with_spaces.expr.roc | 1 + .../pass/add_with_spaces.expr.result-ast | 1 + .../snapshots/pass/add_with_spaces.expr.roc | 1 + .../pass/all_f64_values_parse.expr.result-ast | 1 + .../pass/all_f64_values_parse.expr.roc | 1 + .../pass/all_i64_values_parse.expr.result-ast | 1 + .../pass/all_i64_values_parse.expr.roc | 1 + .../pass/apply_global_tag.expr.result-ast | 1 + .../snapshots/pass/apply_global_tag.expr.roc | 1 + ...enthetical_global_tag_args.expr.result-ast | 1 + ...ply_parenthetical_global_tag_args.expr.roc | 1 + .../pass/apply_private_tag.expr.result-ast | 1 + .../snapshots/pass/apply_private_tag.expr.roc | 1 + .../pass/apply_three_args.expr.result-ast | 1 + .../snapshots/pass/apply_three_args.expr.roc | 1 + .../pass/apply_two_args.expr.result-ast | 1 + .../snapshots/pass/apply_two_args.expr.roc | 1 + .../pass/apply_unary_negation.expr.result-ast | 1 + .../pass/apply_unary_negation.expr.roc | 1 + .../pass/apply_unary_not.expr.result-ast | 1 + .../snapshots/pass/apply_unary_not.expr.roc | 1 + .../pass/basic_apply.expr.result-ast | 1 + .../tests/snapshots/pass/basic_apply.expr.roc | 1 + .../snapshots/pass/basic_docs.expr.result-ast | 1 + .../tests/snapshots/pass/basic_docs.expr.roc | 9 + .../pass/basic_field.expr.result-ast | 1 + .../tests/snapshots/pass/basic_field.expr.roc | 1 + .../pass/basic_global_tag.expr.result-ast | 1 + .../snapshots/pass/basic_global_tag.expr.roc | 1 + .../pass/basic_private_tag.expr.result-ast | 1 + .../snapshots/pass/basic_private_tag.expr.roc | 1 + .../snapshots/pass/basic_var.expr.result-ast | 1 + .../tests/snapshots/pass/basic_var.expr.roc | 1 + .../closure_with_underscores.expr.result-ast | 1 + .../pass/closure_with_underscores.expr.roc | 1 + .../pass/comment_after_op.expr.result-ast | 1 + .../snapshots/pass/comment_after_op.expr.roc | 2 + .../pass/comment_before_op.expr.result-ast | 1 + .../snapshots/pass/comment_before_op.expr.roc | 2 + .../comment_inside_empty_list.expr.result-ast | 1 + .../pass/comment_inside_empty_list.expr.roc | 2 + .../comment_with_non_ascii.expr.result-ast | 1 + .../pass/comment_with_non_ascii.expr.roc | 2 + .../snapshots/pass/empty_list.expr.result-ast | 1 + .../tests/snapshots/pass/empty_list.expr.roc | 1 + .../pass/empty_record.expr.result-ast | 1 + .../snapshots/pass/empty_record.expr.roc | 1 + .../pass/empty_string.expr.result-ast | 1 + .../snapshots/pass/empty_string.expr.roc | 1 + .../snapshots/pass/equals.expr.result-ast | 1 + .../tests/snapshots/pass/equals.expr.roc | 1 + .../pass/equals_with_spaces.expr.result-ast | 1 + .../pass/equals_with_spaces.expr.roc | 1 + .../snapshots/pass/expect.expr.result-ast | 1 + .../tests/snapshots/pass/expect.expr.roc | 3 + .../float_with_underscores.expr.result-ast | 1 + .../pass/float_with_underscores.expr.roc | 1 + .../pass/highest_float.expr.result-ast | 1 + .../snapshots/pass/highest_float.expr.roc | 1 + .../pass/highest_int.expr.result-ast | 1 + .../tests/snapshots/pass/highest_int.expr.roc | 1 + .../snapshots/pass/if_def.expr.result-ast | 1 + .../tests/snapshots/pass/if_def.expr.roc | 3 + .../pass/int_with_underscore.expr.result-ast | 1 + .../pass/int_with_underscore.expr.roc | 1 + .../pass/lowest_float.expr.result-ast | 1 + .../snapshots/pass/lowest_float.expr.roc | 1 + .../snapshots/pass/lowest_int.expr.result-ast | 1 + .../tests/snapshots/pass/lowest_int.expr.roc | 1 + ...ed_ident_due_to_underscore.expr.result-ast | 1 + ...malformed_ident_due_to_underscore.expr.roc | 1 + ...ormed_pattern_field_access.expr.result-ast | 1 + .../malformed_pattern_field_access.expr.roc | 3 + ...formed_pattern_module_name.expr.result-ast | 1 + .../malformed_pattern_module_name.expr.roc | 3 + .../minus_twelve_minus_five.expr.result-ast | 1 + .../pass/minus_twelve_minus_five.expr.roc | 1 + .../snapshots/pass/mixed_docs.expr.result-ast | 1 + .../tests/snapshots/pass/mixed_docs.expr.roc | 7 + .../pass/multi_backpassing.expr.result-ast | 1 + .../snapshots/pass/multi_backpassing.expr.roc | 3 + .../pass/multi_char_string.expr.result-ast | 1 + .../snapshots/pass/multi_char_string.expr.roc | 1 + .../multiline_type_signature.expr.result-ast | 1 + .../pass/multiline_type_signature.expr.roc | 4 + ...ype_signature_with_comment.expr.result-ast | 1 + ...iline_type_signature_with_comment.expr.roc | 4 + .../pass/multiple_fields.expr.result-ast | 1 + .../snapshots/pass/multiple_fields.expr.roc | 1 + .../pass/multiple_operators.expr.result-ast | 1 + .../pass/multiple_operators.expr.roc | 1 + .../pass/neg_inf_float.expr.result-ast | 1 + .../snapshots/pass/neg_inf_float.expr.roc | 1 + .../pass/negative_float.expr.result-ast | 1 + .../snapshots/pass/negative_float.expr.roc | 1 + .../pass/negative_int.expr.result-ast | 1 + .../snapshots/pass/negative_int.expr.roc | 1 + .../pass/newline_after_equals.expr.result-ast | 1 + .../pass/newline_after_equals.expr.roc | 4 + .../pass/newline_after_mul.expr.result-ast | 1 + .../snapshots/pass/newline_after_mul.expr.roc | 2 + .../pass/newline_after_sub.expr.result-ast | 1 + .../snapshots/pass/newline_after_sub.expr.roc | 2 + ...nd_spaces_before_less_than.expr.result-ast | 1 + ...wline_and_spaces_before_less_than.expr.roc | 4 + .../pass/newline_before_add.expr.result-ast | 1 + .../pass/newline_before_add.expr.roc | 2 + .../pass/newline_before_sub.expr.result-ast | 1 + .../pass/newline_before_sub.expr.roc | 2 + .../newline_inside_empty_list.expr.result-ast | 1 + .../pass/newline_inside_empty_list.expr.roc | 2 + .../newline_singleton_list.expr.result-ast | 1 + .../pass/newline_singleton_list.expr.roc | 3 + .../snapshots/pass/not_docs.expr.result-ast | 1 + .../tests/snapshots/pass/not_docs.expr.roc | 7 + .../pass/one_backpassing.expr.result-ast | 1 + .../snapshots/pass/one_backpassing.expr.roc | 4 + .../pass/one_char_string.expr.result-ast | 1 + .../snapshots/pass/one_char_string.expr.roc | 1 + .../snapshots/pass/one_def.expr.result-ast | 1 + .../tests/snapshots/pass/one_def.expr.roc | 4 + .../pass/one_minus_two.expr.result-ast | 1 + .../snapshots/pass/one_minus_two.expr.roc | 1 + .../pass/one_plus_two.expr.result-ast | 1 + .../snapshots/pass/one_plus_two.expr.roc | 1 + .../pass/one_spaced_def.expr.result-ast | 1 + .../snapshots/pass/one_spaced_def.expr.roc | 4 + .../pass/ops_with_newlines.expr.result-ast | 1 + .../snapshots/pass/ops_with_newlines.expr.roc | 4 + .../packed_singleton_list.expr.result-ast | 1 + .../pass/packed_singleton_list.expr.roc | 1 + .../pass/parenthetical_apply.expr.result-ast | 1 + .../pass/parenthetical_apply.expr.roc | 1 + .../parenthetical_basic_field.expr.result-ast | 1 + .../pass/parenthetical_basic_field.expr.roc | 1 + ...etical_field_qualified_var.expr.result-ast | 1 + ...parenthetical_field_qualified_var.expr.roc | 1 + .../pass/parenthetical_var.expr.result-ast | 1 + .../snapshots/pass/parenthetical_var.expr.roc | 1 + .../pass/parse_alias.expr.result-ast | 1 + .../tests/snapshots/pass/parse_alias.expr.roc | 3 + .../pass/parse_as_ann.expr.result-ast | 1 + .../snapshots/pass/parse_as_ann.expr.roc | 3 + ...ttern_with_space_in_parens.expr.result-ast | 1 + .../pattern_with_space_in_parens.expr.roc | 2 + .../pass/pos_inf_float.expr.result-ast | 1 + .../snapshots/pass/pos_inf_float.expr.roc | 1 + .../pass/positive_float.expr.result-ast | 1 + .../snapshots/pass/positive_float.expr.roc | 1 + .../pass/positive_int.expr.result-ast | 1 + .../snapshots/pass/positive_int.expr.roc | 1 + .../private_qualified_tag.expr.result-ast | 1 + .../pass/private_qualified_tag.expr.roc | 1 + .../pass/qualified_field.expr.result-ast | 1 + .../snapshots/pass/qualified_field.expr.roc | 1 + .../pass/qualified_global_tag.expr.result-ast | 1 + .../pass/qualified_global_tag.expr.roc | 1 + .../pass/qualified_var.expr.result-ast | 1 + .../snapshots/pass/qualified_var.expr.roc | 1 + .../record_destructure_def.expr.result-ast | 1 + .../pass/record_destructure_def.expr.roc | 5 + .../pass/record_update.expr.result-ast | 1 + .../snapshots/pass/record_update.expr.roc | 1 + .../pass/record_with_if.expr.result-ast | 1 + .../snapshots/pass/record_with_if.expr.roc | 1 + .../pass/single_arg_closure.expr.result-ast | 1 + .../pass/single_arg_closure.expr.roc | 1 + .../single_underscore_closure.expr.result-ast | 1 + .../pass/single_underscore_closure.expr.roc | 1 + .../space_only_after_minus.expr.result-ast | 1 + .../pass/space_only_after_minus.expr.roc | 1 + .../spaced_singleton_list.expr.result-ast | 1 + .../pass/spaced_singleton_list.expr.roc | 1 + .../spaces_inside_empty_list.expr.result-ast | 1 + .../pass/spaces_inside_empty_list.expr.roc | 1 + .../string_without_escape.expr.result-ast | 1 + .../pass/string_without_escape.expr.roc | 1 + .../pass/sub_var_with_spaces.expr.result-ast | 1 + .../pass/sub_var_with_spaces.expr.roc | 1 + .../pass/sub_with_spaces.expr.result-ast | 1 + .../snapshots/pass/sub_with_spaces.expr.roc | 1 + .../pass/tag_pattern.expr.result-ast | 1 + .../tests/snapshots/pass/tag_pattern.expr.roc | 1 + .../pass/ten_times_eleven.expr.result-ast | 1 + .../snapshots/pass/ten_times_eleven.expr.roc | 1 + .../pass/three_arg_closure.expr.result-ast | 1 + .../snapshots/pass/three_arg_closure.expr.roc | 1 + .../pass/two_arg_closure.expr.result-ast | 1 + .../snapshots/pass/two_arg_closure.expr.roc | 1 + .../pass/two_backpassing.expr.result-ast | 1 + .../snapshots/pass/two_backpassing.expr.roc | 5 + .../pass/two_branch_when.expr.result-ast | 1 + .../snapshots/pass/two_branch_when.expr.roc | 3 + .../pass/two_spaced_def.expr.result-ast | 1 + .../snapshots/pass/two_spaced_def.expr.roc | 5 + .../pass/unary_negation.expr.result-ast | 1 + .../snapshots/pass/unary_negation.expr.roc | 1 + .../unary_negation_access.expr.result-ast | 1 + .../pass/unary_negation_access.expr.roc | 1 + .../pass/unary_negation_arg.expr.result-ast | 1 + .../pass/unary_negation_arg.expr.roc | 1 + ...unary_negation_with_parens.expr.result-ast | 1 + .../pass/unary_negation_with_parens.expr.roc | 1 + .../snapshots/pass/unary_not.expr.result-ast | 1 + .../tests/snapshots/pass/unary_not.expr.roc | 1 + .../unary_not_with_parens.expr.result-ast | 1 + .../pass/unary_not_with_parens.expr.roc | 1 + .../underscore_backpassing.expr.result-ast | 1 + .../pass/underscore_backpassing.expr.roc | 4 + .../snapshots/pass/var_else.expr.result-ast | 1 + .../tests/snapshots/pass/var_else.expr.roc | 1 + .../snapshots/pass/var_if.expr.result-ast | 1 + .../tests/snapshots/pass/var_if.expr.roc | 1 + .../snapshots/pass/var_is.expr.result-ast | 1 + .../tests/snapshots/pass/var_is.expr.roc | 1 + .../pass/var_minus_two.expr.result-ast | 1 + .../snapshots/pass/var_minus_two.expr.roc | 1 + .../snapshots/pass/var_then.expr.result-ast | 1 + .../tests/snapshots/pass/var_then.expr.roc | 1 + .../snapshots/pass/var_when.expr.result-ast | 1 + .../tests/snapshots/pass/var_when.expr.roc | 1 + .../pass/when_if_guard.expr.result-ast | 1 + .../snapshots/pass/when_if_guard.expr.roc | 9 + .../pass/when_in_parens.expr.result-ast | 1 + .../snapshots/pass/when_in_parens.expr.roc | 3 + .../when_in_parens_indented.expr.result-ast | 1 + .../pass/when_in_parens_indented.expr.roc | 3 + ..._with_alternative_patterns.expr.result-ast | 1 + .../when_with_alternative_patterns.expr.roc | 4 + ..._with_function_application.expr.result-ast | 1 + .../when_with_function_application.expr.roc | 4 + ...when_with_negative_numbers.expr.result-ast | 1 + .../pass/when_with_negative_numbers.expr.roc | 3 + .../pass/when_with_numbers.expr.result-ast | 1 + .../snapshots/pass/when_with_numbers.expr.roc | 3 + .../pass/when_with_records.expr.result-ast | 1 + .../snapshots/pass/when_with_records.expr.roc | 3 + .../snapshots/pass/zero_float.expr.result-ast | 1 + .../tests/snapshots/pass/zero_float.expr.roc | 1 + .../snapshots/pass/zero_int.expr.result-ast | 1 + .../tests/snapshots/pass/zero_int.expr.roc | 1 + compiler/parse/tests/test_parse.rs | 357 +++++++++++++----- 243 files changed, 624 insertions(+), 86 deletions(-) create mode 100644 compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/add_with_spaces.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/apply_global_tag.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/apply_private_tag.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/apply_three_args.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/apply_two_args.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/apply_unary_not.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/basic_apply.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/basic_docs.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/basic_field.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/basic_global_tag.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/basic_private_tag.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/basic_var.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/comment_after_op.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/comment_before_op.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/empty_list.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/empty_record.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/empty_string.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/equals.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/equals.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/expect.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/expect.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/float_with_underscores.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/highest_float.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/highest_int.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/if_def.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/if_def.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/int_with_underscore.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/lowest_float.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/lowest_int.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/mixed_docs.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/multi_backpassing.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/multi_char_string.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/multiple_fields.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/multiple_operators.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/neg_inf_float.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/negative_float.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/negative_int.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_after_equals.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_after_mul.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_after_sub.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_before_add.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_before_sub.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/not_docs.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/one_backpassing.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/one_char_string.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/one_def.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/one_def.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/one_minus_two.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/one_plus_two.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/one_spaced_def.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/parenthetical_var.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/parse_alias.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/parse_as_ann.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/pos_inf_float.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/positive_float.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/positive_int.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/qualified_field.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/qualified_var.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/record_destructure_def.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/record_update.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/record_update.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/record_with_if.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/single_arg_closure.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/string_without_escape.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/tag_pattern.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/three_arg_closure.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/two_arg_closure.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/two_backpassing.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/two_branch_when.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/two_spaced_def.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation_access.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/unary_not.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/var_else.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/var_else.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/var_if.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/var_if.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/var_is.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/var_is.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/var_minus_two.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/var_then.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/var_then.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/var_when.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/var_when.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_if_guard.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_in_parens.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_with_function_application.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_with_numbers.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/when_with_records.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/zero_float.expr.roc create mode 100644 compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/zero_int.expr.roc diff --git a/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast new file mode 100644 index 0000000000..e63c70e7fa --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 2-3| Plus)], |L 0-0, C 4-5| Num("2"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.roc b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.roc new file mode 100644 index 0000000000..f027c466fb --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.roc @@ -0,0 +1 @@ +x + 2 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast new file mode 100644 index 0000000000..d066d4cfb5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 3-4| Plus)], |L 0-0, C 7-8| Num("2"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.roc b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.roc new file mode 100644 index 0000000000..ece34b09b5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.roc @@ -0,0 +1 @@ +1 + 2 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast new file mode 100644 index 0000000000..84f580be3e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast @@ -0,0 +1 @@ +Ok(Float("5014168797528723000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc new file mode 100644 index 0000000000..cb1ebb9a8f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc @@ -0,0 +1 @@ +5014168797528723000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast new file mode 100644 index 0000000000..ac1417f545 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast @@ -0,0 +1 @@ +Ok(Num("5308198535548975042")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc new file mode 100644 index 0000000000..fe5339ac2d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc @@ -0,0 +1 @@ +5308198535548975042 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast new file mode 100644 index 0000000000..3fa34c07cd --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-4| GlobalTag("Whee"), [|L 0-0, C 5-7| Num("12"), |L 0-0, C 8-10| Num("34")], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.roc b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.roc new file mode 100644 index 0000000000..70563e8174 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.roc @@ -0,0 +1 @@ +Whee 12 34 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast new file mode 100644 index 0000000000..6adfaab1ae --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-4| GlobalTag("Whee"), [|L 0-0, C 6-8| ParensAround(Num("12")), |L 0-0, C 11-13| ParensAround(Num("34"))], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.roc b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.roc new file mode 100644 index 0000000000..a3ef4e0108 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.roc @@ -0,0 +1 @@ +Whee (12) (34) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast new file mode 100644 index 0000000000..11ccc3249d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-5| PrivateTag("@Whee"), [|L 0-0, C 6-8| Num("12"), |L 0-0, C 9-11| Num("34")], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.roc b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.roc new file mode 100644 index 0000000000..ba23819345 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.roc @@ -0,0 +1 @@ +@Whee 12 34 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast new file mode 100644 index 0000000000..7c0a90d084 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-1| Var { module_name: "", ident: "a" }, [|L 0-0, C 2-3| Var { module_name: "", ident: "b" }, |L 0-0, C 4-5| Var { module_name: "", ident: "c" }, |L 0-0, C 6-7| Var { module_name: "", ident: "d" }], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_three_args.expr.roc b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.roc new file mode 100644 index 0000000000..ff85291034 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.roc @@ -0,0 +1 @@ +a b c d \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast new file mode 100644 index 0000000000..a08b919ef7 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, [|L 0-0, C 6-8| Num("12"), |L 0-0, C 10-12| Num("34")], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_two_args.expr.roc b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.roc new file mode 100644 index 0000000000..5a1f135798 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.roc @@ -0,0 +1 @@ +whee 12 34 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast new file mode 100644 index 0000000000..877fd170ee --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Negate), [|L 0-0, C 7-9| Num("12"), |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.roc b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.roc new file mode 100644 index 0000000000..f04dfd38d3 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.roc @@ -0,0 +1 @@ +-whee 12 foo \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast new file mode 100644 index 0000000000..fadaba0251 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Not), [|L 0-0, C 7-9| Num("12"), |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.roc b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.roc new file mode 100644 index 0000000000..94e1f25809 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.roc @@ -0,0 +1 @@ +!whee 12 foo \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast new file mode 100644 index 0000000000..605813099b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, [|L 0-0, C 5-6| Num("1")], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_apply.expr.roc b/compiler/parse/tests/snapshots/pass/basic_apply.expr.roc new file mode 100644 index 0000000000..c9bcab2318 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_apply.expr.roc @@ -0,0 +1 @@ +whee 1 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast new file mode 100644 index 0000000000..b87ea1a724 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Defs([|L 6-6, C 0-5| Body(|L 6-6, C 0-1| Identifier("x"), |L 6-6, C 4-5| Num("5"))], |L 8-8, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [DocComment("first line of docs"), DocComment(" second line"), DocComment(" third line"), DocComment("fourth line"), DocComment(""), DocComment("sixth line after doc new line")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_docs.expr.roc b/compiler/parse/tests/snapshots/pass/basic_docs.expr.roc new file mode 100644 index 0000000000..2f66a22f48 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_docs.expr.roc @@ -0,0 +1,9 @@ +## first line of docs +## second line +## third line +## fourth line +## +## sixth line after doc new line +x = 5 + +42 diff --git a/compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast new file mode 100644 index 0000000000..2cbab0b493 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast @@ -0,0 +1 @@ +Ok(Access(Var { module_name: "", ident: "rec" }, "field")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_field.expr.roc b/compiler/parse/tests/snapshots/pass/basic_field.expr.roc new file mode 100644 index 0000000000..72832dcc6e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_field.expr.roc @@ -0,0 +1 @@ +rec.field \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast new file mode 100644 index 0000000000..80849d15dd --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast @@ -0,0 +1 @@ +Ok(GlobalTag("Whee")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.roc b/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.roc new file mode 100644 index 0000000000..ab03689fd9 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.roc @@ -0,0 +1 @@ +Whee \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast new file mode 100644 index 0000000000..f2071664f5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast @@ -0,0 +1 @@ +Ok(PrivateTag("@Whee")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.roc b/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.roc new file mode 100644 index 0000000000..476a77dfc2 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.roc @@ -0,0 +1 @@ +@Whee \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast new file mode 100644 index 0000000000..559be82dd4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "", ident: "whee" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/basic_var.expr.roc b/compiler/parse/tests/snapshots/pass/basic_var.expr.roc new file mode 100644 index 0000000000..53871cf18c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/basic_var.expr.roc @@ -0,0 +1 @@ +whee \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast new file mode 100644 index 0000000000..9ce08057a6 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast @@ -0,0 +1 @@ +Ok(Closure([|L 0-0, C 1-2| Underscore(""), |L 0-0, C 4-9| Underscore("name")], |L 0-0, C 13-15| Num("42"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.roc b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.roc new file mode 100644 index 0000000000..13ea565a79 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.roc @@ -0,0 +1 @@ +\_, _name -> 42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast new file mode 100644 index 0000000000..54d205022e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-2| Num("12"), |L 0-0, C 4-5| Star)], |L 1-1, C 1-3| SpaceBefore(Num("92"), [LineComment(" test!")]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_after_op.expr.roc b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.roc new file mode 100644 index 0000000000..8023584069 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.roc @@ -0,0 +1,2 @@ +12 * # test! + 92 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast new file mode 100644 index 0000000000..aad4f7e36e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" test!")]), |L 1-1, C 0-1| Plus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_before_op.expr.roc b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.roc new file mode 100644 index 0000000000..f0f6c3f6a7 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.roc @@ -0,0 +1,2 @@ +3 # test! ++ 4 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast new file mode 100644 index 0000000000..e00db1521b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast @@ -0,0 +1 @@ +Ok(List(Collection { items: [], final_comments: [LineComment("comment")] })) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.roc b/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.roc new file mode 100644 index 0000000000..d1fdba611d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.roc @@ -0,0 +1,2 @@ +[#comment +] \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast new file mode 100644 index 0000000000..46ab6fe925 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" 2 Γ— 2")]), |L 1-1, C 0-1| Plus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.roc b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.roc new file mode 100644 index 0000000000..f522366503 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.roc @@ -0,0 +1,2 @@ +3 # 2 Γ— 2 ++ 4 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast new file mode 100644 index 0000000000..584939a222 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast @@ -0,0 +1 @@ +Ok(List([])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/empty_list.expr.roc b/compiler/parse/tests/snapshots/pass/empty_list.expr.roc new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_list.expr.roc @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast b/compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast new file mode 100644 index 0000000000..0d3758e498 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast @@ -0,0 +1 @@ +Ok(Record(Collection { items: [], final_comments: [] })) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/empty_record.expr.roc b/compiler/parse/tests/snapshots/pass/empty_record.expr.roc new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_record.expr.roc @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast b/compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast new file mode 100644 index 0000000000..8c0f253a42 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast @@ -0,0 +1 @@ +Ok(Str(PlainLine(""))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/empty_string.expr.roc b/compiler/parse/tests/snapshots/pass/empty_string.expr.roc new file mode 100644 index 0000000000..e16c76dff8 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_string.expr.roc @@ -0,0 +1 @@ +"" diff --git a/compiler/parse/tests/snapshots/pass/equals.expr.result-ast b/compiler/parse/tests/snapshots/pass/equals.expr.result-ast new file mode 100644 index 0000000000..c744d69291 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/equals.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 1-3| Equals)], |L 0-0, C 3-4| Var { module_name: "", ident: "y" })) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/equals.expr.roc b/compiler/parse/tests/snapshots/pass/equals.expr.roc new file mode 100644 index 0000000000..470efe6934 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/equals.expr.roc @@ -0,0 +1 @@ +x==y \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast new file mode 100644 index 0000000000..2e41fec549 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 2-4| Equals)], |L 0-0, C 5-6| Var { module_name: "", ident: "y" })) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.roc b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.roc new file mode 100644 index 0000000000..616ee7099e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.roc @@ -0,0 +1 @@ +x == y \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/expect.expr.result-ast b/compiler/parse/tests/snapshots/pass/expect.expr.result-ast new file mode 100644 index 0000000000..2a831c90fd --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/expect.expr.result-ast @@ -0,0 +1 @@ +Ok(Expect(|L 0-0, C 7-13| BinOps([(|L 0-0, C 7-8| Num("1"), |L 0-0, C 9-11| Equals)], |L 0-0, C 12-13| Num("1")), |L 2-2, C 0-1| SpaceBefore(Num("4"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/expect.expr.roc b/compiler/parse/tests/snapshots/pass/expect.expr.roc new file mode 100644 index 0000000000..d5c03f0843 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/expect.expr.roc @@ -0,0 +1,3 @@ +expect 1 == 1 + +4 diff --git a/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast b/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast new file mode 100644 index 0000000000..d191a045b5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast @@ -0,0 +1 @@ +Ok(Float("-1_23_456.0_1_23_456")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.roc b/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.roc new file mode 100644 index 0000000000..b0d09ed2ec --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.roc @@ -0,0 +1 @@ +-1_23_456.0_1_23_456 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast new file mode 100644 index 0000000000..3a173721ea --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast @@ -0,0 +1 @@ +Ok(Float("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/highest_float.expr.roc b/compiler/parse/tests/snapshots/pass/highest_float.expr.roc new file mode 100644 index 0000000000..568e886219 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/highest_float.expr.roc @@ -0,0 +1 @@ +179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast new file mode 100644 index 0000000000..df5bcdf11f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast @@ -0,0 +1 @@ +Ok(Num("9223372036854775807")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/highest_int.expr.roc b/compiler/parse/tests/snapshots/pass/highest_int.expr.roc new file mode 100644 index 0000000000..996d127e59 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/highest_int.expr.roc @@ -0,0 +1 @@ +9223372036854775807 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast new file mode 100644 index 0000000000..58dc1ac3a2 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast @@ -0,0 +1 @@ +Ok(Defs([|L 0-0, C 0-6| Body(|L 0-0, C 0-4| Identifier("iffy"), |L 0-0, C 5-6| Num("5"))], |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/if_def.expr.roc b/compiler/parse/tests/snapshots/pass/if_def.expr.roc new file mode 100644 index 0000000000..868e83bbc8 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/if_def.expr.roc @@ -0,0 +1,3 @@ +iffy=5 + +42 diff --git a/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast b/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast new file mode 100644 index 0000000000..daab165d76 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast @@ -0,0 +1 @@ +Ok(Num("1__23")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.roc b/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.roc new file mode 100644 index 0000000000..18487633d1 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.roc @@ -0,0 +1 @@ +1__23 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast new file mode 100644 index 0000000000..060fa3c8e4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast @@ -0,0 +1 @@ +Ok(Float("-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/lowest_float.expr.roc b/compiler/parse/tests/snapshots/pass/lowest_float.expr.roc new file mode 100644 index 0000000000..d0c1a19c24 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/lowest_float.expr.roc @@ -0,0 +1 @@ +-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast new file mode 100644 index 0000000000..c6f13b67fa --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast @@ -0,0 +1 @@ +Ok(Num("-9223372036854775808")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/lowest_int.expr.roc b/compiler/parse/tests/snapshots/pass/lowest_int.expr.roc new file mode 100644 index 0000000000..9af921bf67 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/lowest_int.expr.roc @@ -0,0 +1 @@ +-9223372036854775808 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast new file mode 100644 index 0000000000..1e9a9935c7 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast @@ -0,0 +1 @@ +Ok(Closure([|L 0-0, C 1-11| MalformedIdent("the_answer", Underscore(0, 5))], |L 0-0, C 15-17| Num("42"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.roc b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.roc new file mode 100644 index 0000000000..2972e6dc77 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.roc @@ -0,0 +1 @@ +\the_answer -> 42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast new file mode 100644 index 0000000000..d5891e3680 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-11| SpaceBefore(Malformed("bar.and"), [Newline])], value: |L 1-1, C 15-16| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 2-2, C 9-10| Num("4"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.roc b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.roc new file mode 100644 index 0000000000..f7a694456b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.roc @@ -0,0 +1,3 @@ +when x is + bar.and -> 1 + _ -> 4 diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast new file mode 100644 index 0000000000..6b0bdfc90a --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-11| SpaceBefore(Malformed("Foo.and"), [Newline])], value: |L 1-1, C 15-16| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 2-2, C 9-10| Num("4"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.roc b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.roc new file mode 100644 index 0000000000..137974847c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.roc @@ -0,0 +1,3 @@ +when x is + Foo.and -> 1 + _ -> 4 diff --git a/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast new file mode 100644 index 0000000000..c64694015e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-3| Num("-12"), |L 0-0, C 3-4| Minus)], |L 0-0, C 4-5| Num("5"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.roc b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.roc new file mode 100644 index 0000000000..8d6e38dba4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.roc @@ -0,0 +1 @@ +-12-5 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast new file mode 100644 index 0000000000..e75ae5e9ee --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Defs([|L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5"))], |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment("## not docs!"), DocComment("docs, but with a problem"), DocComment("(namely that this is a mix of docs and regular comments)"), LineComment(" not docs")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.roc b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.roc new file mode 100644 index 0000000000..4d9a22c8c3 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.roc @@ -0,0 +1,7 @@ +### not docs! +## docs, but with a problem +## (namely that this is a mix of docs and regular comments) +# not docs +x = 5 + +42 diff --git a/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast new file mode 100644 index 0000000000..dc8516328a --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast @@ -0,0 +1 @@ +Ok(Backpassing([|L 0-0, C 0-1| Identifier("x"), |L 0-0, C 3-4| Identifier("y")], |L 0-0, C 8-23| Apply(|L 0-0, C 8-17| Var { module_name: "List", ident: "map2" }, [|L 0-0, C 18-20| List(Collection { items: [], final_comments: [] }), |L 0-0, C 21-23| List(Collection { items: [], final_comments: [] })], Space), |L 2-2, C 0-5| SpaceBefore(BinOps([(|L 2-2, C 0-1| Var { module_name: "", ident: "x" }, |L 2-2, C 2-3| Plus)], |L 2-2, C 4-5| Var { module_name: "", ident: "y" }), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.roc b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.roc new file mode 100644 index 0000000000..06a4454183 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.roc @@ -0,0 +1,3 @@ +x, y <- List.map2 [] [] + +x + y diff --git a/compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast b/compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast new file mode 100644 index 0000000000..95999767a2 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast @@ -0,0 +1 @@ +Ok(Str(PlainLine("foo"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multi_char_string.expr.roc b/compiler/parse/tests/snapshots/pass/multi_char_string.expr.roc new file mode 100644 index 0000000000..810c96eeeb --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multi_char_string.expr.roc @@ -0,0 +1 @@ +"foo" diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast new file mode 100644 index 0000000000..0567c1e5fc --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast @@ -0,0 +1 @@ +Ok(Defs([|L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: Collection { items: [], final_comments: [] }, ext: None }, [Newline]))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.roc b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.roc new file mode 100644 index 0000000000..0ec71af042 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.roc @@ -0,0 +1,4 @@ +f : + {} + +42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast new file mode 100644 index 0000000000..957c78140d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast @@ -0,0 +1 @@ +Ok(Defs([|L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: Collection { items: [], final_comments: [] }, ext: None }, [LineComment(" comment")]))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.roc b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.roc new file mode 100644 index 0000000000..eee9119dcd --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.roc @@ -0,0 +1,4 @@ +f :# comment + {} + +42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast new file mode 100644 index 0000000000..31576b229c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast @@ -0,0 +1 @@ +Ok(Access(Access(Access(Var { module_name: "", ident: "rec" }, "abc"), "def"), "ghi")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multiple_fields.expr.roc b/compiler/parse/tests/snapshots/pass/multiple_fields.expr.roc new file mode 100644 index 0000000000..b5cbe3aa75 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiple_fields.expr.roc @@ -0,0 +1 @@ +rec.abc.def.ghi \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast new file mode 100644 index 0000000000..67018b80c7 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-2| Num("31"), |L 0-0, C 2-3| Star), (|L 0-0, C 3-5| Num("42"), |L 0-0, C 5-6| Plus)], |L 0-0, C 6-9| Num("534"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/multiple_operators.expr.roc b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.roc new file mode 100644 index 0000000000..2e789bcecf --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.roc @@ -0,0 +1 @@ +31*42+534 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast new file mode 100644 index 0000000000..b73f603675 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast @@ -0,0 +1 @@ +Ok(UnaryOp(|L 0-0, C 1-4| Var { module_name: "", ident: "inf" }, |L 0-0, C 0-1| Negate)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.roc b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.roc new file mode 100644 index 0000000000..f9111418ae --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.roc @@ -0,0 +1 @@ +-inf \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast new file mode 100644 index 0000000000..4284d2a8e4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast @@ -0,0 +1 @@ +Ok(Float("-42.9")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/negative_float.expr.roc b/compiler/parse/tests/snapshots/pass/negative_float.expr.roc new file mode 100644 index 0000000000..1409b58f0f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/negative_float.expr.roc @@ -0,0 +1 @@ +-42.9 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast new file mode 100644 index 0000000000..80aa5f34f3 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast @@ -0,0 +1 @@ +Ok(Num("-42")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/negative_int.expr.roc b/compiler/parse/tests/snapshots/pass/negative_int.expr.roc new file mode 100644 index 0000000000..67f7ad0566 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/negative_int.expr.roc @@ -0,0 +1 @@ +-42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast new file mode 100644 index 0000000000..929a66d299 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast @@ -0,0 +1 @@ +Ok(Defs([|L 0-1, C 0-5| Body(|L 0-0, C 0-1| Identifier("x"), |L 1-1, C 4-5| SpaceBefore(Num("5"), [Newline]))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.roc b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.roc new file mode 100644 index 0000000000..0662bdb2c1 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.roc @@ -0,0 +1,4 @@ +x = + 5 + +42 diff --git a/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast new file mode 100644 index 0000000000..4cef64f79d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Num("3"), |L 0-0, C 3-4| Star)], |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.roc b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.roc new file mode 100644 index 0000000000..84e2c946bd --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.roc @@ -0,0 +1,2 @@ +3 * + 4 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast new file mode 100644 index 0000000000..e9200fe6ee --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Num("3"), |L 0-0, C 3-4| Minus)], |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.roc b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.roc new file mode 100644 index 0000000000..92bcc0c2df --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.roc @@ -0,0 +1,2 @@ +3 - + 4 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast new file mode 100644 index 0000000000..b758863e92 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast @@ -0,0 +1 @@ +Ok(Defs([|L 0-1, C 0-7| Body(|L 0-0, C 0-1| Identifier("x"), |L 0-1, C 4-7| BinOps([(|L 0-0, C 4-5| SpaceAfter(Num("1"), [Newline]), |L 1-1, C 4-5| LessThan)], |L 1-1, C 6-7| Num("2")))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.roc b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.roc new file mode 100644 index 0000000000..1d80197ef1 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.roc @@ -0,0 +1,4 @@ +x = 1 + < 2 + +42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast new file mode 100644 index 0000000000..fb5568dc0d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), |L 1-1, C 0-1| Plus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_before_add.expr.roc b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.roc new file mode 100644 index 0000000000..2aef041bd9 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.roc @@ -0,0 +1,2 @@ +3 ++ 4 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast new file mode 100644 index 0000000000..20680de556 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), |L 1-1, C 0-1| Minus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.roc b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.roc new file mode 100644 index 0000000000..19ab26bdea --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.roc @@ -0,0 +1,2 @@ +3 +- 4 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast new file mode 100644 index 0000000000..92d58d3ccf --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast @@ -0,0 +1 @@ +Ok(List(Collection { items: [], final_comments: [Newline] })) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.roc b/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.roc new file mode 100644 index 0000000000..32960f8ced --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.roc @@ -0,0 +1,2 @@ +[ +] \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast new file mode 100644 index 0000000000..c77f1fc342 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast @@ -0,0 +1 @@ +Ok(List([|L 1-1, C 0-1| SpaceBefore(SpaceAfter(Num("1"), [Newline]), [Newline])])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.roc b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.roc new file mode 100644 index 0000000000..730c97e183 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.roc @@ -0,0 +1,3 @@ +[ +1 +] \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast new file mode 100644 index 0000000000..65c891736b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Defs([|L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5"))], |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment("######"), LineComment("## not docs!"), LineComment("#still not docs"), LineComment("#####")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/not_docs.expr.roc b/compiler/parse/tests/snapshots/pass/not_docs.expr.roc new file mode 100644 index 0000000000..28793bd79e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/not_docs.expr.roc @@ -0,0 +1,7 @@ +####### +### not docs! +##still not docs +###### +x = 5 + +42 diff --git a/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast new file mode 100644 index 0000000000..41c5906bea --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Backpassing([|L 1-1, C 0-1| Identifier("x")], |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), |L 3-3, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_backpassing.expr.roc b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.roc new file mode 100644 index 0000000000..a7cfb74204 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.roc @@ -0,0 +1,4 @@ +# leading comment +x <- (\y -> y) + +x diff --git a/compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast new file mode 100644 index 0000000000..da2aa04018 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast @@ -0,0 +1 @@ +Ok(Str(PlainLine("x"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_char_string.expr.roc b/compiler/parse/tests/snapshots/pass/one_char_string.expr.roc new file mode 100644 index 0000000000..92232f694a --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_char_string.expr.roc @@ -0,0 +1 @@ +"x" diff --git a/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast new file mode 100644 index 0000000000..71bda962ae --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Defs([|L 1-1, C 0-3| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 2-3| Num("5"))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_def.expr.roc b/compiler/parse/tests/snapshots/pass/one_def.expr.roc new file mode 100644 index 0000000000..2f6b7e6b76 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_def.expr.roc @@ -0,0 +1,4 @@ +# leading comment +x=5 + +42 diff --git a/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast new file mode 100644 index 0000000000..bcc80fb069 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 1-2| Minus)], |L 0-0, C 2-3| Num("2"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_minus_two.expr.roc b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.roc new file mode 100644 index 0000000000..21869de97e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.roc @@ -0,0 +1 @@ +1-2 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast new file mode 100644 index 0000000000..e465cb4675 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 1-2| Plus)], |L 0-0, C 2-3| Num("2"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_plus_two.expr.roc b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.roc new file mode 100644 index 0000000000..dc462db0d5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.roc @@ -0,0 +1 @@ +1+2 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast new file mode 100644 index 0000000000..83e3d3903d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Defs([|L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5"))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.roc b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.roc new file mode 100644 index 0000000000..b5a1b3af49 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.roc @@ -0,0 +1,4 @@ +# leading comment +x = 5 + +42 diff --git a/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast new file mode 100644 index 0000000000..59379078a4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), |L 1-1, C 0-1| Plus)], |L 3-3, C 2-3| SpaceBefore(Num("4"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.roc b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.roc new file mode 100644 index 0000000000..518b92423c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.roc @@ -0,0 +1,4 @@ +3 ++ + + 4 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast new file mode 100644 index 0000000000..664b584c41 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast @@ -0,0 +1 @@ +Ok(List([|L 0-0, C 1-2| Num("1")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.roc b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.roc new file mode 100644 index 0000000000..bace2a0be1 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.roc @@ -0,0 +1 @@ +[1] \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast new file mode 100644 index 0000000000..264f7b91de --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 1-5| ParensAround(Var { module_name: "", ident: "whee" }), [|L 0-0, C 7-8| Num("1")], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.roc b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.roc new file mode 100644 index 0000000000..f39a9ee9af --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.roc @@ -0,0 +1 @@ +(whee) 1 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast new file mode 100644 index 0000000000..0885a3d485 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast @@ -0,0 +1 @@ +Ok(Access(ParensAround(Var { module_name: "", ident: "rec" }), "field")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.roc b/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.roc new file mode 100644 index 0000000000..687a92bf5c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.roc @@ -0,0 +1 @@ +(rec).field \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast new file mode 100644 index 0000000000..0c4537ba21 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast @@ -0,0 +1 @@ +Ok(Access(ParensAround(Var { module_name: "One.Two", ident: "rec" }), "field")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.roc b/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.roc new file mode 100644 index 0000000000..5359b0e5bb --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.roc @@ -0,0 +1 @@ +(One.Two.rec).field \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast new file mode 100644 index 0000000000..45ce9bd72f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast @@ -0,0 +1 @@ +Ok(ParensAround(Var { module_name: "", ident: "whee" })) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.roc b/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.roc new file mode 100644 index 0000000000..169a3e0e75 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.roc @@ -0,0 +1 @@ +(whee) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast new file mode 100644 index 0000000000..25fe2403c4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast @@ -0,0 +1 @@ +Ok(Defs([|L 0-0, C 0-26| Alias { name: |L 0-0, C 0-4| "Blah", vars: [|L 0-0, C 5-6| Identifier("a"), |L 0-0, C 7-8| Identifier("b")], ann: |L 0-0, C 11-26| Apply("Foo.Bar", "Baz", [|L 0-0, C 23-24| BoundVariable("x"), |L 0-0, C 25-26| BoundVariable("y")]) }], |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parse_alias.expr.roc b/compiler/parse/tests/snapshots/pass/parse_alias.expr.roc new file mode 100644 index 0000000000..f2a402450b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parse_alias.expr.roc @@ -0,0 +1,3 @@ +Blah a b : Foo.Bar.Baz x y + +42 diff --git a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast new file mode 100644 index 0000000000..2d3d9d2dc5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast @@ -0,0 +1 @@ +Ok(Defs([|L 0-0, C 0-33| Annotation(|L 0-0, C 0-3| Identifier("foo"), |L 0-0, C 6-33| As(|L 0-0, C 6-21| Apply("Foo.Bar", "Baz", [|L 0-0, C 18-19| BoundVariable("x"), |L 0-0, C 20-21| BoundVariable("y")]), [], |L 0-0, C 25-33| Apply("", "Blah", [|L 0-0, C 30-31| BoundVariable("a"), |L 0-0, C 32-33| BoundVariable("b")])))], |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.roc b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.roc new file mode 100644 index 0000000000..e5d9c28013 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.roc @@ -0,0 +1,3 @@ +foo : Foo.Bar.Baz x y as Blah a b + +42 diff --git a/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast new file mode 100644 index 0000000000..8defcce4a4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-22| Apply(|L 0-0, C 5-11| GlobalTag("Delmin"), [|L 0-0, C 13-19| ParensAround(Apply(|L 0-0, C 13-16| GlobalTag("Del"), [|L 0-0, C 17-19| Var { module_name: "", ident: "rx" }], Space)), |L 0-0, C 21-22| Num("0")], Space), [WhenBranch { patterns: [|L 1-1, C 4-22| SpaceBefore(Apply(|L 1-1, C 4-10| GlobalTag("Delmin"), [|L 1-1, C 12-18| Apply(|L 1-1, C 12-15| GlobalTag("Del"), [|L 1-1, C 16-18| Identifier("ry")]), |L 1-1, C 21-22| Underscore("")]), [Newline])], value: |L 1-1, C 26-47| Apply(|L 1-1, C 26-30| GlobalTag("Node"), [|L 1-1, C 31-36| GlobalTag("Black"), |L 1-1, C 37-38| Num("0"), |L 1-1, C 39-44| GlobalTag("False"), |L 1-1, C 45-47| Var { module_name: "", ident: "ry" }], Space), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.roc b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.roc new file mode 100644 index 0000000000..c397c8ce35 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.roc @@ -0,0 +1,2 @@ +when Delmin (Del rx) 0 is + Delmin (Del ry ) _ -> Node Black 0 False ry diff --git a/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast new file mode 100644 index 0000000000..02c3fc192c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "", ident: "inf" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.roc b/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.roc new file mode 100644 index 0000000000..a28aa9a0ff --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.roc @@ -0,0 +1 @@ +inf \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast new file mode 100644 index 0000000000..1386884fc2 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast @@ -0,0 +1 @@ +Ok(Float("42.9")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/positive_float.expr.roc b/compiler/parse/tests/snapshots/pass/positive_float.expr.roc new file mode 100644 index 0000000000..9f125123d5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/positive_float.expr.roc @@ -0,0 +1 @@ +42.9 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast new file mode 100644 index 0000000000..535767ea52 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast @@ -0,0 +1 @@ +Ok(Num("42")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/positive_int.expr.roc b/compiler/parse/tests/snapshots/pass/positive_int.expr.roc new file mode 100644 index 0000000000..f70d7bba4a --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/positive_int.expr.roc @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast new file mode 100644 index 0000000000..18b2af3de4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast @@ -0,0 +1 @@ +Ok(MalformedIdent("@One.Two.Whee", BadPrivateTag(0, 4))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.roc b/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.roc new file mode 100644 index 0000000000..e5c825a346 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.roc @@ -0,0 +1 @@ +@One.Two.Whee \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast b/compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast new file mode 100644 index 0000000000..c3790e14b3 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast @@ -0,0 +1 @@ +Ok(Access(Access(Access(Var { module_name: "One.Two", ident: "rec" }, "abc"), "def"), "ghi")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/qualified_field.expr.roc b/compiler/parse/tests/snapshots/pass/qualified_field.expr.roc new file mode 100644 index 0000000000..f5b18894d8 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/qualified_field.expr.roc @@ -0,0 +1 @@ +One.Two.rec.abc.def.ghi \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast new file mode 100644 index 0000000000..3a52b4fe52 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast @@ -0,0 +1 @@ +Ok(MalformedIdent("One.Two.Whee", QualifiedTag(0, 12))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.roc b/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.roc new file mode 100644 index 0000000000..448358be9e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.roc @@ -0,0 +1 @@ +One.Two.Whee \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast new file mode 100644 index 0000000000..ac634bc3b1 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "One.Two", ident: "whee" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/qualified_var.expr.roc b/compiler/parse/tests/snapshots/pass/qualified_var.expr.roc new file mode 100644 index 0000000000..28a06dc970 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/qualified_var.expr.roc @@ -0,0 +1 @@ +One.Two.whee \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast new file mode 100644 index 0000000000..14a36adda0 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Defs([|L 1-1, C 0-12| Body(|L 1-1, C 0-8| RecordDestructure(Collection { items: [|L 1-1, C 2-3| Identifier("x"), |L 1-1, C 5-7| Identifier("y")], final_comments: [] }), |L 1-1, C 11-12| Num("5")), |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline])], |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.roc b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.roc new file mode 100644 index 0000000000..2f565b852a --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.roc @@ -0,0 +1,5 @@ +# leading comment +{ x, y } = 5 +y = 6 + +42 diff --git a/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast new file mode 100644 index 0000000000..345c5b1966 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast @@ -0,0 +1 @@ +Ok(RecordUpdate { update: |L 0-0, C 2-13| Var { module_name: "Foo.Bar", ident: "baz" }, fields: [|L 0-0, C 16-20| RequiredValue(|L 0-0, C 16-17| "x", [], |L 0-0, C 19-20| Num("5")), |L 0-0, C 22-26| RequiredValue(|L 0-0, C 22-23| "y", [], |L 0-0, C 25-26| Num("0"))] }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/record_update.expr.roc b/compiler/parse/tests/snapshots/pass/record_update.expr.roc new file mode 100644 index 0000000000..ac38be8956 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/record_update.expr.roc @@ -0,0 +1 @@ +{ Foo.Bar.baz & x: 5, y: 0 } \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast new file mode 100644 index 0000000000..e860f48ba4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast @@ -0,0 +1 @@ +Ok(Record([|L 0-0, C 1-26| RequiredValue(|L 0-0, C 1-2| "x", [], |L 0-0, C 5-26| If([(|L 0-0, C 8-12| GlobalTag("True"), |L 0-0, C 18-19| Num("1"))], |L 0-0, C 25-26| Num("2"))), |L 0-0, C 28-32| RequiredValue(|L 0-0, C 28-29| "y", [], |L 0-0, C 31-32| Num("3"))])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/record_with_if.expr.roc b/compiler/parse/tests/snapshots/pass/record_with_if.expr.roc new file mode 100644 index 0000000000..7c186e5d31 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/record_with_if.expr.roc @@ -0,0 +1 @@ +{x : if True then 1 else 2, y: 3 } \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast new file mode 100644 index 0000000000..9680e171dd --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast @@ -0,0 +1 @@ +Ok(Closure([|L 0-0, C 1-2| Identifier("a")], |L 0-0, C 6-8| Num("42"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.roc b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.roc new file mode 100644 index 0000000000..188d4d607e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.roc @@ -0,0 +1 @@ +\a -> 42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast new file mode 100644 index 0000000000..fd951daa13 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast @@ -0,0 +1 @@ +Ok(Closure([|L 0-0, C 1-2| Underscore("")], |L 0-0, C 6-8| Num("42"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.roc b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.roc new file mode 100644 index 0000000000..28c65bdeba --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.roc @@ -0,0 +1 @@ +\_ -> 42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast new file mode 100644 index 0000000000..212d337e4e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 1-2| Minus)], |L 0-0, C 3-4| Var { module_name: "", ident: "y" })) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.roc b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.roc new file mode 100644 index 0000000000..d7d545ec40 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.roc @@ -0,0 +1 @@ +x- y \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast new file mode 100644 index 0000000000..3a12140511 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast @@ -0,0 +1 @@ +Ok(List([|L 0-0, C 2-3| Num("1")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.roc b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.roc new file mode 100644 index 0000000000..404b10d49d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.roc @@ -0,0 +1 @@ +[ 1 ] \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast new file mode 100644 index 0000000000..584939a222 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast @@ -0,0 +1 @@ +Ok(List([])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.roc b/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.roc new file mode 100644 index 0000000000..f6ffad5cb3 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.roc @@ -0,0 +1 @@ +[ ] \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast b/compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast new file mode 100644 index 0000000000..9c2d2d1a63 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast @@ -0,0 +1 @@ +Ok(Str(PlainLine("123 abc 456 def"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/string_without_escape.expr.roc b/compiler/parse/tests/snapshots/pass/string_without_escape.expr.roc new file mode 100644 index 0000000000..3c069479a0 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/string_without_escape.expr.roc @@ -0,0 +1 @@ +"123 abc 456 def" \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast new file mode 100644 index 0000000000..4b2859992b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 2-3| Minus)], |L 0-0, C 4-5| Num("2"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.roc b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.roc new file mode 100644 index 0000000000..9b0ac03e68 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.roc @@ -0,0 +1 @@ +x - 2 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast new file mode 100644 index 0000000000..ad3f4a7328 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 3-4| Minus)], |L 0-0, C 7-8| Num("2"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.roc b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.roc new file mode 100644 index 0000000000..e479d53f85 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.roc @@ -0,0 +1 @@ +1 - 2 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast new file mode 100644 index 0000000000..947c450022 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast @@ -0,0 +1 @@ +Ok(Closure([|L 0-0, C 1-6| GlobalTag("Thing")], |L 0-0, C 10-12| Num("42"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/tag_pattern.expr.roc b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.roc new file mode 100644 index 0000000000..62b6fc5abc --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.roc @@ -0,0 +1 @@ +\Thing -> 42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast new file mode 100644 index 0000000000..b963a078d6 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-2| Num("10"), |L 0-0, C 2-3| Star)], |L 0-0, C 3-5| Num("11"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.roc b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.roc new file mode 100644 index 0000000000..db8e7f0e5e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.roc @@ -0,0 +1 @@ +10*11 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast new file mode 100644 index 0000000000..999cc9464e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast @@ -0,0 +1 @@ +Ok(Closure([|L 0-0, C 1-2| Identifier("a"), |L 0-0, C 4-5| Identifier("b"), |L 0-0, C 7-8| Identifier("c")], |L 0-0, C 12-14| Num("42"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.roc b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.roc new file mode 100644 index 0000000000..fe1e9f0cad --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.roc @@ -0,0 +1 @@ +\a, b, c -> 42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast new file mode 100644 index 0000000000..d249da119f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast @@ -0,0 +1 @@ +Ok(Closure([|L 0-0, C 1-2| Identifier("a"), |L 0-0, C 4-5| Identifier("b")], |L 0-0, C 9-11| Num("42"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.roc b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.roc new file mode 100644 index 0000000000..83db21cf1f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.roc @@ -0,0 +1 @@ +\a, b -> 42 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast new file mode 100644 index 0000000000..ab62b49967 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Backpassing([|L 1-1, C 0-1| Identifier("x")], |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), |L 2-4, C 0-1| SpaceBefore(Backpassing([|L 2-2, C 0-1| Identifier("z")], |L 2-2, C 5-7| Record(Collection { items: [], final_comments: [] }), |L 4-4, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline])), [Newline])), [LineComment(" leading comment")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/two_backpassing.expr.roc b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.roc new file mode 100644 index 0000000000..f36a289c6c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.roc @@ -0,0 +1,5 @@ +# leading comment +x <- (\y -> y) +z <- {} + +x diff --git a/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast new file mode 100644 index 0000000000..07f24e4cb4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-3| SpaceBefore(StrLiteral(PlainLine("")), [Newline])], value: |L 1-1, C 7-8| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-7| SpaceBefore(StrLiteral(PlainLine("mise")), [Newline])], value: |L 2-2, C 11-12| Num("2"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/two_branch_when.expr.roc b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.roc new file mode 100644 index 0000000000..783ecbc023 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.roc @@ -0,0 +1,3 @@ +when x is + "" -> 1 + "mise" -> 2 diff --git a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast new file mode 100644 index 0000000000..34b9a590a9 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Defs([|L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5")), |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline])], |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.roc b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.roc new file mode 100644 index 0000000000..3616875083 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.roc @@ -0,0 +1,5 @@ +# leading comment +x = 5 +y = 6 + +42 diff --git a/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast new file mode 100644 index 0000000000..cee72d6e0f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast @@ -0,0 +1 @@ +Ok(UnaryOp(|L 0-0, C 1-4| Var { module_name: "", ident: "foo" }, |L 0-0, C 0-1| Negate)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_negation.expr.roc b/compiler/parse/tests/snapshots/pass/unary_negation.expr.roc new file mode 100644 index 0000000000..46409ea605 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation.expr.roc @@ -0,0 +1 @@ +-foo \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast new file mode 100644 index 0000000000..574e1efa75 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast @@ -0,0 +1 @@ +Ok(UnaryOp(|L 0-0, C 1-11| Access(Var { module_name: "", ident: "rec1" }, "field"), |L 0-0, C 0-1| Negate)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.roc b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.roc new file mode 100644 index 0000000000..c942e53928 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.roc @@ -0,0 +1 @@ +-rec1.field \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast new file mode 100644 index 0000000000..8eecf50e4b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast @@ -0,0 +1 @@ +Ok(Apply(|L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, [|L 0-0, C 6-8| Num("12"), |L 0-0, C 9-13| UnaryOp(|L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, |L 0-0, C 9-10| Negate)], Space)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.roc b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.roc new file mode 100644 index 0000000000..8484ae0e95 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.roc @@ -0,0 +1 @@ +whee 12 -foo \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast new file mode 100644 index 0000000000..24aab96847 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast @@ -0,0 +1 @@ +Ok(UnaryOp(|L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), |L 0-0, C 0-1| Negate)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.roc b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.roc new file mode 100644 index 0000000000..1c89e5dc15 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.roc @@ -0,0 +1 @@ +-(whee 12 foo) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast new file mode 100644 index 0000000000..fb52a8f2a9 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast @@ -0,0 +1 @@ +Ok(UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "blah" }, |L 0-0, C 0-1| Not)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_not.expr.roc b/compiler/parse/tests/snapshots/pass/unary_not.expr.roc new file mode 100644 index 0000000000..9641cc0354 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_not.expr.roc @@ -0,0 +1 @@ +!blah \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast new file mode 100644 index 0000000000..3c59060bec --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast @@ -0,0 +1 @@ +Ok(UnaryOp(|L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), |L 0-0, C 0-1| Not)) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.roc b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.roc new file mode 100644 index 0000000000..2065d557d3 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.roc @@ -0,0 +1 @@ +!(whee 12 foo) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast new file mode 100644 index 0000000000..74db669789 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast @@ -0,0 +1 @@ +Ok(SpaceBefore(Backpassing([|L 1-1, C 0-1| Underscore("")], |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), |L 3-3, C 0-1| SpaceBefore(Num("4"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.roc b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.roc new file mode 100644 index 0000000000..3e0d8ca803 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.roc @@ -0,0 +1,4 @@ +# leading comment +_ <- (\y -> y) + +4 diff --git a/compiler/parse/tests/snapshots/pass/var_else.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_else.expr.result-ast new file mode 100644 index 0000000000..dbfa1c598d --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_else.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "", ident: "elsewhere" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_else.expr.roc b/compiler/parse/tests/snapshots/pass/var_else.expr.roc new file mode 100644 index 0000000000..f98eb10ae8 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_else.expr.roc @@ -0,0 +1 @@ +elsewhere \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_if.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_if.expr.result-ast new file mode 100644 index 0000000000..87be960a7f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_if.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "", ident: "iffy" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_if.expr.roc b/compiler/parse/tests/snapshots/pass/var_if.expr.roc new file mode 100644 index 0000000000..65ad4cb8b4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_if.expr.roc @@ -0,0 +1 @@ +iffy \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_is.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_is.expr.result-ast new file mode 100644 index 0000000000..d02b7f8d56 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_is.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "", ident: "isnt" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_is.expr.roc b/compiler/parse/tests/snapshots/pass/var_is.expr.roc new file mode 100644 index 0000000000..ccdb611527 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_is.expr.roc @@ -0,0 +1 @@ +isnt \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast new file mode 100644 index 0000000000..f0c76694c9 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast @@ -0,0 +1 @@ +Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 1-2| Minus)], |L 0-0, C 2-3| Num("2"))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_minus_two.expr.roc b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.roc new file mode 100644 index 0000000000..9c90f0b33f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.roc @@ -0,0 +1 @@ +x-2 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_then.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_then.expr.result-ast new file mode 100644 index 0000000000..99277807cc --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_then.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "", ident: "thenever" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_then.expr.roc b/compiler/parse/tests/snapshots/pass/var_then.expr.roc new file mode 100644 index 0000000000..5129806177 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_then.expr.roc @@ -0,0 +1 @@ +thenever \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_when.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_when.expr.result-ast new file mode 100644 index 0000000000..a060ee2cc3 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_when.expr.result-ast @@ -0,0 +1 @@ +Ok(Var { module_name: "", ident: "whenever" }) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/var_when.expr.roc b/compiler/parse/tests/snapshots/pass/var_when.expr.roc new file mode 100644 index 0000000000..3e93c51e69 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/var_when.expr.roc @@ -0,0 +1 @@ +whenever \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast new file mode 100644 index 0000000000..64df94bc50 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 2-2, C 8-9| SpaceBefore(Num("1"), [Newline]), guard: None }, WhenBranch { patterns: [|L 4-4, C 4-5| SpaceBefore(Underscore(""), [Newline, Newline])], value: |L 5-5, C 8-9| SpaceBefore(Num("2"), [Newline]), guard: None }, WhenBranch { patterns: [|L 7-7, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline, Newline])], value: |L 8-8, C 8-9| SpaceBefore(Num("3"), [Newline]), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_if_guard.expr.roc b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.roc new file mode 100644 index 0000000000..392b1fe99f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.roc @@ -0,0 +1,9 @@ +when x is + _ -> + 1 + + _ -> + 2 + + Ok -> + 3 diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast new file mode 100644 index 0000000000..ce00005d8c --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast @@ -0,0 +1 @@ +Ok(ParensAround(When(|L 0-0, C 6-7| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline])], value: |L 2-2, C 8-9| SpaceBefore(Num("3"), [Newline]), guard: None }]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens.expr.roc b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.roc new file mode 100644 index 0000000000..e65900b295 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.roc @@ -0,0 +1,3 @@ +(when x is + Ok -> + 3) diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast new file mode 100644 index 0000000000..f47b89c3c4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast @@ -0,0 +1 @@ +Ok(ParensAround(SpaceAfter(When(|L 0-0, C 6-7| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline])], value: |L 1-1, C 10-11| Num("3"), guard: None }]), [Newline]))) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.roc b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.roc new file mode 100644 index 0000000000..21bd43313f --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.roc @@ -0,0 +1,3 @@ +(when x is + Ok -> 3 + ) diff --git a/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast new file mode 100644 index 0000000000..bfa2c2ecdf --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-7| SpaceBefore(StrLiteral(PlainLine("blah")), [Newline]), |L 1-1, C 10-16| StrLiteral(PlainLine("blop"))], value: |L 1-1, C 20-21| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-6| SpaceBefore(StrLiteral(PlainLine("foo")), [Newline]), |L 3-3, C 2-7| SpaceBefore(StrLiteral(PlainLine("bar")), [Newline])], value: |L 3-3, C 11-12| Num("2"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.roc b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.roc new file mode 100644 index 0000000000..2e4d050fe4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.roc @@ -0,0 +1,4 @@ +when x is + "blah" | "blop" -> 1 + "foo" | + "bar" -> 2 diff --git a/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast new file mode 100644 index 0000000000..dfee116add --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-5| SpaceBefore(NumLiteral("1"), [Newline])], value: |L 1-2, C 9-6| Apply(|L 1-1, C 9-16| Var { module_name: "Num", ident: "neg" }, [|L 2-2, C 5-6| SpaceBefore(Num("2"), [Newline])], Space), guard: None }, WhenBranch { patterns: [|L 3-3, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 3-3, C 9-10| Num("4"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.roc b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.roc new file mode 100644 index 0000000000..fd5da76dec --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.roc @@ -0,0 +1,4 @@ +when x is + 1 -> Num.neg + 2 + _ -> 4 diff --git a/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast new file mode 100644 index 0000000000..f2a54893b8 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline])], value: |L 1-1, C 6-7| Num("2"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-3| SpaceBefore(NumLiteral("-3"), [Newline])], value: |L 2-2, C 7-8| Num("4"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.roc b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.roc new file mode 100644 index 0000000000..90eed06a25 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.roc @@ -0,0 +1,3 @@ +when x is + 1 -> 2 + -3 -> 4 diff --git a/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast new file mode 100644 index 0000000000..021bc29827 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline])], value: |L 1-1, C 6-7| Num("2"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-2| SpaceBefore(NumLiteral("3"), [Newline])], value: |L 2-2, C 6-7| Num("4"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.roc b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.roc new file mode 100644 index 0000000000..c10dcafcf0 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.roc @@ -0,0 +1,3 @@ +when x is + 1 -> 2 + 3 -> 4 diff --git a/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast new file mode 100644 index 0000000000..b777de759e --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast @@ -0,0 +1 @@ +Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-6| SpaceBefore(RecordDestructure([|L 1-1, C 3-4| Identifier("y")]), [Newline])], value: |L 1-1, C 10-11| Num("2"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-9| SpaceBefore(RecordDestructure([|L 2-2, C 3-4| Identifier("z"), |L 2-2, C 6-7| Identifier("w")]), [Newline])], value: |L 2-2, C 13-14| Num("4"), guard: None }])) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/when_with_records.expr.roc b/compiler/parse/tests/snapshots/pass/when_with_records.expr.roc new file mode 100644 index 0000000000..3de2e8289b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/when_with_records.expr.roc @@ -0,0 +1,3 @@ +when x is + { y } -> 2 + { z, w } -> 4 diff --git a/compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast new file mode 100644 index 0000000000..61e8fc27e9 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast @@ -0,0 +1 @@ +Ok(Float("0.0")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/zero_float.expr.roc b/compiler/parse/tests/snapshots/pass/zero_float.expr.roc new file mode 100644 index 0000000000..171538eb0b --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/zero_float.expr.roc @@ -0,0 +1 @@ +0.0 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast new file mode 100644 index 0000000000..dad9d51c67 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast @@ -0,0 +1 @@ +Ok(Num("0")) \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/zero_int.expr.roc b/compiler/parse/tests/snapshots/pass/zero_int.expr.roc new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/zero_int.expr.roc @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 5032dcc010..a070c8aee7 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -37,6 +37,193 @@ mod test_parse { use roc_region::all::{Located, Region}; use std::{f64, i64}; + macro_rules! snapshot_tests { + ( + expr => { + $($expr_test_name:ident),* + } + ) => { + #[test] + fn no_extra_snapshot_test_files() { + let tests = &[ + $(concat!(stringify!($expr_test_name), ".expr")),* + ].iter().map(|t| *t).collect::>(); + + let mut base = std::path::PathBuf::from("tests"); + base.push("snapshots"); + base.push("pass"); + let files = std::fs::read_dir(&base).unwrap().map(|f| f.unwrap().file_name().to_str().unwrap().to_string()).collect::>(); + for file in files { + if let Some(file) = file.strip_suffix(".roc") { + assert!(tests.contains(file)); + } else if let Some(file) = file.strip_suffix(".result-ast") { + assert!(tests.contains(file)); + } else { + panic!("unexpected test file found: {}", file); + } + } + } + + mod _preview_tests { + $( + #[test] + fn $expr_test_name() { + + } + )* + } + }; + } + + snapshot_tests! { + expr => { + add_var_with_spaces, + add_with_spaces, + all_f64_values_parse, + all_i64_values_parse, + apply_global_tag, + apply_parenthetical_global_tag_args, + apply_private_tag, + apply_three_args, + apply_two_args, + apply_unary_negation, + apply_unary_not, + basic_apply, + basic_docs, + basic_field, + basic_global_tag, + basic_private_tag, + basic_var, + closure_with_underscores, + comment_after_op, + comment_before_op, + comment_inside_empty_list, + comment_with_non_ascii, + empty_list, + empty_record, + empty_string, + equals, + equals_with_spaces, + expect, + float_with_underscores, + highest_float, + highest_int, + if_def, + int_with_underscore, + lowest_float, + lowest_int, + malformed_ident_due_to_underscore, + malformed_pattern_field_access, + malformed_pattern_module_name, + minus_twelve_minus_five, + mixed_docs, + multi_backpassing, + multi_char_string, + multiline_type_signature, + multiline_type_signature_with_comment, + multiple_fields, + multiple_operators, + neg_inf_float, + negative_float, + negative_int, + newline_after_equals, + newline_after_mul, + newline_after_sub, + newline_and_spaces_before_less_than, + newline_before_add, + newline_before_sub, + newline_inside_empty_list, + newline_singleton_list, + not_docs, + one_backpassing, + one_char_string, + one_def, + one_minus_two, + one_plus_two, + one_spaced_def, + ops_with_newlines, + packed_singleton_list, + parenthetical_apply, + parenthetical_basic_field, + parenthetical_field_qualified_var, + parenthetical_var, + parse_alias, + parse_as_ann, + pattern_with_space_in_parens, + pos_inf_float, + positive_float, + positive_int, + private_qualified_tag, + qualified_field, + qualified_global_tag, + qualified_var, + record_destructure_def, + record_update, + record_with_if, + single_arg_closure, + single_underscore_closure, + space_only_after_minus, + spaced_singleton_list, + spaces_inside_empty_list, + string_without_escape, + sub_var_with_spaces, + sub_with_spaces, + tag_pattern, + ten_times_eleven, + three_arg_closure, + two_arg_closure, + two_backpassing, + two_branch_when, + two_spaced_def, + unary_negation, + unary_negation_access, + unary_negation_arg, + unary_negation_with_parens, + unary_not, + unary_not_with_parens, + underscore_backpassing, + var_else, + var_if, + var_is, + var_minus_two, + var_then, + var_when, + when_if_guard, + when_in_parens, + when_in_parens_indented, + when_with_alternative_patterns, + when_with_function_application, + when_with_negative_numbers, + when_with_numbers, + when_with_records, + zero_float, + zero_int + } + } + + fn save_snapshot(name: &str, ty: &str, input: &str, result: &str) { + let mut parent = std::path::PathBuf::from("tests"); + parent.push("snapshots"); + parent.push("pass"); + let input_path = parent.join(&format!("{}.{}.roc", name, ty)); + let result_path = parent.join(&format!("{}.{}.result-ast", name, ty)); + std::fs::create_dir_all(parent).unwrap(); + std::fs::write(input_path, input).unwrap(); + std::fs::write(result_path, result).unwrap(); + } + + fn test_name() -> String { + std::thread::current().name().unwrap().strip_prefix("test_parse::").unwrap().to_string() + } + + fn save_parse_expr_with<'a>(arena: &'a Bump, input: &'a str) -> Result, SyntaxError<'a>> { + let actual = parse_expr_with(&arena, input.trim()); + let result = format!("{:?}", actual); + + save_snapshot(&test_name(), "expr", input, &result); + actual + } + fn assert_parses_to<'a>(input: &'a str, expected_expr: Expr<'a>) { let arena = Bump::new(); let actual = parse_expr_with(&arena, input.trim()); @@ -459,11 +646,9 @@ mod test_parse { #[test] fn empty_record() { - let arena = Bump::new(); let expected = Record(Collection::empty()); - let actual = parse_expr_with(&arena, "{}"); - assert_eq!(Ok(expected), actual); + assert_parses_to("{}", expected); } #[test] @@ -493,7 +678,7 @@ mod test_parse { fields: Collection::with_items(fields), }; - let actual = parse_expr_with(&arena, "{ Foo.Bar.baz & x: 5, y: 0 }"); + let actual = save_parse_expr_with(&arena, "{ Foo.Bar.baz & x: 5, y: 0 }"); assert_eq!(Ok(expected), actual); } @@ -524,7 +709,7 @@ mod test_parse { ]; let expected = Record(Collection::with_items(fields)); - let actual = parse_expr_with(&arena, "{x : if True then 1 else 2, y: 3 }"); + let actual = save_parse_expr_with(&arena, "{x : if True then 1 else 2, y: 3 }"); assert_eq!(Ok(expected), actual); } @@ -550,7 +735,7 @@ mod test_parse { let expected = Expect(arena.alloc(loc_condition), arena.alloc(loc_continuation)); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -574,7 +759,7 @@ mod test_parse { Located::new(0, 0, 2, 3, Num("2")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "1+2"); + let actual = save_parse_expr_with(&arena, "1+2"); assert_eq!(Ok(expected), actual); } @@ -588,7 +773,7 @@ mod test_parse { Located::new(0, 0, 2, 3, Num("2")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "1-2"); + let actual = save_parse_expr_with(&arena, "1-2"); assert_eq!(Ok(expected), actual); } @@ -611,7 +796,7 @@ mod test_parse { Located::new(0, 0, 2, 3, Num("2")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "x-2"); + let actual = save_parse_expr_with(&arena, "x-2"); assert_eq!(Ok(expected), actual); } @@ -625,7 +810,7 @@ mod test_parse { Located::new(0, 0, 7, 8, Num("2")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "1 + 2"); + let actual = save_parse_expr_with(&arena, "1 + 2"); assert_eq!(Ok(expected), actual); } @@ -639,7 +824,7 @@ mod test_parse { Located::new(0, 0, 7, 8, Num("2")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "1 - 2"); + let actual = save_parse_expr_with(&arena, "1 - 2"); assert_eq!(Ok(expected), actual); } @@ -662,7 +847,7 @@ mod test_parse { Located::new(0, 0, 4, 5, Num("2")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "x + 2"); + let actual = save_parse_expr_with(&arena, "x + 2"); assert_eq!(Ok(expected), actual); } @@ -684,7 +869,7 @@ mod test_parse { Located::new(0, 0, 4, 5, Num("2")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "x - 2"); + let actual = save_parse_expr_with(&arena, "x - 2"); assert_eq!(Ok(expected), actual); } @@ -699,7 +884,7 @@ mod test_parse { Located::new(1, 1, 2, 3, Num("4")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "3 \n+ 4"); + let actual = save_parse_expr_with(&arena, "3 \n+ 4"); assert_eq!(Ok(expected), actual); } @@ -714,7 +899,7 @@ mod test_parse { Located::new(1, 1, 2, 3, Num("4")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "3 \n- 4"); + let actual = save_parse_expr_with(&arena, "3 \n- 4"); assert_eq!(Ok(expected), actual); } @@ -729,7 +914,7 @@ mod test_parse { Located::new(1, 1, 2, 3, spaced_int), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "3 *\n 4"); + let actual = save_parse_expr_with(&arena, "3 *\n 4"); assert_eq!(Ok(expected), actual); } @@ -744,7 +929,7 @@ mod test_parse { Located::new(1, 1, 2, 3, spaced_int), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "3 -\n 4"); + let actual = save_parse_expr_with(&arena, "3 -\n 4"); assert_eq!(Ok(expected), actual); } @@ -771,7 +956,7 @@ mod test_parse { let expected = Defs(defs, arena.alloc(loc_ret)); // let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "x = 1\n < 2\n\n42"); + let actual = save_parse_expr_with(&arena, "x = 1\n < 2\n\n42"); assert_eq!(Ok(expected), actual); } @@ -786,7 +971,7 @@ mod test_parse { Located::new(1, 1, 2, 3, Num("4")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "3 # 2 Γ— 2\n+ 4"); + let actual = save_parse_expr_with(&arena, "3 # 2 Γ— 2\n+ 4"); assert_eq!(Ok(expected), actual); } @@ -801,7 +986,7 @@ mod test_parse { Located::new(1, 1, 2, 3, Num("4")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "3 # test!\n+ 4"); + let actual = save_parse_expr_with(&arena, "3 # test!\n+ 4"); assert_eq!(Ok(expected), actual); } @@ -816,7 +1001,7 @@ mod test_parse { Located::new(1, 1, 1, 3, spaced_int), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "12 * # test!\n 92"); + let actual = save_parse_expr_with(&arena, "12 * # test!\n 92"); assert_eq!(Ok(expected), actual); } @@ -832,7 +1017,7 @@ mod test_parse { Located::new(3, 3, 2, 3, spaced_int2), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "3 \n+ \n\n 4"); + let actual = save_parse_expr_with(&arena, "3 \n+ \n\n 4"); assert_eq!(Ok(expected), actual); } @@ -856,7 +1041,7 @@ mod test_parse { Located::new(0, 0, 3, 4, var2), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "x- y"); + let actual = save_parse_expr_with(&arena, "x- y"); assert_eq!(Ok(expected), actual); } @@ -870,7 +1055,7 @@ mod test_parse { Located::new(0, 0, 4, 5, Num("5")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "-12-5"); + let actual = save_parse_expr_with(&arena, "-12-5"); assert_eq!(Ok(expected), actual); } @@ -884,7 +1069,7 @@ mod test_parse { Located::new(0, 0, 3, 5, Num("11")), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "10*11"); + let actual = save_parse_expr_with(&arena, "10*11"); assert_eq!(Ok(expected), actual); } @@ -906,7 +1091,7 @@ mod test_parse { let right = Located::new(0, 0, 6, 9, Num("534")); let expected = BinOps(&lefts, &right); - let actual = parse_expr_with(&arena, "31*42+534"); + let actual = save_parse_expr_with(&arena, "31*42+534"); assert_eq!(Ok(expected), actual); } @@ -928,7 +1113,7 @@ mod test_parse { Located::new(0, 0, 3, 4, var2), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "x==y"); + let actual = save_parse_expr_with(&arena, "x==y"); assert_eq!(Ok(expected), actual); } @@ -950,7 +1135,7 @@ mod test_parse { Located::new(0, 0, 5, 6, var2), ); let expected = single_binop(&arena, tuple); - let actual = parse_expr_with(&arena, "x == y"); + let actual = save_parse_expr_with(&arena, "x == y"); assert_eq!(Ok(expected), actual); } @@ -964,7 +1149,7 @@ mod test_parse { module_name: "", ident: "whee", }; - let actual = parse_expr_with(&arena, "whee"); + let actual = save_parse_expr_with(&arena, "whee"); assert_eq!(Ok(expected), actual); } @@ -977,7 +1162,7 @@ mod test_parse { module_name: "", ident: "whenever", }; - let actual = parse_expr_with(&arena, "whenever"); + let actual = save_parse_expr_with(&arena, "whenever"); assert_eq!(Ok(expected), actual); } @@ -990,7 +1175,7 @@ mod test_parse { module_name: "", ident: "isnt", }; - let actual = parse_expr_with(&arena, "isnt"); + let actual = save_parse_expr_with(&arena, "isnt"); assert_eq!(Ok(expected), actual); } @@ -1003,7 +1188,7 @@ mod test_parse { module_name: "", ident: "iffy", }; - let actual = parse_expr_with(&arena, "iffy"); + let actual = save_parse_expr_with(&arena, "iffy"); assert_eq!(Ok(expected), actual); } @@ -1016,7 +1201,7 @@ mod test_parse { module_name: "", ident: "thenever", }; - let actual = parse_expr_with(&arena, "thenever"); + let actual = save_parse_expr_with(&arena, "thenever"); assert_eq!(Ok(expected), actual); } @@ -1029,7 +1214,7 @@ mod test_parse { module_name: "", ident: "elsewhere", }; - let actual = parse_expr_with(&arena, "elsewhere"); + let actual = save_parse_expr_with(&arena, "elsewhere"); assert_eq!(Ok(expected), actual); } @@ -1041,7 +1226,7 @@ mod test_parse { module_name: "", ident: "whee", })); - let actual = parse_expr_with(&arena, "(whee)"); + let actual = save_parse_expr_with(&arena, "(whee)"); assert_eq!(Ok(expected), actual); } @@ -1053,7 +1238,7 @@ mod test_parse { module_name: "One.Two", ident: "whee", }; - let actual = parse_expr_with(&arena, "One.Two.whee"); + let actual = save_parse_expr_with(&arena, "One.Two.whee"); assert_eq!(Ok(expected), actual); } @@ -1064,7 +1249,7 @@ mod test_parse { fn basic_global_tag() { let arena = Bump::new(); let expected = Expr::GlobalTag("Whee"); - let actual = parse_expr_with(&arena, "Whee"); + let actual = save_parse_expr_with(&arena, "Whee"); assert_eq!(Ok(expected), actual); } @@ -1073,7 +1258,7 @@ mod test_parse { fn basic_private_tag() { let arena = Bump::new(); let expected = Expr::PrivateTag("@Whee"); - let actual = parse_expr_with(&arena, "@Whee"); + let actual = save_parse_expr_with(&arena, "@Whee"); assert_eq!(Ok(expected), actual); } @@ -1089,7 +1274,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "@Whee 12 34"); + let actual = save_parse_expr_with(&arena, "@Whee 12 34"); assert_eq!(Ok(expected), actual); } @@ -1105,7 +1290,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "Whee 12 34"); + let actual = save_parse_expr_with(&arena, "Whee 12 34"); assert_eq!(Ok(expected), actual); } @@ -1123,7 +1308,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "Whee (12) (34)"); + let actual = save_parse_expr_with(&arena, "Whee (12) (34)"); assert_eq!(Ok(expected), actual); } @@ -1134,7 +1319,7 @@ mod test_parse { let arena = Bump::new(); let expected = Expr::MalformedIdent("One.Two.Whee", BadIdent::QualifiedTag(0, 12)); - let actual = parse_expr_with(&arena, "One.Two.Whee"); + let actual = save_parse_expr_with(&arena, "One.Two.Whee"); assert_eq!(Ok(expected), actual); } @@ -1145,7 +1330,7 @@ mod test_parse { let arena = Bump::new(); let expected = Expr::MalformedIdent("@One.Two.Whee", BadIdent::BadPrivateTag(0, 4)); - let actual = parse_expr_with(&arena, "@One.Two.Whee"); + let actual = save_parse_expr_with(&arena, "@One.Two.Whee"); assert_eq!(Ok(expected), actual); } @@ -1156,7 +1341,7 @@ mod test_parse { let pattern = Located::new(0, 0, 1, 6, Pattern::GlobalTag("Thing")); let patterns = &[pattern]; let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 10, 12, Num("42")))); - let actual = parse_expr_with(&arena, "\\Thing -> 42"); + let actual = save_parse_expr_with(&arena, "\\Thing -> 42"); assert_eq!(Ok(expected), actual); } @@ -1167,7 +1352,7 @@ mod test_parse { fn empty_list() { let arena = Bump::new(); let expected = List(Collection::empty()); - let actual = parse_expr_with(&arena, "[]"); + let actual = save_parse_expr_with(&arena, "[]"); assert_eq!(Ok(expected), actual); } @@ -1177,7 +1362,7 @@ mod test_parse { // This is a regression test! let arena = Bump::new(); let expected = List(Collection::empty()); - let actual = parse_expr_with(&arena, "[ ]"); + let actual = save_parse_expr_with(&arena, "[ ]"); assert_eq!(Ok(expected), actual); } @@ -1186,7 +1371,7 @@ mod test_parse { fn newline_inside_empty_list() { let arena = Bump::new(); let expected = List(Collection::with_items_and_comments(&arena, &[], &[Newline])); - let actual = parse_expr_with(&arena, "[\n]"); + let actual = save_parse_expr_with(&arena, "[\n]"); assert_eq!(Ok(expected), actual); } @@ -1199,7 +1384,7 @@ mod test_parse { &[], &[LineComment("comment")], )); - let actual = parse_expr_with(&arena, "[#comment\n]"); + let actual = save_parse_expr_with(&arena, "[#comment\n]"); assert_eq!(Ok(expected), actual); } @@ -1209,7 +1394,7 @@ mod test_parse { let arena = Bump::new(); let items = &[&*arena.alloc(Located::new(0, 0, 1, 2, Num("1")))]; let expected = List(Collection::with_items(items)); - let actual = parse_expr_with(&arena, "[1]"); + let actual = save_parse_expr_with(&arena, "[1]"); assert_eq!(Ok(expected), actual); } @@ -1219,7 +1404,7 @@ mod test_parse { let arena = Bump::new(); let items = &[&*arena.alloc(Located::new(0, 0, 2, 3, Num("1")))]; let expected = List(Collection::with_items(items)); - let actual = parse_expr_with(&arena, "[ 1 ]"); + let actual = save_parse_expr_with(&arena, "[ 1 ]"); assert_eq!(Ok(expected), actual); } @@ -1234,7 +1419,7 @@ mod test_parse { let item = Expr::SpaceBefore(item, arena.alloc([Newline])); let items = [&*arena.alloc(Located::new(1, 1, 0, 1, item))]; let expected = List(Collection::with_items(&items)); - let actual = parse_expr_with(&arena, "[\n1\n]"); + let actual = save_parse_expr_with(&arena, "[\n1\n]"); assert_eq!(Ok(expected), actual); } @@ -1249,7 +1434,7 @@ mod test_parse { ident: "rec", }; let expected = Access(arena.alloc(var), "field"); - let actual = parse_expr_with(&arena, "rec.field"); + let actual = save_parse_expr_with(&arena, "rec.field"); assert_eq!(Ok(expected), actual); } @@ -1262,7 +1447,7 @@ mod test_parse { ident: "rec", })); let expected = Access(arena.alloc(paren_var), "field"); - let actual = parse_expr_with(&arena, "(rec).field"); + let actual = save_parse_expr_with(&arena, "(rec).field"); assert_eq!(Ok(expected), actual); } @@ -1275,7 +1460,7 @@ mod test_parse { ident: "rec", })); let expected = Access(arena.alloc(paren_var), "field"); - let actual = parse_expr_with(&arena, "(One.Two.rec).field"); + let actual = save_parse_expr_with(&arena, "(One.Two.rec).field"); assert_eq!(Ok(expected), actual); } @@ -1291,7 +1476,7 @@ mod test_parse { arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")), "ghi", ); - let actual = parse_expr_with(&arena, "rec.abc.def.ghi"); + let actual = save_parse_expr_with(&arena, "rec.abc.def.ghi"); assert_eq!(Ok(expected), actual); } @@ -1307,7 +1492,7 @@ mod test_parse { arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")), "ghi", ); - let actual = parse_expr_with(&arena, "One.Two.rec.abc.def.ghi"); + let actual = save_parse_expr_with(&arena, "One.Two.rec.abc.def.ghi"); assert_eq!(Ok(expected), actual); } @@ -1328,7 +1513,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "whee 1"); + let actual = save_parse_expr_with(&arena, "whee 1"); assert_eq!(Ok(expected), actual); } @@ -1353,7 +1538,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "whee 12 34"); + let actual = save_parse_expr_with(&arena, "whee 12 34"); assert_eq!(Ok(expected), actual); } @@ -1406,7 +1591,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "a b c d"); + let actual = save_parse_expr_with(&arena, "a b c d"); assert_eq!(Ok(expected), actual); } @@ -1425,7 +1610,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "(whee) 1"); + let actual = save_parse_expr_with(&arena, "(whee) 1"); assert_eq!(Ok(expected), actual); } @@ -1442,7 +1627,7 @@ mod test_parse { }; let loc_arg1_expr = Located::new(0, 0, 1, 4, arg1_expr); let expected = UnaryOp(arena.alloc(loc_arg1_expr), loc_op); - let actual = parse_expr_with(&arena, "-foo"); + let actual = save_parse_expr_with(&arena, "-foo"); assert_eq!(Ok(expected), actual); } @@ -1457,7 +1642,7 @@ mod test_parse { }; let loc_arg1_expr = Located::new(0, 0, 1, 5, arg1_expr); let expected = UnaryOp(arena.alloc(loc_arg1_expr), loc_op); - let actual = parse_expr_with(&arena, "!blah"); + let actual = save_parse_expr_with(&arena, "!blah"); assert_eq!(Ok(expected), actual); } @@ -1490,7 +1675,7 @@ mod test_parse { ); let unary = Located::new(0, 0, 0, 5, UnaryOp(arena.alloc(function), loc_op)); let expected = Expr::Apply(arena.alloc(unary), args, CalledVia::Space); - let actual = parse_expr_with(&arena, "-whee 12 foo"); + let actual = save_parse_expr_with(&arena, "-whee 12 foo"); assert_eq!(Ok(expected), actual); } @@ -1524,7 +1709,7 @@ mod test_parse { ); let unary = Located::new(0, 0, 0, 5, UnaryOp(arena.alloc(function), loc_op)); let expected = Expr::Apply(arena.alloc(unary), args, CalledVia::Space); - let actual = parse_expr_with(&arena, "!whee 12 foo"); + let actual = save_parse_expr_with(&arena, "!whee 12 foo"); assert_eq!(Ok(expected), actual); } @@ -1560,7 +1745,7 @@ mod test_parse { CalledVia::Space, ))); let expected = UnaryOp(arena.alloc(Located::new(0, 0, 2, 14, apply_expr)), loc_op); - let actual = parse_expr_with(&arena, "-(whee 12 foo)"); + let actual = save_parse_expr_with(&arena, "-(whee 12 foo)"); assert_eq!(Ok(expected), actual); } @@ -1596,7 +1781,7 @@ mod test_parse { CalledVia::Space, ))); let expected = UnaryOp(arena.alloc(Located::new(0, 0, 2, 14, apply_expr)), loc_op); - let actual = parse_expr_with(&arena, "!(whee 12 foo)"); + let actual = save_parse_expr_with(&arena, "!(whee 12 foo)"); assert_eq!(Ok(expected), actual); } @@ -1623,7 +1808,7 @@ mod test_parse { args, CalledVia::Space, ); - let actual = parse_expr_with(&arena, "whee 12 -foo"); + let actual = save_parse_expr_with(&arena, "whee 12 -foo"); assert_eq!(Ok(expected), actual); } @@ -1640,7 +1825,7 @@ mod test_parse { let access = Access(arena.alloc(var), "field"); let loc_access = Located::new(0, 0, 1, 11, access); let expected = UnaryOp(arena.alloc(loc_access), loc_op); - let actual = parse_expr_with(&arena, "-rec1.field"); + let actual = save_parse_expr_with(&arena, "-rec1.field"); assert_eq!(Ok(expected), actual); } @@ -1653,7 +1838,7 @@ mod test_parse { let pattern = Located::new(0, 0, 1, 2, Identifier("a")); let patterns = &[pattern]; let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42")))); - let actual = parse_expr_with(&arena, "\\a -> 42"); + let actual = save_parse_expr_with(&arena, "\\a -> 42"); assert_eq!(Ok(expected), actual); } @@ -1664,7 +1849,7 @@ mod test_parse { let pattern = Located::new(0, 0, 1, 2, Pattern::Underscore("")); let patterns = &[pattern]; let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42")))); - let actual = parse_expr_with(&arena, "\\_ -> 42"); + let actual = save_parse_expr_with(&arena, "\\_ -> 42"); assert_eq!(Ok(expected), actual); } @@ -1687,7 +1872,7 @@ mod test_parse { let expr = Located::new(0, 0, 15, 17, Expr::Num("42")); let expected = Closure(patterns, &expr); - let actual = parse_expr_with(&arena, "\\the_answer -> 42"); + let actual = save_parse_expr_with(&arena, "\\the_answer -> 42"); assert_eq!(Ok(expected), actual); } @@ -1699,7 +1884,7 @@ mod test_parse { let arg2 = Located::new(0, 0, 4, 5, Identifier("b")); let patterns = &[arg1, arg2]; let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 9, 11, Num("42")))); - let actual = parse_expr_with(&arena, "\\a, b -> 42"); + let actual = save_parse_expr_with(&arena, "\\a, b -> 42"); assert_eq!(Ok(expected), actual); } @@ -1715,7 +1900,7 @@ mod test_parse { arena.alloc(patterns), arena.alloc(Located::new(0, 0, 12, 14, Num("42"))), ); - let actual = parse_expr_with(&arena, "\\a, b, c -> 42"); + let actual = save_parse_expr_with(&arena, "\\a, b, c -> 42"); assert_eq!(Ok(expected), actual); } @@ -1730,7 +1915,7 @@ mod test_parse { arena.alloc(patterns), arena.alloc(Located::new(0, 0, 13, 15, Num("42"))), ); - let actual = parse_expr_with(&arena, "\\_, _name -> 42"); + let actual = save_parse_expr_with(&arena, "\\_, _name -> 42"); assert_eq!(Ok(expected), actual); } @@ -2624,7 +2809,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -2668,7 +2853,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -2712,7 +2897,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -2772,7 +2957,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -2858,7 +3043,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -2910,7 +3095,7 @@ mod test_parse { let loc_cond = Located::new(0, 0, 6, 7, var); let when = Expr::When(arena.alloc(loc_cond), branches); let expected = Expr::ParensAround(&when); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -2965,7 +3150,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -3006,7 +3191,7 @@ mod test_parse { let when = Expr::When(arena.alloc(loc_cond), branches); let spaced = Expr::SpaceAfter(&when, &[Newline]); let expected = Expr::ParensAround(&spaced); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -3056,7 +3241,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -3874,7 +4059,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -3919,7 +4104,7 @@ mod test_parse { }; let loc_cond = Located::new(0, 0, 5, 6, var); let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" @@ -3937,7 +4122,7 @@ mod test_parse { fn pattern_with_space_in_parens() { // https://github.com/rtfeldman/roc/issues/929 let arena = Bump::new(); - let actual = parse_expr_with( + let actual = save_parse_expr_with( &arena, indoc!( r#" From d66164674846c050937e78e01c742cc46aaec022 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 13:33:48 -0800 Subject: [PATCH 083/223] Fix test formatting and actually assert that they pass --- Cargo.lock | 2 ++ compiler/parse/Cargo.toml | 2 ++ .../pass/add_var_with_spaces.expr.result-ast | 10 ++++++- .../pass/add_with_spaces.expr.result-ast | 10 ++++++- .../pass/all_f64_values_parse.expr.result-ast | 4 ++- .../pass/all_f64_values_parse.expr.roc | 2 +- .../pass/all_i64_values_parse.expr.result-ast | 4 ++- .../pass/all_i64_values_parse.expr.roc | 2 +- .../pass/apply_global_tag.expr.result-ast | 9 +++++- ...enthetical_global_tag_args.expr.result-ast | 9 +++++- .../pass/apply_private_tag.expr.result-ast | 9 +++++- .../pass/apply_three_args.expr.result-ast | 10 ++++++- .../pass/apply_two_args.expr.result-ast | 9 +++++- .../pass/apply_unary_negation.expr.result-ast | 9 +++++- .../pass/apply_unary_not.expr.result-ast | 9 +++++- .../pass/basic_apply.expr.result-ast | 8 ++++- .../snapshots/pass/basic_docs.expr.result-ast | 29 ++++++++++++++++++- .../pass/basic_field.expr.result-ast | 8 ++++- .../pass/basic_global_tag.expr.result-ast | 4 ++- .../pass/basic_private_tag.expr.result-ast | 4 ++- .../snapshots/pass/basic_var.expr.result-ast | 5 +++- .../closure_with_underscores.expr.result-ast | 8 ++++- .../pass/comment_after_op.expr.result-ast | 10 ++++++- .../pass/comment_before_op.expr.result-ast | 10 ++++++- .../comment_inside_empty_list.expr.result-ast | 11 ++++++- .../comment_with_non_ascii.expr.result-ast | 10 ++++++- .../snapshots/pass/empty_list.expr.result-ast | 4 ++- .../pass/empty_record.expr.result-ast | 4 ++- .../pass/empty_string.expr.result-ast | 6 +++- .../snapshots/pass/equals.expr.result-ast | 10 ++++++- .../pass/equals_with_spaces.expr.result-ast | 10 ++++++- .../snapshots/pass/expect.expr.result-ast | 5 +++- .../float_with_underscores.expr.result-ast | 4 ++- .../pass/highest_float.expr.result-ast | 4 ++- .../pass/highest_int.expr.result-ast | 4 ++- .../snapshots/pass/if_def.expr.result-ast | 7 ++++- .../pass/int_with_underscore.expr.result-ast | 4 ++- .../pass/lowest_float.expr.result-ast | 4 ++- .../snapshots/pass/lowest_int.expr.result-ast | 4 ++- ...ed_ident_due_to_underscore.expr.result-ast | 7 ++++- ...ormed_pattern_field_access.expr.result-ast | 20 ++++++++++++- ...formed_pattern_module_name.expr.result-ast | 20 ++++++++++++- .../minus_twelve_minus_five.expr.result-ast | 10 ++++++- .../snapshots/pass/mixed_docs.expr.result-ast | 23 ++++++++++++++- .../pass/multi_backpassing.expr.result-ast | 9 +++++- .../pass/multi_char_string.expr.result-ast | 6 +++- .../multiline_type_signature.expr.result-ast | 7 ++++- ...ype_signature_with_comment.expr.result-ast | 7 ++++- .../pass/multiple_fields.expr.result-ast | 14 ++++++++- .../pass/multiple_operators.expr.result-ast | 14 ++++++++- .../pass/neg_inf_float.expr.result-ast | 5 +++- .../pass/negative_float.expr.result-ast | 4 ++- .../pass/negative_int.expr.result-ast | 4 ++- .../pass/newline_after_equals.expr.result-ast | 7 ++++- .../pass/newline_after_mul.expr.result-ast | 10 ++++++- .../pass/newline_after_sub.expr.result-ast | 10 ++++++- ...nd_spaces_before_less_than.expr.result-ast | 7 ++++- .../pass/newline_before_add.expr.result-ast | 10 ++++++- .../pass/newline_before_sub.expr.result-ast | 10 ++++++- .../newline_inside_empty_list.expr.result-ast | 9 +++++- .../newline_singleton_list.expr.result-ast | 6 +++- .../snapshots/pass/not_docs.expr.result-ast | 23 ++++++++++++++- .../pass/one_backpassing.expr.result-ast | 15 +++++++++- .../pass/one_char_string.expr.result-ast | 6 +++- .../snapshots/pass/one_def.expr.result-ast | 14 ++++++++- .../pass/one_minus_two.expr.result-ast | 10 ++++++- .../pass/one_plus_two.expr.result-ast | 10 ++++++- .../pass/one_spaced_def.expr.result-ast | 14 ++++++++- .../pass/ops_with_newlines.expr.result-ast | 10 ++++++- .../packed_singleton_list.expr.result-ast | 6 +++- .../pass/parenthetical_apply.expr.result-ast | 8 ++++- .../parenthetical_basic_field.expr.result-ast | 10 ++++++- ...etical_field_qualified_var.expr.result-ast | 10 ++++++- .../pass/parenthetical_var.expr.result-ast | 7 ++++- .../pass/parse_alias.expr.result-ast | 7 ++++- .../pass/parse_as_ann.expr.result-ast | 7 ++++- ...ttern_with_space_in_parens.expr.result-ast | 13 ++++++++- .../pass/pos_inf_float.expr.result-ast | 5 +++- .../pass/positive_float.expr.result-ast | 4 ++- .../pass/positive_int.expr.result-ast | 4 ++- .../private_qualified_tag.expr.result-ast | 8 ++++- .../pass/qualified_field.expr.result-ast | 14 ++++++++- .../pass/qualified_global_tag.expr.result-ast | 8 ++++- .../pass/qualified_var.expr.result-ast | 5 +++- .../record_destructure_def.expr.result-ast | 15 +++++++++- .../pass/record_update.expr.result-ast | 8 ++++- .../pass/record_with_if.expr.result-ast | 7 ++++- .../pass/single_arg_closure.expr.result-ast | 7 ++++- .../single_underscore_closure.expr.result-ast | 7 ++++- .../space_only_after_minus.expr.result-ast | 10 ++++++- .../spaced_singleton_list.expr.result-ast | 6 +++- .../spaces_inside_empty_list.expr.result-ast | 4 ++- .../string_without_escape.expr.result-ast | 6 +++- .../pass/sub_var_with_spaces.expr.result-ast | 10 ++++++- .../pass/sub_with_spaces.expr.result-ast | 10 ++++++- .../pass/tag_pattern.expr.result-ast | 7 ++++- .../pass/ten_times_eleven.expr.result-ast | 10 ++++++- .../pass/three_arg_closure.expr.result-ast | 9 +++++- .../pass/two_arg_closure.expr.result-ast | 8 ++++- .../pass/two_backpassing.expr.result-ast | 15 +++++++++- .../pass/two_branch_when.expr.result-ast | 20 ++++++++++++- .../pass/two_spaced_def.expr.result-ast | 15 +++++++++- .../pass/unary_negation.expr.result-ast | 5 +++- .../unary_negation_access.expr.result-ast | 5 +++- .../pass/unary_negation_arg.expr.result-ast | 9 +++++- ...unary_negation_with_parens.expr.result-ast | 5 +++- .../snapshots/pass/unary_not.expr.result-ast | 5 +++- .../unary_not_with_parens.expr.result-ast | 5 +++- .../underscore_backpassing.expr.result-ast | 15 +++++++++- .../snapshots/pass/var_else.expr.result-ast | 5 +++- .../snapshots/pass/var_if.expr.result-ast | 5 +++- .../snapshots/pass/var_is.expr.result-ast | 5 +++- .../pass/var_minus_two.expr.result-ast | 10 ++++++- .../snapshots/pass/var_then.expr.result-ast | 5 +++- .../snapshots/pass/var_when.expr.result-ast | 5 +++- .../pass/when_if_guard.expr.result-ast | 27 ++++++++++++++++- .../pass/when_in_parens.expr.result-ast | 15 +++++++++- .../when_in_parens_indented.expr.result-ast | 20 ++++++++++++- ..._with_alternative_patterns.expr.result-ast | 22 +++++++++++++- ..._with_function_application.expr.result-ast | 20 ++++++++++++- ...when_with_negative_numbers.expr.result-ast | 20 ++++++++++++- .../pass/when_with_numbers.expr.result-ast | 20 ++++++++++++- .../pass/when_with_records.expr.result-ast | 20 ++++++++++++- .../snapshots/pass/zero_float.expr.result-ast | 4 ++- .../snapshots/pass/zero_int.expr.result-ast | 4 ++- compiler/parse/tests/test_parse.rs | 29 +++++++++++++++++-- 126 files changed, 1047 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c987c0452..7ced962daf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3475,7 +3475,9 @@ dependencies = [ name = "roc_parse" version = "0.1.0" dependencies = [ + "ansi_term", "bumpalo", + "diff", "encode_unicode", "indoc", "pretty_assertions", diff --git a/compiler/parse/Cargo.toml b/compiler/parse/Cargo.toml index 34774f8360..d76b482822 100644 --- a/compiler/parse/Cargo.toml +++ b/compiler/parse/Cargo.toml @@ -17,3 +17,5 @@ pretty_assertions = "1.0.0" indoc = "1.0.3" quickcheck = "1.0.3" quickcheck_macros = "1.0.0" +diff = "0.1.12" +ansi_term = "0.12.1" diff --git a/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast index e63c70e7fa..5dcfecb2c7 100644 --- a/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 2-3| Plus)], |L 0-0, C 4-5| Num("2"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 2-3| Plus, + ), + ], + |L 0-0, C 4-5| Num("2"), +) diff --git a/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast index d066d4cfb5..95d2de93fd 100644 --- a/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 3-4| Plus)], |L 0-0, C 7-8| Num("2"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Num("1"), + |L 0-0, C 3-4| Plus, + ), + ], + |L 0-0, C 7-8| Num("2"), +) diff --git a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast index 84f580be3e..3043e73707 100644 --- a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast @@ -1 +1,3 @@ -Ok(Float("5014168797528723000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0")) \ No newline at end of file +Float( + "-163434311610918100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", +) diff --git a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc index cb1ebb9a8f..8525093bdb 100644 --- a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc +++ b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc @@ -1 +1 @@ -5014168797528723000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0 \ No newline at end of file +-163434311610918100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast index ac1417f545..34a81f72a4 100644 --- a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast @@ -1 +1,3 @@ -Ok(Num("5308198535548975042")) \ No newline at end of file +Num( + "8977008824269102071", +) diff --git a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc index fe5339ac2d..e943571568 100644 --- a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc +++ b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc @@ -1 +1 @@ -5308198535548975042 \ No newline at end of file +8977008824269102071 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast index 3fa34c07cd..2c0cef28bc 100644 --- a/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast @@ -1 +1,8 @@ -Ok(Apply(|L 0-0, C 0-4| GlobalTag("Whee"), [|L 0-0, C 5-7| Num("12"), |L 0-0, C 8-10| Num("34")], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-4| GlobalTag("Whee"), + [ + |L 0-0, C 5-7| Num("12"), + |L 0-0, C 8-10| Num("34"), + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast index 6adfaab1ae..a5b7d31e7e 100644 --- a/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast @@ -1 +1,8 @@ -Ok(Apply(|L 0-0, C 0-4| GlobalTag("Whee"), [|L 0-0, C 6-8| ParensAround(Num("12")), |L 0-0, C 11-13| ParensAround(Num("34"))], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-4| GlobalTag("Whee"), + [ + |L 0-0, C 6-8| ParensAround(Num("12")), + |L 0-0, C 11-13| ParensAround(Num("34")), + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast index 11ccc3249d..6b953d0d04 100644 --- a/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast @@ -1 +1,8 @@ -Ok(Apply(|L 0-0, C 0-5| PrivateTag("@Whee"), [|L 0-0, C 6-8| Num("12"), |L 0-0, C 9-11| Num("34")], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-5| PrivateTag("@Whee"), + [ + |L 0-0, C 6-8| Num("12"), + |L 0-0, C 9-11| Num("34"), + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast index 7c0a90d084..3367a6e7fd 100644 --- a/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast @@ -1 +1,9 @@ -Ok(Apply(|L 0-0, C 0-1| Var { module_name: "", ident: "a" }, [|L 0-0, C 2-3| Var { module_name: "", ident: "b" }, |L 0-0, C 4-5| Var { module_name: "", ident: "c" }, |L 0-0, C 6-7| Var { module_name: "", ident: "d" }], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-1| Var { module_name: "", ident: "a" }, + [ + |L 0-0, C 2-3| Var { module_name: "", ident: "b" }, + |L 0-0, C 4-5| Var { module_name: "", ident: "c" }, + |L 0-0, C 6-7| Var { module_name: "", ident: "d" }, + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast index a08b919ef7..3ff92e86b6 100644 --- a/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast @@ -1 +1,8 @@ -Ok(Apply(|L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, [|L 0-0, C 6-8| Num("12"), |L 0-0, C 10-12| Num("34")], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, + [ + |L 0-0, C 6-8| Num("12"), + |L 0-0, C 10-12| Num("34"), + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast index 877fd170ee..471d65c405 100644 --- a/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast @@ -1 +1,8 @@ -Ok(Apply(|L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Negate), [|L 0-0, C 7-9| Num("12"), |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Negate), + [ + |L 0-0, C 7-9| Num("12"), + |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast index fadaba0251..42bdba2cab 100644 --- a/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast @@ -1 +1,8 @@ -Ok(Apply(|L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Not), [|L 0-0, C 7-9| Num("12"), |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Not), + [ + |L 0-0, C 7-9| Num("12"), + |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast index 605813099b..10ba03c7b4 100644 --- a/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast @@ -1 +1,7 @@ -Ok(Apply(|L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, [|L 0-0, C 5-6| Num("1")], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, + [ + |L 0-0, C 5-6| Num("1"), + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast index b87ea1a724..253faa24be 100644 --- a/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast @@ -1 +1,28 @@ -Ok(SpaceBefore(Defs([|L 6-6, C 0-5| Body(|L 6-6, C 0-1| Identifier("x"), |L 6-6, C 4-5| Num("5"))], |L 8-8, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [DocComment("first line of docs"), DocComment(" second line"), DocComment(" third line"), DocComment("fourth line"), DocComment(""), DocComment("sixth line after doc new line")])) \ No newline at end of file +SpaceBefore( + Defs( + [ + |L 6-6, C 0-5| Body(|L 6-6, C 0-1| Identifier("x"), |L 6-6, C 4-5| Num("5")), + ], + |L 8-8, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + ), + [ + DocComment( + "first line of docs", + ), + DocComment( + " second line", + ), + DocComment( + " third line", + ), + DocComment( + "fourth line", + ), + DocComment( + "", + ), + DocComment( + "sixth line after doc new line", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast index 2cbab0b493..89beaecfa5 100644 --- a/compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_field.expr.result-ast @@ -1 +1,7 @@ -Ok(Access(Var { module_name: "", ident: "rec" }, "field")) \ No newline at end of file +Access( + Var { + module_name: "", + ident: "rec", + }, + "field", +) diff --git a/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast index 80849d15dd..8c0a66666f 100644 --- a/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_global_tag.expr.result-ast @@ -1 +1,3 @@ -Ok(GlobalTag("Whee")) \ No newline at end of file +GlobalTag( + "Whee", +) diff --git a/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast index f2071664f5..1761f76aa1 100644 --- a/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_private_tag.expr.result-ast @@ -1 +1,3 @@ -Ok(PrivateTag("@Whee")) \ No newline at end of file +PrivateTag( + "@Whee", +) diff --git a/compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast index 559be82dd4..ade68e0ead 100644 --- a/compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_var.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "", ident: "whee" }) \ No newline at end of file +Var { + module_name: "", + ident: "whee", +} diff --git a/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast index 9ce08057a6..c92ce0115c 100644 --- a/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast @@ -1 +1,7 @@ -Ok(Closure([|L 0-0, C 1-2| Underscore(""), |L 0-0, C 4-9| Underscore("name")], |L 0-0, C 13-15| Num("42"))) \ No newline at end of file +Closure( + [ + |L 0-0, C 1-2| Underscore(""), + |L 0-0, C 4-9| Underscore("name"), + ], + |L 0-0, C 13-15| Num("42"), +) diff --git a/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast index 54d205022e..b777880f1c 100644 --- a/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-2| Num("12"), |L 0-0, C 4-5| Star)], |L 1-1, C 1-3| SpaceBefore(Num("92"), [LineComment(" test!")]))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-2| Num("12"), + |L 0-0, C 4-5| Star, + ), + ], + |L 1-1, C 1-3| SpaceBefore(Num("92"), [LineComment(" test!")]), +) diff --git a/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast index aad4f7e36e..8ff0bf9290 100644 --- a/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" test!")]), |L 1-1, C 0-1| Plus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" test!")]), + |L 1-1, C 0-1| Plus, + ), + ], + |L 1-1, C 2-3| Num("4"), +) diff --git a/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast index e00db1521b..52f4bb6157 100644 --- a/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.result-ast @@ -1 +1,10 @@ -Ok(List(Collection { items: [], final_comments: [LineComment("comment")] })) \ No newline at end of file +List( + Collection { + items: [], + final_comments: [ + LineComment( + "comment", + ), + ], + }, +) diff --git a/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast index 46ab6fe925..6f2008835b 100644 --- a/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" 2 Γ— 2")]), |L 1-1, C 0-1| Plus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" 2 Γ— 2")]), + |L 1-1, C 0-1| Plus, + ), + ], + |L 1-1, C 2-3| Num("4"), +) diff --git a/compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast index 584939a222..36f4a52b6e 100644 --- a/compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/empty_list.expr.result-ast @@ -1 +1,3 @@ -Ok(List([])) \ No newline at end of file +List( + [], +) diff --git a/compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast b/compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast index 0d3758e498..328cb0d3a3 100644 --- a/compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/empty_record.expr.result-ast @@ -1 +1,3 @@ -Ok(Record(Collection { items: [], final_comments: [] })) \ No newline at end of file +Record( + [], +) diff --git a/compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast b/compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast index 8c0f253a42..a00db728af 100644 --- a/compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/empty_string.expr.result-ast @@ -1 +1,5 @@ -Ok(Str(PlainLine(""))) \ No newline at end of file +Str( + PlainLine( + "", + ), +) diff --git a/compiler/parse/tests/snapshots/pass/equals.expr.result-ast b/compiler/parse/tests/snapshots/pass/equals.expr.result-ast index c744d69291..068907129e 100644 --- a/compiler/parse/tests/snapshots/pass/equals.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/equals.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 1-3| Equals)], |L 0-0, C 3-4| Var { module_name: "", ident: "y" })) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 1-3| Equals, + ), + ], + |L 0-0, C 3-4| Var { module_name: "", ident: "y" }, +) diff --git a/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast index 2e41fec549..392599b087 100644 --- a/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 2-4| Equals)], |L 0-0, C 5-6| Var { module_name: "", ident: "y" })) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 2-4| Equals, + ), + ], + |L 0-0, C 5-6| Var { module_name: "", ident: "y" }, +) diff --git a/compiler/parse/tests/snapshots/pass/expect.expr.result-ast b/compiler/parse/tests/snapshots/pass/expect.expr.result-ast index 2a831c90fd..da20463a0f 100644 --- a/compiler/parse/tests/snapshots/pass/expect.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/expect.expr.result-ast @@ -1 +1,4 @@ -Ok(Expect(|L 0-0, C 7-13| BinOps([(|L 0-0, C 7-8| Num("1"), |L 0-0, C 9-11| Equals)], |L 0-0, C 12-13| Num("1")), |L 2-2, C 0-1| SpaceBefore(Num("4"), [Newline, Newline]))) \ No newline at end of file +Expect( + |L 0-0, C 7-13| BinOps([(|L 0-0, C 7-8| Num("1"), |L 0-0, C 9-11| Equals)], |L 0-0, C 12-13| Num("1")), + |L 2-2, C 0-1| SpaceBefore(Num("4"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast b/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast index d191a045b5..fc78c66972 100644 --- a/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/float_with_underscores.expr.result-ast @@ -1 +1,3 @@ -Ok(Float("-1_23_456.0_1_23_456")) \ No newline at end of file +Float( + "-1_23_456.0_1_23_456", +) diff --git a/compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast index 3a173721ea..9b46a3b26d 100644 --- a/compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/highest_float.expr.result-ast @@ -1 +1,3 @@ -Ok(Float("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0")) \ No newline at end of file +Float( + "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", +) diff --git a/compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast index df5bcdf11f..aefb235b32 100644 --- a/compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/highest_int.expr.result-ast @@ -1 +1,3 @@ -Ok(Num("9223372036854775807")) \ No newline at end of file +Num( + "9223372036854775807", +) diff --git a/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast index 58dc1ac3a2..f3cff47961 100644 --- a/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast @@ -1 +1,6 @@ -Ok(Defs([|L 0-0, C 0-6| Body(|L 0-0, C 0-4| Identifier("iffy"), |L 0-0, C 5-6| Num("5"))], |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file +Defs( + [ + |L 0-0, C 0-6| Body(|L 0-0, C 0-4| Identifier("iffy"), |L 0-0, C 5-6| Num("5")), + ], + |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast b/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast index daab165d76..3912cc7edd 100644 --- a/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/int_with_underscore.expr.result-ast @@ -1 +1,3 @@ -Ok(Num("1__23")) \ No newline at end of file +Num( + "1__23", +) diff --git a/compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast index 060fa3c8e4..6bce8865e0 100644 --- a/compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/lowest_float.expr.result-ast @@ -1 +1,3 @@ -Ok(Float("-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0")) \ No newline at end of file +Float( + "-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", +) diff --git a/compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast index c6f13b67fa..01111135a9 100644 --- a/compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/lowest_int.expr.result-ast @@ -1 +1,3 @@ -Ok(Num("-9223372036854775808")) \ No newline at end of file +Num( + "-9223372036854775808", +) diff --git a/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast index 1e9a9935c7..4c9eb22446 100644 --- a/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast @@ -1 +1,6 @@ -Ok(Closure([|L 0-0, C 1-11| MalformedIdent("the_answer", Underscore(0, 5))], |L 0-0, C 15-17| Num("42"))) \ No newline at end of file +Closure( + [ + |L 0-0, C 1-11| MalformedIdent("the_answer", Underscore(0, 5)), + ], + |L 0-0, C 15-17| Num("42"), +) diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast index d5891e3680..dd9efc3fea 100644 --- a/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast @@ -1 +1,19 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-11| SpaceBefore(Malformed("bar.and"), [Newline])], value: |L 1-1, C 15-16| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 2-2, C 9-10| Num("4"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 4-11| SpaceBefore(Malformed("bar.and"), [Newline]), + ], + value: |L 1-1, C 15-16| Num("1"), + guard: None, + }, + WhenBranch { + patterns: [ + |L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline]), + ], + value: |L 2-2, C 9-10| Num("4"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast index 6b0bdfc90a..d874d1f288 100644 --- a/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast @@ -1 +1,19 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-11| SpaceBefore(Malformed("Foo.and"), [Newline])], value: |L 1-1, C 15-16| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 2-2, C 9-10| Num("4"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 4-11| SpaceBefore(Malformed("Foo.and"), [Newline]), + ], + value: |L 1-1, C 15-16| Num("1"), + guard: None, + }, + WhenBranch { + patterns: [ + |L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline]), + ], + value: |L 2-2, C 9-10| Num("4"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast index c64694015e..a38bca234e 100644 --- a/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-3| Num("-12"), |L 0-0, C 3-4| Minus)], |L 0-0, C 4-5| Num("5"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-3| Num("-12"), + |L 0-0, C 3-4| Minus, + ), + ], + |L 0-0, C 4-5| Num("5"), +) diff --git a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast index e75ae5e9ee..3254254bc9 100644 --- a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast @@ -1 +1,22 @@ -Ok(SpaceBefore(Defs([|L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5"))], |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment("## not docs!"), DocComment("docs, but with a problem"), DocComment("(namely that this is a mix of docs and regular comments)"), LineComment(" not docs")])) \ No newline at end of file +SpaceBefore( + Defs( + [ + |L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5")), + ], + |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + ), + [ + LineComment( + "## not docs!", + ), + DocComment( + "docs, but with a problem", + ), + DocComment( + "(namely that this is a mix of docs and regular comments)", + ), + LineComment( + " not docs", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast index dc8516328a..531c867b6d 100644 --- a/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast @@ -1 +1,8 @@ -Ok(Backpassing([|L 0-0, C 0-1| Identifier("x"), |L 0-0, C 3-4| Identifier("y")], |L 0-0, C 8-23| Apply(|L 0-0, C 8-17| Var { module_name: "List", ident: "map2" }, [|L 0-0, C 18-20| List(Collection { items: [], final_comments: [] }), |L 0-0, C 21-23| List(Collection { items: [], final_comments: [] })], Space), |L 2-2, C 0-5| SpaceBefore(BinOps([(|L 2-2, C 0-1| Var { module_name: "", ident: "x" }, |L 2-2, C 2-3| Plus)], |L 2-2, C 4-5| Var { module_name: "", ident: "y" }), [Newline, Newline]))) \ No newline at end of file +Backpassing( + [ + |L 0-0, C 0-1| Identifier("x"), + |L 0-0, C 3-4| Identifier("y"), + ], + |L 0-0, C 8-23| Apply(|L 0-0, C 8-17| Var { module_name: "List", ident: "map2" }, [|L 0-0, C 18-20| List([]), |L 0-0, C 21-23| List([])], Space), + |L 2-2, C 0-5| SpaceBefore(BinOps([(|L 2-2, C 0-1| Var { module_name: "", ident: "x" }, |L 2-2, C 2-3| Plus)], |L 2-2, C 4-5| Var { module_name: "", ident: "y" }), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast b/compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast index 95999767a2..21f0b7d0a6 100644 --- a/compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multi_char_string.expr.result-ast @@ -1 +1,5 @@ -Ok(Str(PlainLine("foo"))) \ No newline at end of file +Str( + PlainLine( + "foo", + ), +) diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast index 0567c1e5fc..9010dbf1f0 100644 --- a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast @@ -1 +1,6 @@ -Ok(Defs([|L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: Collection { items: [], final_comments: [] }, ext: None }, [Newline]))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file +Defs( + [ + |L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: [], ext: None }, [Newline])), + ], + |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast index 957c78140d..0a0ada87c2 100644 --- a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast @@ -1 +1,6 @@ -Ok(Defs([|L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: Collection { items: [], final_comments: [] }, ext: None }, [LineComment(" comment")]))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file +Defs( + [ + |L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: [], ext: None }, [LineComment(" comment")])), + ], + |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast index 31576b229c..bb7b50e47a 100644 --- a/compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiple_fields.expr.result-ast @@ -1 +1,13 @@ -Ok(Access(Access(Access(Var { module_name: "", ident: "rec" }, "abc"), "def"), "ghi")) \ No newline at end of file +Access( + Access( + Access( + Var { + module_name: "", + ident: "rec", + }, + "abc", + ), + "def", + ), + "ghi", +) diff --git a/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast index 67018b80c7..086c909e83 100644 --- a/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast @@ -1 +1,13 @@ -Ok(BinOps([(|L 0-0, C 0-2| Num("31"), |L 0-0, C 2-3| Star), (|L 0-0, C 3-5| Num("42"), |L 0-0, C 5-6| Plus)], |L 0-0, C 6-9| Num("534"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-2| Num("31"), + |L 0-0, C 2-3| Star, + ), + ( + |L 0-0, C 3-5| Num("42"), + |L 0-0, C 5-6| Plus, + ), + ], + |L 0-0, C 6-9| Num("534"), +) diff --git a/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast index b73f603675..acc5e5f702 100644 --- a/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast @@ -1 +1,4 @@ -Ok(UnaryOp(|L 0-0, C 1-4| Var { module_name: "", ident: "inf" }, |L 0-0, C 0-1| Negate)) \ No newline at end of file +UnaryOp( + |L 0-0, C 1-4| Var { module_name: "", ident: "inf" }, + |L 0-0, C 0-1| Negate, +) diff --git a/compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast index 4284d2a8e4..b4246aee73 100644 --- a/compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/negative_float.expr.result-ast @@ -1 +1,3 @@ -Ok(Float("-42.9")) \ No newline at end of file +Float( + "-42.9", +) diff --git a/compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast index 80aa5f34f3..a41780d138 100644 --- a/compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/negative_int.expr.result-ast @@ -1 +1,3 @@ -Ok(Num("-42")) \ No newline at end of file +Num( + "-42", +) diff --git a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast index 929a66d299..976613078e 100644 --- a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast @@ -1 +1,6 @@ -Ok(Defs([|L 0-1, C 0-5| Body(|L 0-0, C 0-1| Identifier("x"), |L 1-1, C 4-5| SpaceBefore(Num("5"), [Newline]))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file +Defs( + [ + |L 0-1, C 0-5| Body(|L 0-0, C 0-1| Identifier("x"), |L 1-1, C 4-5| SpaceBefore(Num("5"), [Newline])), + ], + |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast index 4cef64f79d..14422bf720 100644 --- a/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Num("3"), |L 0-0, C 3-4| Star)], |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Num("3"), + |L 0-0, C 3-4| Star, + ), + ], + |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast index e9200fe6ee..360329598f 100644 --- a/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Num("3"), |L 0-0, C 3-4| Minus)], |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Num("3"), + |L 0-0, C 3-4| Minus, + ), + ], + |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast index b758863e92..247cd19154 100644 --- a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast @@ -1 +1,6 @@ -Ok(Defs([|L 0-1, C 0-7| Body(|L 0-0, C 0-1| Identifier("x"), |L 0-1, C 4-7| BinOps([(|L 0-0, C 4-5| SpaceAfter(Num("1"), [Newline]), |L 1-1, C 4-5| LessThan)], |L 1-1, C 6-7| Num("2")))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file +Defs( + [ + |L 0-1, C 0-7| Body(|L 0-0, C 0-1| Identifier("x"), |L 0-1, C 4-7| BinOps([(|L 0-0, C 4-5| SpaceAfter(Num("1"), [Newline]), |L 1-1, C 4-5| LessThan)], |L 1-1, C 6-7| Num("2"))), + ], + |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast index fb5568dc0d..06f96fd4ec 100644 --- a/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), |L 1-1, C 0-1| Plus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), + |L 1-1, C 0-1| Plus, + ), + ], + |L 1-1, C 2-3| Num("4"), +) diff --git a/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast index 20680de556..5acd3eaf55 100644 --- a/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), |L 1-1, C 0-1| Minus)], |L 1-1, C 2-3| Num("4"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), + |L 1-1, C 0-1| Minus, + ), + ], + |L 1-1, C 2-3| Num("4"), +) diff --git a/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast index 92d58d3ccf..c2718d68ad 100644 --- a/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_inside_empty_list.expr.result-ast @@ -1 +1,8 @@ -Ok(List(Collection { items: [], final_comments: [Newline] })) \ No newline at end of file +List( + Collection { + items: [], + final_comments: [ + Newline, + ], + }, +) diff --git a/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast index c77f1fc342..6f97b37bdb 100644 --- a/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast @@ -1 +1,5 @@ -Ok(List([|L 1-1, C 0-1| SpaceBefore(SpaceAfter(Num("1"), [Newline]), [Newline])])) \ No newline at end of file +List( + [ + |L 1-1, C 0-1| SpaceBefore(SpaceAfter(Num("1"), [Newline]), [Newline]), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast index 65c891736b..9c59e63603 100644 --- a/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast @@ -1 +1,22 @@ -Ok(SpaceBefore(Defs([|L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5"))], |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment("######"), LineComment("## not docs!"), LineComment("#still not docs"), LineComment("#####")])) \ No newline at end of file +SpaceBefore( + Defs( + [ + |L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5")), + ], + |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + ), + [ + LineComment( + "######", + ), + LineComment( + "## not docs!", + ), + LineComment( + "#still not docs", + ), + LineComment( + "#####", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast index 41c5906bea..082f836bfa 100644 --- a/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast @@ -1 +1,14 @@ -Ok(SpaceBefore(Backpassing([|L 1-1, C 0-1| Identifier("x")], |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), |L 3-3, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file +SpaceBefore( + Backpassing( + [ + |L 1-1, C 0-1| Identifier("x"), + ], + |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), + |L 3-3, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline]), + ), + [ + LineComment( + " leading comment", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast index da2aa04018..e15ee75ac8 100644 --- a/compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_char_string.expr.result-ast @@ -1 +1,5 @@ -Ok(Str(PlainLine("x"))) \ No newline at end of file +Str( + PlainLine( + "x", + ), +) diff --git a/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast index 71bda962ae..9f8258fc18 100644 --- a/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast @@ -1 +1,13 @@ -Ok(SpaceBefore(Defs([|L 1-1, C 0-3| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 2-3| Num("5"))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file +SpaceBefore( + Defs( + [ + |L 1-1, C 0-3| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 2-3| Num("5")), + ], + |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + ), + [ + LineComment( + " leading comment", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast index bcc80fb069..03441c3589 100644 --- a/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 1-2| Minus)], |L 0-0, C 2-3| Num("2"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Num("1"), + |L 0-0, C 1-2| Minus, + ), + ], + |L 0-0, C 2-3| Num("2"), +) diff --git a/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast index e465cb4675..53900d251b 100644 --- a/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 1-2| Plus)], |L 0-0, C 2-3| Num("2"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Num("1"), + |L 0-0, C 1-2| Plus, + ), + ], + |L 0-0, C 2-3| Num("2"), +) diff --git a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast index 83e3d3903d..de72973a81 100644 --- a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast @@ -1 +1,13 @@ -Ok(SpaceBefore(Defs([|L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5"))], |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file +SpaceBefore( + Defs( + [ + |L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5")), + ], + |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + ), + [ + LineComment( + " leading comment", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast index 59379078a4..af56333e09 100644 --- a/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), |L 1-1, C 0-1| Plus)], |L 3-3, C 2-3| SpaceBefore(Num("4"), [Newline, Newline]))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), + |L 1-1, C 0-1| Plus, + ), + ], + |L 3-3, C 2-3| SpaceBefore(Num("4"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast index 664b584c41..f8516076c6 100644 --- a/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast @@ -1 +1,5 @@ -Ok(List([|L 0-0, C 1-2| Num("1")])) \ No newline at end of file +List( + [ + |L 0-0, C 1-2| Num("1"), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast index 264f7b91de..86f76b2eee 100644 --- a/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast @@ -1 +1,7 @@ -Ok(Apply(|L 0-0, C 1-5| ParensAround(Var { module_name: "", ident: "whee" }), [|L 0-0, C 7-8| Num("1")], Space)) \ No newline at end of file +Apply( + |L 0-0, C 1-5| ParensAround(Var { module_name: "", ident: "whee" }), + [ + |L 0-0, C 7-8| Num("1"), + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast index 0885a3d485..a2b8bd86ad 100644 --- a/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parenthetical_basic_field.expr.result-ast @@ -1 +1,9 @@ -Ok(Access(ParensAround(Var { module_name: "", ident: "rec" }), "field")) \ No newline at end of file +Access( + ParensAround( + Var { + module_name: "", + ident: "rec", + }, + ), + "field", +) diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast index 0c4537ba21..ec387d8d3b 100644 --- a/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parenthetical_field_qualified_var.expr.result-ast @@ -1 +1,9 @@ -Ok(Access(ParensAround(Var { module_name: "One.Two", ident: "rec" }), "field")) \ No newline at end of file +Access( + ParensAround( + Var { + module_name: "One.Two", + ident: "rec", + }, + ), + "field", +) diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast index 45ce9bd72f..dd22ad62c6 100644 --- a/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.result-ast @@ -1 +1,6 @@ -Ok(ParensAround(Var { module_name: "", ident: "whee" })) \ No newline at end of file +ParensAround( + Var { + module_name: "", + ident: "whee", + }, +) diff --git a/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast index 25fe2403c4..7122510366 100644 --- a/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast @@ -1 +1,6 @@ -Ok(Defs([|L 0-0, C 0-26| Alias { name: |L 0-0, C 0-4| "Blah", vars: [|L 0-0, C 5-6| Identifier("a"), |L 0-0, C 7-8| Identifier("b")], ann: |L 0-0, C 11-26| Apply("Foo.Bar", "Baz", [|L 0-0, C 23-24| BoundVariable("x"), |L 0-0, C 25-26| BoundVariable("y")]) }], |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file +Defs( + [ + |L 0-0, C 0-26| Alias { name: |L 0-0, C 0-4| "Blah", vars: [|L 0-0, C 5-6| Identifier("a"), |L 0-0, C 7-8| Identifier("b")], ann: |L 0-0, C 11-26| Apply("Foo.Bar", "Baz", [|L 0-0, C 23-24| BoundVariable("x"), |L 0-0, C 25-26| BoundVariable("y")]) }, + ], + |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast index 2d3d9d2dc5..1b9abdea43 100644 --- a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast @@ -1 +1,6 @@ -Ok(Defs([|L 0-0, C 0-33| Annotation(|L 0-0, C 0-3| Identifier("foo"), |L 0-0, C 6-33| As(|L 0-0, C 6-21| Apply("Foo.Bar", "Baz", [|L 0-0, C 18-19| BoundVariable("x"), |L 0-0, C 20-21| BoundVariable("y")]), [], |L 0-0, C 25-33| Apply("", "Blah", [|L 0-0, C 30-31| BoundVariable("a"), |L 0-0, C 32-33| BoundVariable("b")])))], |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]))) \ No newline at end of file +Defs( + [ + |L 0-0, C 0-33| Annotation(|L 0-0, C 0-3| Identifier("foo"), |L 0-0, C 6-33| As(|L 0-0, C 6-21| Apply("Foo.Bar", "Baz", [|L 0-0, C 18-19| BoundVariable("x"), |L 0-0, C 20-21| BoundVariable("y")]), [], |L 0-0, C 25-33| Apply("", "Blah", [|L 0-0, C 30-31| BoundVariable("a"), |L 0-0, C 32-33| BoundVariable("b")]))), + ], + |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), +) diff --git a/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast index 8defcce4a4..00ba5eabe5 100644 --- a/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast @@ -1 +1,12 @@ -Ok(When(|L 0-0, C 5-22| Apply(|L 0-0, C 5-11| GlobalTag("Delmin"), [|L 0-0, C 13-19| ParensAround(Apply(|L 0-0, C 13-16| GlobalTag("Del"), [|L 0-0, C 17-19| Var { module_name: "", ident: "rx" }], Space)), |L 0-0, C 21-22| Num("0")], Space), [WhenBranch { patterns: [|L 1-1, C 4-22| SpaceBefore(Apply(|L 1-1, C 4-10| GlobalTag("Delmin"), [|L 1-1, C 12-18| Apply(|L 1-1, C 12-15| GlobalTag("Del"), [|L 1-1, C 16-18| Identifier("ry")]), |L 1-1, C 21-22| Underscore("")]), [Newline])], value: |L 1-1, C 26-47| Apply(|L 1-1, C 26-30| GlobalTag("Node"), [|L 1-1, C 31-36| GlobalTag("Black"), |L 1-1, C 37-38| Num("0"), |L 1-1, C 39-44| GlobalTag("False"), |L 1-1, C 45-47| Var { module_name: "", ident: "ry" }], Space), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-22| Apply(|L 0-0, C 5-11| GlobalTag("Delmin"), [|L 0-0, C 13-19| ParensAround(Apply(|L 0-0, C 13-16| GlobalTag("Del"), [|L 0-0, C 17-19| Var { module_name: "", ident: "rx" }], Space)), |L 0-0, C 21-22| Num("0")], Space), + [ + WhenBranch { + patterns: [ + |L 1-1, C 4-22| SpaceBefore(Apply(|L 1-1, C 4-10| GlobalTag("Delmin"), [|L 1-1, C 12-18| Apply(|L 1-1, C 12-15| GlobalTag("Del"), [|L 1-1, C 16-18| Identifier("ry")]), |L 1-1, C 21-22| Underscore("")]), [Newline]), + ], + value: |L 1-1, C 26-47| Apply(|L 1-1, C 26-30| GlobalTag("Node"), [|L 1-1, C 31-36| GlobalTag("Black"), |L 1-1, C 37-38| Num("0"), |L 1-1, C 39-44| GlobalTag("False"), |L 1-1, C 45-47| Var { module_name: "", ident: "ry" }], Space), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast index 02c3fc192c..58a09d0639 100644 --- a/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/pos_inf_float.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "", ident: "inf" }) \ No newline at end of file +Var { + module_name: "", + ident: "inf", +} diff --git a/compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast index 1386884fc2..366609e578 100644 --- a/compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/positive_float.expr.result-ast @@ -1 +1,3 @@ -Ok(Float("42.9")) \ No newline at end of file +Float( + "42.9", +) diff --git a/compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast index 535767ea52..23ee1510a7 100644 --- a/compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/positive_int.expr.result-ast @@ -1 +1,3 @@ -Ok(Num("42")) \ No newline at end of file +Num( + "42", +) diff --git a/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast index 18b2af3de4..951f350742 100644 --- a/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/private_qualified_tag.expr.result-ast @@ -1 +1,7 @@ -Ok(MalformedIdent("@One.Two.Whee", BadPrivateTag(0, 4))) \ No newline at end of file +MalformedIdent( + "@One.Two.Whee", + BadPrivateTag( + 0, + 4, + ), +) diff --git a/compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast b/compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast index c3790e14b3..d629481dbe 100644 --- a/compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/qualified_field.expr.result-ast @@ -1 +1,13 @@ -Ok(Access(Access(Access(Var { module_name: "One.Two", ident: "rec" }, "abc"), "def"), "ghi")) \ No newline at end of file +Access( + Access( + Access( + Var { + module_name: "One.Two", + ident: "rec", + }, + "abc", + ), + "def", + ), + "ghi", +) diff --git a/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast index 3a52b4fe52..2ae1a05ac2 100644 --- a/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/qualified_global_tag.expr.result-ast @@ -1 +1,7 @@ -Ok(MalformedIdent("One.Two.Whee", QualifiedTag(0, 12))) \ No newline at end of file +MalformedIdent( + "One.Two.Whee", + QualifiedTag( + 0, + 12, + ), +) diff --git a/compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast b/compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast index ac634bc3b1..14a1b7ab96 100644 --- a/compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/qualified_var.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "One.Two", ident: "whee" }) \ No newline at end of file +Var { + module_name: "One.Two", + ident: "whee", +} diff --git a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast index 14a36adda0..5ec4d07efd 100644 --- a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast @@ -1 +1,14 @@ -Ok(SpaceBefore(Defs([|L 1-1, C 0-12| Body(|L 1-1, C 0-8| RecordDestructure(Collection { items: [|L 1-1, C 2-3| Identifier("x"), |L 1-1, C 5-7| Identifier("y")], final_comments: [] }), |L 1-1, C 11-12| Num("5")), |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline])], |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file +SpaceBefore( + Defs( + [ + |L 1-1, C 0-12| Body(|L 1-1, C 0-8| RecordDestructure([|L 1-1, C 2-3| Identifier("x"), |L 1-1, C 5-7| Identifier("y")]), |L 1-1, C 11-12| Num("5")), + |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline]), + ], + |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + ), + [ + LineComment( + " leading comment", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast index 345c5b1966..b367b0c424 100644 --- a/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast @@ -1 +1,7 @@ -Ok(RecordUpdate { update: |L 0-0, C 2-13| Var { module_name: "Foo.Bar", ident: "baz" }, fields: [|L 0-0, C 16-20| RequiredValue(|L 0-0, C 16-17| "x", [], |L 0-0, C 19-20| Num("5")), |L 0-0, C 22-26| RequiredValue(|L 0-0, C 22-23| "y", [], |L 0-0, C 25-26| Num("0"))] }) \ No newline at end of file +RecordUpdate { + update: |L 0-0, C 2-13| Var { module_name: "Foo.Bar", ident: "baz" }, + fields: [ + |L 0-0, C 16-20| RequiredValue(|L 0-0, C 16-17| "x", [], |L 0-0, C 19-20| Num("5")), + |L 0-0, C 22-26| RequiredValue(|L 0-0, C 22-23| "y", [], |L 0-0, C 25-26| Num("0")), + ], +} diff --git a/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast index e860f48ba4..08540b40b5 100644 --- a/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast @@ -1 +1,6 @@ -Ok(Record([|L 0-0, C 1-26| RequiredValue(|L 0-0, C 1-2| "x", [], |L 0-0, C 5-26| If([(|L 0-0, C 8-12| GlobalTag("True"), |L 0-0, C 18-19| Num("1"))], |L 0-0, C 25-26| Num("2"))), |L 0-0, C 28-32| RequiredValue(|L 0-0, C 28-29| "y", [], |L 0-0, C 31-32| Num("3"))])) \ No newline at end of file +Record( + [ + |L 0-0, C 1-26| RequiredValue(|L 0-0, C 1-2| "x", [], |L 0-0, C 5-26| If([(|L 0-0, C 8-12| GlobalTag("True"), |L 0-0, C 18-19| Num("1"))], |L 0-0, C 25-26| Num("2"))), + |L 0-0, C 28-32| RequiredValue(|L 0-0, C 28-29| "y", [], |L 0-0, C 31-32| Num("3")), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast index 9680e171dd..ee93f985db 100644 --- a/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast @@ -1 +1,6 @@ -Ok(Closure([|L 0-0, C 1-2| Identifier("a")], |L 0-0, C 6-8| Num("42"))) \ No newline at end of file +Closure( + [ + |L 0-0, C 1-2| Identifier("a"), + ], + |L 0-0, C 6-8| Num("42"), +) diff --git a/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast index fd951daa13..a4b25da18c 100644 --- a/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast @@ -1 +1,6 @@ -Ok(Closure([|L 0-0, C 1-2| Underscore("")], |L 0-0, C 6-8| Num("42"))) \ No newline at end of file +Closure( + [ + |L 0-0, C 1-2| Underscore(""), + ], + |L 0-0, C 6-8| Num("42"), +) diff --git a/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast index 212d337e4e..853855b4cf 100644 --- a/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 1-2| Minus)], |L 0-0, C 3-4| Var { module_name: "", ident: "y" })) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 1-2| Minus, + ), + ], + |L 0-0, C 3-4| Var { module_name: "", ident: "y" }, +) diff --git a/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast index 3a12140511..53b37d4c4c 100644 --- a/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast @@ -1 +1,5 @@ -Ok(List([|L 0-0, C 2-3| Num("1")])) \ No newline at end of file +List( + [ + |L 0-0, C 2-3| Num("1"), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast index 584939a222..36f4a52b6e 100644 --- a/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.result-ast @@ -1 +1,3 @@ -Ok(List([])) \ No newline at end of file +List( + [], +) diff --git a/compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast b/compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast index 9c2d2d1a63..07cfaac49f 100644 --- a/compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/string_without_escape.expr.result-ast @@ -1 +1,5 @@ -Ok(Str(PlainLine("123 abc 456 def"))) \ No newline at end of file +Str( + PlainLine( + "123 abc 456 def", + ), +) diff --git a/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast index 4b2859992b..bacbb22bb7 100644 --- a/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 2-3| Minus)], |L 0-0, C 4-5| Num("2"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 2-3| Minus, + ), + ], + |L 0-0, C 4-5| Num("2"), +) diff --git a/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast index ad3f4a7328..8ae13655e0 100644 --- a/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Num("1"), |L 0-0, C 3-4| Minus)], |L 0-0, C 7-8| Num("2"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Num("1"), + |L 0-0, C 3-4| Minus, + ), + ], + |L 0-0, C 7-8| Num("2"), +) diff --git a/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast index 947c450022..b3eb2afca2 100644 --- a/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast @@ -1 +1,6 @@ -Ok(Closure([|L 0-0, C 1-6| GlobalTag("Thing")], |L 0-0, C 10-12| Num("42"))) \ No newline at end of file +Closure( + [ + |L 0-0, C 1-6| GlobalTag("Thing"), + ], + |L 0-0, C 10-12| Num("42"), +) diff --git a/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast index b963a078d6..268cbbfcc5 100644 --- a/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-2| Num("10"), |L 0-0, C 2-3| Star)], |L 0-0, C 3-5| Num("11"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-2| Num("10"), + |L 0-0, C 2-3| Star, + ), + ], + |L 0-0, C 3-5| Num("11"), +) diff --git a/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast index 999cc9464e..74049bd26c 100644 --- a/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast @@ -1 +1,8 @@ -Ok(Closure([|L 0-0, C 1-2| Identifier("a"), |L 0-0, C 4-5| Identifier("b"), |L 0-0, C 7-8| Identifier("c")], |L 0-0, C 12-14| Num("42"))) \ No newline at end of file +Closure( + [ + |L 0-0, C 1-2| Identifier("a"), + |L 0-0, C 4-5| Identifier("b"), + |L 0-0, C 7-8| Identifier("c"), + ], + |L 0-0, C 12-14| Num("42"), +) diff --git a/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast index d249da119f..3fa37c5348 100644 --- a/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast @@ -1 +1,7 @@ -Ok(Closure([|L 0-0, C 1-2| Identifier("a"), |L 0-0, C 4-5| Identifier("b")], |L 0-0, C 9-11| Num("42"))) \ No newline at end of file +Closure( + [ + |L 0-0, C 1-2| Identifier("a"), + |L 0-0, C 4-5| Identifier("b"), + ], + |L 0-0, C 9-11| Num("42"), +) diff --git a/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast index ab62b49967..2d6b4e7935 100644 --- a/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast @@ -1 +1,14 @@ -Ok(SpaceBefore(Backpassing([|L 1-1, C 0-1| Identifier("x")], |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), |L 2-4, C 0-1| SpaceBefore(Backpassing([|L 2-2, C 0-1| Identifier("z")], |L 2-2, C 5-7| Record(Collection { items: [], final_comments: [] }), |L 4-4, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline])), [Newline])), [LineComment(" leading comment")])) \ No newline at end of file +SpaceBefore( + Backpassing( + [ + |L 1-1, C 0-1| Identifier("x"), + ], + |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), + |L 2-4, C 0-1| SpaceBefore(Backpassing([|L 2-2, C 0-1| Identifier("z")], |L 2-2, C 5-7| Record([]), |L 4-4, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline])), [Newline]), + ), + [ + LineComment( + " leading comment", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast index 07f24e4cb4..d7ed770bdd 100644 --- a/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast @@ -1 +1,19 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-3| SpaceBefore(StrLiteral(PlainLine("")), [Newline])], value: |L 1-1, C 7-8| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-7| SpaceBefore(StrLiteral(PlainLine("mise")), [Newline])], value: |L 2-2, C 11-12| Num("2"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 1-3| SpaceBefore(StrLiteral(PlainLine("")), [Newline]), + ], + value: |L 1-1, C 7-8| Num("1"), + guard: None, + }, + WhenBranch { + patterns: [ + |L 2-2, C 1-7| SpaceBefore(StrLiteral(PlainLine("mise")), [Newline]), + ], + value: |L 2-2, C 11-12| Num("2"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast index 34b9a590a9..d496253434 100644 --- a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast @@ -1 +1,14 @@ -Ok(SpaceBefore(Defs([|L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5")), |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline])], |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file +SpaceBefore( + Defs( + [ + |L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5")), + |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline]), + ], + |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + ), + [ + LineComment( + " leading comment", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast index cee72d6e0f..43bf682327 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast @@ -1 +1,4 @@ -Ok(UnaryOp(|L 0-0, C 1-4| Var { module_name: "", ident: "foo" }, |L 0-0, C 0-1| Negate)) \ No newline at end of file +UnaryOp( + |L 0-0, C 1-4| Var { module_name: "", ident: "foo" }, + |L 0-0, C 0-1| Negate, +) diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast index 574e1efa75..0feb302951 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast @@ -1 +1,4 @@ -Ok(UnaryOp(|L 0-0, C 1-11| Access(Var { module_name: "", ident: "rec1" }, "field"), |L 0-0, C 0-1| Negate)) \ No newline at end of file +UnaryOp( + |L 0-0, C 1-11| Access(Var { module_name: "", ident: "rec1" }, "field"), + |L 0-0, C 0-1| Negate, +) diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast index 8eecf50e4b..0b776b64d7 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast @@ -1 +1,8 @@ -Ok(Apply(|L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, [|L 0-0, C 6-8| Num("12"), |L 0-0, C 9-13| UnaryOp(|L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, |L 0-0, C 9-10| Negate)], Space)) \ No newline at end of file +Apply( + |L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, + [ + |L 0-0, C 6-8| Num("12"), + |L 0-0, C 9-13| UnaryOp(|L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, |L 0-0, C 9-10| Negate), + ], + Space, +) diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast index 24aab96847..d5862151cf 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast @@ -1 +1,4 @@ -Ok(UnaryOp(|L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), |L 0-0, C 0-1| Negate)) \ No newline at end of file +UnaryOp( + |L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), + |L 0-0, C 0-1| Negate, +) diff --git a/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast index fb52a8f2a9..d4f1b679c8 100644 --- a/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast @@ -1 +1,4 @@ -Ok(UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "blah" }, |L 0-0, C 0-1| Not)) \ No newline at end of file +UnaryOp( + |L 0-0, C 1-5| Var { module_name: "", ident: "blah" }, + |L 0-0, C 0-1| Not, +) diff --git a/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast index 3c59060bec..b3b866b2b4 100644 --- a/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast @@ -1 +1,4 @@ -Ok(UnaryOp(|L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), |L 0-0, C 0-1| Not)) \ No newline at end of file +UnaryOp( + |L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), + |L 0-0, C 0-1| Not, +) diff --git a/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast index 74db669789..67ae3a32b4 100644 --- a/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast @@ -1 +1,14 @@ -Ok(SpaceBefore(Backpassing([|L 1-1, C 0-1| Underscore("")], |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), |L 3-3, C 0-1| SpaceBefore(Num("4"), [Newline, Newline])), [LineComment(" leading comment")])) \ No newline at end of file +SpaceBefore( + Backpassing( + [ + |L 1-1, C 0-1| Underscore(""), + ], + |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), + |L 3-3, C 0-1| SpaceBefore(Num("4"), [Newline, Newline]), + ), + [ + LineComment( + " leading comment", + ), + ], +) diff --git a/compiler/parse/tests/snapshots/pass/var_else.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_else.expr.result-ast index dbfa1c598d..7c569cf669 100644 --- a/compiler/parse/tests/snapshots/pass/var_else.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/var_else.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "", ident: "elsewhere" }) \ No newline at end of file +Var { + module_name: "", + ident: "elsewhere", +} diff --git a/compiler/parse/tests/snapshots/pass/var_if.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_if.expr.result-ast index 87be960a7f..2b95a15c2e 100644 --- a/compiler/parse/tests/snapshots/pass/var_if.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/var_if.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "", ident: "iffy" }) \ No newline at end of file +Var { + module_name: "", + ident: "iffy", +} diff --git a/compiler/parse/tests/snapshots/pass/var_is.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_is.expr.result-ast index d02b7f8d56..2e84e98557 100644 --- a/compiler/parse/tests/snapshots/pass/var_is.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/var_is.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "", ident: "isnt" }) \ No newline at end of file +Var { + module_name: "", + ident: "isnt", +} diff --git a/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast index f0c76694c9..f353e929ff 100644 --- a/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast @@ -1 +1,9 @@ -Ok(BinOps([(|L 0-0, C 0-1| Var { module_name: "", ident: "x" }, |L 0-0, C 1-2| Minus)], |L 0-0, C 2-3| Num("2"))) \ No newline at end of file +BinOps( + [ + ( + |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 1-2| Minus, + ), + ], + |L 0-0, C 2-3| Num("2"), +) diff --git a/compiler/parse/tests/snapshots/pass/var_then.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_then.expr.result-ast index 99277807cc..b989386f63 100644 --- a/compiler/parse/tests/snapshots/pass/var_then.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/var_then.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "", ident: "thenever" }) \ No newline at end of file +Var { + module_name: "", + ident: "thenever", +} diff --git a/compiler/parse/tests/snapshots/pass/var_when.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_when.expr.result-ast index a060ee2cc3..d7d0d773f3 100644 --- a/compiler/parse/tests/snapshots/pass/var_when.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/var_when.expr.result-ast @@ -1 +1,4 @@ -Ok(Var { module_name: "", ident: "whenever" }) \ No newline at end of file +Var { + module_name: "", + ident: "whenever", +} diff --git a/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast index 64df94bc50..2e789d4e3c 100644 --- a/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast @@ -1 +1,26 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 2-2, C 8-9| SpaceBefore(Num("1"), [Newline]), guard: None }, WhenBranch { patterns: [|L 4-4, C 4-5| SpaceBefore(Underscore(""), [Newline, Newline])], value: |L 5-5, C 8-9| SpaceBefore(Num("2"), [Newline]), guard: None }, WhenBranch { patterns: [|L 7-7, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline, Newline])], value: |L 8-8, C 8-9| SpaceBefore(Num("3"), [Newline]), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 4-5| SpaceBefore(Underscore(""), [Newline]), + ], + value: |L 2-2, C 8-9| SpaceBefore(Num("1"), [Newline]), + guard: None, + }, + WhenBranch { + patterns: [ + |L 4-4, C 4-5| SpaceBefore(Underscore(""), [Newline, Newline]), + ], + value: |L 5-5, C 8-9| SpaceBefore(Num("2"), [Newline]), + guard: None, + }, + WhenBranch { + patterns: [ + |L 7-7, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline, Newline]), + ], + value: |L 8-8, C 8-9| SpaceBefore(Num("3"), [Newline]), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast index ce00005d8c..5c806a67bf 100644 --- a/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast @@ -1 +1,14 @@ -Ok(ParensAround(When(|L 0-0, C 6-7| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline])], value: |L 2-2, C 8-9| SpaceBefore(Num("3"), [Newline]), guard: None }]))) \ No newline at end of file +ParensAround( + When( + |L 0-0, C 6-7| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline]), + ], + value: |L 2-2, C 8-9| SpaceBefore(Num("3"), [Newline]), + guard: None, + }, + ], + ), +) diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast index f47b89c3c4..80f82b2a0c 100644 --- a/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast @@ -1 +1,19 @@ -Ok(ParensAround(SpaceAfter(When(|L 0-0, C 6-7| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline])], value: |L 1-1, C 10-11| Num("3"), guard: None }]), [Newline]))) \ No newline at end of file +ParensAround( + SpaceAfter( + When( + |L 0-0, C 6-7| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline]), + ], + value: |L 1-1, C 10-11| Num("3"), + guard: None, + }, + ], + ), + [ + Newline, + ], + ), +) diff --git a/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast index bfa2c2ecdf..d91e8cdc15 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast @@ -1 +1,21 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-7| SpaceBefore(StrLiteral(PlainLine("blah")), [Newline]), |L 1-1, C 10-16| StrLiteral(PlainLine("blop"))], value: |L 1-1, C 20-21| Num("1"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-6| SpaceBefore(StrLiteral(PlainLine("foo")), [Newline]), |L 3-3, C 2-7| SpaceBefore(StrLiteral(PlainLine("bar")), [Newline])], value: |L 3-3, C 11-12| Num("2"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 1-7| SpaceBefore(StrLiteral(PlainLine("blah")), [Newline]), + |L 1-1, C 10-16| StrLiteral(PlainLine("blop")), + ], + value: |L 1-1, C 20-21| Num("1"), + guard: None, + }, + WhenBranch { + patterns: [ + |L 2-2, C 1-6| SpaceBefore(StrLiteral(PlainLine("foo")), [Newline]), + |L 3-3, C 2-7| SpaceBefore(StrLiteral(PlainLine("bar")), [Newline]), + ], + value: |L 3-3, C 11-12| Num("2"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast index dfee116add..3419dfe72a 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast @@ -1 +1,19 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 4-5| SpaceBefore(NumLiteral("1"), [Newline])], value: |L 1-2, C 9-6| Apply(|L 1-1, C 9-16| Var { module_name: "Num", ident: "neg" }, [|L 2-2, C 5-6| SpaceBefore(Num("2"), [Newline])], Space), guard: None }, WhenBranch { patterns: [|L 3-3, C 4-5| SpaceBefore(Underscore(""), [Newline])], value: |L 3-3, C 9-10| Num("4"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 4-5| SpaceBefore(NumLiteral("1"), [Newline]), + ], + value: |L 1-2, C 9-6| Apply(|L 1-1, C 9-16| Var { module_name: "Num", ident: "neg" }, [|L 2-2, C 5-6| SpaceBefore(Num("2"), [Newline])], Space), + guard: None, + }, + WhenBranch { + patterns: [ + |L 3-3, C 4-5| SpaceBefore(Underscore(""), [Newline]), + ], + value: |L 3-3, C 9-10| Num("4"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast index f2a54893b8..4fbfcfdb99 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast @@ -1 +1,19 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline])], value: |L 1-1, C 6-7| Num("2"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-3| SpaceBefore(NumLiteral("-3"), [Newline])], value: |L 2-2, C 7-8| Num("4"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline]), + ], + value: |L 1-1, C 6-7| Num("2"), + guard: None, + }, + WhenBranch { + patterns: [ + |L 2-2, C 1-3| SpaceBefore(NumLiteral("-3"), [Newline]), + ], + value: |L 2-2, C 7-8| Num("4"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast index 021bc29827..da096daa1f 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast @@ -1 +1,19 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline])], value: |L 1-1, C 6-7| Num("2"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-2| SpaceBefore(NumLiteral("3"), [Newline])], value: |L 2-2, C 6-7| Num("4"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline]), + ], + value: |L 1-1, C 6-7| Num("2"), + guard: None, + }, + WhenBranch { + patterns: [ + |L 2-2, C 1-2| SpaceBefore(NumLiteral("3"), [Newline]), + ], + value: |L 2-2, C 6-7| Num("4"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast index b777de759e..ec9232bf7a 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast @@ -1 +1,19 @@ -Ok(When(|L 0-0, C 5-6| Var { module_name: "", ident: "x" }, [WhenBranch { patterns: [|L 1-1, C 1-6| SpaceBefore(RecordDestructure([|L 1-1, C 3-4| Identifier("y")]), [Newline])], value: |L 1-1, C 10-11| Num("2"), guard: None }, WhenBranch { patterns: [|L 2-2, C 1-9| SpaceBefore(RecordDestructure([|L 2-2, C 3-4| Identifier("z"), |L 2-2, C 6-7| Identifier("w")]), [Newline])], value: |L 2-2, C 13-14| Num("4"), guard: None }])) \ No newline at end of file +When( + |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + [ + WhenBranch { + patterns: [ + |L 1-1, C 1-6| SpaceBefore(RecordDestructure([|L 1-1, C 3-4| Identifier("y")]), [Newline]), + ], + value: |L 1-1, C 10-11| Num("2"), + guard: None, + }, + WhenBranch { + patterns: [ + |L 2-2, C 1-9| SpaceBefore(RecordDestructure([|L 2-2, C 3-4| Identifier("z"), |L 2-2, C 6-7| Identifier("w")]), [Newline]), + ], + value: |L 2-2, C 13-14| Num("4"), + guard: None, + }, + ], +) diff --git a/compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast index 61e8fc27e9..b164e7a7fe 100644 --- a/compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/zero_float.expr.result-ast @@ -1 +1,3 @@ -Ok(Float("0.0")) \ No newline at end of file +Float( + "0.0", +) diff --git a/compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast b/compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast index dad9d51c67..0a7ff7c8ce 100644 --- a/compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/zero_int.expr.result-ast @@ -1 +1,3 @@ -Ok(Num("0")) \ No newline at end of file +Num( + "0", +) diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index a070c8aee7..ee8ffeeee0 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -68,7 +68,7 @@ mod test_parse { $( #[test] fn $expr_test_name() { - + super::snapshot_expr_test(stringify!($expr_test_name)); } )* } @@ -201,6 +201,28 @@ mod test_parse { } } + fn snapshot_expr_test(name: &str) { + let ty = "expr"; + let mut parent = std::path::PathBuf::from("tests"); + parent.push("snapshots"); + parent.push("pass"); + let input_path = parent.join(&format!("{}.{}.roc", name, ty)); + let result_path = parent.join(&format!("{}.{}.result-ast", name, ty)); + + let input = std::fs::read_to_string(&input_path).unwrap(); + let expected_result = std::fs::read_to_string(&result_path).unwrap(); + + let arena = Bump::new(); + let actual_ast = parse_expr_with(&arena, input.trim()).unwrap(); + let actual_result = format!("{:#?}\n", actual_ast); + + if std::env::var("ROC_PARSER_SNAPSHOT_TEST_OVERWRITE").is_ok() { + std::fs::write(&result_path, actual_result).unwrap(); + } else { + assert_eq!(expected_result, actual_result); + } + } + fn save_snapshot(name: &str, ty: &str, input: &str, result: &str) { let mut parent = std::path::PathBuf::from("tests"); parent.push("snapshots"); @@ -218,7 +240,7 @@ mod test_parse { fn save_parse_expr_with<'a>(arena: &'a Bump, input: &'a str) -> Result, SyntaxError<'a>> { let actual = parse_expr_with(&arena, input.trim()); - let result = format!("{:?}", actual); + let result = format!("{:#?}\n", actual.as_ref().unwrap()); save_snapshot(&test_name(), "expr", input, &result); actual @@ -227,7 +249,8 @@ mod test_parse { fn assert_parses_to<'a>(input: &'a str, expected_expr: Expr<'a>) { let arena = Bump::new(); let actual = parse_expr_with(&arena, input.trim()); - + let result = format!("{:#?}\n", actual.as_ref().unwrap()); + save_snapshot(&test_name(), "expr", input, &result); assert_eq!(Ok(expected_expr), actual); } From 6465a4031eb8d218af733a39b504ac41e9176b84 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 13:45:50 -0800 Subject: [PATCH 084/223] delete old tests --- .../pass/all_f64_values_parse.expr.result-ast | 3 - .../pass/all_f64_values_parse.expr.roc | 1 - .../pass/all_i64_values_parse.expr.result-ast | 3 - .../pass/all_i64_values_parse.expr.roc | 1 - compiler/parse/tests/test_parse.rs | 2776 +---------------- 5 files changed, 13 insertions(+), 2771 deletions(-) delete mode 100644 compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast delete mode 100644 compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc delete mode 100644 compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast delete mode 100644 compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc diff --git a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast deleted file mode 100644 index 3043e73707..0000000000 --- a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.result-ast +++ /dev/null @@ -1,3 +0,0 @@ -Float( - "-163434311610918100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", -) diff --git a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc b/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc deleted file mode 100644 index 8525093bdb..0000000000 --- a/compiler/parse/tests/snapshots/pass/all_f64_values_parse.expr.roc +++ /dev/null @@ -1 +0,0 @@ --163434311610918100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0 \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast deleted file mode 100644 index 34a81f72a4..0000000000 --- a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.result-ast +++ /dev/null @@ -1,3 +0,0 @@ -Num( - "8977008824269102071", -) diff --git a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc b/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc deleted file mode 100644 index e943571568..0000000000 --- a/compiler/parse/tests/snapshots/pass/all_i64_values_parse.expr.roc +++ /dev/null @@ -1 +0,0 @@ -8977008824269102071 \ No newline at end of file diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index ee8ffeeee0..1ce8f0e055 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -55,23 +55,21 @@ mod test_parse { let files = std::fs::read_dir(&base).unwrap().map(|f| f.unwrap().file_name().to_str().unwrap().to_string()).collect::>(); for file in files { if let Some(file) = file.strip_suffix(".roc") { - assert!(tests.contains(file)); + assert!(tests.contains(file), "{}", file); } else if let Some(file) = file.strip_suffix(".result-ast") { - assert!(tests.contains(file)); + assert!(tests.contains(file), "{}", file); } else { panic!("unexpected test file found: {}", file); } } } - mod _preview_tests { - $( - #[test] - fn $expr_test_name() { - super::snapshot_expr_test(stringify!($expr_test_name)); - } - )* - } + $( + #[test] + fn $expr_test_name() { + snapshot_expr_test(stringify!($expr_test_name)); + } + )* }; } @@ -79,8 +77,6 @@ mod test_parse { expr => { add_var_with_spaces, add_with_spaces, - all_f64_values_parse, - all_i64_values_parse, apply_global_tag, apply_parenthetical_global_tag_args, apply_private_tag, @@ -113,8 +109,8 @@ mod test_parse { lowest_float, lowest_int, malformed_ident_due_to_underscore, - malformed_pattern_field_access, - malformed_pattern_module_name, + malformed_pattern_field_access, // See https://github.com/rtfeldman/roc/issues/399 + malformed_pattern_module_name, // See https://github.com/rtfeldman/roc/issues/399 minus_twelve_minus_five, mixed_docs, multi_backpassing, @@ -126,7 +122,7 @@ mod test_parse { neg_inf_float, negative_float, negative_int, - newline_after_equals, + newline_after_equals, // Regression test for https://github.com/rtfeldman/roc/issues/51 newline_after_mul, newline_after_sub, newline_and_spaces_before_less_than, @@ -149,7 +145,7 @@ mod test_parse { parenthetical_var, parse_alias, parse_as_ann, - pattern_with_space_in_parens, + pattern_with_space_in_parens, // https://github.com/rtfeldman/roc/issues/929 pos_inf_float, positive_float, positive_int, @@ -176,7 +172,7 @@ mod test_parse { two_branch_when, two_spaced_def, unary_negation, - unary_negation_access, + unary_negation_access, // Regression test for https://github.com/rtfeldman/roc/issues/509 unary_negation_arg, unary_negation_with_parens, unary_not, @@ -249,8 +245,6 @@ mod test_parse { fn assert_parses_to<'a>(input: &'a str, expected_expr: Expr<'a>) { let arena = Bump::new(); let actual = parse_expr_with(&arena, input.trim()); - let result = format!("{:#?}\n", actual.as_ref().unwrap()); - save_snapshot(&test_name(), "expr", input, &result); assert_eq!(Ok(expected_expr), actual); } @@ -295,72 +289,6 @@ mod test_parse { } } - fn single_binop<'a>( - arena: &'a Bump, - args: ( - Located>, - Located, - Located>, - ), - ) -> Expr<'a> { - let (left, op, right) = args; - - Expr::BinOps(arena.alloc([(left, op)]), arena.alloc(right)) - } - - // STRING LITERALS - - fn expect_parsed_str(input: &str, expected: &str) { - assert_parses_to(expected, Expr::Str(PlainLine(input))); - } - - #[test] - fn empty_string() { - assert_parses_to( - indoc!( - r#" - "" - "# - ), - Str(PlainLine("")), - ); - } - - #[test] - fn one_char_string() { - assert_parses_to( - indoc!( - r#" - "x" - "# - ), - Expr::Str(PlainLine("x")), - ); - } - - #[test] - fn multi_char_string() { - assert_parses_to( - indoc!( - r#" - "foo" - "# - ), - Expr::Str(PlainLine("foo")), - ); - } - - #[test] - fn string_without_escape() { - expect_parsed_str("a", r#""a""#); - expect_parsed_str("ab", r#""ab""#); - expect_parsed_str("abc", r#""abc""#); - expect_parsed_str("123", r#""123""#); - expect_parsed_str("abc123", r#""abc123""#); - expect_parsed_str("123abc", r#""123abc""#); - expect_parsed_str("123 abc 456 def", r#""123 abc 456 def""#); - } - // BACKSLASH ESCAPES #[test] @@ -534,123 +462,11 @@ mod test_parse { assert_parsing_fails(&too_long_str, SyntaxError::LineTooLong(0)); } - // INT LITERALS - - #[test] - fn zero_int() { - assert_parses_to("0", Num("0")); - } - - #[test] - fn positive_int() { - assert_parses_to("1", Num("1")); - assert_parses_to("42", Num("42")); - } - - #[test] - fn negative_int() { - assert_parses_to("-1", Num("-1")); - assert_parses_to("-42", Num("-42")); - } - - #[test] - fn highest_int() { - assert_parses_to( - i64::MAX.to_string().as_str(), - Num(i64::MAX.to_string().as_str()), - ); - } - - #[test] - fn lowest_int() { - assert_parses_to( - i64::MIN.to_string().as_str(), - Num(i64::MIN.to_string().as_str()), - ); - } - - #[test] - fn int_with_underscore() { - assert_parses_to("1_2_34_567", Num("1_2_34_567")); - assert_parses_to("-1_2_34_567", Num("-1_2_34_567")); - // The following cases are silly. They aren't supported on purpose, - // but there would be a performance cost to explicitly disallowing them, - // which doesn't seem like it would benefit anyone. - assert_parses_to("1_", Num("1_")); - assert_parses_to("1__23", Num("1__23")); - } - #[quickcheck] fn all_i64_values_parse(num: i64) { assert_parses_to(num.to_string().as_str(), Num(num.to_string().as_str())); } - // FLOAT LITERALS - - #[test] - fn zero_float() { - assert_parses_to("0.0", Float("0.0")); - } - - #[test] - fn positive_float() { - assert_parses_to("1.0", Float("1.0")); - assert_parses_to("1.1", Float("1.1")); - assert_parses_to("42.0", Float("42.0")); - assert_parses_to("42.9", Float("42.9")); - } - - #[test] - fn negative_float() { - assert_parses_to("-1.0", Float("-1.0")); - assert_parses_to("-1.1", Float("-1.1")); - assert_parses_to("-42.0", Float("-42.0")); - assert_parses_to("-42.9", Float("-42.9")); - } - - #[test] - fn float_with_underscores() { - assert_parses_to("1_23_456.0_1_23_456", Float("1_23_456.0_1_23_456")); - assert_parses_to("-1_23_456.0_1_23_456", Float("-1_23_456.0_1_23_456")); - } - - #[test] - fn highest_float() { - let string = format!("{}.0", f64::MAX); - - assert_parses_to(&string, Float(&string)); - } - - #[test] - fn lowest_float() { - let string = format!("{}.0", f64::MIN); - - assert_parses_to(&string, Float(&string)); - } - - #[test] - fn pos_inf_float() { - assert_parses_to( - "inf", - Var { - module_name: "", - ident: "inf", - }, - ); - } - - #[test] - fn neg_inf_float() { - let arena = Bump::new(); - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Negate); - let inf_expr = Var { - module_name: "", - ident: "inf", - }; - let loc_inf_expr = Located::new(0, 0, 1, 4, inf_expr); - assert_parses_to("-inf", UnaryOp(arena.alloc(loc_inf_expr), loc_op)); - } - #[quickcheck] fn all_f64_values_parse(num: f64) { let string = num.to_string(); @@ -665,1681 +481,6 @@ mod test_parse { } } - // RECORD LITERALS - - #[test] - fn empty_record() { - let expected = Record(Collection::empty()); - - assert_parses_to("{}", expected); - } - - #[test] - fn record_update() { - let arena = Bump::new(); - let label1 = RequiredValue( - Located::new(0, 0, 16, 17, "x"), - &[], - arena.alloc(Located::new(0, 0, 19, 20, Num("5"))), - ); - let label2 = RequiredValue( - Located::new(0, 0, 22, 23, "y"), - &[], - arena.alloc(Located::new(0, 0, 25, 26, Num("0"))), - ); - let fields: &[_] = &[ - Located::new(0, 0, 16, 20, label1), - Located::new(0, 0, 22, 26, label2), - ]; - let var = Var { - module_name: "Foo.Bar", - ident: "baz", - }; - let update_target = Located::new(0, 0, 2, 13, var); - let expected = RecordUpdate { - update: &*arena.alloc(update_target), - fields: Collection::with_items(fields), - }; - - let actual = save_parse_expr_with(&arena, "{ Foo.Bar.baz & x: 5, y: 0 }"); - assert_eq!(Ok(expected), actual); - } - - #[test] - fn record_with_if() { - let arena = Bump::new(); - let if_expr = Expr::If( - arena.alloc([( - Located::new(0, 0, 8, 12, Expr::GlobalTag("True")), - Located::new(0, 0, 18, 19, Expr::Num("1")), - )]), - arena.alloc(Located::new(0, 0, 25, 26, Num("2"))), - ); - - let label1 = RequiredValue( - Located::new(0, 0, 1, 2, "x"), - &[], - arena.alloc(Located::new(0, 0, 5, 26, if_expr)), - ); - let label2 = RequiredValue( - Located::new(0, 0, 28, 29, "y"), - &[], - arena.alloc(Located::new(0, 0, 31, 32, Num("3"))), - ); - let fields = &[ - Located::new(0, 0, 1, 26, label1), - Located::new(0, 0, 28, 32, label2), - ]; - let expected = Record(Collection::with_items(fields)); - - let actual = save_parse_expr_with(&arena, "{x : if True then 1 else 2, y: 3 }"); - assert_eq!(Ok(expected), actual); - } - - // EXPECT - - #[test] - fn expect() { - let arena = Bump::new(); - - let equals = ( - Located::new(0, 0, 7, 8, Num("1")), - Located::new(0, 0, 9, 11, BinOp::Equals), - ); - - let condition = BinOps( - arena.alloc([equals]), - arena.alloc(Located::new(0, 0, 12, 13, Num("1"))), - ); - let loc_condition = Located::new(0, 0, 7, 13, condition); - - let continuation = Expr::SpaceBefore(arena.alloc(Num("4")), &[Newline, Newline]); - let loc_continuation = Located::new(2, 2, 0, 1, continuation); - - let expected = Expect(arena.alloc(loc_condition), arena.alloc(loc_continuation)); - - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - expect 1 == 1 - - 4 - "# - ), - ); - assert_eq!(Ok(expected), actual); - } - - // OPERATORS - - #[test] - fn one_plus_two() { - let arena = Bump::new(); - let tuple = ( - Located::new(0, 0, 0, 1, Num("1")), - Located::new(0, 0, 1, 2, Plus), - Located::new(0, 0, 2, 3, Num("2")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "1+2"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn one_minus_two() { - let arena = Bump::new(); - let tuple = ( - Located::new(0, 0, 0, 1, Num("1")), - Located::new(0, 0, 1, 2, Minus), - Located::new(0, 0, 2, 3, Num("2")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "1-2"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn var_minus_two() { - let arena = Bump::new(); - let tuple = ( - Located::new( - 0, - 0, - 0, - 1, - Var { - module_name: "", - ident: "x", - }, - ), - Located::new(0, 0, 1, 2, Minus), - Located::new(0, 0, 2, 3, Num("2")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "x-2"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn add_with_spaces() { - let arena = Bump::new(); - let tuple = ( - Located::new(0, 0, 0, 1, Num("1")), - Located::new(0, 0, 3, 4, Plus), - Located::new(0, 0, 7, 8, Num("2")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "1 + 2"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn sub_with_spaces() { - let arena = Bump::new(); - let tuple = ( - Located::new(0, 0, 0, 1, Num("1")), - Located::new(0, 0, 3, 4, Minus), - Located::new(0, 0, 7, 8, Num("2")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "1 - 2"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn add_var_with_spaces() { - // This is a regression test! It used to break with subtraction and work - // with other arithmetic operatos. - // - // Subtraction is special when it comes to parsing, because of unary negation. - - let arena = Bump::new(); - let var = Var { - module_name: "", - ident: "x", - }; - let tuple = ( - Located::new(0, 0, 0, 1, var), - Located::new(0, 0, 2, 3, Plus), - Located::new(0, 0, 4, 5, Num("2")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "x + 2"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn sub_var_with_spaces() { - // This is a regression test! It used to break with subtraction and work - // with other arithmetic operatos. - // - // Subtraction is special when it comes to parsing, because of unary negation. - let arena = Bump::new(); - let var = Var { - module_name: "", - ident: "x", - }; - let tuple = ( - Located::new(0, 0, 0, 1, var), - Located::new(0, 0, 2, 3, Minus), - Located::new(0, 0, 4, 5, Num("2")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "x - 2"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn newline_before_add() { - let arena = Bump::new(); - let spaced_int = Expr::SpaceAfter(arena.alloc(Num("3")), &[Newline]); - let tuple = ( - Located::new(0, 0, 0, 1, spaced_int), - Located::new(1, 1, 0, 1, Plus), - Located::new(1, 1, 2, 3, Num("4")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "3 \n+ 4"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn newline_before_sub() { - let arena = Bump::new(); - let spaced_int = Expr::SpaceAfter(arena.alloc(Num("3")), &[Newline]); - let tuple = ( - Located::new(0, 0, 0, 1, spaced_int), - Located::new(1, 1, 0, 1, Minus), - Located::new(1, 1, 2, 3, Num("4")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "3 \n- 4"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn newline_after_mul() { - let arena = Bump::new(); - let spaced_int = arena.alloc(Num("4")).before(&[Newline]); - let tuple = ( - Located::new(0, 0, 0, 1, Num("3")), - Located::new(0, 0, 3, 4, Star), - Located::new(1, 1, 2, 3, spaced_int), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "3 *\n 4"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn newline_after_sub() { - let arena = Bump::new(); - let spaced_int = arena.alloc(Num("4")).before(&[Newline]); - let tuple = ( - Located::new(0, 0, 0, 1, Num("3")), - Located::new(0, 0, 3, 4, Minus), - Located::new(1, 1, 2, 3, spaced_int), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "3 -\n 4"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn newline_and_spaces_before_less_than() { - let arena = Bump::new(); - let spaced_int = arena.alloc(Num("1")).after(&[Newline]); - let tuple = ( - Located::new(0, 0, 4, 5, spaced_int), - Located::new(1, 1, 4, 5, LessThan), - Located::new(1, 1, 6, 7, Num("2")), - ); - - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let def = Def::Body( - arena.alloc(Located::new(0, 0, 0, 1, Identifier("x"))), - arena.alloc(Located::new(0, 1, 4, 7, single_binop(&arena, tuple))), - ); - let loc_def = &*arena.alloc(Located::new(0, 1, 0, 7, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice()); - let loc_ret = Located::new(3, 3, 0, 2, ret); - let expected = Defs(defs, arena.alloc(loc_ret)); - - // let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "x = 1\n < 2\n\n42"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn comment_with_non_ascii() { - let arena = Bump::new(); - let spaced_int = arena.alloc(Num("3")).after(&[LineComment(" 2 Γ— 2")]); - let tuple = ( - Located::new(0, 0, 0, 1, spaced_int), - Located::new(1, 1, 0, 1, Plus), - Located::new(1, 1, 2, 3, Num("4")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "3 # 2 Γ— 2\n+ 4"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn comment_before_op() { - let arena = Bump::new(); - let spaced_int = arena.alloc(Num("3")).after(&[LineComment(" test!")]); - let tuple = ( - Located::new(0, 0, 0, 1, spaced_int), - Located::new(1, 1, 0, 1, Plus), - Located::new(1, 1, 2, 3, Num("4")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "3 # test!\n+ 4"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn comment_after_op() { - let arena = Bump::new(); - let spaced_int = arena.alloc(Num("92")).before(&[LineComment(" test!")]); - let tuple = ( - Located::new(0, 0, 0, 2, Num("12")), - Located::new(0, 0, 4, 5, Star), - Located::new(1, 1, 1, 3, spaced_int), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "12 * # test!\n 92"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn ops_with_newlines() { - let arena = Bump::new(); - let spaced_int1 = arena.alloc(Num("3")).after(&[Newline]); - let spaced_int2 = arena.alloc(Num("4")).before(&[Newline, Newline]); - let tuple = ( - Located::new(0, 0, 0, 1, spaced_int1), - Located::new(1, 1, 0, 1, Plus), - Located::new(3, 3, 2, 3, spaced_int2), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "3 \n+ \n\n 4"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn space_only_after_minus() { - // This is an edge case with minus because of unary negation. - // (x- y) should parse like subtraction (x - (y)), not function application (x (-y)) - let arena = Bump::new(); - let var1 = Var { - module_name: "", - ident: "x", - }; - let var2 = Var { - module_name: "", - ident: "y", - }; - let tuple = ( - Located::new(0, 0, 0, 1, var1), - Located::new(0, 0, 1, 2, Minus), - Located::new(0, 0, 3, 4, var2), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "x- y"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn minus_twelve_minus_five() { - let arena = Bump::new(); - let tuple = ( - Located::new(0, 0, 0, 3, Num("-12")), - Located::new(0, 0, 3, 4, Minus), - Located::new(0, 0, 4, 5, Num("5")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "-12-5"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn ten_times_eleven() { - let arena = Bump::new(); - let tuple = ( - Located::new(0, 0, 0, 2, Num("10")), - Located::new(0, 0, 2, 3, Star), - Located::new(0, 0, 3, 5, Num("11")), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "10*11"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn multiple_operators() { - let arena = Bump::new(); - - let lefts = [ - ( - Located::new(0, 0, 0, 2, Num("31")), - Located::new(0, 0, 2, 3, Star), - ), - ( - Located::new(0, 0, 3, 5, Num("42")), - Located::new(0, 0, 5, 6, Plus), - ), - ]; - let right = Located::new(0, 0, 6, 9, Num("534")); - - let expected = BinOps(&lefts, &right); - let actual = save_parse_expr_with(&arena, "31*42+534"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn equals() { - let arena = Bump::new(); - let var1 = Var { - module_name: "", - ident: "x", - }; - let var2 = Var { - module_name: "", - ident: "y", - }; - let tuple = ( - Located::new(0, 0, 0, 1, var1), - Located::new(0, 0, 1, 3, Equals), - Located::new(0, 0, 3, 4, var2), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "x==y"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn equals_with_spaces() { - let arena = Bump::new(); - let var1 = Var { - module_name: "", - ident: "x", - }; - let var2 = Var { - module_name: "", - ident: "y", - }; - let tuple = ( - Located::new(0, 0, 0, 1, var1), - Located::new(0, 0, 2, 4, Equals), - Located::new(0, 0, 5, 6, var2), - ); - let expected = single_binop(&arena, tuple); - let actual = save_parse_expr_with(&arena, "x == y"); - - assert_eq!(Ok(expected), actual); - } - - // VAR - - #[test] - fn basic_var() { - let arena = Bump::new(); - let expected = Var { - module_name: "", - ident: "whee", - }; - let actual = save_parse_expr_with(&arena, "whee"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn var_when() { - // Regression test for identifiers beginning with keywords (if/then/else/when/is) - let arena = Bump::new(); - let expected = Var { - module_name: "", - ident: "whenever", - }; - let actual = save_parse_expr_with(&arena, "whenever"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn var_is() { - // Regression test for identifiers beginning with keywords (if/then/else/when/is) - let arena = Bump::new(); - let expected = Var { - module_name: "", - ident: "isnt", - }; - let actual = save_parse_expr_with(&arena, "isnt"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn var_if() { - // Regression test for identifiers beginning with keywords (if/then/else/when/is) - let arena = Bump::new(); - let expected = Var { - module_name: "", - ident: "iffy", - }; - let actual = save_parse_expr_with(&arena, "iffy"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn var_then() { - // Regression test for identifiers beginning with keywords (if/then/else/when/is) - let arena = Bump::new(); - let expected = Var { - module_name: "", - ident: "thenever", - }; - let actual = save_parse_expr_with(&arena, "thenever"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn var_else() { - // Regression test for identifiers beginning with keywords (if/then/else/when/is) - let arena = Bump::new(); - let expected = Var { - module_name: "", - ident: "elsewhere", - }; - let actual = save_parse_expr_with(&arena, "elsewhere"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn parenthetical_var() { - let arena = Bump::new(); - let expected = ParensAround(arena.alloc(Var { - module_name: "", - ident: "whee", - })); - let actual = save_parse_expr_with(&arena, "(whee)"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn qualified_var() { - let arena = Bump::new(); - let expected = Var { - module_name: "One.Two", - ident: "whee", - }; - let actual = save_parse_expr_with(&arena, "One.Two.whee"); - - assert_eq!(Ok(expected), actual); - } - - // TAG - - #[test] - fn basic_global_tag() { - let arena = Bump::new(); - let expected = Expr::GlobalTag("Whee"); - let actual = save_parse_expr_with(&arena, "Whee"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn basic_private_tag() { - let arena = Bump::new(); - let expected = Expr::PrivateTag("@Whee"); - let actual = save_parse_expr_with(&arena, "@Whee"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn apply_private_tag() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 6, 8, Num("12"))); - let arg2 = arena.alloc(Located::new(0, 0, 9, 11, Num("34"))); - let args = &[&*arg1, &*arg2]; - let expected = Expr::Apply( - arena.alloc(Located::new(0, 0, 0, 5, Expr::PrivateTag("@Whee"))), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "@Whee 12 34"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn apply_global_tag() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 5, 7, Num("12"))); - let arg2 = arena.alloc(Located::new(0, 0, 8, 10, Num("34"))); - let args = &[&*arg1, &*arg2]; - let expected = Expr::Apply( - arena.alloc(Located::new(0, 0, 0, 4, Expr::GlobalTag("Whee"))), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "Whee 12 34"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn apply_parenthetical_global_tag_args() { - let arena = Bump::new(); - let int1 = ParensAround(arena.alloc(Num("12"))); - let int2 = ParensAround(arena.alloc(Num("34"))); - let arg1 = arena.alloc(Located::new(0, 0, 6, 8, int1)); - let arg2 = arena.alloc(Located::new(0, 0, 11, 13, int2)); - let args = &[&*arg1, &*arg2]; - let expected = Expr::Apply( - arena.alloc(Located::new(0, 0, 0, 4, Expr::GlobalTag("Whee"))), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "Whee (12) (34)"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn qualified_global_tag() { - use roc_parse::ident::BadIdent; - - let arena = Bump::new(); - let expected = Expr::MalformedIdent("One.Two.Whee", BadIdent::QualifiedTag(0, 12)); - let actual = save_parse_expr_with(&arena, "One.Two.Whee"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn private_qualified_tag() { - use roc_parse::ident::BadIdent; - - let arena = Bump::new(); - let expected = Expr::MalformedIdent("@One.Two.Whee", BadIdent::BadPrivateTag(0, 4)); - let actual = save_parse_expr_with(&arena, "@One.Two.Whee"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn tag_pattern() { - let arena = Bump::new(); - let pattern = Located::new(0, 0, 1, 6, Pattern::GlobalTag("Thing")); - let patterns = &[pattern]; - let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 10, 12, Num("42")))); - let actual = save_parse_expr_with(&arena, "\\Thing -> 42"); - - assert_eq!(Ok(expected), actual); - } - - // LISTS - - #[test] - fn empty_list() { - let arena = Bump::new(); - let expected = List(Collection::empty()); - let actual = save_parse_expr_with(&arena, "[]"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn spaces_inside_empty_list() { - // This is a regression test! - let arena = Bump::new(); - let expected = List(Collection::empty()); - let actual = save_parse_expr_with(&arena, "[ ]"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn newline_inside_empty_list() { - let arena = Bump::new(); - let expected = List(Collection::with_items_and_comments(&arena, &[], &[Newline])); - let actual = save_parse_expr_with(&arena, "[\n]"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn comment_inside_empty_list() { - let arena = Bump::new(); - let expected = List(Collection::with_items_and_comments( - &arena, - &[], - &[LineComment("comment")], - )); - let actual = save_parse_expr_with(&arena, "[#comment\n]"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn packed_singleton_list() { - let arena = Bump::new(); - let items = &[&*arena.alloc(Located::new(0, 0, 1, 2, Num("1")))]; - let expected = List(Collection::with_items(items)); - let actual = save_parse_expr_with(&arena, "[1]"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn spaced_singleton_list() { - let arena = Bump::new(); - let items = &[&*arena.alloc(Located::new(0, 0, 2, 3, Num("1")))]; - let expected = List(Collection::with_items(items)); - let actual = save_parse_expr_with(&arena, "[ 1 ]"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn newline_singleton_list() { - let arena = Bump::new(); - let item = &*arena.alloc(Expr::SpaceAfter( - arena.alloc(Num("1")), - arena.alloc([Newline]), - )); - let item = Expr::SpaceBefore(item, arena.alloc([Newline])); - let items = [&*arena.alloc(Located::new(1, 1, 0, 1, item))]; - let expected = List(Collection::with_items(&items)); - let actual = save_parse_expr_with(&arena, "[\n1\n]"); - - assert_eq!(Ok(expected), actual); - } - - // FIELD ACCESS - - #[test] - fn basic_field() { - let arena = Bump::new(); - let var = Var { - module_name: "", - ident: "rec", - }; - let expected = Access(arena.alloc(var), "field"); - let actual = save_parse_expr_with(&arena, "rec.field"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn parenthetical_basic_field() { - let arena = Bump::new(); - let paren_var = ParensAround(arena.alloc(Var { - module_name: "", - ident: "rec", - })); - let expected = Access(arena.alloc(paren_var), "field"); - let actual = save_parse_expr_with(&arena, "(rec).field"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn parenthetical_field_qualified_var() { - let arena = Bump::new(); - let paren_var = ParensAround(arena.alloc(Var { - module_name: "One.Two", - ident: "rec", - })); - let expected = Access(arena.alloc(paren_var), "field"); - let actual = save_parse_expr_with(&arena, "(One.Two.rec).field"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn multiple_fields() { - let arena = Bump::new(); - let var = Var { - module_name: "", - ident: "rec", - }; - let expected = Access( - arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")), - "ghi", - ); - let actual = save_parse_expr_with(&arena, "rec.abc.def.ghi"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn qualified_field() { - let arena = Bump::new(); - let var = Var { - module_name: "One.Two", - ident: "rec", - }; - let expected = Access( - arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")), - "ghi", - ); - let actual = save_parse_expr_with(&arena, "One.Two.rec.abc.def.ghi"); - - assert_eq!(Ok(expected), actual); - } - - // APPLY - - #[test] - fn basic_apply() { - let arena = Bump::new(); - let arg = arena.alloc(Located::new(0, 0, 5, 6, Num("1"))); - let args = &[&*arg]; - let expr = Var { - module_name: "", - ident: "whee", - }; - let expected = Expr::Apply( - arena.alloc(Located::new(0, 0, 0, 4, expr)), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "whee 1"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn apply_two_args() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 6, 8, Num("12"))); - let arg2 = arena.alloc(Located::new(0, 0, 10, 12, Num("34"))); - let args = &[&*arg1, &*arg2]; - let expected = Expr::Apply( - arena.alloc(Located::new( - 0, - 0, - 0, - 4, - Var { - module_name: "", - ident: "whee", - }, - )), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "whee 12 34"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn apply_three_args() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new( - 0, - 0, - 2, - 3, - Var { - module_name: "", - ident: "b", - }, - )); - let arg2 = arena.alloc(Located::new( - 0, - 0, - 4, - 5, - Var { - module_name: "", - ident: "c", - }, - )); - let arg3 = arena.alloc(Located::new( - 0, - 0, - 6, - 7, - Var { - module_name: "", - ident: "d", - }, - )); - let args = &[&*arg1, &*arg2, &*arg3]; - let expected = Expr::Apply( - arena.alloc(Located::new( - 0, - 0, - 0, - 1, - Var { - module_name: "", - ident: "a", - }, - )), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "a b c d"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn parenthetical_apply() { - let arena = Bump::new(); - let arg = arena.alloc(Located::new(0, 0, 7, 8, Num("1"))); - let args = &[&*arg]; - let parens_var = Expr::ParensAround(arena.alloc(Var { - module_name: "", - ident: "whee", - })); - let expected = Expr::Apply( - arena.alloc(Located::new(0, 0, 1, 5, parens_var)), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "(whee) 1"); - - assert_eq!(Ok(expected), actual); - } - - // UNARY OPERATORS - - #[test] - fn unary_negation() { - let arena = Bump::new(); - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Negate); - let arg1_expr = Var { - module_name: "", - ident: "foo", - }; - let loc_arg1_expr = Located::new(0, 0, 1, 4, arg1_expr); - let expected = UnaryOp(arena.alloc(loc_arg1_expr), loc_op); - let actual = save_parse_expr_with(&arena, "-foo"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn unary_not() { - let arena = Bump::new(); - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Not); - let arg1_expr = Var { - module_name: "", - ident: "blah", - }; - let loc_arg1_expr = Located::new(0, 0, 1, 5, arg1_expr); - let expected = UnaryOp(arena.alloc(loc_arg1_expr), loc_op); - let actual = save_parse_expr_with(&arena, "!blah"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn apply_unary_negation() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 7, 9, Num("12"))); - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Negate); - let arg2 = arena.alloc(Located::new( - 0, - 0, - 10, - 13, - Var { - module_name: "", - ident: "foo", - }, - )); - let args = &[&*arg1, &*arg2]; - let function = Located::new( - 0, - 0, - 1, - 5, - Var { - module_name: "", - ident: "whee", - }, - ); - let unary = Located::new(0, 0, 0, 5, UnaryOp(arena.alloc(function), loc_op)); - let expected = Expr::Apply(arena.alloc(unary), args, CalledVia::Space); - let actual = save_parse_expr_with(&arena, "-whee 12 foo"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn apply_unary_not() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 7, 9, Num("12"))); - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Not); - let arg2 = arena.alloc(Located::new( - 0, - 0, - 10, - 13, - Var { - module_name: "", - ident: "foo", - }, - )); - let args = &[&*arg1, &*arg2]; - - let function = Located::new( - 0, - 0, - 1, - 5, - Var { - module_name: "", - ident: "whee", - }, - ); - let unary = Located::new(0, 0, 0, 5, UnaryOp(arena.alloc(function), loc_op)); - let expected = Expr::Apply(arena.alloc(unary), args, CalledVia::Space); - let actual = save_parse_expr_with(&arena, "!whee 12 foo"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn unary_negation_with_parens() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 8, 10, Num("12"))); - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Negate); - let arg2 = arena.alloc(Located::new( - 0, - 0, - 11, - 14, - Var { - module_name: "", - ident: "foo", - }, - )); - let args = &[&*arg1, &*arg2]; - let apply_expr = Expr::ParensAround(arena.alloc(Expr::Apply( - arena.alloc(Located::new( - 0, - 0, - 2, - 6, - Var { - module_name: "", - ident: "whee", - }, - )), - args, - CalledVia::Space, - ))); - let expected = UnaryOp(arena.alloc(Located::new(0, 0, 2, 14, apply_expr)), loc_op); - let actual = save_parse_expr_with(&arena, "-(whee 12 foo)"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn unary_not_with_parens() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 8, 10, Num("12"))); - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Not); - let arg2 = arena.alloc(Located::new( - 0, - 0, - 11, - 14, - Var { - module_name: "", - ident: "foo", - }, - )); - let args = &[&*arg1, &*arg2]; - let apply_expr = Expr::ParensAround(arena.alloc(Expr::Apply( - arena.alloc(Located::new( - 0, - 0, - 2, - 6, - Var { - module_name: "", - ident: "whee", - }, - )), - args, - CalledVia::Space, - ))); - let expected = UnaryOp(arena.alloc(Located::new(0, 0, 2, 14, apply_expr)), loc_op); - let actual = save_parse_expr_with(&arena, "!(whee 12 foo)"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn unary_negation_arg() { - let arena = Bump::new(); - let arg1 = arena.alloc(Located::new(0, 0, 6, 8, Num("12"))); - let loc_op = Located::new(0, 0, 9, 10, UnaryOp::Negate); - let var1 = Var { - module_name: "", - ident: "foo", - }; - let loc_arg1_expr = Located::new(0, 0, 10, 13, var1); - let arg_op = UnaryOp(arena.alloc(loc_arg1_expr), loc_op); - let arg2 = arena.alloc(Located::new(0, 0, 9, 13, arg_op)); - let args = &[&*arg1, &*arg2]; - let var2 = Var { - module_name: "", - ident: "whee", - }; - let expected = Expr::Apply( - arena.alloc(Located::new(0, 0, 0, 4, var2)), - args, - CalledVia::Space, - ); - let actual = save_parse_expr_with(&arena, "whee 12 -foo"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn unary_negation_access() { - // Regression test for https://github.com/rtfeldman/roc/issues/509 - let arena = Bump::new(); - let var = Var { - module_name: "", - ident: "rec1", - }; - let loc_op = Located::new(0, 0, 0, 1, UnaryOp::Negate); - let access = Access(arena.alloc(var), "field"); - let loc_access = Located::new(0, 0, 1, 11, access); - let expected = UnaryOp(arena.alloc(loc_access), loc_op); - let actual = save_parse_expr_with(&arena, "-rec1.field"); - - assert_eq!(Ok(expected), actual); - } - - // CLOSURE - - #[test] - fn single_arg_closure() { - let arena = Bump::new(); - let pattern = Located::new(0, 0, 1, 2, Identifier("a")); - let patterns = &[pattern]; - let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42")))); - let actual = save_parse_expr_with(&arena, "\\a -> 42"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn single_underscore_closure() { - let arena = Bump::new(); - let pattern = Located::new(0, 0, 1, 2, Pattern::Underscore("")); - let patterns = &[pattern]; - let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42")))); - let actual = save_parse_expr_with(&arena, "\\_ -> 42"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn malformed_ident_due_to_underscore() { - // This is a regression test against a bug where if you included an - // underscore in an argument name, it would parse as three arguments - // (and would ignore the underscore as if it had been blank space). - let arena = Bump::new(); - - let pattern = Located::new( - 0, - 0, - 1, - 11, - Pattern::MalformedIdent("the_answer", roc_parse::ident::BadIdent::Underscore(0, 5)), - ); - let patterns = &[pattern]; - let expr = Located::new(0, 0, 15, 17, Expr::Num("42")); - - let expected = Closure(patterns, &expr); - let actual = save_parse_expr_with(&arena, "\\the_answer -> 42"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn two_arg_closure() { - let arena = Bump::new(); - let arg1 = Located::new(0, 0, 1, 2, Identifier("a")); - let arg2 = Located::new(0, 0, 4, 5, Identifier("b")); - let patterns = &[arg1, arg2]; - let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 9, 11, Num("42")))); - let actual = save_parse_expr_with(&arena, "\\a, b -> 42"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn three_arg_closure() { - let arena = Bump::new(); - let arg1 = Located::new(0, 0, 1, 2, Identifier("a")); - let arg2 = Located::new(0, 0, 4, 5, Identifier("b")); - let arg3 = Located::new(0, 0, 7, 8, Identifier("c")); - let patterns = bumpalo::vec![in &arena; arg1, arg2, arg3]; - let expected = Closure( - arena.alloc(patterns), - arena.alloc(Located::new(0, 0, 12, 14, Num("42"))), - ); - let actual = save_parse_expr_with(&arena, "\\a, b, c -> 42"); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn closure_with_underscores() { - let arena = Bump::new(); - let underscore1 = Located::new(0, 0, 1, 2, Pattern::Underscore("")); - let underscore2 = Located::new(0, 0, 4, 9, Pattern::Underscore("name")); - let patterns = bumpalo::vec![in &arena; underscore1, underscore2]; - let expected = Closure( - arena.alloc(patterns), - arena.alloc(Located::new(0, 0, 13, 15, Num("42"))), - ); - let actual = save_parse_expr_with(&arena, "\\_, _name -> 42"); - - assert_eq!(Ok(expected), actual); - } - - // DEF - - #[test] - fn one_def() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let def = Def::Body( - arena.alloc(Located::new(1, 1, 0, 1, Identifier("x"))), - arena.alloc(Located::new(1, 1, 2, 3, Num("5"))), - ); - let loc_def = &*arena.alloc(Located::new(1, 1, 0, 3, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice()); - let loc_ret = Located::new(3, 3, 0, 2, ret); - let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")]; - let expected = Expr::SpaceBefore( - arena.alloc(Defs(defs, arena.alloc(loc_ret))), - reset_indentation.into_bump_slice(), - ); - - assert_parses_to( - indoc!( - r#"# leading comment - x=5 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn if_def() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let def = Def::Body( - arena.alloc(Located::new(0, 0, 0, 4, Identifier("iffy"))), - arena.alloc(Located::new(0, 0, 5, 6, Num("5"))), - ); - let loc_def = &*arena.alloc(Located::new(0, 0, 0, 6, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice()); - let loc_ret = Located::new(2, 2, 0, 2, ret); - let expected = Defs(defs, arena.alloc(loc_ret)); - - assert_parses_to( - indoc!( - r#" - iffy=5 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn one_spaced_def() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let def = Def::Body( - arena.alloc(Located::new(1, 1, 0, 1, Identifier("x"))), - arena.alloc(Located::new(1, 1, 4, 5, Num("5"))), - ); - let loc_def = &*arena.alloc(Located::new(1, 1, 0, 5, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice()); - let loc_ret = Located::new(3, 3, 0, 2, ret); - let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")]; - let expected = Expr::SpaceBefore( - arena.alloc(Defs(defs, arena.alloc(loc_ret))), - reset_indentation.into_bump_slice(), - ); - - assert_parses_to( - indoc!( - r#"# leading comment - x = 5 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn two_spaced_def() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let newline = bumpalo::vec![in &arena; Newline]; - let def1 = Def::Body( - arena.alloc(Located::new(1, 1, 0, 1, Identifier("x"))), - arena.alloc(Located::new(1, 1, 4, 5, Num("5"))), - ); - let loc_def1 = &*arena.alloc(Located::new(1, 1, 0, 5, def1)); - let def2 = Def::SpaceBefore( - &*arena.alloc(Def::Body( - arena.alloc(Located::new(2, 2, 0, 1, Identifier("y"))), - arena.alloc(Located::new(2, 2, 4, 5, Num("6"))), - )), - newline.into_bump_slice(), - ); - let loc_def2 = &*arena.alloc(Located::new(2, 2, 0, 5, def2)); - let defs = &[loc_def1, loc_def2]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice()); - let loc_ret = Located::new(4, 4, 0, 2, ret); - let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")]; - let expected = Expr::SpaceBefore( - arena.alloc(Defs(defs, arena.alloc(loc_ret))), - reset_indentation.into_bump_slice(), - ); - - assert_parses_to( - indoc!( - r#"# leading comment - x = 5 - y = 6 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn record_destructure_def() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let newline = bumpalo::vec![in &arena; Newline]; - let fields = bumpalo::vec![in &arena; - Located::new(1, 1, 2, 3, Identifier("x")), - Located::new(1, 1, 5, 7, Identifier("y")) - ]; - let def1 = Def::Body( - arena.alloc(Located::new( - 1, - 1, - 0, - 8, - RecordDestructure(Collection::with_items(&fields)), - )), - arena.alloc(Located::new(1, 1, 11, 12, Num("5"))), - ); - let loc_def1 = &*arena.alloc(Located::new(1, 1, 0, 12, def1)); - let def2 = Def::SpaceBefore( - &*arena.alloc(Def::Body( - arena.alloc(Located::new(2, 2, 0, 1, Identifier("y"))), - arena.alloc(Located::new(2, 2, 4, 5, Num("6"))), - )), - &newline, - ); - let loc_def2 = &*arena.alloc(Located::new(2, 2, 0, 5, def2)); - let defs = &[loc_def1, loc_def2]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), &newlines); - let loc_ret = Located::new(4, 4, 0, 2, ret); - let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")]; - let expected = Expr::SpaceBefore( - arena.alloc(Defs(defs, arena.alloc(loc_ret))), - &reset_indentation, - ); - - assert_parses_to( - indoc!( - r#" - # leading comment - { x, y } = 5 - y = 6 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn one_backpassing() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let identifier_x = Located::new(1, 1, 0, 1, Identifier("x")); - let identifier_y = Located::new(1, 1, 7, 8, Identifier("y")); - - let var_x = Var { - module_name: "", - ident: "x", - }; - - let var_y = Var { - module_name: "", - ident: "y", - }; - let loc_var_y = arena.alloc(Located::new(1, 1, 12, 13, var_y)); - - let closure = ParensAround(arena.alloc(Closure(arena.alloc([identifier_y]), loc_var_y))); - let loc_closure = Located::new(1, 1, 5, 14, closure); - - let ret = Expr::SpaceBefore(arena.alloc(var_x), newlines.into_bump_slice()); - let loc_ret = Located::new(3, 3, 0, 1, ret); - - let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")]; - let expected = Expr::SpaceBefore( - arena.alloc(Expr::Backpassing( - arena.alloc([identifier_x]), - arena.alloc(loc_closure), - arena.alloc(loc_ret), - )), - reset_indentation.into_bump_slice(), - ); - - assert_parses_to( - indoc!( - r#"# leading comment - x <- (\y -> y) - - x - "# - ), - expected, - ); - } - - #[test] - fn underscore_backpassing() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let underscore = Located::new(1, 1, 0, 1, Pattern::Underscore("")); - let identifier_y = Located::new(1, 1, 7, 8, Identifier("y")); - - let num_4 = Num("4"); - - let var_y = Var { - module_name: "", - ident: "y", - }; - let loc_var_y = arena.alloc(Located::new(1, 1, 12, 13, var_y)); - - let closure = ParensAround(arena.alloc(Closure(arena.alloc([identifier_y]), loc_var_y))); - let loc_closure = Located::new(1, 1, 5, 14, closure); - - let ret = Expr::SpaceBefore(arena.alloc(num_4), newlines.into_bump_slice()); - let loc_ret = Located::new(3, 3, 0, 1, ret); - - let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")]; - let expected = Expr::SpaceBefore( - arena.alloc(Expr::Backpassing( - arena.alloc([underscore]), - arena.alloc(loc_closure), - arena.alloc(loc_ret), - )), - reset_indentation.into_bump_slice(), - ); - - assert_parses_to( - indoc!( - r#"# leading comment - _ <- (\y -> y) - - 4 - "# - ), - expected, - ); - } - - #[test] - fn two_backpassing() { - let arena = Bump::new(); - - let inner_backpassing = { - let identifier_z = Located::new(2, 2, 0, 1, Identifier("z")); - - let empty_record = Record(Collection::empty()); - let loc_empty_record = Located::new(2, 2, 5, 7, empty_record); - - let var_x = Var { - module_name: "", - ident: "x", - }; - - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let ret = Expr::SpaceBefore(arena.alloc(var_x), newlines.into_bump_slice()); - let loc_ret = Located::new(4, 4, 0, 1, ret); - - Expr::SpaceBefore( - arena.alloc(Expr::Backpassing( - arena.alloc([identifier_z]), - arena.alloc(loc_empty_record), - arena.alloc(loc_ret), - )), - arena.alloc([Newline]), - ) - }; - - let identifier_x = Located::new(1, 1, 0, 1, Identifier("x")); - let identifier_y = Located::new(1, 1, 7, 8, Identifier("y")); - - let var_y = Var { - module_name: "", - ident: "y", - }; - let loc_var_y = arena.alloc(Located::new(1, 1, 12, 13, var_y)); - - let closure = ParensAround(arena.alloc(Closure(arena.alloc([identifier_y]), loc_var_y))); - let loc_closure = Located::new(1, 1, 5, 14, closure); - - let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")]; - let expected = Expr::SpaceBefore( - arena.alloc(Expr::Backpassing( - arena.alloc([identifier_x]), - arena.alloc(loc_closure), - arena.alloc(Located::new(2, 4, 0, 1, inner_backpassing)), - )), - reset_indentation.into_bump_slice(), - ); - - assert_parses_to( - indoc!( - r#"# leading comment - x <- (\y -> y) - z <- {} - - x - "# - ), - expected, - ); - } - - #[test] - fn multi_backpassing() { - let arena = Bump::new(); - - let identifier_x = Located::new(0, 0, 0, 1, Identifier("x")); - let identifier_y = Located::new(0, 0, 3, 4, Identifier("y")); - - let var_x = Var { - module_name: "", - ident: "x", - }; - let loc_var_x = Located::new(2, 2, 0, 1, var_x); - - let var_y = Var { - module_name: "", - ident: "y", - }; - let loc_var_y = Located::new(2, 2, 4, 5, var_y); - - let var_list_map2 = Var { - module_name: "List", - ident: "map2", - }; - - let apply = Expr::Apply( - arena.alloc(Located::new(0, 0, 8, 17, var_list_map2)), - bumpalo::vec![ in &arena; - &*arena.alloc(Located::new(0, 0, 18, 20, Expr::List(Collection::empty()))), - &*arena.alloc(Located::new(0, 0, 21, 23, Expr::List(Collection::empty()))), - ] - .into_bump_slice(), - CalledVia::Space, - ); - - let loc_closure = Located::new(0, 0, 8, 23, apply); - - let binop = single_binop( - &arena, - ( - loc_var_x, - Located::new(2, 2, 2, 3, roc_module::operator::BinOp::Plus), - loc_var_y, - ), - ); - - let spaced_binop = Expr::SpaceBefore(arena.alloc(binop), &[Newline, Newline]); - - let expected = Expr::Backpassing( - arena.alloc([identifier_x, identifier_y]), - arena.alloc(loc_closure), - arena.alloc(Located::new(2, 2, 0, 5, spaced_binop)), - ); - - assert_parses_to( - indoc!( - r#" - x, y <- List.map2 [] [] - - x + y - "# - ), - expected, - ); - } - // #[test] // fn type_signature_def() { // let arena = Bump::new(); @@ -2376,156 +517,6 @@ mod test_parse { // ); // } - #[test] - fn parse_as_ann() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let loc_x = Located::new(0, 0, 18, 19, TypeAnnotation::BoundVariable("x")); - let loc_y = Located::new(0, 0, 20, 21, TypeAnnotation::BoundVariable("y")); - let loc_a = Located::new(0, 0, 30, 31, TypeAnnotation::BoundVariable("a")); - let loc_b = Located::new(0, 0, 32, 33, TypeAnnotation::BoundVariable("b")); - let applied_ann_args = bumpalo::vec![in &arena; loc_x, loc_y]; - let applied_ann = - TypeAnnotation::Apply("Foo.Bar", "Baz", applied_ann_args.into_bump_slice()); - let loc_applied_ann = &*arena.alloc(Located::new(0, 0, 6, 21, applied_ann)); - let applied_as_args = bumpalo::vec![in &arena; loc_a, loc_b]; - let applied_as = TypeAnnotation::Apply("", "Blah", applied_as_args.into_bump_slice()); - let loc_applied_as = &*arena.alloc(Located::new(0, 0, 25, 33, applied_as)); - let as_ann = TypeAnnotation::As(loc_applied_ann, &[], loc_applied_as); - let signature = Def::Annotation( - Located::new(0, 0, 0, 3, Identifier("foo")), - Located::new(0, 0, 6, 33, as_ann), - ); - - let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 33, signature)); - let defs = &[loc_ann]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice()); - let loc_ret = Located::new(2, 2, 0, 2, ret); - let expected = Defs(defs, arena.alloc(loc_ret)); - - assert_parses_to( - indoc!( - r#" - foo : Foo.Bar.Baz x y as Blah a b - - 42 - "# - ), - expected, - ); - } - - #[test] - fn parse_alias() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline, Newline]; - let loc_x = Located::new(0, 0, 23, 24, TypeAnnotation::BoundVariable("x")); - let loc_y = Located::new(0, 0, 25, 26, TypeAnnotation::BoundVariable("y")); - let loc_a = Located::new(0, 0, 5, 6, Pattern::Identifier("a")); - let loc_b = Located::new(0, 0, 7, 8, Pattern::Identifier("b")); - let applied_ann_args = bumpalo::vec![in &arena; loc_a, loc_b]; - let applied_alias_args = bumpalo::vec![in &arena; loc_x, loc_y]; - let applied_alias = - TypeAnnotation::Apply("Foo.Bar", "Baz", applied_alias_args.into_bump_slice()); - let signature = Def::Alias { - name: Located::new(0, 0, 0, 4, "Blah"), - vars: applied_ann_args.into_bump_slice(), - ann: Located::new(0, 0, 11, 26, applied_alias), - }; - - let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 26, signature)); - let defs = &[loc_ann]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice()); - let loc_ret = Located::new(2, 2, 0, 2, ret); - let expected = Defs(defs, arena.alloc(loc_ret)); - - assert_parses_to( - indoc!( - r#" - Blah a b : Foo.Bar.Baz x y - - 42 - "# - ), - expected, - ); - } - - #[test] - fn multiline_type_signature() { - assert_parses_to( - "f :\n {}\n\n42", - Defs( - &[&Located::new( - 0, - 1, - 0, - 6, - Def::Annotation( - Located::new(0, 0, 0, 1, Pattern::Identifier("f")), - Located::new( - 1, - 1, - 4, - 6, - TypeAnnotation::SpaceBefore( - &TypeAnnotation::Record { - fields: Collection::empty(), - ext: None, - }, - &[Newline], - ), - ), - ), - )], - &Located::new( - 3, - 3, - 0, - 2, - Expr::SpaceBefore(&Expr::Num("42"), &[Newline, Newline]), - ), - ), - ); - } - - #[test] - fn multiline_type_signature_with_comment() { - assert_parses_to( - "f :# comment\n {}\n\n42", - Defs( - &[&Located::new( - 0, - 1, - 0, - 6, - Def::Annotation( - Located::new(0, 0, 0, 1, Pattern::Identifier("f")), - Located::new( - 1, - 1, - 4, - 6, - TypeAnnotation::SpaceBefore( - &TypeAnnotation::Record { - fields: Collection::empty(), - ext: None, - }, - &[LineComment(" comment")], - ), - ), - ), - )], - &Located::new( - 3, - 3, - 0, - 2, - Expr::SpaceBefore(&Expr::Num("42"), &[Newline, Newline]), - ), - ), - ); - } // #[test] // fn type_signature_function_def() { // use TypeAnnotation; @@ -2797,488 +788,6 @@ mod test_parse { // ); // } - // WHEN - - #[test] - fn two_branch_when() { - let arena = Bump::new(); - let newlines = bumpalo::vec![in &arena; Newline]; - let pattern1 = Pattern::SpaceBefore( - arena.alloc(StrLiteral(PlainLine(""))), - newlines.into_bump_slice(), - ); - let loc_pattern1 = Located::new(1, 1, 1, 3, pattern1); - let expr1 = Num("1"); - let loc_expr1 = Located::new(1, 1, 7, 8, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("mise"))), newlines); - let loc_pattern2 = Located::new(2, 2, 1, 7, pattern2); - let expr2 = Num("2"); - let loc_expr2 = Located::new(2, 2, 11, 12, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - "" -> 1 - "mise" -> 2 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_with_numbers() { - let arena = Bump::new(); - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(NumLiteral("1")), newlines); - let loc_pattern1 = Located::new(1, 1, 1, 2, pattern1); - let expr1 = Num("2"); - let loc_expr1 = Located::new(1, 1, 6, 7, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(NumLiteral("3")), newlines); - let loc_pattern2 = Located::new(2, 2, 1, 2, pattern2); - let expr2 = Num("4"); - let loc_expr2 = Located::new(2, 2, 6, 7, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - 1 -> 2 - 3 -> 4 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_with_negative_numbers() { - let arena = Bump::new(); - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(NumLiteral("1")), newlines); - let loc_pattern1 = Located::new(1, 1, 1, 2, pattern1); - let expr1 = Num("2"); - let loc_expr1 = Located::new(1, 1, 6, 7, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(NumLiteral("-3")), newlines); - let loc_pattern2 = Located::new(2, 2, 1, 3, pattern2); - let expr2 = Num("4"); - let loc_expr2 = Located::new(2, 2, 7, 8, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - 1 -> 2 - -3 -> 4 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_with_function_application() { - let arena = Bump::new(); - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(NumLiteral("1")), newlines); - let loc_pattern1 = Located::new(1, 1, 4, 5, pattern1); - let num_2 = Num("2"); - let num_neg = Located::new( - 1, - 1, - 9, - 16, - Expr::Var { - module_name: "Num", - ident: "neg", - }, - ); - let expr0 = Located::new(2, 2, 5, 6, Expr::SpaceBefore(&num_2, &[Newline])); - let expr1 = Expr::Apply( - &num_neg, - &*arena.alloc([&*arena.alloc(expr0)]), - CalledVia::Space, - ); - let loc_expr1 = Located::new(1, 2, 9, 6, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), newlines); - let loc_pattern2 = Located::new(3, 3, 4, 5, pattern2); - let expr2 = Num("4"); - let loc_expr2 = Located::new(3, 3, 9, 10, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - 1 -> Num.neg - 2 - _ -> 4 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_if_guard() { - let arena = Bump::new(); - - let branch1 = { - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), newlines); - let loc_pattern1 = Located::new(1, 1, 4, 5, pattern1); - let num_1 = Num("1"); - let expr1 = Located::new( - 2, - 2, - 8, - 9, - Expr::SpaceBefore(arena.alloc(num_1), &[Newline]), - ); - let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1); - &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }) - }; - - let branch2 = { - let pattern1 = - Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), &[Newline, Newline]); - let loc_pattern1 = Located::new(4, 4, 4, 5, pattern1); - let num_1 = Num("2"); - let expr1 = Located::new( - 5, - 5, - 8, - 9, - Expr::SpaceBefore(arena.alloc(num_1), &[Newline]), - ); - let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1); - &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }) - }; - - let branch3 = { - let pattern1 = - Pattern::SpaceBefore(arena.alloc(Pattern::GlobalTag("Ok")), &[Newline, Newline]); - let loc_pattern1 = Located::new(7, 7, 4, 6, pattern1); - let num_1 = Num("3"); - let expr1 = Located::new( - 8, - 8, - 8, - 9, - Expr::SpaceBefore(arena.alloc(num_1), &[Newline]), - ); - let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1); - &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }) - }; - - let branches = &[branch1, branch2, branch3]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - _ -> - 1 - - _ -> - 2 - - Ok -> - 3 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_in_parens() { - let arena = Bump::new(); - - let branch1 = { - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::GlobalTag("Ok")), newlines); - let loc_pattern1 = Located::new(1, 1, 4, 6, pattern1); - let num_1 = Num("3"); - let expr1 = Located::new( - 2, - 2, - 8, - 9, - Expr::SpaceBefore(arena.alloc(num_1), &[Newline]), - ); - let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1); - &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }) - }; - - let branches = &[branch1]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 6, 7, var); - let when = Expr::When(arena.alloc(loc_cond), branches); - let expected = Expr::ParensAround(&when); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - (when x is - Ok -> - 3) - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_with_records() { - let arena = Bump::new(); - let newlines = &[Newline]; - let identifiers1 = &[Located::new(1, 1, 3, 4, Identifier("y"))]; - let pattern1 = Pattern::SpaceBefore( - arena.alloc(RecordDestructure(Collection::with_items(identifiers1))), - newlines, - ); - let loc_pattern1 = Located::new(1, 1, 1, 6, pattern1); - let expr1 = Num("2"); - let loc_expr1 = Located::new(1, 1, 10, 11, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let identifiers2 = &[ - Located::new(2, 2, 3, 4, Identifier("z")), - Located::new(2, 2, 6, 7, Identifier("w")), - ]; - let pattern2 = Pattern::SpaceBefore( - arena.alloc(RecordDestructure(Collection::with_items(identifiers2))), - newlines, - ); - let loc_pattern2 = Located::new(2, 2, 1, 9, pattern2); - let expr2 = Num("4"); - let loc_expr2 = Located::new(2, 2, 13, 14, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - { y } -> 2 - { z, w } -> 4 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_in_parens_indented() { - let arena = Bump::new(); - - let branch1 = { - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::GlobalTag("Ok")), newlines); - let loc_pattern1 = Located::new(1, 1, 4, 6, pattern1); - let num_1 = Num("3"); - let expr1 = Located::new(1, 1, 10, 11, num_1); - let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1); - &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }) - }; - - let branches = &[branch1]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 6, 7, var); - let when = Expr::When(arena.alloc(loc_cond), branches); - let spaced = Expr::SpaceAfter(&when, &[Newline]); - let expected = Expr::ParensAround(&spaced); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - (when x is - Ok -> 3 - ) - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn when_with_alternative_patterns() { - let arena = Bump::new(); - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("blah"))), newlines); - let pattern1_alt = StrLiteral(PlainLine("blop")); - let loc_pattern1 = Located::new(1, 1, 1, 7, pattern1); - let loc_pattern1_alt = Located::new(1, 1, 10, 16, pattern1_alt); - let expr1 = Num("1"); - let loc_expr1 = Located::new(1, 1, 20, 21, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1, loc_pattern1_alt]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("foo"))), newlines); - let newlines = &[Newline]; - let pattern2_alt = - Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("bar"))), newlines); - let loc_pattern2 = Located::new(2, 2, 1, 6, pattern2); - let loc_pattern2_alt = Located::new(3, 3, 2, 7, pattern2_alt); - let expr2 = Num("2"); - let loc_expr2 = Located::new(3, 3, 11, 12, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2, loc_pattern2_alt]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - "blah" | "blop" -> 1 - "foo" | - "bar" -> 2 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - // MODULE #[test] @@ -3899,265 +1408,6 @@ mod test_parse { } } - #[test] - fn newline_after_equals() { - // Regression test for https://github.com/rtfeldman/roc/issues/51 - let arena = Bump::new(); - let newlines = &[Newline, Newline]; - let num = arena.alloc(Num("5")); - let def = Def::Body( - arena.alloc(Located::new(0, 0, 0, 1, Identifier("x"))), - arena.alloc(Located::new(1, 1, 4, 5, Expr::SpaceBefore(num, &[Newline]))), - ); - let loc_def = &*arena.alloc(Located::new(0, 1, 0, 5, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines); - let loc_ret = Located::new(3, 3, 0, 2, ret); - let expected = Defs(defs, arena.alloc(loc_ret)); - - assert_parses_to( - indoc!( - r#" - x = - 5 - - 42 - "# - ), - expected, - ); - } - - // DOCS - - #[test] - fn basic_docs() { - let arena = Bump::new(); - let newlines = &[Newline, Newline]; - let def = Def::Body( - arena.alloc(Located::new(6, 6, 0, 1, Identifier("x"))), - arena.alloc(Located::new(6, 6, 4, 5, Num("5"))), - ); - let loc_def = &*arena.alloc(Located::new(6, 6, 0, 5, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines); - let loc_ret = Located::new(8, 8, 0, 2, ret); - let reset_indentation = &[ - DocComment("first line of docs"), - DocComment(" second line"), - DocComment(" third line"), - DocComment("fourth line"), - DocComment(""), - DocComment("sixth line after doc new line"), - ]; - let expected = Expr::SpaceBefore( - arena.alloc(Defs(defs, arena.alloc(loc_ret))), - reset_indentation, - ); - - assert_parses_to( - indoc!( - r#" - ## first line of docs - ## second line - ## third line - ## fourth line - ## - ## sixth line after doc new line - x = 5 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn not_docs() { - let arena = Bump::new(); - let newlines = &[Newline, Newline]; - let def = Def::Body( - arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))), - arena.alloc(Located::new(4, 4, 4, 5, Num("5"))), - ); - let loc_def = &*arena.alloc(Located::new(4, 4, 0, 5, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines); - let loc_ret = Located::new(6, 6, 0, 2, ret); - let reset_indentation = &[ - LineComment("######"), - LineComment("## not docs!"), - LineComment("#still not docs"), - LineComment("#####"), - ]; - let expected = Expr::SpaceBefore( - arena.alloc(Defs(defs, arena.alloc(loc_ret))), - reset_indentation, - ); - - assert_parses_to( - indoc!( - r#" - ####### - ### not docs! - ##still not docs - ###### - x = 5 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn mixed_docs() { - let arena = Bump::new(); - let newlines = &[Newline, Newline]; - let def = Def::Body( - arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))), - arena.alloc(Located::new(4, 4, 4, 5, Num("5"))), - ); - let loc_def = &*arena.alloc(Located::new(4, 4, 0, 5, def)); - let defs = &[loc_def]; - let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines); - let loc_ret = Located::new(6, 6, 0, 2, ret); - let reset_indentation = &[ - LineComment("## not docs!"), - DocComment("docs, but with a problem"), - DocComment("(namely that this is a mix of docs and regular comments)"), - LineComment(" not docs"), - ]; - let expected = Expr::SpaceBefore( - arena.alloc(Defs(defs, arena.alloc(loc_ret))), - reset_indentation, - ); - - assert_parses_to( - indoc!( - r#" - ### not docs! - ## docs, but with a problem - ## (namely that this is a mix of docs and regular comments) - # not docs - x = 5 - - 42 - "# - ), - expected, - ); - } - - #[test] - fn malformed_pattern_field_access() { - // See https://github.com/rtfeldman/roc/issues/399 - let arena = Bump::new(); - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::Malformed("bar.and")), newlines); - let loc_pattern1 = Located::new(1, 1, 4, 11, pattern1); - let expr1 = Num("1"); - let loc_expr1 = Located::new(1, 1, 15, 16, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), newlines); - let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2); - let expr2 = Num("4"); - let loc_expr2 = Located::new(2, 2, 9, 10, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - bar.and -> 1 - _ -> 4 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn malformed_pattern_module_name() { - // See https://github.com/rtfeldman/roc/issues/399 - let arena = Bump::new(); - let newlines = &[Newline]; - let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::Malformed("Foo.and")), newlines); - let loc_pattern1 = Located::new(1, 1, 4, 11, pattern1); - let expr1 = Num("1"); - let loc_expr1 = Located::new(1, 1, 15, 16, expr1); - let branch1 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern1]), - value: loc_expr1, - guard: None, - }); - let newlines = &[Newline]; - let pattern2 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), newlines); - let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2); - let expr2 = Num("4"); - let loc_expr2 = Located::new(2, 2, 9, 10, expr2); - let branch2 = &*arena.alloc(WhenBranch { - patterns: arena.alloc([loc_pattern2]), - value: loc_expr2, - guard: None, - }); - let branches = &[branch1, branch2]; - let var = Var { - module_name: "", - ident: "x", - }; - let loc_cond = Located::new(0, 0, 5, 6, var); - let expected = Expr::When(arena.alloc(loc_cond), branches); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when x is - Foo.and -> 1 - _ -> 4 - "# - ), - ); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn pattern_with_space_in_parens() { - // https://github.com/rtfeldman/roc/issues/929 - let arena = Bump::new(); - let actual = save_parse_expr_with( - &arena, - indoc!( - r#" - when Delmin (Del rx) 0 is - Delmin (Del ry ) _ -> Node Black 0 False ry - "# - ), - ); - - assert!(actual.is_ok()); - } - #[test] fn parse_expr_size() { assert_eq!(std::mem::size_of::(), 40); From a4a244cda083eef6acde97de0e1c48c16f67a83b Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 14:08:56 -0800 Subject: [PATCH 085/223] migrate header + some module tests --- .../pass/empty_app_header.header.result-ast | 19 + .../pass/empty_app_header.header.roc | 1 + .../empty_interface_header.header.result-ast | 13 + .../pass/empty_interface_header.header.roc | 1 + .../empty_platform_header.header.result-ast | 33 + .../pass/empty_platform_header.header.roc | 1 + .../pass/full_app_header.header.result-ast | 31 + .../snapshots/pass/full_app_header.header.roc | 4 + ...p_header_trailing_commas.header.result-ast | 31 + ...full_app_header_trailing_commas.header.roc | 8 + .../pass/minimal_app_header.header.result-ast | 19 + .../pass/minimal_app_header.header.roc | 1 + .../pass/nested_module.header.result-ast | 13 + .../snapshots/pass/nested_module.header.roc | 1 + ...nonempty_platform_header.header.result-ast | 51 ++ .../pass/nonempty_platform_header.header.roc | 7 + .../standalone_module_defs.module.result-ast | 5 + .../pass/standalone_module_defs.module.roc | 7 + compiler/parse/tests/test_parse.rs | 580 ++---------------- 19 files changed, 300 insertions(+), 526 deletions(-) create mode 100644 compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/empty_app_header.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/empty_interface_header.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/empty_platform_header.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/full_app_header.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/minimal_app_header.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/nested_module.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/nested_module.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.roc create mode 100644 compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/standalone_module_defs.module.roc diff --git a/compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast b/compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast new file mode 100644 index 0000000000..a8d7a076dc --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast @@ -0,0 +1,19 @@ +App { + header: AppHeader { + name: |L 0-0, C 4-14| PlainLine("test-app"), + packages: [], + imports: [], + provides: [], + to: |L 0-0, C 53-57| ExistingPackage("blah"), + before_header: [], + after_app_keyword: [], + before_packages: [], + after_packages: [], + before_imports: [], + after_imports: [], + before_provides: [], + after_provides: [], + before_to: [], + after_to: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/empty_app_header.header.roc b/compiler/parse/tests/snapshots/pass/empty_app_header.header.roc new file mode 100644 index 0000000000..e524c249e9 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_app_header.header.roc @@ -0,0 +1 @@ +app "test-app" packages {} imports [] provides [] to blah diff --git a/compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast b/compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast new file mode 100644 index 0000000000..f0ad966519 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast @@ -0,0 +1,13 @@ +Interface { + header: InterfaceHeader { + name: |L 0-0, C 10-13| ModuleName("Foo"), + exposes: [], + imports: [], + before_header: [], + after_interface_keyword: [], + before_exposes: [], + after_exposes: [], + before_imports: [], + after_imports: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/empty_interface_header.header.roc b/compiler/parse/tests/snapshots/pass/empty_interface_header.header.roc new file mode 100644 index 0000000000..5959237bda --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_interface_header.header.roc @@ -0,0 +1 @@ +interface Foo exposes [] imports [] diff --git a/compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast b/compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast new file mode 100644 index 0000000000..7ce3a5f245 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast @@ -0,0 +1,33 @@ +Platform { + header: PlatformHeader { + name: |L 0-0, C 9-23| PackageName { account: "rtfeldman", pkg: "blah" }, + requires: PlatformRequires { + rigids: [], + signature: |L 0-0, C 38-47| Entry { ident: |L 0-0, C 38-42| "main", spaces_before_colon: [], ann: |L 0-0, C 45-47| Record { fields: [], ext: None } }, + }, + exposes: [], + packages: [], + imports: [], + provides: [], + effects: Effects { + spaces_before_effects_keyword: [], + spaces_after_effects_keyword: [], + spaces_after_type_name: [], + effect_shortname: "fx", + effect_type_name: "Blah", + entries: [], + }, + before_header: [], + after_platform_keyword: [], + before_requires: [], + after_requires: [], + before_exposes: [], + after_exposes: [], + before_packages: [], + after_packages: [], + before_imports: [], + after_imports: [], + before_provides: [], + after_provides: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/empty_platform_header.header.roc b/compiler/parse/tests/snapshots/pass/empty_platform_header.header.roc new file mode 100644 index 0000000000..86550152a0 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/empty_platform_header.header.roc @@ -0,0 +1 @@ +platform rtfeldman/blah requires {} { main : {} } exposes [] packages {} imports [] provides [] effects fx.Blah {} \ No newline at end of file diff --git a/compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast b/compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast new file mode 100644 index 0000000000..d66ee260f5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast @@ -0,0 +1,31 @@ +App { + header: AppHeader { + name: |L 0-0, C 4-15| PlainLine("quicksort"), + packages: [ + |L 1-1, C 15-33| Entry { shorthand: "base", spaces_after_shorthand: [], package_or_path: |L 1-1, C 21-33| Path(PlainLine("./platform")) }, + ], + imports: [ + |L 2-2, C 14-25| Package("foo", ModuleName("Bar.Baz"), []), + ], + provides: [ + |L 3-3, C 15-24| Exposed("quicksort"), + ], + to: |L 3-3, C 30-34| ExistingPackage("base"), + before_header: [], + after_app_keyword: [], + before_packages: [ + Newline, + ], + after_packages: [], + before_imports: [ + Newline, + ], + after_imports: [], + before_provides: [ + Newline, + ], + after_provides: [], + before_to: [], + after_to: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/full_app_header.header.roc b/compiler/parse/tests/snapshots/pass/full_app_header.header.roc new file mode 100644 index 0000000000..ce81012e75 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/full_app_header.header.roc @@ -0,0 +1,4 @@ +app "quicksort" + packages { base: "./platform" } + imports [ foo.Bar.Baz ] + provides [ quicksort ] to base diff --git a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast new file mode 100644 index 0000000000..a6154275d6 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast @@ -0,0 +1,31 @@ +App { + header: AppHeader { + name: |L 0-0, C 4-15| PlainLine("quicksort"), + packages: [ + |L 1-1, C 15-33| Entry { shorthand: "base", spaces_after_shorthand: [], package_or_path: |L 1-1, C 21-33| Path(PlainLine("./platform")) }, + ], + imports: [ + |L 2-6, C 14-5| Package("foo", ModuleName("Bar"), Collection { items: [|L 3-3, C 8-11| SpaceBefore(Exposed("Baz"), [Newline]), |L 4-4, C 8-17| SpaceBefore(Exposed("FourtyTwo"), [Newline])], final_comments: [Newline, LineComment(" I'm a happy comment")] }), + ], + provides: [ + |L 7-7, C 15-24| Exposed("quicksort"), + ], + to: |L 7-7, C 31-35| ExistingPackage("base"), + before_header: [], + after_app_keyword: [], + before_packages: [ + Newline, + ], + after_packages: [], + before_imports: [ + Newline, + ], + after_imports: [], + before_provides: [ + Newline, + ], + after_provides: [], + before_to: [], + after_to: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc new file mode 100644 index 0000000000..30b50e51d6 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc @@ -0,0 +1,8 @@ +app "quicksort" + packages { base: "./platform", } + imports [ foo.Bar.{ + Baz, + FourtyTwo, + # I'm a happy comment + } ] + provides [ quicksort, ] to base diff --git a/compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast b/compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast new file mode 100644 index 0000000000..41ea70e9f5 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast @@ -0,0 +1,19 @@ +App { + header: AppHeader { + name: |L 0-0, C 4-14| PlainLine("test-app"), + packages: [], + imports: [], + provides: [], + to: |L 0-0, C 30-38| NewPackage(Path(PlainLine("./blah"))), + before_header: [], + after_app_keyword: [], + before_packages: [], + after_packages: [], + before_imports: [], + after_imports: [], + before_provides: [], + after_provides: [], + before_to: [], + after_to: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/minimal_app_header.header.roc b/compiler/parse/tests/snapshots/pass/minimal_app_header.header.roc new file mode 100644 index 0000000000..4678035773 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/minimal_app_header.header.roc @@ -0,0 +1 @@ +app "test-app" provides [] to "./blah" diff --git a/compiler/parse/tests/snapshots/pass/nested_module.header.result-ast b/compiler/parse/tests/snapshots/pass/nested_module.header.result-ast new file mode 100644 index 0000000000..77fc6b1137 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/nested_module.header.result-ast @@ -0,0 +1,13 @@ +Interface { + header: InterfaceHeader { + name: |L 0-0, C 10-21| ModuleName("Foo.Bar.Baz"), + exposes: [], + imports: [], + before_header: [], + after_interface_keyword: [], + before_exposes: [], + after_exposes: [], + before_imports: [], + after_imports: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/nested_module.header.roc b/compiler/parse/tests/snapshots/pass/nested_module.header.roc new file mode 100644 index 0000000000..f43501c404 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/nested_module.header.roc @@ -0,0 +1 @@ +interface Foo.Bar.Baz exposes [] imports [] diff --git a/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast b/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast new file mode 100644 index 0000000000..dd29e16963 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast @@ -0,0 +1,51 @@ +Platform { + header: PlatformHeader { + name: |L 0-0, C 9-19| PackageName { account: "foo", pkg: "barbaz" }, + requires: PlatformRequires { + rigids: [ + |L 1-1, C 14-26| Entry { rigid: "model", alias: "Model" }, + ], + signature: |L 1-1, C 30-39| Entry { ident: |L 1-1, C 30-34| "main", spaces_before_colon: [], ann: |L 1-1, C 37-39| Record { fields: [], ext: None } }, + }, + exposes: [], + packages: [ + |L 3-3, C 15-27| Entry { shorthand: "foo", spaces_after_shorthand: [], package_or_path: |L 3-3, C 20-27| Path(PlainLine("./foo")) }, + ], + imports: [], + provides: [ + |L 5-5, C 15-26| Exposed("mainForHost"), + ], + effects: Effects { + spaces_before_effects_keyword: [ + Newline, + ], + spaces_after_effects_keyword: [], + spaces_after_type_name: [], + effect_shortname: "fx", + effect_type_name: "Effect", + entries: [], + }, + before_header: [], + after_platform_keyword: [], + before_requires: [ + Newline, + ], + after_requires: [], + before_exposes: [ + Newline, + ], + after_exposes: [], + before_packages: [ + Newline, + ], + after_packages: [], + before_imports: [ + Newline, + ], + after_imports: [], + before_provides: [ + Newline, + ], + after_provides: [], + }, +} diff --git a/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.roc b/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.roc new file mode 100644 index 0000000000..d12bc9f00a --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.roc @@ -0,0 +1,7 @@ +platform foo/barbaz + requires {model=>Model} { main : {} } + exposes [] + packages { foo: "./foo" } + imports [] + provides [ mainForHost ] + effects fx.Effect {} diff --git a/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast new file mode 100644 index 0000000000..1eae8ebab4 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast @@ -0,0 +1,5 @@ +[ + |L 1-1, C 0-7| SpaceBefore(Body(|L 1-1, C 0-3| Identifier("foo"), |L 1-1, C 6-7| Num("1")), [LineComment(" comment 1")]), + |L 4-4, C 0-10| SpaceBefore(Body(|L 4-4, C 0-3| Identifier("bar"), |L 4-4, C 6-10| Str(PlainLine("hi"))), [Newline, Newline, LineComment(" comment 2")]), + |L 5-5, C 0-13| SpaceAfter(SpaceBefore(Body(|L 5-5, C 0-3| Identifier("baz"), |L 5-5, C 6-13| Str(PlainLine("stuff"))), [Newline]), [Newline, LineComment(" comment n")]), +] diff --git a/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.roc b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.roc new file mode 100644 index 0000000000..2c6e02bbfd --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.roc @@ -0,0 +1,7 @@ +# comment 1 +foo = 1 + +# comment 2 +bar = "hi" +baz = "stuff" +# comment n diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 1ce8f0e055..db6345ca06 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -42,11 +42,19 @@ mod test_parse { expr => { $($expr_test_name:ident),* } + header => { + $($header_test_name:ident),* + } + module => { + $($module_test_name:ident),* + } ) => { #[test] fn no_extra_snapshot_test_files() { let tests = &[ - $(concat!(stringify!($expr_test_name), ".expr")),* + $(concat!(stringify!($expr_test_name), ".expr")),*, + $(concat!(stringify!($header_test_name), ".header")),*, + $(concat!(stringify!($module_test_name), ".module")),*, ].iter().map(|t| *t).collect::>(); let mut base = std::path::PathBuf::from("tests"); @@ -67,7 +75,36 @@ mod test_parse { $( #[test] fn $expr_test_name() { - snapshot_expr_test(stringify!($expr_test_name)); + snapshot_test(stringify!($expr_test_name), "expr", |input| { + let arena = Bump::new(); + let actual_ast = parse_expr_with(&arena, input.trim()).unwrap(); + format!("{:#?}\n", actual_ast) + }); + } + )* + + $( + #[test] + fn $header_test_name() { + snapshot_test(stringify!($header_test_name), "header", |input| { + let arena = Bump::new(); + let actual_ast = roc_parse::module::parse_header(&arena, State::new(input.as_bytes())) + .map(|tuple| tuple.0).unwrap(); + format!("{:#?}\n", actual_ast) + }); + } + )* + + $( + #[test] + fn $module_test_name() { + snapshot_test(stringify!($module_test_name), "module", |input| { + let arena = Bump::new(); + let actual_ast = module_defs() + .parse(&arena, State::new(input.as_bytes())) + .map(|tuple| tuple.1).unwrap(); + format!("{:#?}\n", actual_ast) + }); } )* }; @@ -195,10 +232,22 @@ mod test_parse { zero_float, zero_int } + header => { + empty_app_header, + empty_interface_header, + empty_platform_header, + full_app_header, + full_app_header_trailing_commas, + minimal_app_header, + nested_module, + nonempty_platform_header + } + module => { + standalone_module_defs + } } - fn snapshot_expr_test(name: &str) { - let ty = "expr"; + fn snapshot_test(name: &str, ty: &str, func: impl Fn(&str) -> String) { let mut parent = std::path::PathBuf::from("tests"); parent.push("snapshots"); parent.push("pass"); @@ -208,9 +257,7 @@ mod test_parse { let input = std::fs::read_to_string(&input_path).unwrap(); let expected_result = std::fs::read_to_string(&result_path).unwrap(); - let arena = Bump::new(); - let actual_ast = parse_expr_with(&arena, input.trim()).unwrap(); - let actual_result = format!("{:#?}\n", actual_ast); + let actual_result = func(&input); if std::env::var("ROC_PARSER_SNAPSHOT_TEST_OVERWRITE").is_ok() { std::fs::write(&result_path, actual_result).unwrap(); @@ -788,467 +835,6 @@ mod test_parse { // ); // } - // MODULE - - #[test] - fn empty_app_header() { - let arena = Bump::new(); - let packages = Collection::empty(); - let imports = Collection::empty(); - let provides = Collection::empty(); - let module_name = StrLiteral::PlainLine("test-app"); - let header = AppHeader { - name: Located::new(0, 0, 4, 14, module_name), - packages, - imports, - provides, - to: Located::new(0, 0, 53, 57, To::ExistingPackage("blah")), - before_header: &[], - after_app_keyword: &[], - before_packages: &[], - after_packages: &[], - before_imports: &[], - after_imports: &[], - before_provides: &[], - after_provides: &[], - before_to: &[], - after_to: &[], - }; - - let expected = roc_parse::ast::Module::App { header }; - - let src = indoc!( - r#" - app "test-app" packages {} imports [] provides [] to blah - "# - ); - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn minimal_app_header() { - use PackageOrPath::Path; - - let arena = Bump::new(); - let packages = Collection::empty(); - let imports = Collection::empty(); - let provides = Collection::empty(); - let module_name = StrLiteral::PlainLine("test-app"); - let header = AppHeader { - before_header: &[], - name: Located::new(0, 0, 4, 14, module_name), - packages, - imports, - provides, - to: Located::new(0, 0, 30, 38, To::NewPackage(Path(PlainLine("./blah")))), - after_app_keyword: &[], - before_packages: &[], - after_packages: &[], - before_imports: &[], - after_imports: &[], - before_provides: &[], - after_provides: &[], - before_to: &[], - after_to: &[], - }; - - let expected = roc_parse::ast::Module::App { header }; - - let src = indoc!( - r#" - app "test-app" provides [] to "./blah" - "# - ); - - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn full_app_header() { - use ExposesEntry::Exposed; - use PackageOrPath::Path; - - let newlines = &[Newline]; - let pkg_entry = PackageEntry::Entry { - shorthand: "base", - spaces_after_shorthand: &[], - package_or_path: Located::new(1, 1, 21, 33, Path(PlainLine("./platform"))), - }; - let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); - let arena = Bump::new(); - let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); - let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Collection::empty()); - let loc_import = Located::new(2, 2, 14, 25, import); - let imports = Collection::with_items(arena.alloc([loc_import])); - let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort")); - let provides = Collection::with_items(arena.alloc([provide_entry])); - let module_name = StrLiteral::PlainLine("quicksort"); - - let header = AppHeader { - before_header: &[], - name: Located::new(0, 0, 4, 15, module_name), - packages, - imports, - provides, - to: Located::new(3, 3, 30, 34, To::ExistingPackage("base")), - after_app_keyword: &[], - before_packages: newlines, - after_packages: &[], - before_imports: newlines, - after_imports: &[], - before_provides: newlines, - after_provides: &[], - before_to: &[], - after_to: &[], - }; - - let expected = roc_parse::ast::Module::App { header }; - - let src = indoc!( - r#" - app "quicksort" - packages { base: "./platform" } - imports [ foo.Bar.Baz ] - provides [ quicksort ] to base - "# - ); - - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn full_app_header_trailing_commas() { - use ExposesEntry::Exposed; - use PackageOrPath::Path; - - let newlines = &[Newline]; - let pkg_entry = PackageEntry::Entry { - shorthand: "base", - spaces_after_shorthand: &[], - package_or_path: Located::new(1, 1, 21, 33, Path(PlainLine("./platform"))), - }; - let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); - let arena = Bump::new(); - let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); - let import = ImportsEntry::Package( - "foo", - ModuleName::new("Bar"), - Collection::with_items_and_comments( - &arena, - arena.alloc([ - Located::new( - 3, - 3, - 8, - 11, - ExposesEntry::SpaceBefore( - arena.alloc(ExposesEntry::Exposed("Baz")), - arena.alloc([Newline]), - ), - ), - Located::new( - 4, - 4, - 8, - 17, - ExposesEntry::SpaceBefore( - arena.alloc(ExposesEntry::Exposed("FourtyTwo")), - arena.alloc([Newline]), - ), - ), - ]), - arena.alloc([Newline, LineComment(" I'm a happy comment")]), - ), - ); - let loc_import = Located::new(2, 6, 14, 5, import); - let imports = Collection::with_items(arena.alloc([loc_import])); - let provide_entry = Located::new(7, 7, 15, 24, Exposed("quicksort")); - let provides = Collection::with_items(arena.alloc([provide_entry])); - let module_name = StrLiteral::PlainLine("quicksort"); - - let header = AppHeader { - before_header: &[], - name: Located::new(0, 0, 4, 15, module_name), - packages, - imports, - provides, - to: Located::new(7, 7, 31, 35, To::ExistingPackage("base")), - after_app_keyword: &[], - before_packages: newlines, - after_packages: &[], - before_imports: newlines, - after_imports: &[], - before_provides: newlines, - after_provides: &[], - before_to: &[], - after_to: &[], - }; - - let expected = roc_parse::ast::Module::App { header }; - - let src = indoc!( - r#" - app "quicksort" - packages { base: "./platform", } - imports [ foo.Bar.{ - Baz, - FourtyTwo, - # I'm a happy comment - } ] - provides [ quicksort, ] to base - "# - ); - - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn empty_platform_header() { - let pkg_name = PackageName { - account: "rtfeldman", - pkg: "blah", - }; - let arena = Bump::new(); - let effects = Effects { - effect_type_name: "Blah", - effect_shortname: "fx", - entries: &[], - spaces_before_effects_keyword: &[], - spaces_after_effects_keyword: &[], - spaces_after_type_name: &[], - }; - - let requires = { - let region1 = Region::new(0, 0, 38, 47); - let region2 = Region::new(0, 0, 45, 47); - - PlatformRequires { - rigids: Collection::empty(), - signature: Located::at( - region1, - TypedIdent::Entry { - ident: Located::new(0, 0, 38, 42, "main"), - spaces_before_colon: &[], - ann: Located::at( - region2, - TypeAnnotation::Record { - fields: Collection::empty(), - ext: None, - }, - ), - }, - ), - } - }; - - let header = PlatformHeader { - before_header: &[], - name: Located::new(0, 0, 9, 23, pkg_name), - requires, - exposes: Collection::empty(), - packages: Collection::empty(), - imports: Collection::empty(), - provides: Collection::empty(), - effects, - after_platform_keyword: &[], - before_requires: &[], - after_requires: &[], - before_exposes: &[], - after_exposes: &[], - before_packages: &[], - after_packages: &[], - before_imports: &[], - after_imports: &[], - before_provides: &[], - after_provides: &[], - }; - - let expected = roc_parse::ast::Module::Platform { header }; - - let src = "platform rtfeldman/blah requires {} { main : {} } exposes [] packages {} imports [] provides [] effects fx.Blah {}"; - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn nonempty_platform_header() { - use ExposesEntry::Exposed; - use PackageOrPath::Path; - - let newlines = &[Newline]; - let pkg_name = PackageName { - account: "foo", - pkg: "barbaz", - }; - let pkg_entry = PackageEntry::Entry { - shorthand: "foo", - spaces_after_shorthand: &[], - package_or_path: Located::new(3, 3, 20, 27, Path(PlainLine("./foo"))), - }; - let loc_pkg_entry = Located::new(3, 3, 15, 27, pkg_entry); - let arena = Bump::new(); - let packages = Collection::with_items(arena.alloc([loc_pkg_entry])); - let imports = Collection::empty(); - let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost")); - let provides = Collection::with_items(arena.alloc([provide_entry])); - let effects = Effects { - effect_type_name: "Effect", - effect_shortname: "fx", - entries: &[], - spaces_before_effects_keyword: newlines, - spaces_after_effects_keyword: &[], - spaces_after_type_name: &[], - }; - - let requires = { - let region1 = Region::new(1, 1, 30, 39); - let region2 = Region::new(1, 1, 37, 39); - let region3 = Region::new(1, 1, 14, 26); - - PlatformRequires { - rigids: Collection::with_items(arena.alloc([Located::at( - region3, - PlatformRigid::Entry { - alias: "Model", - rigid: "model", - }, - )])), - signature: Located::at( - region1, - TypedIdent::Entry { - ident: Located::new(1, 1, 30, 34, "main"), - spaces_before_colon: &[], - ann: Located::at( - region2, - TypeAnnotation::Record { - fields: Collection::empty(), - ext: None, - }, - ), - }, - ), - } - }; - - let header = PlatformHeader { - before_header: &[], - name: Located::new(0, 0, 9, 19, pkg_name), - requires, - exposes: Collection::empty(), - packages, - imports, - provides, - effects, - after_platform_keyword: &[], - before_requires: newlines, - after_requires: &[], - before_exposes: newlines, - after_exposes: &[], - before_packages: newlines, - after_packages: &[], - before_imports: newlines, - after_imports: &[], - before_provides: newlines, - after_provides: &[], - }; - - let expected = roc_parse::ast::Module::Platform { header }; - - let src = indoc!( - r#" - platform foo/barbaz - requires {model=>Model} { main : {} } - exposes [] - packages { foo: "./foo" } - imports [] - provides [ mainForHost ] - effects fx.Effect {} - "# - ); - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn empty_interface_header() { - let arena = Bump::new(); - let exposes = Collection::empty(); - let imports = Collection::empty(); - let module_name = ModuleName::new("Foo"); - let header = InterfaceHeader { - before_header: &[], - name: Located::new(0, 0, 10, 13, module_name), - exposes, - imports, - - after_interface_keyword: &[], - before_exposes: &[], - after_exposes: &[], - before_imports: &[], - after_imports: &[], - }; - - let expected = roc_parse::ast::Module::Interface { header }; - - let src = indoc!( - r#" - interface Foo exposes [] imports [] - "# - ); - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - - #[test] - fn nested_module() { - let arena = Bump::new(); - let exposes = Collection::empty(); - let imports = Collection::empty(); - let module_name = ModuleName::new("Foo.Bar.Baz"); - let header = InterfaceHeader { - before_header: &[], - name: Located::new(0, 0, 10, 21, module_name), - exposes, - imports, - - after_interface_keyword: &[], - before_exposes: &[], - after_exposes: &[], - before_imports: &[], - after_imports: &[], - }; - - let expected = roc_parse::ast::Module::Interface { header }; - - let src = indoc!( - r#" - interface Foo.Bar.Baz exposes [] imports [] - "# - ); - let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert_eq!(Ok(expected), actual); - } - #[test] fn repro_keyword_bug() { // Reproducing this bug requires a bizarre set of things to all be true: @@ -1280,64 +866,6 @@ mod test_parse { assert_eq!(occurrences, 2); } - #[test] - fn standalone_module_defs() { - use Def::*; - - let arena = Bump::new(); - let pattern1 = Identifier("foo"); - let pattern2 = Identifier("bar"); - let pattern3 = Identifier("baz"); - let def1 = SpaceBefore( - arena.alloc(Body( - arena.alloc(Located::new(1, 1, 0, 3, pattern1)), - arena.alloc(Located::new(1, 1, 6, 7, Num("1"))), - )), - &[LineComment(" comment 1")], - ); - let def2 = SpaceBefore( - arena.alloc(Body( - arena.alloc(Located::new(4, 4, 0, 3, pattern2)), - arena.alloc(Located::new(4, 4, 6, 10, Str(PlainLine("hi")))), - )), - &[Newline, Newline, LineComment(" comment 2")], - ); - let def3 = SpaceAfter( - arena.alloc(SpaceBefore( - arena.alloc(Body( - arena.alloc(Located::new(5, 5, 0, 3, pattern3)), - arena.alloc(Located::new(5, 5, 6, 13, Str(PlainLine("stuff")))), - )), - &[Newline], - )), - &[Newline, LineComment(" comment n")], - ); - - let expected = bumpalo::vec![in &arena; - Located::new(1,1, 0, 7, def1), - Located::new(4,4, 0, 10, def2), - Located::new(5,5, 0, 13, def3), - ]; - - let src = indoc!( - r#" - # comment 1 - foo = 1 - - # comment 2 - bar = "hi" - baz = "stuff" - # comment n - "# - ); - - let actual = module_defs() - .parse(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.1); - - assert_eq!(Ok(expected), actual); - } - #[test] fn module_def_newline() { let arena = Bump::new(); From cb30d7446bfbd12df4e0fab8d3e542406a0f5f6d Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 12 Nov 2021 14:20:42 -0800 Subject: [PATCH 086/223] migrate other module tests --- .../pass/module_def_newline.module.result-ast | 3 ++ .../pass/module_def_newline.module.roc | 4 ++ .../nested_def_annotation.module.result-ast | 3 ++ .../pass/nested_def_annotation.module.roc | 6 +++ compiler/parse/tests/test_parse.rs | 46 ++----------------- 5 files changed, 19 insertions(+), 43 deletions(-) create mode 100644 compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/module_def_newline.module.roc create mode 100644 compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/nested_def_annotation.module.roc diff --git a/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast b/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast new file mode 100644 index 0000000000..d5e303be34 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast @@ -0,0 +1,3 @@ +[ + |L 0-3, C 0-5| SpaceAfter(SpaceBefore(Body(|L 0-0, C 0-4| Identifier("main"), |L 1-3, C 4-5| SpaceBefore(Defs([|L 1-1, C 4-10| Body(|L 1-1, C 4-5| Identifier("i"), |L 1-1, C 8-10| Num("64"))], |L 3-3, C 4-5| SpaceBefore(Var { module_name: "", ident: "i" }, [Newline, Newline])), [Newline])), []), [Newline]), +] diff --git a/compiler/parse/tests/snapshots/pass/module_def_newline.module.roc b/compiler/parse/tests/snapshots/pass/module_def_newline.module.roc new file mode 100644 index 0000000000..c14cf34253 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/module_def_newline.module.roc @@ -0,0 +1,4 @@ +main = + i = 64 + + i diff --git a/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast new file mode 100644 index 0000000000..9257867e69 --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast @@ -0,0 +1,3 @@ +[ + |L 0-5, C 0-20| SpaceAfter(SpaceBefore(Body(|L 0-0, C 0-4| Identifier("main"), |L 1-5, C 4-20| SpaceBefore(Defs([|L 2-3, C 4-20| AnnotatedBody { ann_pattern: |L 1-1, C 4-16| Identifier("wrappedNotEq"), ann_type: |L 1-1, C 27-31| Function([|L 1-1, C 19-20| BoundVariable("a"), |L 1-1, C 22-23| BoundVariable("a")], |L 1-1, C 27-31| Apply("", "Bool", [])), comment: None, body_pattern: |L 2-2, C 4-16| Identifier("wrappedNotEq"), body_expr: |L 2-3, C 19-20| Closure([|L 2-2, C 20-24| Identifier("num1"), |L 2-2, C 26-30| Identifier("num2")], |L 3-3, C 8-20| SpaceBefore(BinOps([(|L 3-3, C 8-12| Var { module_name: "", ident: "num1" }, |L 3-3, C 13-15| NotEquals)], |L 3-3, C 16-20| Var { module_name: "", ident: "num2" }), [Newline])) }], |L 5-5, C 4-20| SpaceBefore(Apply(|L 5-5, C 4-16| Var { module_name: "", ident: "wrappedNotEq" }, [|L 5-5, C 17-18| Num("2"), |L 5-5, C 19-20| Num("3")], Space), [Newline, Newline])), [Newline])), []), [Newline]), +] diff --git a/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.roc b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.roc new file mode 100644 index 0000000000..a7d12703ae --- /dev/null +++ b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.roc @@ -0,0 +1,6 @@ +main = + wrappedNotEq : a, a -> Bool + wrappedNotEq = \num1, num2 -> + num1 != num2 + + wrappedNotEq 2 3 diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index db6345ca06..09d0dea181 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -243,7 +243,9 @@ mod test_parse { nonempty_platform_header } module => { - standalone_module_defs + standalone_module_defs, + module_def_newline, + nested_def_annotation } } @@ -866,48 +868,6 @@ mod test_parse { assert_eq!(occurrences, 2); } - #[test] - fn module_def_newline() { - let arena = Bump::new(); - - let src = indoc!( - r#" - main = - i = 64 - - i - "# - ); - - let actual = module_defs() - .parse(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert!(actual.is_ok()); - } - - #[test] - fn nested_def_annotation() { - let arena = Bump::new(); - - let src = indoc!( - r#" - main = - wrappedNotEq : a, a -> Bool - wrappedNotEq = \num1, num2 -> - num1 != num2 - - wrappedNotEq 2 3 - "# - ); - - let actual = module_defs() - .parse(&arena, State::new(src.as_bytes())) - .map(|tuple| tuple.0); - - assert!(actual.is_ok()); - } - #[test] fn outdenting_newline_after_else() { let arena = &Bump::new(); From ab99abc63d0ab08f0917d42c4292036c57239f45 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Sun, 14 Nov 2021 18:39:51 -0800 Subject: [PATCH 087/223] Remove unused items, add todo for improving formatting --- compiler/parse/tests/test_parse.rs | 37 ++++-------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 09d0dea181..f1f70dafdf 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -15,21 +15,12 @@ extern crate roc_parse; mod test_parse { use bumpalo::collections::vec::Vec; use bumpalo::{self, Bump}; - use roc_module::operator::BinOp::{self, *}; - use roc_module::operator::{CalledVia, UnaryOp}; - use roc_parse::ast::AssignedField::*; - use roc_parse::ast::CommentOrNewline::*; use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::Pattern::{self, *}; use roc_parse::ast::StrLiteral::{self, *}; use roc_parse::ast::StrSegment::*; use roc_parse::ast::{ - self, Collection, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch, - }; - use roc_parse::header::{ - AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, - PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, - TypedIdent, + self, EscapedChar }; use roc_parse::module::module_defs; use roc_parse::parser::{Parser, State, SyntaxError}; @@ -264,33 +255,13 @@ mod test_parse { if std::env::var("ROC_PARSER_SNAPSHOT_TEST_OVERWRITE").is_ok() { std::fs::write(&result_path, actual_result).unwrap(); } else { + // TODO: do a diff over the "real" content of these strings, rather than + // the debug-formatted content. As is, we get an ugly single-line diff + // from pretty_assertions assert_eq!(expected_result, actual_result); } } - fn save_snapshot(name: &str, ty: &str, input: &str, result: &str) { - let mut parent = std::path::PathBuf::from("tests"); - parent.push("snapshots"); - parent.push("pass"); - let input_path = parent.join(&format!("{}.{}.roc", name, ty)); - let result_path = parent.join(&format!("{}.{}.result-ast", name, ty)); - std::fs::create_dir_all(parent).unwrap(); - std::fs::write(input_path, input).unwrap(); - std::fs::write(result_path, result).unwrap(); - } - - fn test_name() -> String { - std::thread::current().name().unwrap().strip_prefix("test_parse::").unwrap().to_string() - } - - fn save_parse_expr_with<'a>(arena: &'a Bump, input: &'a str) -> Result, SyntaxError<'a>> { - let actual = parse_expr_with(&arena, input.trim()); - let result = format!("{:#?}\n", actual.as_ref().unwrap()); - - save_snapshot(&test_name(), "expr", input, &result); - actual - } - fn assert_parses_to<'a>(input: &'a str, expected_expr: Expr<'a>) { let arena = Bump::new(); let actual = parse_expr_with(&arena, input.trim()); From 76c3212c1747c438493f3b12adb1b5ba7cb17f4b Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Sun, 14 Nov 2021 18:42:39 -0800 Subject: [PATCH 088/223] Make Debug for Located print it's value multi-lined if requested (with '{:#?}') --- .../pass/add_var_with_spaces.expr.result-ast | 9 +- .../pass/add_with_spaces.expr.result-ast | 8 +- .../pass/apply_global_tag.expr.result-ast | 12 ++- ...enthetical_global_tag_args.expr.result-ast | 16 ++- .../pass/apply_private_tag.expr.result-ast | 12 ++- .../pass/apply_three_args.expr.result-ast | 20 +++- .../pass/apply_two_args.expr.result-ast | 13 ++- .../pass/apply_unary_negation.expr.result-ast | 17 +++- .../pass/apply_unary_not.expr.result-ast | 17 +++- .../pass/basic_apply.expr.result-ast | 9 +- .../snapshots/pass/basic_docs.expr.result-ast | 19 +++- .../closure_with_underscores.expr.result-ast | 12 ++- .../pass/comment_after_op.expr.result-ast | 15 ++- .../pass/comment_before_op.expr.result-ast | 15 ++- .../comment_with_non_ascii.expr.result-ast | 15 ++- .../pass/empty_app_header.header.result-ast | 8 +- .../empty_interface_header.header.result-ast | 4 +- .../empty_platform_header.header.result-ast | 14 ++- .../snapshots/pass/equals.expr.result-ast | 10 +- .../pass/equals_with_spaces.expr.result-ast | 10 +- .../snapshots/pass/expect.expr.result-ast | 24 ++++- .../pass/full_app_header.header.result-ast | 30 +++++- ...p_header_trailing_commas.header.result-ast | 55 ++++++++++- .../snapshots/pass/if_def.expr.result-ast | 19 +++- ...ed_ident_due_to_underscore.expr.result-ast | 12 ++- ...ormed_pattern_field_access.expr.result-ast | 31 +++++- ...formed_pattern_module_name.expr.result-ast | 31 +++++- .../pass/minimal_app_header.header.result-ast | 12 ++- .../minus_twelve_minus_five.expr.result-ast | 8 +- .../snapshots/pass/mixed_docs.expr.result-ast | 19 +++- .../pass/module_def_newline.module.result-ast | 41 +++++++- .../pass/multi_backpassing.expr.result-ast | 46 ++++++++- .../multiline_type_signature.expr.result-ast | 25 ++++- ...ype_signature_with_comment.expr.result-ast | 27 ++++- .../pass/multiple_operators.expr.result-ast | 12 ++- .../pass/neg_inf_float.expr.result-ast | 5 +- .../nested_def_annotation.module.result-ast | 98 ++++++++++++++++++- .../pass/nested_module.header.result-ast | 4 +- .../pass/newline_after_equals.expr.result-ast | 24 ++++- .../pass/newline_after_mul.expr.result-ast | 13 ++- .../pass/newline_after_sub.expr.result-ast | 13 ++- ...nd_spaces_before_less_than.expr.result-ast | 34 ++++++- .../pass/newline_before_add.expr.result-ast | 13 ++- .../pass/newline_before_sub.expr.result-ast | 13 ++- .../newline_singleton_list.expr.result-ast | 14 ++- ...nonempty_platform_header.header.result-ast | 33 ++++++- .../snapshots/pass/not_docs.expr.result-ast | 19 +++- .../pass/one_backpassing.expr.result-ast | 29 +++++- .../snapshots/pass/one_def.expr.result-ast | 19 +++- .../pass/one_minus_two.expr.result-ast | 8 +- .../pass/one_plus_two.expr.result-ast | 8 +- .../pass/one_spaced_def.expr.result-ast | 19 +++- .../pass/ops_with_newlines.expr.result-ast | 19 +++- .../packed_singleton_list.expr.result-ast | 4 +- .../pass/parenthetical_apply.expr.result-ast | 11 ++- .../pass/parse_alias.expr.result-ast | 34 ++++++- .../pass/parse_as_ann.expr.result-ast | 43 +++++++- ...ttern_with_space_in_parens.expr.result-ast | 74 +++++++++++++- .../record_destructure_def.expr.result-ast | 40 +++++++- .../pass/record_update.expr.result-ast | 21 +++- .../pass/record_with_if.expr.result-ast | 28 +++++- .../pass/single_arg_closure.expr.result-ast | 8 +- .../single_underscore_closure.expr.result-ast | 8 +- .../space_only_after_minus.expr.result-ast | 10 +- .../spaced_singleton_list.expr.result-ast | 4 +- .../standalone_module_defs.module.result-ast | 60 +++++++++++- .../pass/sub_var_with_spaces.expr.result-ast | 9 +- .../pass/sub_with_spaces.expr.result-ast | 8 +- .../pass/tag_pattern.expr.result-ast | 8 +- .../pass/ten_times_eleven.expr.result-ast | 8 +- .../pass/three_arg_closure.expr.result-ast | 16 ++- .../pass/two_arg_closure.expr.result-ast | 12 ++- .../pass/two_backpassing.expr.result-ast | 44 ++++++++- .../pass/two_branch_when.expr.result-ast | 35 ++++++- .../pass/two_spaced_def.expr.result-ast | 33 ++++++- .../pass/unary_negation.expr.result-ast | 5 +- .../unary_negation_access.expr.result-ast | 8 +- .../pass/unary_negation_arg.expr.result-ast | 17 +++- ...unary_negation_with_parens.expr.result-ast | 19 +++- .../snapshots/pass/unary_not.expr.result-ast | 5 +- .../unary_not_with_parens.expr.result-ast | 19 +++- .../underscore_backpassing.expr.result-ast | 28 +++++- .../pass/var_minus_two.expr.result-ast | 9 +- .../pass/when_if_guard.expr.result-ast | 61 ++++++++++-- .../pass/when_in_parens.expr.result-ast | 23 ++++- .../when_in_parens_indented.expr.result-ast | 18 +++- ..._with_alternative_patterns.expr.result-ast | 52 ++++++++-- ..._with_function_application.expr.result-ast | 45 ++++++++- ...when_with_negative_numbers.expr.result-ast | 31 +++++- .../pass/when_with_numbers.expr.result-ast | 31 +++++- .../pass/when_with_records.expr.result-ast | 42 +++++++- compiler/region/src/all.rs | 6 +- 92 files changed, 1733 insertions(+), 236 deletions(-) diff --git a/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast index 5dcfecb2c7..5d07b7897e 100644 --- a/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/add_var_with_spaces.expr.result-ast @@ -1,9 +1,14 @@ BinOps( [ ( - |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 0-1| Var { + module_name: "", + ident: "x", + }, |L 0-0, C 2-3| Plus, ), ], - |L 0-0, C 4-5| Num("2"), + |L 0-0, C 4-5| Num( + "2", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast index 95d2de93fd..b3ba87f0bf 100644 --- a/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.result-ast @@ -1,9 +1,13 @@ BinOps( [ ( - |L 0-0, C 0-1| Num("1"), + |L 0-0, C 0-1| Num( + "1", + ), |L 0-0, C 3-4| Plus, ), ], - |L 0-0, C 7-8| Num("2"), + |L 0-0, C 7-8| Num( + "2", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast index 2c0cef28bc..8e6245cb9f 100644 --- a/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_global_tag.expr.result-ast @@ -1,8 +1,14 @@ Apply( - |L 0-0, C 0-4| GlobalTag("Whee"), + |L 0-0, C 0-4| GlobalTag( + "Whee", + ), [ - |L 0-0, C 5-7| Num("12"), - |L 0-0, C 8-10| Num("34"), + |L 0-0, C 5-7| Num( + "12", + ), + |L 0-0, C 8-10| Num( + "34", + ), ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast index a5b7d31e7e..14cf85eed0 100644 --- a/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_parenthetical_global_tag_args.expr.result-ast @@ -1,8 +1,18 @@ Apply( - |L 0-0, C 0-4| GlobalTag("Whee"), + |L 0-0, C 0-4| GlobalTag( + "Whee", + ), [ - |L 0-0, C 6-8| ParensAround(Num("12")), - |L 0-0, C 11-13| ParensAround(Num("34")), + |L 0-0, C 6-8| ParensAround( + Num( + "12", + ), + ), + |L 0-0, C 11-13| ParensAround( + Num( + "34", + ), + ), ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast index 6b953d0d04..47719397a0 100644 --- a/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_private_tag.expr.result-ast @@ -1,8 +1,14 @@ Apply( - |L 0-0, C 0-5| PrivateTag("@Whee"), + |L 0-0, C 0-5| PrivateTag( + "@Whee", + ), [ - |L 0-0, C 6-8| Num("12"), - |L 0-0, C 9-11| Num("34"), + |L 0-0, C 6-8| Num( + "12", + ), + |L 0-0, C 9-11| Num( + "34", + ), ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast index 3367a6e7fd..45d7902727 100644 --- a/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_three_args.expr.result-ast @@ -1,9 +1,21 @@ Apply( - |L 0-0, C 0-1| Var { module_name: "", ident: "a" }, + |L 0-0, C 0-1| Var { + module_name: "", + ident: "a", + }, [ - |L 0-0, C 2-3| Var { module_name: "", ident: "b" }, - |L 0-0, C 4-5| Var { module_name: "", ident: "c" }, - |L 0-0, C 6-7| Var { module_name: "", ident: "d" }, + |L 0-0, C 2-3| Var { + module_name: "", + ident: "b", + }, + |L 0-0, C 4-5| Var { + module_name: "", + ident: "c", + }, + |L 0-0, C 6-7| Var { + module_name: "", + ident: "d", + }, ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast index 3ff92e86b6..a4e39d6fd5 100644 --- a/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_two_args.expr.result-ast @@ -1,8 +1,15 @@ Apply( - |L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, + |L 0-0, C 0-4| Var { + module_name: "", + ident: "whee", + }, [ - |L 0-0, C 6-8| Num("12"), - |L 0-0, C 10-12| Num("34"), + |L 0-0, C 6-8| Num( + "12", + ), + |L 0-0, C 10-12| Num( + "34", + ), ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast index 471d65c405..54e180b592 100644 --- a/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.result-ast @@ -1,8 +1,19 @@ Apply( - |L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Negate), + |L 0-0, C 0-5| UnaryOp( + |L 0-0, C 1-5| Var { + module_name: "", + ident: "whee", + }, + |L 0-0, C 0-1| Negate, + ), [ - |L 0-0, C 7-9| Num("12"), - |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, + |L 0-0, C 7-9| Num( + "12", + ), + |L 0-0, C 10-13| Var { + module_name: "", + ident: "foo", + }, ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast index 42bdba2cab..86eee8cafa 100644 --- a/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.result-ast @@ -1,8 +1,19 @@ Apply( - |L 0-0, C 0-5| UnaryOp(|L 0-0, C 1-5| Var { module_name: "", ident: "whee" }, |L 0-0, C 0-1| Not), + |L 0-0, C 0-5| UnaryOp( + |L 0-0, C 1-5| Var { + module_name: "", + ident: "whee", + }, + |L 0-0, C 0-1| Not, + ), [ - |L 0-0, C 7-9| Num("12"), - |L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, + |L 0-0, C 7-9| Num( + "12", + ), + |L 0-0, C 10-13| Var { + module_name: "", + ident: "foo", + }, ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast index 10ba03c7b4..6d906548f6 100644 --- a/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_apply.expr.result-ast @@ -1,7 +1,12 @@ Apply( - |L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, + |L 0-0, C 0-4| Var { + module_name: "", + ident: "whee", + }, [ - |L 0-0, C 5-6| Num("1"), + |L 0-0, C 5-6| Num( + "1", + ), ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast index 253faa24be..3e891ee430 100644 --- a/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast @@ -1,9 +1,24 @@ SpaceBefore( Defs( [ - |L 6-6, C 0-5| Body(|L 6-6, C 0-1| Identifier("x"), |L 6-6, C 4-5| Num("5")), + |L 6-6, C 0-5| Body( + |L 6-6, C 0-1| Identifier( + "x", + ), + |L 6-6, C 4-5| Num( + "5", + ), + ), ], - |L 8-8, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 8-8, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ), [ DocComment( diff --git a/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast index c92ce0115c..61ea2b2405 100644 --- a/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/closure_with_underscores.expr.result-ast @@ -1,7 +1,13 @@ Closure( [ - |L 0-0, C 1-2| Underscore(""), - |L 0-0, C 4-9| Underscore("name"), + |L 0-0, C 1-2| Underscore( + "", + ), + |L 0-0, C 4-9| Underscore( + "name", + ), ], - |L 0-0, C 13-15| Num("42"), + |L 0-0, C 13-15| Num( + "42", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast index b777880f1c..34d2472071 100644 --- a/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_after_op.expr.result-ast @@ -1,9 +1,20 @@ BinOps( [ ( - |L 0-0, C 0-2| Num("12"), + |L 0-0, C 0-2| Num( + "12", + ), |L 0-0, C 4-5| Star, ), ], - |L 1-1, C 1-3| SpaceBefore(Num("92"), [LineComment(" test!")]), + |L 1-1, C 1-3| SpaceBefore( + Num( + "92", + ), + [ + LineComment( + " test!", + ), + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast index 8ff0bf9290..af6abd380a 100644 --- a/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_before_op.expr.result-ast @@ -1,9 +1,20 @@ BinOps( [ ( - |L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" test!")]), + |L 0-0, C 0-1| SpaceAfter( + Num( + "3", + ), + [ + LineComment( + " test!", + ), + ], + ), |L 1-1, C 0-1| Plus, ), ], - |L 1-1, C 2-3| Num("4"), + |L 1-1, C 2-3| Num( + "4", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast index 6f2008835b..ded9ef9ea0 100644 --- a/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.result-ast @@ -1,9 +1,20 @@ BinOps( [ ( - |L 0-0, C 0-1| SpaceAfter(Num("3"), [LineComment(" 2 Γ— 2")]), + |L 0-0, C 0-1| SpaceAfter( + Num( + "3", + ), + [ + LineComment( + " 2 Γ— 2", + ), + ], + ), |L 1-1, C 0-1| Plus, ), ], - |L 1-1, C 2-3| Num("4"), + |L 1-1, C 2-3| Num( + "4", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast b/compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast index a8d7a076dc..74bf278e99 100644 --- a/compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/empty_app_header.header.result-ast @@ -1,10 +1,14 @@ App { header: AppHeader { - name: |L 0-0, C 4-14| PlainLine("test-app"), + name: |L 0-0, C 4-14| PlainLine( + "test-app", + ), packages: [], imports: [], provides: [], - to: |L 0-0, C 53-57| ExistingPackage("blah"), + to: |L 0-0, C 53-57| ExistingPackage( + "blah", + ), before_header: [], after_app_keyword: [], before_packages: [], diff --git a/compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast b/compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast index f0ad966519..0e71559779 100644 --- a/compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/empty_interface_header.header.result-ast @@ -1,6 +1,8 @@ Interface { header: InterfaceHeader { - name: |L 0-0, C 10-13| ModuleName("Foo"), + name: |L 0-0, C 10-13| ModuleName( + "Foo", + ), exposes: [], imports: [], before_header: [], diff --git a/compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast b/compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast index 7ce3a5f245..fa3993d530 100644 --- a/compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/empty_platform_header.header.result-ast @@ -1,9 +1,19 @@ Platform { header: PlatformHeader { - name: |L 0-0, C 9-23| PackageName { account: "rtfeldman", pkg: "blah" }, + name: |L 0-0, C 9-23| PackageName { + account: "rtfeldman", + pkg: "blah", + }, requires: PlatformRequires { rigids: [], - signature: |L 0-0, C 38-47| Entry { ident: |L 0-0, C 38-42| "main", spaces_before_colon: [], ann: |L 0-0, C 45-47| Record { fields: [], ext: None } }, + signature: |L 0-0, C 38-47| Entry { + ident: |L 0-0, C 38-42| "main", + spaces_before_colon: [], + ann: |L 0-0, C 45-47| Record { + fields: [], + ext: None, + }, + }, }, exposes: [], packages: [], diff --git a/compiler/parse/tests/snapshots/pass/equals.expr.result-ast b/compiler/parse/tests/snapshots/pass/equals.expr.result-ast index 068907129e..e69ba3d3da 100644 --- a/compiler/parse/tests/snapshots/pass/equals.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/equals.expr.result-ast @@ -1,9 +1,15 @@ BinOps( [ ( - |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 0-1| Var { + module_name: "", + ident: "x", + }, |L 0-0, C 1-3| Equals, ), ], - |L 0-0, C 3-4| Var { module_name: "", ident: "y" }, + |L 0-0, C 3-4| Var { + module_name: "", + ident: "y", + }, ) diff --git a/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast index 392599b087..10e4d471e7 100644 --- a/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/equals_with_spaces.expr.result-ast @@ -1,9 +1,15 @@ BinOps( [ ( - |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 0-1| Var { + module_name: "", + ident: "x", + }, |L 0-0, C 2-4| Equals, ), ], - |L 0-0, C 5-6| Var { module_name: "", ident: "y" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "y", + }, ) diff --git a/compiler/parse/tests/snapshots/pass/expect.expr.result-ast b/compiler/parse/tests/snapshots/pass/expect.expr.result-ast index da20463a0f..06d5710e1a 100644 --- a/compiler/parse/tests/snapshots/pass/expect.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/expect.expr.result-ast @@ -1,4 +1,24 @@ Expect( - |L 0-0, C 7-13| BinOps([(|L 0-0, C 7-8| Num("1"), |L 0-0, C 9-11| Equals)], |L 0-0, C 12-13| Num("1")), - |L 2-2, C 0-1| SpaceBefore(Num("4"), [Newline, Newline]), + |L 0-0, C 7-13| BinOps( + [ + ( + |L 0-0, C 7-8| Num( + "1", + ), + |L 0-0, C 9-11| Equals, + ), + ], + |L 0-0, C 12-13| Num( + "1", + ), + ), + |L 2-2, C 0-1| SpaceBefore( + Num( + "4", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast b/compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast index d66ee260f5..ae59f87b1d 100644 --- a/compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/full_app_header.header.result-ast @@ -1,16 +1,36 @@ App { header: AppHeader { - name: |L 0-0, C 4-15| PlainLine("quicksort"), + name: |L 0-0, C 4-15| PlainLine( + "quicksort", + ), packages: [ - |L 1-1, C 15-33| Entry { shorthand: "base", spaces_after_shorthand: [], package_or_path: |L 1-1, C 21-33| Path(PlainLine("./platform")) }, + |L 1-1, C 15-33| Entry { + shorthand: "base", + spaces_after_shorthand: [], + package_or_path: |L 1-1, C 21-33| Path( + PlainLine( + "./platform", + ), + ), + }, ], imports: [ - |L 2-2, C 14-25| Package("foo", ModuleName("Bar.Baz"), []), + |L 2-2, C 14-25| Package( + "foo", + ModuleName( + "Bar.Baz", + ), + [], + ), ], provides: [ - |L 3-3, C 15-24| Exposed("quicksort"), + |L 3-3, C 15-24| Exposed( + "quicksort", + ), ], - to: |L 3-3, C 30-34| ExistingPackage("base"), + to: |L 3-3, C 30-34| ExistingPackage( + "base", + ), before_header: [], after_app_keyword: [], before_packages: [ diff --git a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast index a6154275d6..d90da83618 100644 --- a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast @@ -1,16 +1,61 @@ App { header: AppHeader { - name: |L 0-0, C 4-15| PlainLine("quicksort"), + name: |L 0-0, C 4-15| PlainLine( + "quicksort", + ), packages: [ - |L 1-1, C 15-33| Entry { shorthand: "base", spaces_after_shorthand: [], package_or_path: |L 1-1, C 21-33| Path(PlainLine("./platform")) }, + |L 1-1, C 15-33| Entry { + shorthand: "base", + spaces_after_shorthand: [], + package_or_path: |L 1-1, C 21-33| Path( + PlainLine( + "./platform", + ), + ), + }, ], imports: [ - |L 2-6, C 14-5| Package("foo", ModuleName("Bar"), Collection { items: [|L 3-3, C 8-11| SpaceBefore(Exposed("Baz"), [Newline]), |L 4-4, C 8-17| SpaceBefore(Exposed("FourtyTwo"), [Newline])], final_comments: [Newline, LineComment(" I'm a happy comment")] }), + |L 2-6, C 14-5| Package( + "foo", + ModuleName( + "Bar", + ), + Collection { + items: [ + |L 3-3, C 8-11| SpaceBefore( + Exposed( + "Baz", + ), + [ + Newline, + ], + ), + |L 4-4, C 8-17| SpaceBefore( + Exposed( + "FourtyTwo", + ), + [ + Newline, + ], + ), + ], + final_comments: [ + Newline, + LineComment( + " I'm a happy comment", + ), + ], + }, + ), ], provides: [ - |L 7-7, C 15-24| Exposed("quicksort"), + |L 7-7, C 15-24| Exposed( + "quicksort", + ), ], - to: |L 7-7, C 31-35| ExistingPackage("base"), + to: |L 7-7, C 31-35| ExistingPackage( + "base", + ), before_header: [], after_app_keyword: [], before_packages: [ diff --git a/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast index f3cff47961..08f0ebe98f 100644 --- a/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast @@ -1,6 +1,21 @@ Defs( [ - |L 0-0, C 0-6| Body(|L 0-0, C 0-4| Identifier("iffy"), |L 0-0, C 5-6| Num("5")), + |L 0-0, C 0-6| Body( + |L 0-0, C 0-4| Identifier( + "iffy", + ), + |L 0-0, C 5-6| Num( + "5", + ), + ), ], - |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 2-2, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast index 4c9eb22446..00c40bc292 100644 --- a/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/malformed_ident_due_to_underscore.expr.result-ast @@ -1,6 +1,14 @@ Closure( [ - |L 0-0, C 1-11| MalformedIdent("the_answer", Underscore(0, 5)), + |L 0-0, C 1-11| MalformedIdent( + "the_answer", + Underscore( + 0, + 5, + ), + ), ], - |L 0-0, C 15-17| Num("42"), + |L 0-0, C 15-17| Num( + "42", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast index dd9efc3fea..038dab88da 100644 --- a/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.result-ast @@ -1,18 +1,39 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 4-11| SpaceBefore(Malformed("bar.and"), [Newline]), + |L 1-1, C 4-11| SpaceBefore( + Malformed( + "bar.and", + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 15-16| Num("1"), + value: |L 1-1, C 15-16| Num( + "1", + ), guard: None, }, WhenBranch { patterns: [ - |L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline]), + |L 2-2, C 4-5| SpaceBefore( + Underscore( + "", + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 9-10| Num("4"), + value: |L 2-2, C 9-10| Num( + "4", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast index d874d1f288..65b4c3c94f 100644 --- a/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.result-ast @@ -1,18 +1,39 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 4-11| SpaceBefore(Malformed("Foo.and"), [Newline]), + |L 1-1, C 4-11| SpaceBefore( + Malformed( + "Foo.and", + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 15-16| Num("1"), + value: |L 1-1, C 15-16| Num( + "1", + ), guard: None, }, WhenBranch { patterns: [ - |L 2-2, C 4-5| SpaceBefore(Underscore(""), [Newline]), + |L 2-2, C 4-5| SpaceBefore( + Underscore( + "", + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 9-10| Num("4"), + value: |L 2-2, C 9-10| Num( + "4", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast b/compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast index 41ea70e9f5..cb26ef49e9 100644 --- a/compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/minimal_app_header.header.result-ast @@ -1,10 +1,18 @@ App { header: AppHeader { - name: |L 0-0, C 4-14| PlainLine("test-app"), + name: |L 0-0, C 4-14| PlainLine( + "test-app", + ), packages: [], imports: [], provides: [], - to: |L 0-0, C 30-38| NewPackage(Path(PlainLine("./blah"))), + to: |L 0-0, C 30-38| NewPackage( + Path( + PlainLine( + "./blah", + ), + ), + ), before_header: [], after_app_keyword: [], before_packages: [], diff --git a/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast index a38bca234e..2540766a37 100644 --- a/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.result-ast @@ -1,9 +1,13 @@ BinOps( [ ( - |L 0-0, C 0-3| Num("-12"), + |L 0-0, C 0-3| Num( + "-12", + ), |L 0-0, C 3-4| Minus, ), ], - |L 0-0, C 4-5| Num("5"), + |L 0-0, C 4-5| Num( + "5", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast index 3254254bc9..eb8ed8b3ea 100644 --- a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast @@ -1,9 +1,24 @@ SpaceBefore( Defs( [ - |L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5")), + |L 4-4, C 0-5| Body( + |L 4-4, C 0-1| Identifier( + "x", + ), + |L 4-4, C 4-5| Num( + "5", + ), + ), ], - |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 6-6, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast b/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast index d5e303be34..1a9e243989 100644 --- a/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast @@ -1,3 +1,42 @@ [ - |L 0-3, C 0-5| SpaceAfter(SpaceBefore(Body(|L 0-0, C 0-4| Identifier("main"), |L 1-3, C 4-5| SpaceBefore(Defs([|L 1-1, C 4-10| Body(|L 1-1, C 4-5| Identifier("i"), |L 1-1, C 8-10| Num("64"))], |L 3-3, C 4-5| SpaceBefore(Var { module_name: "", ident: "i" }, [Newline, Newline])), [Newline])), []), [Newline]), + |L 0-3, C 0-5| SpaceAfter( + SpaceBefore( + Body( + |L 0-0, C 0-4| Identifier( + "main", + ), + |L 1-3, C 4-5| SpaceBefore( + Defs( + [ + |L 1-1, C 4-10| Body( + |L 1-1, C 4-5| Identifier( + "i", + ), + |L 1-1, C 8-10| Num( + "64", + ), + ), + ], + |L 3-3, C 4-5| SpaceBefore( + Var { + module_name: "", + ident: "i", + }, + [ + Newline, + Newline, + ], + ), + ), + [ + Newline, + ], + ), + ), + [], + ), + [ + Newline, + ], + ), ] diff --git a/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast index 531c867b6d..d077cef709 100644 --- a/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.result-ast @@ -1,8 +1,46 @@ Backpassing( [ - |L 0-0, C 0-1| Identifier("x"), - |L 0-0, C 3-4| Identifier("y"), + |L 0-0, C 0-1| Identifier( + "x", + ), + |L 0-0, C 3-4| Identifier( + "y", + ), ], - |L 0-0, C 8-23| Apply(|L 0-0, C 8-17| Var { module_name: "List", ident: "map2" }, [|L 0-0, C 18-20| List([]), |L 0-0, C 21-23| List([])], Space), - |L 2-2, C 0-5| SpaceBefore(BinOps([(|L 2-2, C 0-1| Var { module_name: "", ident: "x" }, |L 2-2, C 2-3| Plus)], |L 2-2, C 4-5| Var { module_name: "", ident: "y" }), [Newline, Newline]), + |L 0-0, C 8-23| Apply( + |L 0-0, C 8-17| Var { + module_name: "List", + ident: "map2", + }, + [ + |L 0-0, C 18-20| List( + [], + ), + |L 0-0, C 21-23| List( + [], + ), + ], + Space, + ), + |L 2-2, C 0-5| SpaceBefore( + BinOps( + [ + ( + |L 2-2, C 0-1| Var { + module_name: "", + ident: "x", + }, + |L 2-2, C 2-3| Plus, + ), + ], + |L 2-2, C 4-5| Var { + module_name: "", + ident: "y", + }, + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast index 9010dbf1f0..c6e1c801ac 100644 --- a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast @@ -1,6 +1,27 @@ Defs( [ - |L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: [], ext: None }, [Newline])), + |L 0-1, C 0-6| Annotation( + |L 0-0, C 0-1| Identifier( + "f", + ), + |L 1-1, C 4-6| SpaceBefore( + Record { + fields: [], + ext: None, + }, + [ + Newline, + ], + ), + ), ], - |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 3-3, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast index 0a0ada87c2..8ba2bc2b26 100644 --- a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast @@ -1,6 +1,29 @@ Defs( [ - |L 0-1, C 0-6| Annotation(|L 0-0, C 0-1| Identifier("f"), |L 1-1, C 4-6| SpaceBefore(Record { fields: [], ext: None }, [LineComment(" comment")])), + |L 0-1, C 0-6| Annotation( + |L 0-0, C 0-1| Identifier( + "f", + ), + |L 1-1, C 4-6| SpaceBefore( + Record { + fields: [], + ext: None, + }, + [ + LineComment( + " comment", + ), + ], + ), + ), ], - |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 3-3, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast index 086c909e83..f5e1463092 100644 --- a/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiple_operators.expr.result-ast @@ -1,13 +1,19 @@ BinOps( [ ( - |L 0-0, C 0-2| Num("31"), + |L 0-0, C 0-2| Num( + "31", + ), |L 0-0, C 2-3| Star, ), ( - |L 0-0, C 3-5| Num("42"), + |L 0-0, C 3-5| Num( + "42", + ), |L 0-0, C 5-6| Plus, ), ], - |L 0-0, C 6-9| Num("534"), + |L 0-0, C 6-9| Num( + "534", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast index acc5e5f702..617306a026 100644 --- a/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/neg_inf_float.expr.result-ast @@ -1,4 +1,7 @@ UnaryOp( - |L 0-0, C 1-4| Var { module_name: "", ident: "inf" }, + |L 0-0, C 1-4| Var { + module_name: "", + ident: "inf", + }, |L 0-0, C 0-1| Negate, ) diff --git a/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast index 9257867e69..0c597f8d28 100644 --- a/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast @@ -1,3 +1,99 @@ [ - |L 0-5, C 0-20| SpaceAfter(SpaceBefore(Body(|L 0-0, C 0-4| Identifier("main"), |L 1-5, C 4-20| SpaceBefore(Defs([|L 2-3, C 4-20| AnnotatedBody { ann_pattern: |L 1-1, C 4-16| Identifier("wrappedNotEq"), ann_type: |L 1-1, C 27-31| Function([|L 1-1, C 19-20| BoundVariable("a"), |L 1-1, C 22-23| BoundVariable("a")], |L 1-1, C 27-31| Apply("", "Bool", [])), comment: None, body_pattern: |L 2-2, C 4-16| Identifier("wrappedNotEq"), body_expr: |L 2-3, C 19-20| Closure([|L 2-2, C 20-24| Identifier("num1"), |L 2-2, C 26-30| Identifier("num2")], |L 3-3, C 8-20| SpaceBefore(BinOps([(|L 3-3, C 8-12| Var { module_name: "", ident: "num1" }, |L 3-3, C 13-15| NotEquals)], |L 3-3, C 16-20| Var { module_name: "", ident: "num2" }), [Newline])) }], |L 5-5, C 4-20| SpaceBefore(Apply(|L 5-5, C 4-16| Var { module_name: "", ident: "wrappedNotEq" }, [|L 5-5, C 17-18| Num("2"), |L 5-5, C 19-20| Num("3")], Space), [Newline, Newline])), [Newline])), []), [Newline]), + |L 0-5, C 0-20| SpaceAfter( + SpaceBefore( + Body( + |L 0-0, C 0-4| Identifier( + "main", + ), + |L 1-5, C 4-20| SpaceBefore( + Defs( + [ + |L 2-3, C 4-20| AnnotatedBody { + ann_pattern: |L 1-1, C 4-16| Identifier( + "wrappedNotEq", + ), + ann_type: |L 1-1, C 27-31| Function( + [ + |L 1-1, C 19-20| BoundVariable( + "a", + ), + |L 1-1, C 22-23| BoundVariable( + "a", + ), + ], + |L 1-1, C 27-31| Apply( + "", + "Bool", + [], + ), + ), + comment: None, + body_pattern: |L 2-2, C 4-16| Identifier( + "wrappedNotEq", + ), + body_expr: |L 2-3, C 19-20| Closure( + [ + |L 2-2, C 20-24| Identifier( + "num1", + ), + |L 2-2, C 26-30| Identifier( + "num2", + ), + ], + |L 3-3, C 8-20| SpaceBefore( + BinOps( + [ + ( + |L 3-3, C 8-12| Var { + module_name: "", + ident: "num1", + }, + |L 3-3, C 13-15| NotEquals, + ), + ], + |L 3-3, C 16-20| Var { + module_name: "", + ident: "num2", + }, + ), + [ + Newline, + ], + ), + ), + }, + ], + |L 5-5, C 4-20| SpaceBefore( + Apply( + |L 5-5, C 4-16| Var { + module_name: "", + ident: "wrappedNotEq", + }, + [ + |L 5-5, C 17-18| Num( + "2", + ), + |L 5-5, C 19-20| Num( + "3", + ), + ], + Space, + ), + [ + Newline, + Newline, + ], + ), + ), + [ + Newline, + ], + ), + ), + [], + ), + [ + Newline, + ], + ), ] diff --git a/compiler/parse/tests/snapshots/pass/nested_module.header.result-ast b/compiler/parse/tests/snapshots/pass/nested_module.header.result-ast index 77fc6b1137..532089580b 100644 --- a/compiler/parse/tests/snapshots/pass/nested_module.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/nested_module.header.result-ast @@ -1,6 +1,8 @@ Interface { header: InterfaceHeader { - name: |L 0-0, C 10-21| ModuleName("Foo.Bar.Baz"), + name: |L 0-0, C 10-21| ModuleName( + "Foo.Bar.Baz", + ), exposes: [], imports: [], before_header: [], diff --git a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast index 976613078e..70cc7456f6 100644 --- a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast @@ -1,6 +1,26 @@ Defs( [ - |L 0-1, C 0-5| Body(|L 0-0, C 0-1| Identifier("x"), |L 1-1, C 4-5| SpaceBefore(Num("5"), [Newline])), + |L 0-1, C 0-5| Body( + |L 0-0, C 0-1| Identifier( + "x", + ), + |L 1-1, C 4-5| SpaceBefore( + Num( + "5", + ), + [ + Newline, + ], + ), + ), ], - |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 3-3, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast index 14422bf720..977121c8ea 100644 --- a/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.result-ast @@ -1,9 +1,18 @@ BinOps( [ ( - |L 0-0, C 0-1| Num("3"), + |L 0-0, C 0-1| Num( + "3", + ), |L 0-0, C 3-4| Star, ), ], - |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]), + |L 1-1, C 2-3| SpaceBefore( + Num( + "4", + ), + [ + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast index 360329598f..f6ac47b32a 100644 --- a/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.result-ast @@ -1,9 +1,18 @@ BinOps( [ ( - |L 0-0, C 0-1| Num("3"), + |L 0-0, C 0-1| Num( + "3", + ), |L 0-0, C 3-4| Minus, ), ], - |L 1-1, C 2-3| SpaceBefore(Num("4"), [Newline]), + |L 1-1, C 2-3| SpaceBefore( + Num( + "4", + ), + [ + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast index 247cd19154..78bbc9865e 100644 --- a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast @@ -1,6 +1,36 @@ Defs( [ - |L 0-1, C 0-7| Body(|L 0-0, C 0-1| Identifier("x"), |L 0-1, C 4-7| BinOps([(|L 0-0, C 4-5| SpaceAfter(Num("1"), [Newline]), |L 1-1, C 4-5| LessThan)], |L 1-1, C 6-7| Num("2"))), + |L 0-1, C 0-7| Body( + |L 0-0, C 0-1| Identifier( + "x", + ), + |L 0-1, C 4-7| BinOps( + [ + ( + |L 0-0, C 4-5| SpaceAfter( + Num( + "1", + ), + [ + Newline, + ], + ), + |L 1-1, C 4-5| LessThan, + ), + ], + |L 1-1, C 6-7| Num( + "2", + ), + ), + ), ], - |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 3-3, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast index 06f96fd4ec..73c9b6b40d 100644 --- a/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_before_add.expr.result-ast @@ -1,9 +1,18 @@ BinOps( [ ( - |L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), + |L 0-0, C 0-1| SpaceAfter( + Num( + "3", + ), + [ + Newline, + ], + ), |L 1-1, C 0-1| Plus, ), ], - |L 1-1, C 2-3| Num("4"), + |L 1-1, C 2-3| Num( + "4", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast index 5acd3eaf55..4b8d5725c4 100644 --- a/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_before_sub.expr.result-ast @@ -1,9 +1,18 @@ BinOps( [ ( - |L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), + |L 0-0, C 0-1| SpaceAfter( + Num( + "3", + ), + [ + Newline, + ], + ), |L 1-1, C 0-1| Minus, ), ], - |L 1-1, C 2-3| Num("4"), + |L 1-1, C 2-3| Num( + "4", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast index 6f97b37bdb..15f065505b 100644 --- a/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.result-ast @@ -1,5 +1,17 @@ List( [ - |L 1-1, C 0-1| SpaceBefore(SpaceAfter(Num("1"), [Newline]), [Newline]), + |L 1-1, C 0-1| SpaceBefore( + SpaceAfter( + Num( + "1", + ), + [ + Newline, + ], + ), + [ + Newline, + ], + ), ], ) diff --git a/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast b/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast index dd29e16963..8497dc8470 100644 --- a/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/nonempty_platform_header.header.result-ast @@ -1,19 +1,42 @@ Platform { header: PlatformHeader { - name: |L 0-0, C 9-19| PackageName { account: "foo", pkg: "barbaz" }, + name: |L 0-0, C 9-19| PackageName { + account: "foo", + pkg: "barbaz", + }, requires: PlatformRequires { rigids: [ - |L 1-1, C 14-26| Entry { rigid: "model", alias: "Model" }, + |L 1-1, C 14-26| Entry { + rigid: "model", + alias: "Model", + }, ], - signature: |L 1-1, C 30-39| Entry { ident: |L 1-1, C 30-34| "main", spaces_before_colon: [], ann: |L 1-1, C 37-39| Record { fields: [], ext: None } }, + signature: |L 1-1, C 30-39| Entry { + ident: |L 1-1, C 30-34| "main", + spaces_before_colon: [], + ann: |L 1-1, C 37-39| Record { + fields: [], + ext: None, + }, + }, }, exposes: [], packages: [ - |L 3-3, C 15-27| Entry { shorthand: "foo", spaces_after_shorthand: [], package_or_path: |L 3-3, C 20-27| Path(PlainLine("./foo")) }, + |L 3-3, C 15-27| Entry { + shorthand: "foo", + spaces_after_shorthand: [], + package_or_path: |L 3-3, C 20-27| Path( + PlainLine( + "./foo", + ), + ), + }, ], imports: [], provides: [ - |L 5-5, C 15-26| Exposed("mainForHost"), + |L 5-5, C 15-26| Exposed( + "mainForHost", + ), ], effects: Effects { spaces_before_effects_keyword: [ diff --git a/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast index 9c59e63603..0a5c470bc0 100644 --- a/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast @@ -1,9 +1,24 @@ SpaceBefore( Defs( [ - |L 4-4, C 0-5| Body(|L 4-4, C 0-1| Identifier("x"), |L 4-4, C 4-5| Num("5")), + |L 4-4, C 0-5| Body( + |L 4-4, C 0-1| Identifier( + "x", + ), + |L 4-4, C 4-5| Num( + "5", + ), + ), ], - |L 6-6, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 6-6, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast index 082f836bfa..257e698479 100644 --- a/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_backpassing.expr.result-ast @@ -1,10 +1,33 @@ SpaceBefore( Backpassing( [ - |L 1-1, C 0-1| Identifier("x"), + |L 1-1, C 0-1| Identifier( + "x", + ), ], - |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), - |L 3-3, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline]), + |L 1-1, C 5-14| ParensAround( + Closure( + [ + |L 1-1, C 7-8| Identifier( + "y", + ), + ], + |L 1-1, C 12-13| Var { + module_name: "", + ident: "y", + }, + ), + ), + |L 3-3, C 0-1| SpaceBefore( + Var { + module_name: "", + ident: "x", + }, + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast index 9f8258fc18..daa047957c 100644 --- a/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast @@ -1,9 +1,24 @@ SpaceBefore( Defs( [ - |L 1-1, C 0-3| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 2-3| Num("5")), + |L 1-1, C 0-3| Body( + |L 1-1, C 0-1| Identifier( + "x", + ), + |L 1-1, C 2-3| Num( + "5", + ), + ), ], - |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 3-3, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast index 03441c3589..77fd849f59 100644 --- a/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_minus_two.expr.result-ast @@ -1,9 +1,13 @@ BinOps( [ ( - |L 0-0, C 0-1| Num("1"), + |L 0-0, C 0-1| Num( + "1", + ), |L 0-0, C 1-2| Minus, ), ], - |L 0-0, C 2-3| Num("2"), + |L 0-0, C 2-3| Num( + "2", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast index 53900d251b..7e45139380 100644 --- a/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_plus_two.expr.result-ast @@ -1,9 +1,13 @@ BinOps( [ ( - |L 0-0, C 0-1| Num("1"), + |L 0-0, C 0-1| Num( + "1", + ), |L 0-0, C 1-2| Plus, ), ], - |L 0-0, C 2-3| Num("2"), + |L 0-0, C 2-3| Num( + "2", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast index de72973a81..001962d745 100644 --- a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast @@ -1,9 +1,24 @@ SpaceBefore( Defs( [ - |L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5")), + |L 1-1, C 0-5| Body( + |L 1-1, C 0-1| Identifier( + "x", + ), + |L 1-1, C 4-5| Num( + "5", + ), + ), ], - |L 3-3, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 3-3, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast index af56333e09..f35a0b6c44 100644 --- a/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.result-ast @@ -1,9 +1,24 @@ BinOps( [ ( - |L 0-0, C 0-1| SpaceAfter(Num("3"), [Newline]), + |L 0-0, C 0-1| SpaceAfter( + Num( + "3", + ), + [ + Newline, + ], + ), |L 1-1, C 0-1| Plus, ), ], - |L 3-3, C 2-3| SpaceBefore(Num("4"), [Newline, Newline]), + |L 3-3, C 2-3| SpaceBefore( + Num( + "4", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast index f8516076c6..2548a5221e 100644 --- a/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/packed_singleton_list.expr.result-ast @@ -1,5 +1,7 @@ List( [ - |L 0-0, C 1-2| Num("1"), + |L 0-0, C 1-2| Num( + "1", + ), ], ) diff --git a/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast index 86f76b2eee..ea1031f76d 100644 --- a/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parenthetical_apply.expr.result-ast @@ -1,7 +1,14 @@ Apply( - |L 0-0, C 1-5| ParensAround(Var { module_name: "", ident: "whee" }), + |L 0-0, C 1-5| ParensAround( + Var { + module_name: "", + ident: "whee", + }, + ), [ - |L 0-0, C 7-8| Num("1"), + |L 0-0, C 7-8| Num( + "1", + ), ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast index 7122510366..f23f7883e8 100644 --- a/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast @@ -1,6 +1,36 @@ Defs( [ - |L 0-0, C 0-26| Alias { name: |L 0-0, C 0-4| "Blah", vars: [|L 0-0, C 5-6| Identifier("a"), |L 0-0, C 7-8| Identifier("b")], ann: |L 0-0, C 11-26| Apply("Foo.Bar", "Baz", [|L 0-0, C 23-24| BoundVariable("x"), |L 0-0, C 25-26| BoundVariable("y")]) }, + |L 0-0, C 0-26| Alias { + name: |L 0-0, C 0-4| "Blah", + vars: [ + |L 0-0, C 5-6| Identifier( + "a", + ), + |L 0-0, C 7-8| Identifier( + "b", + ), + ], + ann: |L 0-0, C 11-26| Apply( + "Foo.Bar", + "Baz", + [ + |L 0-0, C 23-24| BoundVariable( + "x", + ), + |L 0-0, C 25-26| BoundVariable( + "y", + ), + ], + ), + }, ], - |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 2-2, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast index 1b9abdea43..08b1230271 100644 --- a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast @@ -1,6 +1,45 @@ Defs( [ - |L 0-0, C 0-33| Annotation(|L 0-0, C 0-3| Identifier("foo"), |L 0-0, C 6-33| As(|L 0-0, C 6-21| Apply("Foo.Bar", "Baz", [|L 0-0, C 18-19| BoundVariable("x"), |L 0-0, C 20-21| BoundVariable("y")]), [], |L 0-0, C 25-33| Apply("", "Blah", [|L 0-0, C 30-31| BoundVariable("a"), |L 0-0, C 32-33| BoundVariable("b")]))), + |L 0-0, C 0-33| Annotation( + |L 0-0, C 0-3| Identifier( + "foo", + ), + |L 0-0, C 6-33| As( + |L 0-0, C 6-21| Apply( + "Foo.Bar", + "Baz", + [ + |L 0-0, C 18-19| BoundVariable( + "x", + ), + |L 0-0, C 20-21| BoundVariable( + "y", + ), + ], + ), + [], + |L 0-0, C 25-33| Apply( + "", + "Blah", + [ + |L 0-0, C 30-31| BoundVariable( + "a", + ), + |L 0-0, C 32-33| BoundVariable( + "b", + ), + ], + ), + ), + ), ], - |L 2-2, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 2-2, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ) diff --git a/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast index 00ba5eabe5..962f52971a 100644 --- a/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast @@ -1,11 +1,79 @@ When( - |L 0-0, C 5-22| Apply(|L 0-0, C 5-11| GlobalTag("Delmin"), [|L 0-0, C 13-19| ParensAround(Apply(|L 0-0, C 13-16| GlobalTag("Del"), [|L 0-0, C 17-19| Var { module_name: "", ident: "rx" }], Space)), |L 0-0, C 21-22| Num("0")], Space), + |L 0-0, C 5-22| Apply( + |L 0-0, C 5-11| GlobalTag( + "Delmin", + ), + [ + |L 0-0, C 13-19| ParensAround( + Apply( + |L 0-0, C 13-16| GlobalTag( + "Del", + ), + [ + |L 0-0, C 17-19| Var { + module_name: "", + ident: "rx", + }, + ], + Space, + ), + ), + |L 0-0, C 21-22| Num( + "0", + ), + ], + Space, + ), [ WhenBranch { patterns: [ - |L 1-1, C 4-22| SpaceBefore(Apply(|L 1-1, C 4-10| GlobalTag("Delmin"), [|L 1-1, C 12-18| Apply(|L 1-1, C 12-15| GlobalTag("Del"), [|L 1-1, C 16-18| Identifier("ry")]), |L 1-1, C 21-22| Underscore("")]), [Newline]), + |L 1-1, C 4-22| SpaceBefore( + Apply( + |L 1-1, C 4-10| GlobalTag( + "Delmin", + ), + [ + |L 1-1, C 12-18| Apply( + |L 1-1, C 12-15| GlobalTag( + "Del", + ), + [ + |L 1-1, C 16-18| Identifier( + "ry", + ), + ], + ), + |L 1-1, C 21-22| Underscore( + "", + ), + ], + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 26-47| Apply(|L 1-1, C 26-30| GlobalTag("Node"), [|L 1-1, C 31-36| GlobalTag("Black"), |L 1-1, C 37-38| Num("0"), |L 1-1, C 39-44| GlobalTag("False"), |L 1-1, C 45-47| Var { module_name: "", ident: "ry" }], Space), + value: |L 1-1, C 26-47| Apply( + |L 1-1, C 26-30| GlobalTag( + "Node", + ), + [ + |L 1-1, C 31-36| GlobalTag( + "Black", + ), + |L 1-1, C 37-38| Num( + "0", + ), + |L 1-1, C 39-44| GlobalTag( + "False", + ), + |L 1-1, C 45-47| Var { + module_name: "", + ident: "ry", + }, + ], + Space, + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast index 5ec4d07efd..db061e68f7 100644 --- a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast @@ -1,10 +1,44 @@ SpaceBefore( Defs( [ - |L 1-1, C 0-12| Body(|L 1-1, C 0-8| RecordDestructure([|L 1-1, C 2-3| Identifier("x"), |L 1-1, C 5-7| Identifier("y")]), |L 1-1, C 11-12| Num("5")), - |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline]), + |L 1-1, C 0-12| Body( + |L 1-1, C 0-8| RecordDestructure( + [ + |L 1-1, C 2-3| Identifier( + "x", + ), + |L 1-1, C 5-7| Identifier( + "y", + ), + ], + ), + |L 1-1, C 11-12| Num( + "5", + ), + ), + |L 2-2, C 0-5| SpaceBefore( + Body( + |L 2-2, C 0-1| Identifier( + "y", + ), + |L 2-2, C 4-5| Num( + "6", + ), + ), + [ + Newline, + ], + ), ], - |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 4-4, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast index b367b0c424..7ee1e6b7b0 100644 --- a/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_update.expr.result-ast @@ -1,7 +1,22 @@ RecordUpdate { - update: |L 0-0, C 2-13| Var { module_name: "Foo.Bar", ident: "baz" }, + update: |L 0-0, C 2-13| Var { + module_name: "Foo.Bar", + ident: "baz", + }, fields: [ - |L 0-0, C 16-20| RequiredValue(|L 0-0, C 16-17| "x", [], |L 0-0, C 19-20| Num("5")), - |L 0-0, C 22-26| RequiredValue(|L 0-0, C 22-23| "y", [], |L 0-0, C 25-26| Num("0")), + |L 0-0, C 16-20| RequiredValue( + |L 0-0, C 16-17| "x", + [], + |L 0-0, C 19-20| Num( + "5", + ), + ), + |L 0-0, C 22-26| RequiredValue( + |L 0-0, C 22-23| "y", + [], + |L 0-0, C 25-26| Num( + "0", + ), + ), ], } diff --git a/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast index 08540b40b5..b4f4133f3b 100644 --- a/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_with_if.expr.result-ast @@ -1,6 +1,30 @@ Record( [ - |L 0-0, C 1-26| RequiredValue(|L 0-0, C 1-2| "x", [], |L 0-0, C 5-26| If([(|L 0-0, C 8-12| GlobalTag("True"), |L 0-0, C 18-19| Num("1"))], |L 0-0, C 25-26| Num("2"))), - |L 0-0, C 28-32| RequiredValue(|L 0-0, C 28-29| "y", [], |L 0-0, C 31-32| Num("3")), + |L 0-0, C 1-26| RequiredValue( + |L 0-0, C 1-2| "x", + [], + |L 0-0, C 5-26| If( + [ + ( + |L 0-0, C 8-12| GlobalTag( + "True", + ), + |L 0-0, C 18-19| Num( + "1", + ), + ), + ], + |L 0-0, C 25-26| Num( + "2", + ), + ), + ), + |L 0-0, C 28-32| RequiredValue( + |L 0-0, C 28-29| "y", + [], + |L 0-0, C 31-32| Num( + "3", + ), + ), ], ) diff --git a/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast index ee93f985db..ca8f338bbd 100644 --- a/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/single_arg_closure.expr.result-ast @@ -1,6 +1,10 @@ Closure( [ - |L 0-0, C 1-2| Identifier("a"), + |L 0-0, C 1-2| Identifier( + "a", + ), ], - |L 0-0, C 6-8| Num("42"), + |L 0-0, C 6-8| Num( + "42", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast index a4b25da18c..c3657bfca5 100644 --- a/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/single_underscore_closure.expr.result-ast @@ -1,6 +1,10 @@ Closure( [ - |L 0-0, C 1-2| Underscore(""), + |L 0-0, C 1-2| Underscore( + "", + ), ], - |L 0-0, C 6-8| Num("42"), + |L 0-0, C 6-8| Num( + "42", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast index 853855b4cf..7ba8b91f84 100644 --- a/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.result-ast @@ -1,9 +1,15 @@ BinOps( [ ( - |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 0-1| Var { + module_name: "", + ident: "x", + }, |L 0-0, C 1-2| Minus, ), ], - |L 0-0, C 3-4| Var { module_name: "", ident: "y" }, + |L 0-0, C 3-4| Var { + module_name: "", + ident: "y", + }, ) diff --git a/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast index 53b37d4c4c..38acc0b739 100644 --- a/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.result-ast @@ -1,5 +1,7 @@ List( [ - |L 0-0, C 2-3| Num("1"), + |L 0-0, C 2-3| Num( + "1", + ), ], ) diff --git a/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast index 1eae8ebab4..df2876e5a3 100644 --- a/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast @@ -1,5 +1,59 @@ [ - |L 1-1, C 0-7| SpaceBefore(Body(|L 1-1, C 0-3| Identifier("foo"), |L 1-1, C 6-7| Num("1")), [LineComment(" comment 1")]), - |L 4-4, C 0-10| SpaceBefore(Body(|L 4-4, C 0-3| Identifier("bar"), |L 4-4, C 6-10| Str(PlainLine("hi"))), [Newline, Newline, LineComment(" comment 2")]), - |L 5-5, C 0-13| SpaceAfter(SpaceBefore(Body(|L 5-5, C 0-3| Identifier("baz"), |L 5-5, C 6-13| Str(PlainLine("stuff"))), [Newline]), [Newline, LineComment(" comment n")]), + |L 1-1, C 0-7| SpaceBefore( + Body( + |L 1-1, C 0-3| Identifier( + "foo", + ), + |L 1-1, C 6-7| Num( + "1", + ), + ), + [ + LineComment( + " comment 1", + ), + ], + ), + |L 4-4, C 0-10| SpaceBefore( + Body( + |L 4-4, C 0-3| Identifier( + "bar", + ), + |L 4-4, C 6-10| Str( + PlainLine( + "hi", + ), + ), + ), + [ + Newline, + Newline, + LineComment( + " comment 2", + ), + ], + ), + |L 5-5, C 0-13| SpaceAfter( + SpaceBefore( + Body( + |L 5-5, C 0-3| Identifier( + "baz", + ), + |L 5-5, C 6-13| Str( + PlainLine( + "stuff", + ), + ), + ), + [ + Newline, + ], + ), + [ + Newline, + LineComment( + " comment n", + ), + ], + ), ] diff --git a/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast index bacbb22bb7..a0930ee9cf 100644 --- a/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/sub_var_with_spaces.expr.result-ast @@ -1,9 +1,14 @@ BinOps( [ ( - |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 0-1| Var { + module_name: "", + ident: "x", + }, |L 0-0, C 2-3| Minus, ), ], - |L 0-0, C 4-5| Num("2"), + |L 0-0, C 4-5| Num( + "2", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast index 8ae13655e0..f68168b626 100644 --- a/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.result-ast @@ -1,9 +1,13 @@ BinOps( [ ( - |L 0-0, C 0-1| Num("1"), + |L 0-0, C 0-1| Num( + "1", + ), |L 0-0, C 3-4| Minus, ), ], - |L 0-0, C 7-8| Num("2"), + |L 0-0, C 7-8| Num( + "2", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast index b3eb2afca2..921fe3c6ad 100644 --- a/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/tag_pattern.expr.result-ast @@ -1,6 +1,10 @@ Closure( [ - |L 0-0, C 1-6| GlobalTag("Thing"), + |L 0-0, C 1-6| GlobalTag( + "Thing", + ), ], - |L 0-0, C 10-12| Num("42"), + |L 0-0, C 10-12| Num( + "42", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast index 268cbbfcc5..431a12166e 100644 --- a/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.result-ast @@ -1,9 +1,13 @@ BinOps( [ ( - |L 0-0, C 0-2| Num("10"), + |L 0-0, C 0-2| Num( + "10", + ), |L 0-0, C 2-3| Star, ), ], - |L 0-0, C 3-5| Num("11"), + |L 0-0, C 3-5| Num( + "11", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast index 74049bd26c..e40979f575 100644 --- a/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/three_arg_closure.expr.result-ast @@ -1,8 +1,16 @@ Closure( [ - |L 0-0, C 1-2| Identifier("a"), - |L 0-0, C 4-5| Identifier("b"), - |L 0-0, C 7-8| Identifier("c"), + |L 0-0, C 1-2| Identifier( + "a", + ), + |L 0-0, C 4-5| Identifier( + "b", + ), + |L 0-0, C 7-8| Identifier( + "c", + ), ], - |L 0-0, C 12-14| Num("42"), + |L 0-0, C 12-14| Num( + "42", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast index 3fa37c5348..cba1cb7d83 100644 --- a/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_arg_closure.expr.result-ast @@ -1,7 +1,13 @@ Closure( [ - |L 0-0, C 1-2| Identifier("a"), - |L 0-0, C 4-5| Identifier("b"), + |L 0-0, C 1-2| Identifier( + "a", + ), + |L 0-0, C 4-5| Identifier( + "b", + ), ], - |L 0-0, C 9-11| Num("42"), + |L 0-0, C 9-11| Num( + "42", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast index 2d6b4e7935..d1fefd06d4 100644 --- a/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_backpassing.expr.result-ast @@ -1,10 +1,48 @@ SpaceBefore( Backpassing( [ - |L 1-1, C 0-1| Identifier("x"), + |L 1-1, C 0-1| Identifier( + "x", + ), ], - |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), - |L 2-4, C 0-1| SpaceBefore(Backpassing([|L 2-2, C 0-1| Identifier("z")], |L 2-2, C 5-7| Record([]), |L 4-4, C 0-1| SpaceBefore(Var { module_name: "", ident: "x" }, [Newline, Newline])), [Newline]), + |L 1-1, C 5-14| ParensAround( + Closure( + [ + |L 1-1, C 7-8| Identifier( + "y", + ), + ], + |L 1-1, C 12-13| Var { + module_name: "", + ident: "y", + }, + ), + ), + |L 2-4, C 0-1| SpaceBefore( + Backpassing( + [ + |L 2-2, C 0-1| Identifier( + "z", + ), + ], + |L 2-2, C 5-7| Record( + [], + ), + |L 4-4, C 0-1| SpaceBefore( + Var { + module_name: "", + ident: "x", + }, + [ + Newline, + Newline, + ], + ), + ), + [ + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast index d7ed770bdd..bfda25dc05 100644 --- a/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_branch_when.expr.result-ast @@ -1,18 +1,43 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 1-3| SpaceBefore(StrLiteral(PlainLine("")), [Newline]), + |L 1-1, C 1-3| SpaceBefore( + StrLiteral( + PlainLine( + "", + ), + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 7-8| Num("1"), + value: |L 1-1, C 7-8| Num( + "1", + ), guard: None, }, WhenBranch { patterns: [ - |L 2-2, C 1-7| SpaceBefore(StrLiteral(PlainLine("mise")), [Newline]), + |L 2-2, C 1-7| SpaceBefore( + StrLiteral( + PlainLine( + "mise", + ), + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 11-12| Num("2"), + value: |L 2-2, C 11-12| Num( + "2", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast index d496253434..4b7817ea4c 100644 --- a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast @@ -1,10 +1,37 @@ SpaceBefore( Defs( [ - |L 1-1, C 0-5| Body(|L 1-1, C 0-1| Identifier("x"), |L 1-1, C 4-5| Num("5")), - |L 2-2, C 0-5| SpaceBefore(Body(|L 2-2, C 0-1| Identifier("y"), |L 2-2, C 4-5| Num("6")), [Newline]), + |L 1-1, C 0-5| Body( + |L 1-1, C 0-1| Identifier( + "x", + ), + |L 1-1, C 4-5| Num( + "5", + ), + ), + |L 2-2, C 0-5| SpaceBefore( + Body( + |L 2-2, C 0-1| Identifier( + "y", + ), + |L 2-2, C 4-5| Num( + "6", + ), + ), + [ + Newline, + ], + ), ], - |L 4-4, C 0-2| SpaceBefore(Num("42"), [Newline, Newline]), + |L 4-4, C 0-2| SpaceBefore( + Num( + "42", + ), + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast index 43bf682327..0b69481d27 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation.expr.result-ast @@ -1,4 +1,7 @@ UnaryOp( - |L 0-0, C 1-4| Var { module_name: "", ident: "foo" }, + |L 0-0, C 1-4| Var { + module_name: "", + ident: "foo", + }, |L 0-0, C 0-1| Negate, ) diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast index 0feb302951..bac391b5bb 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation_access.expr.result-ast @@ -1,4 +1,10 @@ UnaryOp( - |L 0-0, C 1-11| Access(Var { module_name: "", ident: "rec1" }, "field"), + |L 0-0, C 1-11| Access( + Var { + module_name: "", + ident: "rec1", + }, + "field", + ), |L 0-0, C 0-1| Negate, ) diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast index 0b776b64d7..b584acfb8b 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.result-ast @@ -1,8 +1,19 @@ Apply( - |L 0-0, C 0-4| Var { module_name: "", ident: "whee" }, + |L 0-0, C 0-4| Var { + module_name: "", + ident: "whee", + }, [ - |L 0-0, C 6-8| Num("12"), - |L 0-0, C 9-13| UnaryOp(|L 0-0, C 10-13| Var { module_name: "", ident: "foo" }, |L 0-0, C 9-10| Negate), + |L 0-0, C 6-8| Num( + "12", + ), + |L 0-0, C 9-13| UnaryOp( + |L 0-0, C 10-13| Var { + module_name: "", + ident: "foo", + }, + |L 0-0, C 9-10| Negate, + ), ], Space, ) diff --git a/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast index d5862151cf..995295897e 100644 --- a/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.result-ast @@ -1,4 +1,21 @@ UnaryOp( - |L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), + |L 0-0, C 2-14| ParensAround( + Apply( + |L 0-0, C 2-6| Var { + module_name: "", + ident: "whee", + }, + [ + |L 0-0, C 8-10| Num( + "12", + ), + |L 0-0, C 11-14| Var { + module_name: "", + ident: "foo", + }, + ], + Space, + ), + ), |L 0-0, C 0-1| Negate, ) diff --git a/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast index d4f1b679c8..1264450798 100644 --- a/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_not.expr.result-ast @@ -1,4 +1,7 @@ UnaryOp( - |L 0-0, C 1-5| Var { module_name: "", ident: "blah" }, + |L 0-0, C 1-5| Var { + module_name: "", + ident: "blah", + }, |L 0-0, C 0-1| Not, ) diff --git a/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast index b3b866b2b4..4d744df18b 100644 --- a/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.result-ast @@ -1,4 +1,21 @@ UnaryOp( - |L 0-0, C 2-14| ParensAround(Apply(|L 0-0, C 2-6| Var { module_name: "", ident: "whee" }, [|L 0-0, C 8-10| Num("12"), |L 0-0, C 11-14| Var { module_name: "", ident: "foo" }], Space)), + |L 0-0, C 2-14| ParensAround( + Apply( + |L 0-0, C 2-6| Var { + module_name: "", + ident: "whee", + }, + [ + |L 0-0, C 8-10| Num( + "12", + ), + |L 0-0, C 11-14| Var { + module_name: "", + ident: "foo", + }, + ], + Space, + ), + ), |L 0-0, C 0-1| Not, ) diff --git a/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast index 67ae3a32b4..afb4402f55 100644 --- a/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.result-ast @@ -1,10 +1,32 @@ SpaceBefore( Backpassing( [ - |L 1-1, C 0-1| Underscore(""), + |L 1-1, C 0-1| Underscore( + "", + ), ], - |L 1-1, C 5-14| ParensAround(Closure([|L 1-1, C 7-8| Identifier("y")], |L 1-1, C 12-13| Var { module_name: "", ident: "y" })), - |L 3-3, C 0-1| SpaceBefore(Num("4"), [Newline, Newline]), + |L 1-1, C 5-14| ParensAround( + Closure( + [ + |L 1-1, C 7-8| Identifier( + "y", + ), + ], + |L 1-1, C 12-13| Var { + module_name: "", + ident: "y", + }, + ), + ), + |L 3-3, C 0-1| SpaceBefore( + Num( + "4", + ), + [ + Newline, + Newline, + ], + ), ), [ LineComment( diff --git a/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast index f353e929ff..f3eedcea65 100644 --- a/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/var_minus_two.expr.result-ast @@ -1,9 +1,14 @@ BinOps( [ ( - |L 0-0, C 0-1| Var { module_name: "", ident: "x" }, + |L 0-0, C 0-1| Var { + module_name: "", + ident: "x", + }, |L 0-0, C 1-2| Minus, ), ], - |L 0-0, C 2-3| Num("2"), + |L 0-0, C 2-3| Num( + "2", + ), ) diff --git a/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast index 2e789d4e3c..83f3424244 100644 --- a/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_if_guard.expr.result-ast @@ -1,25 +1,72 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 4-5| SpaceBefore(Underscore(""), [Newline]), + |L 1-1, C 4-5| SpaceBefore( + Underscore( + "", + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 8-9| SpaceBefore(Num("1"), [Newline]), + value: |L 2-2, C 8-9| SpaceBefore( + Num( + "1", + ), + [ + Newline, + ], + ), guard: None, }, WhenBranch { patterns: [ - |L 4-4, C 4-5| SpaceBefore(Underscore(""), [Newline, Newline]), + |L 4-4, C 4-5| SpaceBefore( + Underscore( + "", + ), + [ + Newline, + Newline, + ], + ), ], - value: |L 5-5, C 8-9| SpaceBefore(Num("2"), [Newline]), + value: |L 5-5, C 8-9| SpaceBefore( + Num( + "2", + ), + [ + Newline, + ], + ), guard: None, }, WhenBranch { patterns: [ - |L 7-7, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline, Newline]), + |L 7-7, C 4-6| SpaceBefore( + GlobalTag( + "Ok", + ), + [ + Newline, + Newline, + ], + ), ], - value: |L 8-8, C 8-9| SpaceBefore(Num("3"), [Newline]), + value: |L 8-8, C 8-9| SpaceBefore( + Num( + "3", + ), + [ + Newline, + ], + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast index 5c806a67bf..324e03f7ce 100644 --- a/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_in_parens.expr.result-ast @@ -1,12 +1,29 @@ ParensAround( When( - |L 0-0, C 6-7| Var { module_name: "", ident: "x" }, + |L 0-0, C 6-7| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline]), + |L 1-1, C 4-6| SpaceBefore( + GlobalTag( + "Ok", + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 8-9| SpaceBefore(Num("3"), [Newline]), + value: |L 2-2, C 8-9| SpaceBefore( + Num( + "3", + ), + [ + Newline, + ], + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast index 80f82b2a0c..b7fcacfb2d 100644 --- a/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.result-ast @@ -1,13 +1,25 @@ ParensAround( SpaceAfter( When( - |L 0-0, C 6-7| Var { module_name: "", ident: "x" }, + |L 0-0, C 6-7| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 4-6| SpaceBefore(GlobalTag("Ok"), [Newline]), + |L 1-1, C 4-6| SpaceBefore( + GlobalTag( + "Ok", + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 10-11| Num("3"), + value: |L 1-1, C 10-11| Num( + "3", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast index d91e8cdc15..46a12593ae 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.result-ast @@ -1,20 +1,58 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 1-7| SpaceBefore(StrLiteral(PlainLine("blah")), [Newline]), - |L 1-1, C 10-16| StrLiteral(PlainLine("blop")), + |L 1-1, C 1-7| SpaceBefore( + StrLiteral( + PlainLine( + "blah", + ), + ), + [ + Newline, + ], + ), + |L 1-1, C 10-16| StrLiteral( + PlainLine( + "blop", + ), + ), ], - value: |L 1-1, C 20-21| Num("1"), + value: |L 1-1, C 20-21| Num( + "1", + ), guard: None, }, WhenBranch { patterns: [ - |L 2-2, C 1-6| SpaceBefore(StrLiteral(PlainLine("foo")), [Newline]), - |L 3-3, C 2-7| SpaceBefore(StrLiteral(PlainLine("bar")), [Newline]), + |L 2-2, C 1-6| SpaceBefore( + StrLiteral( + PlainLine( + "foo", + ), + ), + [ + Newline, + ], + ), + |L 3-3, C 2-7| SpaceBefore( + StrLiteral( + PlainLine( + "bar", + ), + ), + [ + Newline, + ], + ), ], - value: |L 3-3, C 11-12| Num("2"), + value: |L 3-3, C 11-12| Num( + "2", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast index 3419dfe72a..6438516e8d 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.result-ast @@ -1,18 +1,53 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 4-5| SpaceBefore(NumLiteral("1"), [Newline]), + |L 1-1, C 4-5| SpaceBefore( + NumLiteral( + "1", + ), + [ + Newline, + ], + ), ], - value: |L 1-2, C 9-6| Apply(|L 1-1, C 9-16| Var { module_name: "Num", ident: "neg" }, [|L 2-2, C 5-6| SpaceBefore(Num("2"), [Newline])], Space), + value: |L 1-2, C 9-6| Apply( + |L 1-1, C 9-16| Var { + module_name: "Num", + ident: "neg", + }, + [ + |L 2-2, C 5-6| SpaceBefore( + Num( + "2", + ), + [ + Newline, + ], + ), + ], + Space, + ), guard: None, }, WhenBranch { patterns: [ - |L 3-3, C 4-5| SpaceBefore(Underscore(""), [Newline]), + |L 3-3, C 4-5| SpaceBefore( + Underscore( + "", + ), + [ + Newline, + ], + ), ], - value: |L 3-3, C 9-10| Num("4"), + value: |L 3-3, C 9-10| Num( + "4", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast index 4fbfcfdb99..b1c09c7e0c 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.result-ast @@ -1,18 +1,39 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline]), + |L 1-1, C 1-2| SpaceBefore( + NumLiteral( + "1", + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 6-7| Num("2"), + value: |L 1-1, C 6-7| Num( + "2", + ), guard: None, }, WhenBranch { patterns: [ - |L 2-2, C 1-3| SpaceBefore(NumLiteral("-3"), [Newline]), + |L 2-2, C 1-3| SpaceBefore( + NumLiteral( + "-3", + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 7-8| Num("4"), + value: |L 2-2, C 7-8| Num( + "4", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast index da096daa1f..e1ed86ded5 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.result-ast @@ -1,18 +1,39 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 1-2| SpaceBefore(NumLiteral("1"), [Newline]), + |L 1-1, C 1-2| SpaceBefore( + NumLiteral( + "1", + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 6-7| Num("2"), + value: |L 1-1, C 6-7| Num( + "2", + ), guard: None, }, WhenBranch { patterns: [ - |L 2-2, C 1-2| SpaceBefore(NumLiteral("3"), [Newline]), + |L 2-2, C 1-2| SpaceBefore( + NumLiteral( + "3", + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 6-7| Num("4"), + value: |L 2-2, C 6-7| Num( + "4", + ), guard: None, }, ], diff --git a/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast b/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast index ec9232bf7a..174cc8abb2 100644 --- a/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/when_with_records.expr.result-ast @@ -1,18 +1,50 @@ When( - |L 0-0, C 5-6| Var { module_name: "", ident: "x" }, + |L 0-0, C 5-6| Var { + module_name: "", + ident: "x", + }, [ WhenBranch { patterns: [ - |L 1-1, C 1-6| SpaceBefore(RecordDestructure([|L 1-1, C 3-4| Identifier("y")]), [Newline]), + |L 1-1, C 1-6| SpaceBefore( + RecordDestructure( + [ + |L 1-1, C 3-4| Identifier( + "y", + ), + ], + ), + [ + Newline, + ], + ), ], - value: |L 1-1, C 10-11| Num("2"), + value: |L 1-1, C 10-11| Num( + "2", + ), guard: None, }, WhenBranch { patterns: [ - |L 2-2, C 1-9| SpaceBefore(RecordDestructure([|L 2-2, C 3-4| Identifier("z"), |L 2-2, C 6-7| Identifier("w")]), [Newline]), + |L 2-2, C 1-9| SpaceBefore( + RecordDestructure( + [ + |L 2-2, C 3-4| Identifier( + "z", + ), + |L 2-2, C 6-7| Identifier( + "w", + ), + ], + ), + [ + Newline, + ], + ), ], - value: |L 2-2, C 13-14| Num("4"), + value: |L 2-2, C 13-14| Num( + "4", + ), guard: None, }, ], diff --git a/compiler/region/src/all.rs b/compiler/region/src/all.rs index 4c7d605b58..5794ad153b 100644 --- a/compiler/region/src/all.rs +++ b/compiler/region/src/all.rs @@ -230,7 +230,11 @@ where // because it makes failed assertions much harder to read. self.value.fmt(f) } else { - write!(f, "{:?} {:?}", region, self.value) + if f.alternate() { + write!(f, "{:?} {:#?}", region, self.value) + } else { + write!(f, "{:?} {:?}", region, self.value) + } } } } From 343a680be951c7ca97cc41f1d0d98657cc8a482f Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Sun, 14 Nov 2021 18:43:53 -0800 Subject: [PATCH 089/223] Fix spelling/formatting/clippy/unused imports --- .../full_app_header_trailing_commas.header.result-ast | 4 ++-- .../pass/full_app_header_trailing_commas.header.roc | 2 +- compiler/parse/tests/test_parse.rs | 9 +++------ compiler/region/src/all.rs | 8 +++----- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast index d90da83618..da4c7707a8 100644 --- a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.result-ast @@ -30,9 +30,9 @@ App { Newline, ], ), - |L 4-4, C 8-17| SpaceBefore( + |L 4-4, C 8-16| SpaceBefore( Exposed( - "FourtyTwo", + "FortyTwo", ), [ Newline, diff --git a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc index 30b50e51d6..7e5398b845 100644 --- a/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc +++ b/compiler/parse/tests/snapshots/pass/full_app_header_trailing_commas.header.roc @@ -2,7 +2,7 @@ app "quicksort" packages { base: "./platform", } imports [ foo.Bar.{ Baz, - FourtyTwo, + FortyTwo, # I'm a happy comment } ] provides [ quicksort, ] to base diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index f1f70dafdf..cf7cd3f79d 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -16,12 +16,9 @@ mod test_parse { use bumpalo::collections::vec::Vec; use bumpalo::{self, Bump}; use roc_parse::ast::Expr::{self, *}; - use roc_parse::ast::Pattern::{self, *}; - use roc_parse::ast::StrLiteral::{self, *}; + use roc_parse::ast::StrLiteral::*; use roc_parse::ast::StrSegment::*; - use roc_parse::ast::{ - self, EscapedChar - }; + use roc_parse::ast::{self, EscapedChar}; use roc_parse::module::module_defs; use roc_parse::parser::{Parser, State, SyntaxError}; use roc_parse::test_helpers::parse_expr_with; @@ -60,7 +57,7 @@ mod test_parse { } else { panic!("unexpected test file found: {}", file); } - } + } } $( diff --git a/compiler/region/src/all.rs b/compiler/region/src/all.rs index 5794ad153b..90c05be8b1 100644 --- a/compiler/region/src/all.rs +++ b/compiler/region/src/all.rs @@ -229,12 +229,10 @@ where // Also in tests, we don't want to bother printing the locations // because it makes failed assertions much harder to read. self.value.fmt(f) + } else if f.alternate() { + write!(f, "{:?} {:#?}", region, self.value) } else { - if f.alternate() { - write!(f, "{:?} {:#?}", region, self.value) - } else { - write!(f, "{:?} {:?}", region, self.value) - } + write!(f, "{:?} {:?}", region, self.value) } } } From 1c17797aa637d59ff153fa274d598e309473c583 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 09:01:36 +0000 Subject: [PATCH 090/223] Fix de-duplication of builtin imports --- compiler/gen_wasm/src/backend.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 7ba303ed13..2a4e712ae4 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -779,14 +779,15 @@ impl<'a> WasmBackend<'a> { }; self.module.import.entries.push(import); - let sym_idx = self.linker_symbols.len() as u32; + let sym_idx = self.linker_symbols.len(); let sym_info = SymInfo::Function(WasmObjectSymbol::Imported { flags: WASM_SYM_UNDEFINED, index: import_index, }); self.linker_symbols.push(sym_info); + self.builtin_sym_index_map.insert(name, sym_idx); - (import_index, sym_idx) + (import_index, sym_idx as u32) } }; self.code_builder.call( From e200e6c3469db04c9374cea3eedbc328a49d10e7 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 09:52:16 +0000 Subject: [PATCH 091/223] Clippy + fmt --- compiler/gen_dev/src/lib.rs | 9 ++++++--- compiler/module/src/low_level.rs | 5 +---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 7890a45675..f8b61ade46 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -229,13 +229,13 @@ where } => { // If this function is just a lowlevel wrapper, then inline it if let Some(lowlevel) = LowLevel::from_wrapper_symbol(*func_sym) { - return self.build_run_low_level( + self.build_run_low_level( sym, &lowlevel, arguments, arg_layouts, ret_layout, - ); + ) } else if func_sym .module_string(&self.env().interns) .starts_with(ModuleName::APP) @@ -247,7 +247,10 @@ where self.load_literal_symbols(arguments)?; self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout) } else { - Err(format!("the function, {:?}, is not yet implemented", func_sym)) + Err(format!( + "the function, {:?}, is not yet implemented", + func_sym + )) } } diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index b4e4133348..2dfcb00864 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -143,10 +143,7 @@ impl LowLevel { pub fn is_higher_order(&self) -> bool { use LowLevel::*; - match self { - higher_order!() => true, - _ => false, - } + matches!(self, higher_order!()) } pub fn function_argument_position(&self) -> usize { From 8e29daa16007f68936dd3f70f65393d951830138 Mon Sep 17 00:00:00 2001 From: satotake Date: Mon, 15 Nov 2021 11:28:38 +0000 Subject: [PATCH 092/223] remove low-level `List.drop` codes --- compiler/builtins/bitcode/src/list.zig | 36 ------------------------ compiler/builtins/bitcode/src/main.zig | 1 - compiler/builtins/src/bitcode.rs | 1 - compiler/gen_llvm/src/llvm/build.rs | 29 +++---------------- compiler/gen_llvm/src/llvm/build_list.rs | 22 --------------- compiler/gen_wasm/src/low_level.rs | 6 ++-- compiler/module/src/low_level.rs | 2 -- compiler/mono/src/borrow.rs | 1 - compiler/mono/src/low_level.rs | 1 - 9 files changed, 7 insertions(+), 92 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index 7dda2126c5..d012e92e26 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -899,42 +899,6 @@ pub fn listSublist( return RocList.empty(); } -pub fn listDrop( - list: RocList, - alignment: u32, - element_width: usize, - drop_count: usize, - dec: Dec, -) callconv(.C) RocList { - if (list.bytes) |source_ptr| { - const size = list.len(); - const keep_count = size - drop_count; - - var i: usize = 0; - const iterations = std.math.min(drop_count, size); - - while (i < iterations) : (i += 1) { - const element = source_ptr + i * element_width; - dec(element); - } - - if (drop_count >= size) { - return RocList.empty(); - } - - const output = RocList.allocate(alignment, keep_count, element_width); - const target_ptr = output.bytes orelse unreachable; - - @memcpy(target_ptr, source_ptr + drop_count * element_width, keep_count * element_width); - - utils.decref(list.bytes, size * element_width, alignment); - - return output; - } else { - return RocList.empty(); - } -} - pub fn listDropAt( list: RocList, alignment: u32, diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index 374aaa7bc5..2375e19119 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -46,7 +46,6 @@ comptime { exportListFn(list.listSortWith, "sort_with"); exportListFn(list.listConcat, "concat"); exportListFn(list.listSublist, "sublist"); - exportListFn(list.listDrop, "drop"); exportListFn(list.listDropAt, "drop_at"); exportListFn(list.listSet, "set"); exportListFn(list.listSetInPlace, "set_in_place"); diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index f8ad6f920f..993d5fb22a 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -184,7 +184,6 @@ pub const LIST_REPEAT: &str = "roc_builtins.list.repeat"; pub const LIST_APPEND: &str = "roc_builtins.list.append"; pub const LIST_PREPEND: &str = "roc_builtins.list.prepend"; pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist"; -pub const LIST_DROP: &str = "roc_builtins.list.drop"; pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at"; pub const LIST_SWAP: &str = "roc_builtins.list.swap"; pub const LIST_SINGLE: &str = "roc_builtins.list.single"; diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index dc0499ae67..d8ee5bc03f 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -9,10 +9,10 @@ use crate::llvm::build_dict::{ use crate::llvm::build_hash::generic_hash; use crate::llvm::build_list::{ self, allocate_list, empty_list, empty_polymorphic_list, list_any, list_append, list_concat, - list_contains, list_drop, list_drop_at, list_find_trivial_not_found, list_find_unsafe, - list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, - list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, - list_reverse, list_set, list_single, list_sort_with, list_sublist, list_swap, + list_contains, list_drop_at, list_find_trivial_not_found, list_find_unsafe, list_get_unsafe, + list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, list_map2, + list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, + list_set, list_single, list_sort_with, list_sublist, list_swap, }; use crate::llvm::build_str::{ empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, @@ -5194,27 +5194,6 @@ fn run_low_level<'a, 'ctx, 'env>( _ => unreachable!("Invalid layout {:?} in List.sublist", list_layout), } } - ListDrop => { - // List.drop : List elem, Nat -> List elem - debug_assert_eq!(args.len(), 2); - - let (list, list_layout) = load_symbol_and_layout(scope, &args[0]); - let original_wrapper = list.into_struct_value(); - - let count = load_symbol(scope, &args[1]); - - match list_layout { - Layout::Builtin(Builtin::EmptyList) => empty_list(env), - Layout::Builtin(Builtin::List(element_layout)) => list_drop( - env, - layout_ids, - original_wrapper, - count.into_int_value(), - element_layout, - ), - _ => unreachable!("Invalid layout {:?} in List.drop", list_layout), - } - } ListDropAt => { // List.dropAt : List elem, Nat -> List elem debug_assert_eq!(args.len(), 2); diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index e78fa2f765..d68525b420 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -321,28 +321,6 @@ pub fn list_sublist<'a, 'ctx, 'env>( ) } -/// List.drop : List elem, Nat -> List elem -pub fn list_drop<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - layout_ids: &mut LayoutIds<'a>, - original_wrapper: StructValue<'ctx>, - count: IntValue<'ctx>, - element_layout: &Layout<'a>, -) -> BasicValueEnum<'ctx> { - let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout); - call_bitcode_fn_returns_list( - env, - &[ - pass_list_cc(env, original_wrapper.into()), - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), - count.into(), - dec_element_fn.as_global_value().as_pointer_value().into(), - ], - bitcode::LIST_DROP, - ) -} - /// List.dropAt : List elem, Nat -> List elem pub fn list_drop_at<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 2cf05a7a08..baa0f29eb6 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -34,9 +34,9 @@ pub fn build_call_low_level<'a>( | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListSublist - | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize | DictEmpty - | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues - | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { + | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize | DictEmpty | DictInsert + | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues | DictUnion + | DictIntersection | DictDifference | DictWalk | SetFromList => { return NotImplemented; } diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index dd9a4f020b..784c7875bd 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -44,7 +44,6 @@ pub enum LowLevel { ListKeepErrs, ListSortWith, ListSublist, - ListDrop, ListDropAt, ListSwap, ListAny, @@ -136,7 +135,6 @@ macro_rules! first_order { | ListGetUnsafe | ListSet | ListSublist - | ListDrop | ListDropAt | ListSingle | ListRepeat diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 045dfb38cb..fd4c946b4e 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -967,7 +967,6 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] { // List.append should own its first argument ListAppend => arena.alloc_slice_copy(&[owned, owned]), ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]), - ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]), ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]), ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]), diff --git a/compiler/mono/src/low_level.rs b/compiler/mono/src/low_level.rs index 2139ea59aa..058a2958eb 100644 --- a/compiler/mono/src/low_level.rs +++ b/compiler/mono/src/low_level.rs @@ -101,7 +101,6 @@ enum FirstOrder { ListGetUnsafe, ListSet, ListSublist, - ListDrop, ListDropAt, ListSingle, ListRepeat, From 6e23919811762db234cf47320a5bccc708c55c9c Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 15 Nov 2021 13:43:19 +0100 Subject: [PATCH 093/223] put mcpu in comments --- cli/src/build.rs | 6 +++--- cli/src/lib.rs | 2 +- cli/tests/cli_run.rs | 1 - cli_utils/Cargo.lock | 24 +----------------------- compiler/build/src/link.rs | 12 +++++++----- linker/src/lib.rs | 8 +++++++- 6 files changed, 19 insertions(+), 34 deletions(-) diff --git a/cli/src/build.rs b/cli/src/build.rs index 97af317837..b70ef86d69 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -117,7 +117,7 @@ pub fn build_file<'a>( .keys() .map(|x| x.as_str(&loaded.interns).to_string()) .collect(), - target_valgrind + target_valgrind, ); // TODO try to move as much of this linking as possible to the precompiled @@ -290,7 +290,7 @@ fn spawn_rebuild_thread( binary_path: PathBuf, target: &Triple, exported_symbols: Vec, - target_valgrind: bool + target_valgrind: bool, ) -> std::thread::JoinHandle { let thread_local_target = target.clone(); std::thread::spawn(move || { @@ -311,7 +311,7 @@ fn spawn_rebuild_thread( &thread_local_target, host_input_path.as_path(), None, - target_valgrind + target_valgrind, ); } } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 2958abbd64..63118350c3 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -307,7 +307,7 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result { link_type, surgically_link, precompiled, - target_valgrind + target_valgrind, ); match res_binary_path { diff --git a/cli/tests/cli_run.rs b/cli/tests/cli_run.rs index a8975d2ff0..992e9af704 100644 --- a/cli/tests/cli_run.rs +++ b/cli/tests/cli_run.rs @@ -53,7 +53,6 @@ mod cli_run { expected_ending: &str, use_valgrind: bool, ) { - let mut all_flags = vec![]; all_flags.extend_from_slice(flags); diff --git a/cli_utils/Cargo.lock b/cli_utils/Cargo.lock index f41f503d27..4889a1da49 100644 --- a/cli_utils/Cargo.lock +++ b/cli_utils/Cargo.lock @@ -2398,8 +2398,6 @@ name = "roc_build" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "libloading 0.7.1", "roc_builtins", @@ -2440,8 +2438,6 @@ name = "roc_can" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "roc_builtins", "roc_collections", "roc_module", @@ -2459,8 +2455,6 @@ dependencies = [ "bumpalo", "clap 3.0.0-beta.5", "const_format", - "im", - "im-rc", "inkwell 0.1.0", "libloading 0.7.1", "mimalloc", @@ -2562,8 +2556,6 @@ dependencies = [ "fs_extra", "futures", "glyph_brush", - "im", - "im-rc", "libc", "log", "nonempty", @@ -2599,8 +2591,6 @@ name = "roc_fmt" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "roc_collections", "roc_module", "roc_parse", @@ -2612,8 +2602,6 @@ name = "roc_gen_dev" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "object 0.26.2", "roc_builtins", "roc_collections", @@ -2632,20 +2620,13 @@ name = "roc_gen_llvm" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "morphic_lib", "roc_builtins", "roc_collections", "roc_module", "roc_mono", - "roc_problem", - "roc_region", - "roc_solve", "roc_std", - "roc_types", - "roc_unify", "target-lexicon", ] @@ -2654,6 +2635,7 @@ name = "roc_gen_wasm" version = "0.1.0" dependencies = [ "bumpalo", + "roc_builtins", "roc_collections", "roc_module", "roc_mono", @@ -2726,7 +2708,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "hashbrown 0.11.2", - "linked-hash-map", "morphic_lib", "roc_can", "roc_collections", @@ -2737,7 +2718,6 @@ dependencies = [ "roc_std", "roc_types", "roc_unify", - "ven_ena", "ven_graph", "ven_pretty", ] @@ -2773,8 +2753,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "distance", - "im", - "im-rc", "roc_can", "roc_collections", "roc_module", diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index 484178415b..92572650c3 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -86,7 +86,7 @@ pub fn build_zig_host_native( target: &str, opt_level: OptLevel, shared_lib_path: Option<&Path>, - target_valgrind: bool, + _target_valgrind: bool, ) -> Output { let mut command = Command::new("zig"); command @@ -120,12 +120,13 @@ pub fn build_zig_host_native( target, ]); - if target_valgrind { + // use single threaded testing for cli_run and enable this code if valgrind fails with unhandled instruction bytes, see #1963. + /*if target_valgrind { command.args(&[ "-mcpu", "x86_64" ]); - } + }*/ if matches!(opt_level, OptLevel::Optimize) { command.args(&["-O", "ReleaseSafe"]); @@ -350,6 +351,7 @@ pub fn rebuild_host( shared_lib_path: Option<&Path>, target_valgrind: bool, ) { + dbg!("rebuilding host"); let c_host_src = host_input_path.with_file_name("host.c"); let c_host_dest = host_input_path.with_file_name("c_host.o"); let zig_host_src = host_input_path.with_file_name("host.zig"); @@ -418,7 +420,7 @@ pub fn rebuild_host( "i386-linux-musl", opt_level, shared_lib_path, - target_valgrind + target_valgrind, ) } @@ -433,7 +435,7 @@ pub fn rebuild_host( target_triple_str(target), opt_level, shared_lib_path, - target_valgrind + target_valgrind, ) } _ => panic!("Unsupported architecture {:?}", target.architecture), diff --git a/linker/src/lib.rs b/linker/src/lib.rs index 58f801115f..9bd11cecb6 100644 --- a/linker/src/lib.rs +++ b/linker/src/lib.rs @@ -146,7 +146,13 @@ pub fn build_and_preprocess_host( ) -> io::Result<()> { let dummy_lib = host_input_path.with_file_name("libapp.so"); generate_dynamic_lib(target, exposed_to_host, &dummy_lib)?; - rebuild_host(opt_level, target, host_input_path, Some(&dummy_lib), target_valgrind); + rebuild_host( + opt_level, + target, + host_input_path, + Some(&dummy_lib), + target_valgrind, + ); let dynhost = host_input_path.with_file_name("dynhost"); let metadata = host_input_path.with_file_name("metadata"); let prehost = host_input_path.with_file_name("preprocessedhost"); From 04db9fe212f3b30968923b2b05a1f76f90343956 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 15 Nov 2021 13:54:05 +0100 Subject: [PATCH 094/223] removed dbg --- compiler/build/src/link.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index 92572650c3..1e9f909968 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -351,7 +351,6 @@ pub fn rebuild_host( shared_lib_path: Option<&Path>, target_valgrind: bool, ) { - dbg!("rebuilding host"); let c_host_src = host_input_path.with_file_name("host.c"); let c_host_dest = host_input_path.with_file_name("c_host.o"); let zig_host_src = host_input_path.with_file_name("host.zig"); From 46636ef331dfb15425b47d53466ccf6422abc504 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 12:49:15 +0000 Subject: [PATCH 095/223] Ensure lowlevel inlining does not skip bounds checks --- compiler/gen_dev/src/lib.rs | 2 +- compiler/gen_wasm/src/backend.rs | 2 +- compiler/module/src/low_level.rs | 38 +++++++++++++++++--------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index f8b61ade46..7abe230395 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -228,7 +228,7 @@ where .. } => { // If this function is just a lowlevel wrapper, then inline it - if let Some(lowlevel) = LowLevel::from_wrapper_symbol(*func_sym) { + if let Some(lowlevel) = LowLevel::from_inlined_wrapper(*func_sym) { self.build_run_low_level( sym, &lowlevel, diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 2a4e712ae4..1d0928611e 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -471,7 +471,7 @@ impl<'a> WasmBackend<'a> { }) => match call_type { CallType::ByName { name: func_sym, .. } => { // If this function is just a lowlevel wrapper, then inline it - if let Some(lowlevel) = LowLevel::from_wrapper_symbol(*func_sym) { + if let Some(lowlevel) = LowLevel::from_inlined_wrapper(*func_sym) { return self.build_low_level(lowlevel, arguments, wasm_layout); } diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index 2dfcb00864..fd07a644ad 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -169,8 +169,10 @@ impl LowLevel { } } - /// Used in dev backends to optimise away the wrapper functions - pub fn from_wrapper_symbol(symbol: Symbol) -> Option { + /// Used in dev backends to inline some lowlevel wrapper functions + /// For wrappers that contain logic, we return None to prevent inlining + /// (Mention each explicitly rather than using `_`, to show they have not been forgotten) + pub fn from_inlined_wrapper(symbol: Symbol) -> Option { use LowLevel::*; match symbol { @@ -183,8 +185,8 @@ impl LowLevel { Symbol::STR_SPLIT => Some(StrSplit), Symbol::STR_COUNT_GRAPHEMES => Some(StrCountGraphemes), Symbol::STR_FROM_INT => Some(StrFromInt), - Symbol::STR_FROM_UTF8 => Some(StrFromUtf8), - Symbol::STR_FROM_UTF8_RANGE => Some(StrFromUtf8Range), + Symbol::STR_FROM_UTF8 => None, + Symbol::STR_FROM_UTF8_RANGE => None, Symbol::STR_TO_UTF8 => Some(StrToUtf8), Symbol::STR_REPEAT => Some(StrRepeat), Symbol::STR_FROM_FLOAT => Some(StrFromFloat), @@ -192,8 +194,8 @@ impl LowLevel { Symbol::STR_TRIM_LEFT => Some(StrTrimLeft), Symbol::STR_TRIM_RIGHT => Some(StrTrimRight), Symbol::LIST_LEN => Some(ListLen), - Symbol::LIST_GET => Some(ListGetUnsafe), - Symbol::LIST_SET => Some(ListSet), + Symbol::LIST_GET => None, + Symbol::LIST_SET => None, Symbol::LIST_SINGLE => Some(ListSingle), Symbol::LIST_REPEAT => Some(ListRepeat), Symbol::LIST_REVERSE => Some(ListReverse), @@ -220,13 +222,13 @@ impl LowLevel { Symbol::LIST_DROP_AT => Some(ListDropAt), Symbol::LIST_SWAP => Some(ListSwap), Symbol::LIST_ANY => Some(ListAny), - Symbol::LIST_FIND => Some(ListFindUnsafe), + Symbol::LIST_FIND => None, Symbol::DICT_LEN => Some(DictSize), Symbol::DICT_EMPTY => Some(DictEmpty), Symbol::DICT_INSERT => Some(DictInsert), Symbol::DICT_REMOVE => Some(DictRemove), Symbol::DICT_CONTAINS => Some(DictContains), - Symbol::DICT_GET => Some(DictGetUnsafe), + Symbol::DICT_GET => None, Symbol::DICT_KEYS => Some(DictKeys), Symbol::DICT_VALUES => Some(DictValues), Symbol::DICT_UNION => Some(DictUnion), @@ -236,28 +238,28 @@ impl LowLevel { Symbol::SET_FROM_LIST => Some(SetFromList), Symbol::NUM_ADD => Some(NumAdd), Symbol::NUM_ADD_WRAP => Some(NumAddWrap), - Symbol::NUM_ADD_CHECKED => Some(NumAddChecked), + Symbol::NUM_ADD_CHECKED => None, Symbol::NUM_SUB => Some(NumSub), Symbol::NUM_SUB_WRAP => Some(NumSubWrap), - Symbol::NUM_SUB_CHECKED => Some(NumSubChecked), + Symbol::NUM_SUB_CHECKED => None, Symbol::NUM_MUL => Some(NumMul), Symbol::NUM_MUL_WRAP => Some(NumMulWrap), - Symbol::NUM_MUL_CHECKED => Some(NumMulChecked), + Symbol::NUM_MUL_CHECKED => None, Symbol::NUM_GT => Some(NumGt), Symbol::NUM_GTE => Some(NumGte), Symbol::NUM_LT => Some(NumLt), Symbol::NUM_LTE => Some(NumLte), Symbol::NUM_COMPARE => Some(NumCompare), - Symbol::NUM_DIV_FLOAT => Some(NumDivUnchecked), - Symbol::NUM_DIV_CEIL => Some(NumDivCeilUnchecked), - Symbol::NUM_REM => Some(NumRemUnchecked), + Symbol::NUM_DIV_FLOAT => None, + Symbol::NUM_DIV_CEIL => None, + Symbol::NUM_REM => None, Symbol::NUM_IS_MULTIPLE_OF => Some(NumIsMultipleOf), Symbol::NUM_ABS => Some(NumAbs), Symbol::NUM_NEG => Some(NumNeg), Symbol::NUM_SIN => Some(NumSin), Symbol::NUM_COS => Some(NumCos), - Symbol::NUM_SQRT => Some(NumSqrtUnchecked), - Symbol::NUM_LOG => Some(NumLogUnchecked), + Symbol::NUM_SQRT => None, + Symbol::NUM_LOG => None, Symbol::NUM_ROUND => Some(NumRound), Symbol::NUM_TO_FLOAT => Some(NumToFloat), Symbol::NUM_POW => Some(NumPow), @@ -268,8 +270,8 @@ impl LowLevel { Symbol::NUM_ATAN => Some(NumAtan), Symbol::NUM_ACOS => Some(NumAcos), Symbol::NUM_ASIN => Some(NumAsin), - Symbol::NUM_BYTES_TO_U16 => Some(NumBytesToU16), - Symbol::NUM_BYTES_TO_U32 => Some(NumBytesToU32), + Symbol::NUM_BYTES_TO_U16 => None, + Symbol::NUM_BYTES_TO_U32 => None, Symbol::NUM_BITWISE_AND => Some(NumBitwiseAnd), Symbol::NUM_BITWISE_XOR => Some(NumBitwiseXor), Symbol::NUM_BITWISE_OR => Some(NumBitwiseOr), From a5c3809290c5567e026730324984399e3dcab99f Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 11:58:30 +0000 Subject: [PATCH 096/223] Delete DataCountSection. Not well-supported and only needed for instructions we don't use https://webassembly.github.io/spec/core/binary/modules.html#binary-datacountsec Tools like wasm2wat and wasm-validate reject the module when this section is included! Its purpose is to enable single-pass validation for two specific instructions that were not in the original Wasm MVP: memory.init and data.drop. We don't use them in our Roc backend. It seems to make sense just to drop the section. --- compiler/gen_wasm/src/wasm_module/sections.rs | 43 +------------------ 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/sections.rs b/compiler/gen_wasm/src/wasm_module/sections.rs index 2ff0805604..855d5062ee 100644 --- a/compiler/gen_wasm/src/wasm_module/sections.rs +++ b/compiler/gen_wasm/src/wasm_module/sections.rs @@ -29,6 +29,8 @@ pub enum SectionId { Element = 9, Code = 10, Data = 11, + /// DataCount section is unused. Only needed for single-pass validation of + /// memory.init and data.drop, which we don't use DataCount = 12, } @@ -525,42 +527,6 @@ impl Serialize for DataSection<'_> { } } -/******************************************************************* - * - * Data Count section - * - * Pre-declares the number of segments in the Data section. - * This helps the runtime to validate the module in a single pass. - * The order of sections is DataCount -> Code -> Data - * - *******************************************************************/ - -#[derive(Debug)] -struct DataCountSection { - count: u32, -} - -impl DataCountSection { - fn new(data_section: &DataSection<'_>) -> Self { - let count = data_section - .segments - .iter() - .filter(|seg| !seg.init.is_empty()) - .count() as u32; - DataCountSection { count } - } -} - -impl Serialize for DataCountSection { - fn serialize(&self, buffer: &mut T) { - if self.count > 0 { - let header_indices = write_section_header(buffer, SectionId::DataCount); - buffer.encode_u32(self.count); - update_section_size(buffer, header_indices); - } - } -} - /******************************************************************* * * Module @@ -658,11 +624,6 @@ impl<'a> WasmModule<'a> { counter.serialize_and_count(buffer, &self.start); counter.serialize_and_count(buffer, &self.element); - // Data Count section forward-declares the size of the Data section - // so that Code section can be validated in one pass - let data_count_section = DataCountSection::new(&self.data); - counter.serialize_and_count(buffer, &data_count_section); - // Code section is the only one with relocations so we can stop counting let code_section_index = counter.section_index; let code_section_body_index = self From 73dda714de6ffd2218ddaa0c83a9159f32a319bc Mon Sep 17 00:00:00 2001 From: satotake Date: Mon, 15 Nov 2021 13:50:11 +0000 Subject: [PATCH 097/223] Add builtin `List.split` --- compiler/builtins/bitcode/src/list.zig | 3 + compiler/builtins/src/std.rs | 19 ++++++ compiler/can/src/builtins.rs | 95 ++++++++++++++++++++++---- compiler/module/src/symbol.rs | 1 + compiler/solve/tests/solve_expr.rs | 8 +++ compiler/test_gen/src/gen_list.rs | 41 +++++++++++ 6 files changed, 154 insertions(+), 13 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index 7dda2126c5..3a74abe0a1 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -870,6 +870,9 @@ pub fn listSublist( len: usize, dec: Dec, ) callconv(.C) RocList { + if (len == 0) { + return RocList.empty(); + } if (list.bytes) |source_ptr| { const size = list.len(); diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 0f8d1fe154..41ed828beb 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -1015,6 +1015,25 @@ pub fn types() -> MutMap { Box::new(list_type(flex(TVAR1))), ); + // split : List elem, Nat -> { before: List elem, others: List elem } + add_top_level_function_type!( + Symbol::LIST_SPLIT, + vec![list_type(flex(TVAR1)), nat_type(),], + Box::new(SolvedType::Record { + fields: vec![ + ( + "before".into(), + RecordField::Required(list_type(flex(TVAR1))) + ), + ( + "others".into(), + RecordField::Required(list_type(flex(TVAR1))) + ), + ], + ext: Box::new(SolvedType::EmptyRecord), + },), + ); + // drop : List elem, Nat -> List elem add_top_level_function_type!( Symbol::LIST_DROP, diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 924e0f6567..942cdd8468 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -1,9 +1,9 @@ use crate::def::Def; use crate::expr::{ClosureData, Expr::*}; -use crate::expr::{Expr, Recursive, WhenBranch}; +use crate::expr::{Expr, Field, Recursive, WhenBranch}; use crate::pattern::Pattern; use roc_collections::all::SendMap; -use roc_module::ident::TagName; +use roc_module::ident::{Lowercase, TagName}; use roc_module::low_level::LowLevel; use roc_module::operator::CalledVia; use roc_module::symbol::Symbol; @@ -96,6 +96,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option LIST_TAKE_FIRST => list_take_first, LIST_TAKE_LAST => list_take_last, LIST_SUBLIST => list_sublist, + LIST_SPLIT => list_split, LIST_DROP => list_drop, LIST_DROP_AT => list_drop_at, LIST_DROP_FIRST => list_drop_first, @@ -2147,6 +2148,74 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +/// List.split : List elem, Nat -> { before: List elem, others: List elem } +fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def { + let list_var = var_store.fresh(); + let index_var = var_store.fresh(); + + let sym_list = Symbol::ARG_1; + let sym_index = Symbol::ARG_2; + + let ret_var = var_store.fresh(); + let zero = int(index_var, Variable::NATURAL, 0); + + let get_before = RunLowLevel { + op: LowLevel::ListSublist, + args: vec![ + (list_var, Var(sym_list)), + (index_var, zero), + (index_var, Var(sym_index)), + ], + ret_var: list_var, + }; + + let get_list_len = RunLowLevel { + op: LowLevel::ListLen, + args: vec![(list_var, Var(sym_list))], + ret_var: index_var, + }; + + let get_others_len = RunLowLevel { + op: LowLevel::NumSubWrap, + args: vec![(index_var, get_list_len), (index_var, Var(sym_index))], + ret_var: index_var, + }; + + let get_others = RunLowLevel { + op: LowLevel::ListSublist, + args: vec![ + (list_var, Var(sym_list)), + (index_var, Var(sym_index)), + (index_var, get_others_len), + ], + ret_var: list_var, + }; + + let before = Field { + var: list_var, + region: Region::zero(), + loc_expr: Box::new(no_region(get_before)), + }; + let others = Field { + var: list_var, + region: Region::zero(), + loc_expr: Box::new(no_region(get_others)), + }; + + let body = record( + vec![("before".into(), before), ("others".into(), others)], + var_store, + ); + + defn( + symbol, + vec![(list_var, sym_list), (index_var, sym_index)], + var_store, + body, + ret_var, + ) +} + /// List.drop : List elem, Nat -> List elem fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); @@ -4296,17 +4365,17 @@ fn tag(name: &'static str, args: Vec, var_store: &mut VarStore) -> Expr { } } -// #[inline(always)] -// fn record(fields: Vec<(Lowercase, Field)>, var_store: &mut VarStore) -> Expr { -// let mut send_map = SendMap::default(); -// for (k, v) in fields { -// send_map.insert(k, v); -// } -// Expr::Record { -// record_var: var_store.fresh(), -// fields: send_map, -// } -// } +#[inline(always)] +fn record(fields: Vec<(Lowercase, Field)>, var_store: &mut VarStore) -> Expr { + let mut send_map = SendMap::default(); + for (k, v) in fields { + send_map.insert(k, v); + } + Expr::Record { + record_var: var_store.fresh(), + fields: send_map, + } +} #[inline(always)] fn defn( diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 44bf51012a..4367d70b34 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1072,6 +1072,7 @@ define_builtins! { 47 LIST_FIND: "find" 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" + 50 LIST_SPLIT: "split" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index dcf74d79bb..1e12191375 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3793,6 +3793,14 @@ mod solve_expr { ); } + #[test] + fn list_split() { + infer_eq_without_problem( + indoc!("List.split"), + "List a, Nat -> { before : List a, others : List a }", + ); + } + #[test] fn list_drop_last() { infer_eq_without_problem( diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 5e0f737e72..86aba0e539 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -248,6 +248,47 @@ fn list_sublist() { ); } +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn list_split() { + assert_evals_to!( + r#" + list = List.split [1, 2, 3] 0 + list.before + "#, + RocList::from_slice(&[]), + RocList + ); + assert_evals_to!( + r#" + list = List.split [1, 2, 3] 0 + list.others + "#, + RocList::from_slice(&[1, 2, 3]), + RocList + ); + + assert_evals_to!( + "List.split [1, 2, 3] 1", + (RocList::from_slice(&[1]), RocList::from_slice(&[2, 3]),), + (RocList, RocList,) + ); + assert_evals_to!( + "List.split [1, 2, 3] 3", + (RocList::from_slice(&[1, 2, 3]), RocList::from_slice(&[]),), + (RocList, RocList,) + ); + assert_evals_to!( + "List.split [1, 2, 3] 4", + (RocList::from_slice(&[1, 2, 3]), RocList::from_slice(&[]),), + (RocList, RocList,) + ); + assert_evals_to!( + "List.split [] 1", + (RocList::from_slice(&[]), RocList::from_slice(&[]),), + (RocList, RocList,) + ); +} #[test] #[cfg(any(feature = "gen-llvm"))] fn list_drop() { From 7330e3b11aa18480f20d242741c7451a0ba5c2ee Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 15 Nov 2021 15:12:37 +0100 Subject: [PATCH 098/223] clippy fix --- cli/src/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/src/build.rs b/cli/src/build.rs index b70ef86d69..761513fcc5 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -282,6 +282,7 @@ pub fn build_file<'a>( }) } +#[allow(clippy::too_many_arguments)] fn spawn_rebuild_thread( opt_level: OptLevel, surgically_link: bool, From 7ac1c7a72fbe72538905e2676528ec625812b279 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 12:11:36 +0000 Subject: [PATCH 099/223] Get long string literals working in gen_wasm --- compiler/gen_wasm/src/backend.rs | 4 ++-- .../gen_wasm/src/wasm_module/code_builder.rs | 11 +++++++---- compiler/test_gen/src/wasm_str.rs | 19 +++++++++---------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 1d0928611e..8b91379120 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -626,8 +626,8 @@ impl<'a> WasmBackend<'a> { self.lookup_string_constant(string, sym, layout); self.code_builder.get_local(local_id); - self.code_builder.insert_memory_relocation(linker_sym_index); - self.code_builder.i32_const(elements_addr as i32); + self.code_builder + .i32_const_mem_addr(elements_addr, linker_sym_index); self.code_builder.i32_store(Align::Bytes4, offset); self.code_builder.get_local(local_id); diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index 5468784926..2109f3e436 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -9,7 +9,7 @@ use super::opcodes::{OpCode, OpCode::*}; use super::serialize::{SerialBuffer, Serialize}; use crate::{round_up_to_alignment, FRAME_ALIGNMENT_BYTES, STACK_POINTER_GLOBAL_ID}; -const ENABLE_DEBUG_LOG: bool = true; +const ENABLE_DEBUG_LOG: bool = false; macro_rules! log_instruction { ($($x: expr),+) => { if ENABLE_DEBUG_LOG { println!($($x,)*); } @@ -572,11 +572,14 @@ impl<'a> CodeBuilder<'a> { ); } - /// Insert a linker relocation for a memory address - pub fn insert_memory_relocation(&mut self, symbol_index: u32) { + /// Insert a const reference to a memory address + pub fn i32_const_mem_addr(&mut self, addr: u32, symbol_index: u32) { + self.inst_base(I32CONST, 0, true); + let offset = self.code.len() as u32; + self.code.encode_padded_u32(addr); self.relocations.push(RelocationEntry::Offset { type_id: OffsetRelocType::MemoryAddrLeb, - offset: self.code.len() as u32, + offset, symbol_index, addend: 0, }); diff --git a/compiler/test_gen/src/wasm_str.rs b/compiler/test_gen/src/wasm_str.rs index d893f362f1..fcba6143c1 100644 --- a/compiler/test_gen/src/wasm_str.rs +++ b/compiler/test_gen/src/wasm_str.rs @@ -12,7 +12,7 @@ use crate::helpers::wasm::assert_evals_to; #[allow(unused_imports)] use indoc::indoc; -// use roc_std::RocStr; +use roc_std::RocStr; // #[test] // fn str_split_bigger_delimiter_small_str() { @@ -287,15 +287,14 @@ fn small_str_zeroed_literal() { ); } -// TODO: fix linking errors for undefined symbols roc_alloc, roc_dealloc -// #[test] -// fn long_str_literal() { -// assert_evals_to!( -// "\"0123456789 123456789 123456789\"", -// RocStr::from_slice(b"0123456789 123456789 123456789"), -// RocStr -// ); -// } +#[test] +fn long_str_literal() { + assert_evals_to!( + "\"0123456789 123456789 123456789\"", + RocStr::from_slice(b"0123456789 123456789 123456789"), + RocStr + ); +} // #[test] // fn small_str_concat_empty_first_arg() { From db081cd84bb6d7c814e40fd9aa3e39e21cc96d60 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 15 Nov 2021 20:12:48 +0100 Subject: [PATCH 100/223] WIP --- compiler/solve/src/solve.rs | 259 ++++++++++++++++++++++++++++++++++++ compiler/types/src/subs.rs | 18 ++- 2 files changed, 273 insertions(+), 4 deletions(-) diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index efa09d4dde..60d3906078 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1381,6 +1381,265 @@ fn instantiate_rigids_help( var } +fn deep_copy_var_to_help( + source: &Subs, + target: &mut Subs, + max_rank: Rank, + pools: &mut Pools, + var: Variable, +) -> Variable { + use roc_types::subs::Content::*; + use roc_types::subs::FlatType::*; + + let desc = source.get_without_compacting(var); + + if let Some(copy) = desc.copy.into_variable() { + return copy; + } else if desc.rank != Rank::NONE { + panic!( + "about to return a variable in source, but should only return variables from target" + ); + return var; + } + + let make_descriptor = |content| Descriptor { + content, + rank: max_rank, + mark: Mark::NONE, + copy: OptVariable::NONE, + }; + + let content = desc.content; + let copy = target.fresh(make_descriptor(content.clone())); + + pools.get_mut(max_rank).push(copy); + + // Link the original variable to the new variable. This lets us + // avoid making multiple copies of the variable we are instantiating. + // + // Need to do this before recursively copying to avoid looping. + source.set( + var, + Descriptor { + content: content.clone(), + rank: desc.rank, + mark: Mark::NONE, + copy: copy.into(), + }, + ); + + // Now we recursively copy the content of the variable. + // We have already marked the variable as copied, so we + // will not repeat this work or crawl this variable again. + match content { + Structure(flat_type) => { + let new_flat_type = match flat_type { + Apply(symbol, args) => { + let mut new_arg_vars = Vec::with_capacity(args.len()); + + for index in args.into_iter() { + let var = source[index]; + let copy_var = deep_copy_var_to_help(source, target, max_rank, pools, var); + new_arg_vars.push(copy_var); + } + + let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars); + + Apply(symbol, arg_vars) + } + + Func(arg_vars, closure_var, ret_var) => { + let new_ret_var = + deep_copy_var_to_help(source, target, max_rank, pools, ret_var); + let new_closure_var = + deep_copy_var_to_help(source, target, max_rank, pools, closure_var); + + let mut new_arg_vars = Vec::with_capacity(arg_vars.len()); + + for index in arg_vars.into_iter() { + let var = source[index]; + let copy_var = deep_copy_var_to_help(source, target, max_rank, pools, var); + new_arg_vars.push(copy_var); + } + + let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars); + + Func(arg_vars, new_closure_var, new_ret_var) + } + + same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same, + + Record(fields, ext_var) => { + let record_fields = { + let mut new_vars = Vec::with_capacity(fields.len()); + + for index in fields.iter_variables() { + let var = source[index]; + let copy_var = + deep_copy_var_to_help(source, target, max_rank, pools, var); + + new_vars.push(copy_var); + } + + let field_names_start = target.field_names.len() as u32; + let variables_start = target.variables.len() as u32; + let field_types_start = target.record_fields.len() as u32; + + let mut length = 0; + + for ((i1, _, i3), var) in fields.iter_all().zip(new_vars) { + let record_field = source[i3].map(|_| var); + + target.field_names.push(source[i1].clone()); + target.record_fields.push(record_field.map(|_| ())); + target.variables.push(*record_field.as_inner()); + + length += 1; + } + + RecordFields { + length, + field_names_start, + variables_start, + field_types_start, + } + }; + + Record( + record_fields, + deep_copy_var_to_help(source, target, max_rank, pools, ext_var), + ) + } + + TagUnion(tags, ext_var) => { + let mut new_variable_slices = Vec::with_capacity(tags.len()); + + let mut new_variables = Vec::new(); + for index in tags.variables() { + let slice = source[index]; + for var_index in slice { + let var = source[var_index]; + let new_var = + deep_copy_var_to_help(source, target, max_rank, pools, var); + new_variables.push(new_var); + } + + let new_slice = + VariableSubsSlice::insert_into_subs(target, new_variables.drain(..)); + + new_variable_slices.push(new_slice); + } + + let new_variables = { + let start = target.variable_slices.len() as u32; + let length = new_variable_slices.len() as u16; + target.variable_slices.extend(new_variable_slices); + + SubsSlice::new(start, length) + }; + + let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables); + + let new_ext = deep_copy_var_to_help(source, target, max_rank, pools, ext_var); + TagUnion(union_tags, new_ext) + } + + FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion( + tag_name, + symbol, + deep_copy_var_to_help(source, target, max_rank, pools, ext_var), + ), + + RecursiveTagUnion(rec_var, tags, ext_var) => { + let mut new_variable_slices = Vec::with_capacity(tags.len()); + + let mut new_variables = Vec::new(); + for index in tags.variables() { + let slice = source[index]; + for var_index in slice { + let var = source[var_index]; + let new_var = + deep_copy_var_to_help(source, target, max_rank, pools, var); + new_variables.push(new_var); + } + + let new_slice = + VariableSubsSlice::insert_into_subs(target, new_variables.drain(..)); + + new_variable_slices.push(new_slice); + } + + let new_variables = { + let start = target.variable_slices.len() as u32; + let length = new_variable_slices.len() as u16; + target.variable_slices.extend(new_variable_slices); + + SubsSlice::new(start, length) + }; + + let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables); + + let new_ext = deep_copy_var_to_help(source, target, max_rank, pools, ext_var); + let new_rec_var = + deep_copy_var_to_help(source, target, max_rank, pools, rec_var); + + RecursiveTagUnion(new_rec_var, union_tags, new_ext) + } + }; + + target.set(copy, make_descriptor(Structure(new_flat_type))); + + copy + } + + FlexVar(_) | Error => copy, + + RecursionVar { + opt_name, + structure, + } => { + let new_structure = deep_copy_var_to_help(source, target, max_rank, pools, structure); + + target.set( + copy, + make_descriptor(RecursionVar { + opt_name, + structure: new_structure, + }), + ); + + copy + } + + RigidVar(name) => { + target.set(copy, make_descriptor(FlexVar(Some(name)))); + + copy + } + + Alias(symbol, mut args, real_type_var) => { + let mut new_vars = Vec::with_capacity(args.variables().len()); + + for var_index in args.variables() { + let var = source[var_index]; + let new_var = deep_copy_var_to_help(source, target, max_rank, pools, var); + + new_vars.push(new_var); + } + + args.replace_variables(target, new_vars); + + let new_real_type_var = + deep_copy_var_to_help(source, target, max_rank, pools, real_type_var); + let new_content = Alias(symbol, args, new_real_type_var); + + target.set(copy, make_descriptor(new_content)); + + copy + } + } +} + fn deep_copy_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, var: Variable) -> Variable { let copy = deep_copy_var_help(subs, rank, pools, var); diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 420ac0c322..55d1b51c05 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -9,10 +9,12 @@ use ven_ena::unify::{InPlace, Snapshot, UnificationTable, UnifyKey}; // if your changes cause this number to go down, great! // please change it to the lower number. // if it went up, maybe check that the change is really required -static_assertions::assert_eq_size!([u8; 48], Descriptor); -static_assertions::assert_eq_size!([u8; 32], Content); -static_assertions::assert_eq_size!([u8; 24], FlatType); -static_assertions::assert_eq_size!([u8; 48], Problem); +static_assertions::assert_eq_size!([u8; 6 * 8], Descriptor); +static_assertions::assert_eq_size!([u8; 4 * 8], Content); +static_assertions::assert_eq_size!([u8; 3 * 8], FlatType); +static_assertions::assert_eq_size!([u8; 6 * 8], Problem); +static_assertions::assert_eq_size!([u8; 12], UnionTags); +static_assertions::assert_eq_size!([u8; 2 * 8], RecordFields); #[derive(Clone, Copy, Hash, PartialEq, Eq)] pub struct Mark(i32); @@ -1326,6 +1328,12 @@ impl From for Descriptor { } } +static_assertions::assert_eq_size!([u8; 4 * 8], Content); +static_assertions::assert_eq_size!([u8; 4 * 8], (Variable, Option)); +static_assertions::assert_eq_size!([u8; 3 * 8], (Symbol, AliasVariables, Variable)); +static_assertions::assert_eq_size!([u8; 12], AliasVariables); +static_assertions::assert_eq_size!([u8; 3 * 8], FlatType); + #[derive(Clone, Debug)] pub enum Content { /// A type variable which the user did not name in an annotation, @@ -1466,6 +1474,8 @@ impl Content { } } +static_assertions::assert_eq_size!([u8; 3 * 8], FlatType); + #[derive(Clone, Debug)] pub enum FlatType { Apply(Symbol, VariableSubsSlice), From 163656b2bd5436cc9561f1ea82a3e6d39fa81740 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 15 Nov 2021 20:13:45 +0100 Subject: [PATCH 101/223] fix merge conflict --- compiler/module/src/low_level.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index 89826f3651..77f551b980 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -217,7 +217,6 @@ impl LowLevel { Symbol::LIST_KEEP_ERRS => Some(ListKeepErrs), Symbol::LIST_SORT_WITH => Some(ListSortWith), Symbol::LIST_SUBLIST => Some(ListSublist), - Symbol::LIST_DROP => Some(ListDrop), Symbol::LIST_DROP_AT => Some(ListDropAt), Symbol::LIST_SWAP => Some(ListSwap), Symbol::LIST_ANY => Some(ListAny), From 8ad2f13ba91807b2cffc7fda3f2abcd04d7acee6 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 19:17:27 +0000 Subject: [PATCH 102/223] Map some Str lowlevels to builtin calls --- compiler/gen_wasm/src/low_level.rs | 35 +++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index ac680e0b18..27a99bc7b9 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -27,16 +27,31 @@ pub fn decode_low_level<'a>( let panic_ret_type = || panic!("Invalid return layout for {:?}: {:?}", lowlevel, ret_layout); match lowlevel { - StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt - | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft - | StrTrimRight | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim - | ListLen | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse - | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap - | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk - | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith - | ListSublist | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize - | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys - | DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { + StrConcat => return BuiltinCall(bitcode::STR_CONCAT), + StrJoinWith => return BuiltinCall(bitcode::STR_JOIN_WITH), + StrIsEmpty => return NotImplemented, + StrStartsWith => return BuiltinCall(bitcode::STR_STARTS_WITH), + StrStartsWithCodePt => return BuiltinCall(bitcode::STR_STARTS_WITH_CODE_PT), + StrEndsWith => return BuiltinCall(bitcode::STR_ENDS_WITH), + StrSplit => return NotImplemented, + StrCountGraphemes => return NotImplemented, + StrFromInt => return NotImplemented, + StrFromUtf8 => return BuiltinCall(bitcode::STR_FROM_UTF8), + StrTrimLeft => return BuiltinCall(bitcode::STR_TRIM_LEFT), + StrTrimRight => return BuiltinCall(bitcode::STR_TRIM_RIGHT), + StrFromUtf8Range => return BuiltinCall(bitcode::STR_FROM_UTF8_RANGE), + StrToUtf8 => return BuiltinCall(bitcode::STR_TO_UTF8), + StrRepeat => return BuiltinCall(bitcode::STR_REPEAT), + StrFromFloat => return BuiltinCall(bitcode::STR_FROM_FLOAT), + StrTrim => return BuiltinCall(bitcode::STR_TRIM), + + ListLen | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat + | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 + | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil + | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListSublist + | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize | DictEmpty + | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues + | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { return NotImplemented; } From e9f920827eb50fb6592f1df390dda94c337e8ff1 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 19:20:16 +0000 Subject: [PATCH 103/223] Add support for Zig/LLVM "fast calling convention" --- compiler/gen_wasm/src/backend.rs | 32 ++++- compiler/gen_wasm/src/lib.rs | 43 ++++--- compiler/gen_wasm/src/storage.rs | 161 +++++++++++++++++--------- compiler/test_gen/src/helpers/wasm.rs | 49 ++++---- compiler/test_gen/src/wasm_str.rs | 42 +++---- 5 files changed, 205 insertions(+), 122 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 8b91379120..c094a9cf3c 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -444,6 +444,13 @@ impl<'a> WasmBackend<'a> { Ok(()) } + + Stmt::Refcounting(_modify, following) => { + // TODO: actually deal with refcounting. For hello world, we just skipped it. + self.build_stmt(following, ret_layout)?; + Ok(()) + } + x => Err(format!("statement not yet implemented: {:?}", x)), } } @@ -558,7 +565,8 @@ impl<'a> WasmBackend<'a> { arguments: &'a [Symbol], return_layout: WasmLayout, ) -> Result<(), String> { - self.storage.load_symbols(&mut self.code_builder, arguments); + self.storage + .load_symbols_fastcc(&mut self.code_builder, arguments, &return_layout); let build_result = decode_low_level( &mut self.code_builder, @@ -764,11 +772,27 @@ impl<'a> WasmBackend<'a> { }, None => { - let mut param_types = Vec::with_capacity_in(arguments.len(), self.env.arena); - param_types.extend(arguments.iter().map(|a| self.storage.get(a).value_type())); + let mut param_types = Vec::with_capacity_in(1 + arguments.len(), self.env.arena); + + let ret_type = if ret_layout.is_stack_memory() { + param_types.push(ValueType::I32); + None + } else { + Some(ret_layout.value_type()) + }; + + for arg in arguments { + param_types.push(match self.storage.get(arg) { + StoredValue::StackMemory { size, .. } if *size > 4 && *size <= 8 => { + ValueType::I64 + } + _ => ValueType::I32, + }); + } + let signature_index = self.module.types.insert(Signature { param_types, - ret_type: Some(ret_layout.value_type()), // TODO: handle builtins with no return value + ret_type, }); let import_index = self.module.import.entries.len() as u32; diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index c1f2eec941..2e40ca9ea3 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -7,6 +7,7 @@ pub mod wasm_module; use bumpalo::{self, collections::Vec, Bump}; use roc_collections::all::{MutMap, MutSet}; +use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, Symbol}; use roc_mono::ir::{Proc, ProcLayout}; use roc_mono::layout::LayoutIds; @@ -47,34 +48,50 @@ pub fn build_module_help<'a>( procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, ) -> Result, String> { let mut layout_ids = LayoutIds::default(); - let mut proc_symbols = Vec::with_capacity_in(procedures.len(), env.arena); + let mut generated_procs = Vec::with_capacity_in(procedures.len(), env.arena); + let mut generated_symbols = Vec::with_capacity_in(procedures.len(), env.arena); let mut linker_symbols = Vec::with_capacity_in(procedures.len() * 2, env.arena); - let mut exports = Vec::with_capacity_in(procedures.len(), env.arena); + let mut exports = Vec::with_capacity_in(4, env.arena); - // Collect the symbols & names for the procedures - for (i, (sym, layout)) in procedures.keys().enumerate() { - proc_symbols.push(*sym); + // Collect the symbols & names for the procedures, + // and filter out procs we're going to inline + let mut fn_index = 0; + for ((sym, layout), proc) in procedures.into_iter() { + if LowLevel::from_inlined_wrapper(sym).is_some() { + continue; + } + generated_procs.push(proc); + generated_symbols.push(sym); let fn_name = layout_ids - .get_toplevel(*sym, layout) - .to_symbol_string(*sym, &env.interns); + .get_toplevel(sym, &layout) + .to_symbol_string(sym, &env.interns); - if env.exposed_to_host.contains(sym) { + if env.exposed_to_host.contains(&sym) { exports.push(Export { name: fn_name.clone(), ty: ExportType::Func, - index: i as u32, + index: fn_index as u32, }); } - let linker_sym = SymInfo::for_function(i as u32, fn_name); + let linker_sym = SymInfo::for_function(fn_index as u32, fn_name); linker_symbols.push(linker_sym); + + fn_index += 1; } - // Main loop: Build the Wasm module + // Build the Wasm module let (mut module, linker_symbols) = { - let mut backend = WasmBackend::new(env, layout_ids, proc_symbols, linker_symbols, exports); - for ((sym, _), proc) in procedures.into_iter() { + let mut backend = WasmBackend::new( + env, + layout_ids, + generated_symbols.clone(), + linker_symbols, + exports, + ); + + for (proc, sym) in generated_procs.into_iter().zip(generated_symbols) { backend.build_proc(proc, sym)?; } (backend.module, backend.linker_symbols) diff --git a/compiler/gen_wasm/src/storage.rs b/compiler/gen_wasm/src/storage.rs index fbec6ff61a..64565bc9a4 100644 --- a/compiler/gen_wasm/src/storage.rs +++ b/compiler/gen_wasm/src/storage.rs @@ -5,7 +5,7 @@ use roc_collections::all::MutMap; use roc_module::symbol::Symbol; use crate::layout::WasmLayout; -use crate::wasm_module::{CodeBuilder, LocalId, ValueType, VmSymbolState}; +use crate::wasm_module::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState}; use crate::{copy_memory, round_up_to_alignment, CopyMemoryConfig, PTR_SIZE, PTR_TYPE}; pub enum StoredValueKind { @@ -194,6 +194,67 @@ impl<'a> Storage<'a> { }) } + /// Load a symbol using the C Calling Convention + fn load_symbol_ccc(&mut self, code_builder: &mut CodeBuilder, sym: Symbol) { + let storage = self.get(&sym).to_owned(); + match storage { + StoredValue::VirtualMachineStack { + vm_state, + value_type, + size, + } => { + let next_local_id = self.get_next_local_id(); + let maybe_next_vm_state = code_builder.load_symbol(sym, vm_state, next_local_id); + match maybe_next_vm_state { + // The act of loading the value changed the VM state, so update it + Some(next_vm_state) => { + self.symbol_storage_map.insert( + sym, + StoredValue::VirtualMachineStack { + vm_state: next_vm_state, + value_type, + size, + }, + ); + } + None => { + // Loading the value required creating a new local, because + // it was not in a convenient position in the VM stack. + self.local_types.push(value_type); + self.symbol_storage_map.insert( + sym, + StoredValue::Local { + local_id: next_local_id, + value_type, + size, + }, + ); + } + } + } + StoredValue::Local { local_id, .. } + | StoredValue::StackMemory { + location: StackMemoryLocation::PointerArg(local_id), + .. + } => { + code_builder.get_local(local_id); + code_builder.set_top_symbol(sym); + } + + StoredValue::StackMemory { + location: StackMemoryLocation::FrameOffset(offset), + .. + } => { + code_builder.get_local(self.stack_frame_pointer.unwrap()); + if offset != 0 { + code_builder.i32_const(offset as i32); + code_builder.i32_add(); + } + code_builder.set_top_symbol(sym); + } + } + } + /// Load symbols to the top of the VM stack /// Avoid calling this method in a loop with one symbol at a time! It will work, /// but it generates very inefficient Wasm code. @@ -204,61 +265,55 @@ impl<'a> Storage<'a> { return; } for sym in symbols.iter() { - let storage = self.get(sym).to_owned(); - match storage { - StoredValue::VirtualMachineStack { - vm_state, - value_type, - size, - } => { - let next_local_id = self.get_next_local_id(); - let maybe_next_vm_state = - code_builder.load_symbol(*sym, vm_state, next_local_id); - match maybe_next_vm_state { - // The act of loading the value changed the VM state, so update it - Some(next_vm_state) => { - self.symbol_storage_map.insert( - *sym, - StoredValue::VirtualMachineStack { - vm_state: next_vm_state, - value_type, - size, - }, - ); - } - None => { - // Loading the value required creating a new local, because - // it was not in a convenient position in the VM stack. - self.local_types.push(value_type); - self.symbol_storage_map.insert( - *sym, - StoredValue::Local { - local_id: next_local_id, - value_type, - size, - }, - ); - } - } - } - StoredValue::Local { local_id, .. } - | StoredValue::StackMemory { - location: StackMemoryLocation::PointerArg(local_id), - .. - } => { - code_builder.get_local(local_id); - code_builder.set_top_symbol(*sym); + self.load_symbol_ccc(code_builder, *sym); + } + } + + /// Load symbols in a way compatible with LLVM's "fast calling convention" + /// A bug in Zig means it always uses this for Wasm even when we specify C calling convention. + /// It squashes small structs into primitive values where possible, avoiding stack memory + /// in favour of CPU registers (or VM stack values, which eventually become CPU registers). + /// We need to convert some of our structs from our internal C-like representation to work with Zig. + /// Why not just always use the fastcc representation? Because of non-Zig platforms. + pub fn load_symbols_fastcc( + &mut self, + code_builder: &mut CodeBuilder, + symbols: &[Symbol], + return_layout: &WasmLayout, + ) { + if return_layout.is_stack_memory() { + // Load the address where the return value should be written + self.load_symbol_ccc(code_builder, symbols[0]); + }; + + for sym in symbols { + if let StoredValue::StackMemory { + location, + size, + alignment_bytes, + } = self.get(sym) + { + if *size == 0 { + unimplemented!("Passing zero-sized values is not implemented yet"); + } else if *size > 8 { + return self.load_symbol_ccc(code_builder, *sym); } - StoredValue::StackMemory { - location: StackMemoryLocation::FrameOffset(offset), - .. - } => { - code_builder.get_local(self.stack_frame_pointer.unwrap()); - code_builder.i32_const(offset as i32); - code_builder.i32_add(); - code_builder.set_top_symbol(*sym); + let (local_id, offset) = location.local_and_offset(self.stack_frame_pointer); + code_builder.get_local(local_id); + let align = Align::from(*alignment_bytes); + + if *size == 1 { + code_builder.i32_load8_u(align, offset); + } else if *size == 2 { + code_builder.i32_load16_u(align, offset); + } else if *size <= 4 { + code_builder.i32_load(align, offset); + } else { + code_builder.i64_load(align, offset); } + } else { + self.load_symbol_ccc(code_builder, *sym); } } } diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index 4f6945522d..2e90c0c313 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -9,7 +9,7 @@ use roc_can::builtins::builtin_defs_map; use roc_collections::all::{MutMap, MutSet}; use roc_gen_wasm::MEMORY_NAME; -use tempfile::tempdir; +use tempfile::{TempDir, tempdir}; const TEST_WRAPPER_NAME: &str = "test_wrapper"; @@ -118,39 +118,34 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( let mut module_bytes = std::vec::Vec::with_capacity(4096); wasm_module.serialize_mut(&mut module_bytes); - // for debugging (e.g. with wasm2wat or wasm-objdump) - if false { - use std::io::Write; - - let mut hash_state = DefaultHasher::new(); - src.hash(&mut hash_state); - let src_hash = hash_state.finish(); - - // Filename contains a hash of the Roc test source code. Helpful when comparing across commits. - let dir = "/tmp/roc/gen_wasm"; - std::fs::create_dir_all(dir).unwrap(); - let path = format!("{}/test-{:016x}.wasm", dir, src_hash); - - // Print out filename (appears just after test name) - println!("dumping file {:?}", path); - - match std::fs::File::create(path) { - Err(e) => eprintln!("Problem creating wasm debug file: {:?}", e), - Ok(mut file) => { - file.write_all(&module_bytes).unwrap(); - } - } - } - // now, do wasmer stuff use wasmer::{Instance, Module, Store}; let store = Store::default(); + // Keep the final .wasm file for debugging with wasm-objdump or wasm2wat + const DEBUG_WASM_FILE: bool = true; + let wasmer_module = { - let dir = tempdir().unwrap(); - let dirpath = dir.path(); + let tmp_dir: TempDir; // directory for normal test runs, deleted when dropped + let debug_dir: String; // persistent directory for debugging + + let dirpath: &Path = + if DEBUG_WASM_FILE { + // Directory name based on a hash of the Roc source + let mut hash_state = DefaultHasher::new(); + src.hash(&mut hash_state); + let src_hash = hash_state.finish(); + debug_dir = format!("/tmp/roc/gen_wasm/{:016x}", src_hash); + std::fs::create_dir_all(&debug_dir).unwrap(); + println!("Debug command:\n\twasm-objdump -sdx {}/final.wasm", &debug_dir); + Path::new(&debug_dir) + } else { + tmp_dir = tempdir().unwrap(); + tmp_dir.path() + }; + let final_wasm_file = dirpath.join("final.wasm"); let app_o_file = dirpath.join("app.o"); diff --git a/compiler/test_gen/src/wasm_str.rs b/compiler/test_gen/src/wasm_str.rs index fcba6143c1..d616365c7d 100644 --- a/compiler/test_gen/src/wasm_str.rs +++ b/compiler/test_gen/src/wasm_str.rs @@ -296,31 +296,23 @@ fn long_str_literal() { ); } -// #[test] -// fn small_str_concat_empty_first_arg() { -// assert_llvm_evals_to!( -// r#"Str.concat "" "JJJJJJJJJJJJJJJ""#, -// [ -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0b1000_1111 -// ], -// [u8; 16] -// ); -// } +#[test] +fn small_str_concat_empty_first_arg() { + assert_evals_to!( + r#"Str.concat "" "JJJJJJJ""#, + [ + 0x4a, + 0x4a, + 0x4a, + 0x4a, + 0x4a, + 0x4a, + 0x4a, + 0b1000_0111 + ], + [u8; 8] + ); +} // #[test] // fn small_str_concat_empty_second_arg() { From 7c4300a7a151a84027578be2f5ca99ab06012026 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 15 Nov 2021 22:43:32 +0100 Subject: [PATCH 104/223] clarify what pending means --- compiler/mono/src/ir.rs | 85 +++++++++++++++++++++++++++++++------ compiler/solve/src/solve.rs | 13 +++++- 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index c0c02f3466..fa2b0b7cbf 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -438,16 +438,70 @@ impl<'a> ExternalSpecializations<'a> { } } +#[derive(Clone, Debug)] +pub struct Suspended<'a> { + pub store: Subs, + pub symbols: Vec<'a, Symbol>, + pub layouts: Vec<'a, ProcLayout<'a>>, + pub variables: Vec<'a, Variable>, +} + +impl<'a> Suspended<'a> { + fn specialization( + &mut self, + subs: &mut Subs, + symbol: Symbol, + proc_layout: ProcLayout<'a>, + variable: Variable, + ) { + // de-duplicate + for (i, s) in self.symbols.iter().enumerate() { + if *s == symbol { + let existing = &self.layouts[i]; + if &proc_layout == existing { + // symbol + layout combo exists + return; + } + } + } + + self.symbols.push(symbol); + self.layouts.push(proc_layout); + + let variable = roc_solve::solve::deep_copy_var_to(subs, &mut self.store, variable); + self.variables.push(variable); + } +} + +#[derive(Clone, Debug)] +enum PendingSpecializations<'a> { + /// We are finding specializations we need. This is a separate step so + /// that we can give specializations we need to modules higher up in the dependency chain, so + /// that they can start making specializations too + Finding(BumpMap, PendingSpecialization<'a>>>), + /// We are making specializations. If any new one comes up, we can just make it immediately + Making, +} + +impl<'a> PendingSpecializations<'a> { + fn into_option( + self, + ) -> Option, PendingSpecialization<'a>>>> { + match self { + PendingSpecializations::Finding(x) => Some(x), + PendingSpecializations::Making => None, + } + } +} + #[derive(Clone, Debug)] pub struct Procs<'a> { pub partial_procs: PartialProcs<'a>, pub imported_module_thunks: &'a [Symbol], pub module_thunks: &'a [Symbol], - pub pending_specializations: - Option, PendingSpecialization<'a>>>>, + pending_specializations: PendingSpecializations<'a>, pub specialized: BumpMap<(Symbol, ProcLayout<'a>), InProgressProc<'a>>, pub runtime_errors: BumpMap, - pub call_by_pointer_wrappers: BumpMap, pub externals_we_need: BumpMap>, } @@ -457,10 +511,9 @@ impl<'a> Procs<'a> { partial_procs: PartialProcs::new_in(arena), imported_module_thunks: &[], module_thunks: &[], - pending_specializations: Some(BumpMap::new_in(arena)), + pending_specializations: PendingSpecializations::Finding(BumpMap::new_in(arena)), specialized: BumpMap::new_in(arena), runtime_errors: BumpMap::new_in(arena), - call_by_pointer_wrappers: BumpMap::new_in(arena), externals_we_need: BumpMap::new_in(arena), } } @@ -557,7 +610,7 @@ impl<'a> Procs<'a> { } match &mut self.pending_specializations { - Some(pending_specializations) => { + PendingSpecializations::Finding(pending_specializations) => { // register the pending specialization, so this gets code genned later add_pending(pending_specializations, symbol, layout, pending); @@ -590,7 +643,7 @@ impl<'a> Procs<'a> { } } } - None => { + PendingSpecializations::Making => { // Mark this proc as in-progress, so if we're dealing with // mutually recursive functions, we don't loop forever. // (We had a bug around this before this system existed!) @@ -690,12 +743,12 @@ impl<'a> Procs<'a> { // This should only be called when pending_specializations is Some. // Otherwise, it's being called in the wrong pass! match &mut self.pending_specializations { - Some(pending_specializations) => { + PendingSpecializations::Finding(pending_specializations) => { let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); add_pending(pending_specializations, name, layout, pending) } - None => { + PendingSpecializations::Making => { let symbol = name; let partial_proc_id = match self.partial_procs.symbol_to_id(symbol) { @@ -1743,7 +1796,11 @@ pub fn specialize_all<'a>( // When calling from_can, pending_specializations should be unavailable. // This must be a single pass, and we must not add any more entries to it! - let opt_pending_specializations = std::mem::replace(&mut procs.pending_specializations, None); + let opt_pending_specializations = std::mem::replace( + &mut procs.pending_specializations, + PendingSpecializations::Making, + ) + .into_option(); let it = specializations_for_host .into_iter() @@ -6651,7 +6708,7 @@ fn call_by_name_help<'a>( } match &mut procs.pending_specializations { - Some(pending_specializations) => { + PendingSpecializations::Finding(pending_specializations) => { debug_assert!(!env.is_imported_symbol(proc_name)); // register the pending specialization, so this gets code genned later @@ -6686,7 +6743,7 @@ fn call_by_name_help<'a>( let iter = loc_args.into_iter().rev().zip(field_symbols.iter().rev()); assign_to_symbols(env, procs, layout_cache, iter, result) } - None => { + PendingSpecializations::Making => { let opt_partial_proc = procs.partial_procs.symbol_to_id(proc_name); /* @@ -6808,7 +6865,7 @@ fn call_by_name_module_thunk<'a>( } match &mut procs.pending_specializations { - Some(pending_specializations) => { + PendingSpecializations::Finding(pending_specializations) => { debug_assert!(!env.is_imported_symbol(proc_name)); // register the pending specialization, so this gets code genned later @@ -6821,7 +6878,7 @@ fn call_by_name_module_thunk<'a>( force_thunk(env, proc_name, inner_layout, assigned, hole) } - None => { + PendingSpecializations::Making => { let opt_partial_proc = procs.partial_procs.symbol_to_id(proc_name); match opt_partial_proc { diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index 60d3906078..ba9af2bc38 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1381,8 +1381,19 @@ fn instantiate_rigids_help( var } +pub fn deep_copy_var_to( + source: &mut Subs, // mut to set the copy + target: &mut Subs, + var: Variable, +) -> Variable { + let mut pools = Pools::default(); + let rank = Rank::toplevel(); + + deep_copy_var_to_help(source, target, rank, &mut pools, var) +} + fn deep_copy_var_to_help( - source: &Subs, + source: &mut Subs, // mut to set the copy target: &mut Subs, max_rank: Rank, pools: &mut Pools, From c4dd112a256728552b4b82f7fae9a1f7a9653472 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Mon, 15 Nov 2021 14:00:24 -0800 Subject: [PATCH 105/223] Allow generating new .result-ast files with ROC_PARSER_SNAPSHOT_TEST_OVERWRITE --- compiler/parse/tests/test_parse.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index cf7cd3f79d..d293e294cf 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -245,13 +245,14 @@ mod test_parse { let result_path = parent.join(&format!("{}.{}.result-ast", name, ty)); let input = std::fs::read_to_string(&input_path).unwrap(); - let expected_result = std::fs::read_to_string(&result_path).unwrap(); let actual_result = func(&input); if std::env::var("ROC_PARSER_SNAPSHOT_TEST_OVERWRITE").is_ok() { std::fs::write(&result_path, actual_result).unwrap(); } else { + let expected_result = std::fs::read_to_string(&result_path).unwrap(); + // TODO: do a diff over the "real" content of these strings, rather than // the debug-formatted content. As is, we get an ugly single-line diff // from pretty_assertions From 541465bc2e79d884d1ffa46b8a0f2554f7accd99 Mon Sep 17 00:00:00 2001 From: satotake Date: Tue, 16 Nov 2021 11:13:37 +0000 Subject: [PATCH 106/223] Use let --- compiler/can/src/builtins.rs | 15 +++++++++++++-- compiler/module/src/symbol.rs | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 942cdd8468..8bcf8367d2 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2155,14 +2155,23 @@ fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def { let sym_list = Symbol::ARG_1; let sym_index = Symbol::ARG_2; + let sym_temp = Symbol::LIST_SPLIT_TEMP; let ret_var = var_store.fresh(); let zero = int(index_var, Variable::NATURAL, 0); + let def_temp = Def { + annotation: None, + expr_var: list_var, + loc_expr: no_region(Var(sym_list)), + loc_pattern: no_region(Pattern::Identifier(sym_temp)), + pattern_vars: Default::default(), + }; + let get_before = RunLowLevel { op: LowLevel::ListSublist, args: vec![ - (list_var, Var(sym_list)), + (list_var, Var(sym_temp)), (index_var, zero), (index_var, Var(sym_index)), ], @@ -2202,11 +2211,13 @@ fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def { loc_expr: Box::new(no_region(get_others)), }; - let body = record( + let get_rec = record( vec![("before".into(), before), ("others".into(), others)], var_store, ); + let body = LetNonRec(Box::new(def_temp), Box::new(no_region(get_rec)), ret_var); + defn( symbol, vec![(list_var, sym_list), (index_var, sym_index)], diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 4367d70b34..1a22062408 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1073,6 +1073,7 @@ define_builtins! { 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" 50 LIST_SPLIT: "split" + 51 LIST_SPLIT_TEMP: "#splitTemp" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias From 1feab3651c08e2538abda1dec5fc3c9af47aeabe Mon Sep 17 00:00:00 2001 From: Cristiano Piemontese Date: Tue, 16 Nov 2021 12:42:07 +0100 Subject: [PATCH 107/223] add host rebuild info logs --- cli/src/build.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cli/src/build.rs b/cli/src/build.rs index bbb5d6a9fa..333a0f240c 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -291,6 +291,8 @@ fn spawn_rebuild_thread( ) -> std::thread::JoinHandle { let thread_local_target = target.clone(); std::thread::spawn(move || { + print!("πŸ”¨ Rebuilding host... "); + let rebuild_host_start = SystemTime::now(); if !precompiled { if surgically_link { @@ -316,6 +318,9 @@ fn spawn_rebuild_thread( std::fs::copy(prehost, binary_path.as_path()).unwrap(); } let rebuild_host_end = rebuild_host_start.elapsed().unwrap(); + + println!("Done!"); + rebuild_host_end.as_millis() }) } From b8f40011b9b500ca01cfca8881646e93d87d441e Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 15 Nov 2021 23:15:12 +0000 Subject: [PATCH 108/223] Generate a test "platform" with libc allocator functions --- compiler/gen_wasm/src/wasm_module/sections.rs | 3 +- compiler/test_gen/src/helpers/wasm.rs | 163 ++++++++++++++++-- compiler/test_gen/src/wasm_str.rs | 11 +- 3 files changed, 149 insertions(+), 28 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/sections.rs b/compiler/gen_wasm/src/wasm_module/sections.rs index 855d5062ee..495a738a6b 100644 --- a/compiler/gen_wasm/src/wasm_module/sections.rs +++ b/compiler/gen_wasm/src/wasm_module/sections.rs @@ -241,8 +241,7 @@ impl<'a> Serialize for ImportSection<'a> { #[derive(Debug)] pub struct FunctionSection<'a> { - /// Private. See WasmModule::add_function_signature - signature_indices: Vec<'a, u32>, + pub signature_indices: Vec<'a, u32>, } impl<'a> FunctionSection<'a> { diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index 2e90c0c313..0bd30b636f 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -1,16 +1,22 @@ +use bumpalo::collections::vec::Vec; +use bumpalo::Bump; use std::cell::Cell; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; +use tempfile::{tempdir, TempDir}; use crate::helpers::from_wasm32_memory::FromWasm32Memory; use crate::helpers::wasm32_test_result::Wasm32TestResult; use roc_builtins::bitcode; use roc_can::builtins::builtin_defs_map; use roc_collections::all::{MutMap, MutSet}; +use roc_gen_wasm::wasm_module::linking::{WasmObjectSymbol, WASM_SYM_UNDEFINED}; +use roc_gen_wasm::wasm_module::sections::{Import, ImportDesc}; +use roc_gen_wasm::wasm_module::{ + CodeBuilder, Export, ExportType, LocalId, Signature, SymInfo, ValueType, WasmModule, +}; use roc_gen_wasm::MEMORY_NAME; -use tempfile::{TempDir, tempdir}; - const TEST_WRAPPER_NAME: &str = "test_wrapper"; std::thread_local! { @@ -115,6 +121,9 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( main_fn_index as u32, ); + // We can either generate the test platform or write an external source file, whatever works + generate_test_platform(&mut wasm_module, arena); + let mut module_bytes = std::vec::Vec::with_capacity(4096); wasm_module.serialize_mut(&mut module_bytes); @@ -131,20 +140,22 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( let tmp_dir: TempDir; // directory for normal test runs, deleted when dropped let debug_dir: String; // persistent directory for debugging - let dirpath: &Path = - if DEBUG_WASM_FILE { - // Directory name based on a hash of the Roc source - let mut hash_state = DefaultHasher::new(); - src.hash(&mut hash_state); - let src_hash = hash_state.finish(); - debug_dir = format!("/tmp/roc/gen_wasm/{:016x}", src_hash); - std::fs::create_dir_all(&debug_dir).unwrap(); - println!("Debug command:\n\twasm-objdump -sdx {}/final.wasm", &debug_dir); - Path::new(&debug_dir) - } else { - tmp_dir = tempdir().unwrap(); - tmp_dir.path() - }; + let dirpath: &Path = if DEBUG_WASM_FILE { + // Directory name based on a hash of the Roc source + let mut hash_state = DefaultHasher::new(); + src.hash(&mut hash_state); + let src_hash = hash_state.finish(); + debug_dir = format!("/tmp/roc/gen_wasm/{:016x}", src_hash); + std::fs::create_dir_all(&debug_dir).unwrap(); + println!( + "Debug command:\n\twasm-objdump -sdx {}/final.wasm", + &debug_dir + ); + Path::new(&debug_dir) + } else { + tmp_dir = tempdir().unwrap(); + tmp_dir.path() + }; let final_wasm_file = dirpath.join("final.wasm"); let app_o_file = dirpath.join("app.o"); @@ -271,3 +282,123 @@ pub fn identity(value: T) -> T { pub(crate) use assert_evals_to; #[allow(unused_imports)] pub(crate) use assert_wasm_evals_to; + +fn wrap_libc_fn<'a>( + module: &mut WasmModule<'a>, + arena: &'a Bump, + roc_name: &'a str, + libc_name: &'a str, + params: &'a [(ValueType, bool)], + ret_type: Option, +) { + let symbol_table = module.linking.symbol_table_mut(); + + // Type signatures + let mut wrapper_signature = Signature { + param_types: Vec::with_capacity_in(params.len(), arena), + ret_type, + }; + let mut libc_signature = Signature { + param_types: Vec::with_capacity_in(params.len(), arena), + ret_type, + }; + for (ty, used) in params.iter() { + wrapper_signature.param_types.push(*ty); + if *used { + libc_signature.param_types.push(*ty); + } + } + + /* + * Import a function from libc + */ + let libc_signature_index = module.types.insert(libc_signature); + + // Import + let import_index = module.import.entries.len() as u32; + module.import.entries.push(Import { + module: "env", + name: libc_name.to_string(), + description: ImportDesc::Func { + signature_index: libc_signature_index, + }, + }); + + // Linker info + let libc_sym_idx = symbol_table.len() as u32; + symbol_table.push(SymInfo::Function(WasmObjectSymbol::Imported { + flags: WASM_SYM_UNDEFINED, + index: import_index, + })); + + /* + * Export a wrapper function + */ + + // Declaration + let wrapper_sig_index = module.types.insert(wrapper_signature); + module.function.signature_indices.push(wrapper_sig_index); + + // Body + let mut code_builder = CodeBuilder::new(arena); + let mut num_libc_args = 0; + for (i, (_, used)) in params.iter().enumerate() { + if *used { + code_builder.get_local(LocalId(i as u32)); + num_libc_args += 1; + } + } + code_builder.call( + import_index, + libc_sym_idx, + num_libc_args, + ret_type.is_some(), + ); + code_builder.build_fn_header(&[], 0, None); + let wrapper_index = module.code.code_builders.len() as u32; + module.code.code_builders.push(code_builder); + + // Export + module.export.entries.push(Export { + name: roc_name.to_string(), + ty: ExportType::Func, + index: wrapper_index, + }); + + // Linker symbol + symbol_table.push(SymInfo::Function(WasmObjectSymbol::Defined { + flags: 0, + index: wrapper_index, + name: roc_name.to_string(), + })); +} + +fn generate_test_platform<'a>(module: &mut WasmModule<'a>, arena: &'a Bump) { + use ValueType::I32; + + wrap_libc_fn( + module, + arena, + "roc_alloc", + "malloc", + // only the first argument of roc_alloc is passed to malloc + &[(I32, true), (I32, false)], + Some(I32), + ); + wrap_libc_fn( + module, + arena, + "roc_dealloc", + "free", + &[(I32, true), (I32, false)], + None, + ); + wrap_libc_fn( + module, + arena, + "roc_realloc", + "realloc", + &[(I32, true), (I32, false), (I32, true), (I32, false)], + Some(I32), + ); +} diff --git a/compiler/test_gen/src/wasm_str.rs b/compiler/test_gen/src/wasm_str.rs index d616365c7d..fb12eb3d91 100644 --- a/compiler/test_gen/src/wasm_str.rs +++ b/compiler/test_gen/src/wasm_str.rs @@ -300,16 +300,7 @@ fn long_str_literal() { fn small_str_concat_empty_first_arg() { assert_evals_to!( r#"Str.concat "" "JJJJJJJ""#, - [ - 0x4a, - 0x4a, - 0x4a, - 0x4a, - 0x4a, - 0x4a, - 0x4a, - 0b1000_0111 - ], + [0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0b1000_0111], [u8; 8] ); } From 5d4518c8d1943d34ed22f627c3341c990623b598 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Tue, 16 Nov 2021 12:00:13 +0000 Subject: [PATCH 109/223] Try using C for the wasm test platform --- compiler/test_gen/src/helpers/wasm.rs | 2 +- .../test_gen/src/helpers/wasm_test_platform.c | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 compiler/test_gen/src/helpers/wasm_test_platform.c diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index 0bd30b636f..d2d7fa8a99 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -122,7 +122,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( ); // We can either generate the test platform or write an external source file, whatever works - generate_test_platform(&mut wasm_module, arena); + // generate_test_platform(&mut wasm_module, arena); let mut module_bytes = std::vec::Vec::with_capacity(4096); wasm_module.serialize_mut(&mut module_bytes); diff --git a/compiler/test_gen/src/helpers/wasm_test_platform.c b/compiler/test_gen/src/helpers/wasm_test_platform.c new file mode 100644 index 0000000000..a607d38a8c --- /dev/null +++ b/compiler/test_gen/src/helpers/wasm_test_platform.c @@ -0,0 +1,23 @@ +#include +extern void* test_wrapper(); + +void* roc_alloc(size_t size, unsigned int alignment) { + return malloc(size); +} + +void* roc_realloc(void* ptr, size_t old_size, size_t new_size, unsigned int alignment) { + return realloc(ptr, new_size); +} + +void roc_dealloc(void* ptr, unsigned int alignment) { + free(ptr); +} + +// Having a main function seems to make it easier to convince tools +// to include everything in the output binary. +// Using C as the source language makes it easier to convince them +// to include libc for wasm target, not host. +// The returned int is the memory address of the test result +int main(void) { + return test_wrapper(); +} From 46e6e227760c5671f22cf262afbda0e81904a309 Mon Sep 17 00:00:00 2001 From: satotake Date: Tue, 16 Nov 2021 12:58:45 +0000 Subject: [PATCH 110/223] use closure --- compiler/can/src/builtins.rs | 101 ++++++++++++++++++++++------------ compiler/module/src/symbol.rs | 2 +- 2 files changed, 67 insertions(+), 36 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 8bcf8367d2..08351ff157 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2153,74 +2153,105 @@ fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); let index_var = var_store.fresh(); - let sym_list = Symbol::ARG_1; - let sym_index = Symbol::ARG_2; - let sym_temp = Symbol::LIST_SPLIT_TEMP; + let list_sym = Symbol::ARG_1; + let index_sym = Symbol::ARG_2; + + let clos_sym = Symbol::LIST_SPLIT_CLOS; + let clos_start_sym = Symbol::ARG_3; + let clos_len_sym = Symbol::ARG_4; + + let clos_fun_var = var_store.fresh(); + let clos_start_var = var_store.fresh(); + let clos_len_var = var_store.fresh(); + let clos_ret_var = var_store.fresh(); let ret_var = var_store.fresh(); let zero = int(index_var, Variable::NATURAL, 0); - let def_temp = Def { - annotation: None, - expr_var: list_var, - loc_expr: no_region(Var(sym_list)), - loc_pattern: no_region(Pattern::Identifier(sym_temp)), - pattern_vars: Default::default(), - }; - - let get_before = RunLowLevel { - op: LowLevel::ListSublist, - args: vec![ - (list_var, Var(sym_temp)), - (index_var, zero), - (index_var, Var(sym_index)), + let clos = Closure(ClosureData { + function_type: clos_fun_var, + closure_type: var_store.fresh(), + closure_ext_var: var_store.fresh(), + return_type: clos_ret_var, + name: clos_sym, + recursive: Recursive::NotRecursive, + captured_symbols: vec![(list_sym, clos_ret_var)], + arguments: vec![ + ( + clos_start_var, + no_region(Pattern::Identifier(clos_start_sym)), + ), + (clos_len_var, no_region(Pattern::Identifier(clos_len_sym))), ], - ret_var: list_var, - }; + loc_body: { + Box::new(no_region(RunLowLevel { + op: LowLevel::ListSublist, + args: vec![ + (clos_ret_var, Var(list_sym)), + (clos_start_var, Var(clos_start_sym)), + (clos_len_var, Var(clos_len_sym)), + ], + ret_var: clos_ret_var, + })) + }, + }); + + let fun = Box::new(( + clos_fun_var, + no_region(clos), + var_store.fresh(), + clos_ret_var, + )); + + let get_before = Call( + fun.clone(), + vec![ + (index_var, no_region(zero)), + (index_var, no_region(Var(index_sym))), + ], + CalledVia::Space, + ); let get_list_len = RunLowLevel { op: LowLevel::ListLen, - args: vec![(list_var, Var(sym_list))], + args: vec![(list_var, Var(list_sym))], ret_var: index_var, }; let get_others_len = RunLowLevel { op: LowLevel::NumSubWrap, - args: vec![(index_var, get_list_len), (index_var, Var(sym_index))], + args: vec![(index_var, get_list_len), (index_var, Var(index_sym))], ret_var: index_var, }; - let get_others = RunLowLevel { - op: LowLevel::ListSublist, - args: vec![ - (list_var, Var(sym_list)), - (index_var, Var(sym_index)), - (index_var, get_others_len), + let get_others = Call( + fun, + vec![ + (index_var, no_region(Var(index_sym))), + (index_var, no_region(get_others_len)), ], - ret_var: list_var, - }; + CalledVia::Space, + ); let before = Field { - var: list_var, + var: clos_ret_var, region: Region::zero(), loc_expr: Box::new(no_region(get_before)), }; let others = Field { - var: list_var, + var: clos_ret_var, region: Region::zero(), loc_expr: Box::new(no_region(get_others)), }; - let get_rec = record( + let body = record( vec![("before".into(), before), ("others".into(), others)], var_store, ); - let body = LetNonRec(Box::new(def_temp), Box::new(no_region(get_rec)), ret_var); - defn( symbol, - vec![(list_var, sym_list), (index_var, sym_index)], + vec![(list_var, list_sym), (index_var, index_sym)], var_store, body, ret_var, diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 1a22062408..65b8d366cf 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1073,7 +1073,7 @@ define_builtins! { 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" 50 LIST_SPLIT: "split" - 51 LIST_SPLIT_TEMP: "#splitTemp" + 51 LIST_SPLIT_CLOS: "#splitClos" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias From c05f9dc1df25a42c07fc51607ec4902ed4913760 Mon Sep 17 00:00:00 2001 From: satotake Date: Wed, 17 Nov 2021 00:15:27 +0900 Subject: [PATCH 111/223] Fix link in gen_dev README.md --- compiler/gen_dev/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/gen_dev/README.md b/compiler/gen_dev/README.md index 12321accf1..6a86279cce 100644 --- a/compiler/gen_dev/README.md +++ b/compiler/gen_dev/README.md @@ -70,7 +70,7 @@ This is the general procedure I follow with some helpful links: A good place to look for missing features is in the test files for generation in [test_gen](https://github.com/rtfeldman/roc/tree/trunk/compiler/test_gen). Any test that is not enabled for the `gen-dev` feature still needs to be added to the dev backend. Eventually all features should be enabled for the dev backend. 1. Pick/write the simplest test case you can find for the new feature. Just add `feature = "gen-dev"` to the `cfg` line for the test case. -1. Uncomment the code to print out procedures [from here](https://github.com/rtfeldman/roc/blob/trunk/compiler/gen_dev/tests/helpers/eval.rs) and run the test. +1. Uncomment the code to print out procedures [from here](https://github.com/rtfeldman/roc/blob/b03ed18553569314a420d5bf1fb0ead4b6b5ecda/compiler/test_gen/src/helpers/dev.rs#L76) and run the test. It should fail and print out the mono ir for this test case. Seeing the actual mono ir tends to be very helpful for complex additions. 1. Generally it will fail in one of the match statements in the [Backend](https://github.com/rtfeldman/roc/blob/trunk/compiler/gen_dev/src/lib.rs) trait. From 71bef85984d06919ba560fca35c230a865581d8e Mon Sep 17 00:00:00 2001 From: satotake Date: Tue, 16 Nov 2021 15:21:44 +0000 Subject: [PATCH 112/223] add x86_64 Int Num.neg support for gen_dev --- compiler/gen_dev/src/generic64/aarch64.rs | 4 ++++ compiler/gen_dev/src/generic64/mod.rs | 18 ++++++++++++++++++ compiler/gen_dev/src/generic64/x86_64.rs | 5 +++++ compiler/gen_dev/src/lib.rs | 20 ++++++++++++++++++++ compiler/test_gen/src/gen_num.rs | 13 ++++++++++++- 5 files changed, 59 insertions(+), 1 deletion(-) diff --git a/compiler/gen_dev/src/generic64/aarch64.rs b/compiler/gen_dev/src/generic64/aarch64.rs index 32273fbf91..908940bf6f 100644 --- a/compiler/gen_dev/src/generic64/aarch64.rs +++ b/compiler/gen_dev/src/generic64/aarch64.rs @@ -446,6 +446,10 @@ impl Assembler for AArch64Assembler { unimplemented!("stack offsets over 32k are not yet implement for AArch64"); } } + #[inline(always)] + fn neg_reg64_reg64(_buf: &mut Vec<'_, u8>, _dst: AArch64GeneralReg, _src: AArch64GeneralReg) { + unimplemented!("neg is not yet implement for AArch64"); + } #[inline(always)] fn sub_reg64_reg64_imm32( diff --git a/compiler/gen_dev/src/generic64/mod.rs b/compiler/gen_dev/src/generic64/mod.rs index 212d6572f7..7fdb8fe688 100644 --- a/compiler/gen_dev/src/generic64/mod.rs +++ b/compiler/gen_dev/src/generic64/mod.rs @@ -149,6 +149,7 @@ pub trait Assembler { fn mov_stack32_freg64(buf: &mut Vec<'_, u8>, offset: i32, src: FloatReg); fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GeneralReg); + fn neg_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GeneralReg, src: GeneralReg); fn imul_reg64_reg64_reg64( buf: &mut Vec<'_, u8>, dst: GeneralReg, @@ -786,6 +787,23 @@ impl< } } + fn build_num_neg( + &mut self, + dst: &Symbol, + src: &Symbol, + layout: &Layout<'a>, + ) -> Result<(), String> { + match layout { + Layout::Builtin(Builtin::Int64) => { + let dst_reg = self.claim_general_reg(dst)?; + let src_reg = self.load_to_general_reg(src)?; + ASM::neg_reg64_reg64(&mut self.buf, dst_reg, src_reg); + Ok(()) + } + x => Err(format!("NumNeg: layout, {:?}, not implemented yet", x)), + } + } + fn build_num_sub( &mut self, dst: &Symbol, diff --git a/compiler/gen_dev/src/generic64/x86_64.rs b/compiler/gen_dev/src/generic64/x86_64.rs index 67f3d82a08..f79b89c1ad 100644 --- a/compiler/gen_dev/src/generic64/x86_64.rs +++ b/compiler/gen_dev/src/generic64/x86_64.rs @@ -1053,6 +1053,11 @@ impl Assembler for X86_64Assembler { mov_base64_offset32_reg64(buf, X86_64GeneralReg::RSP, offset, src) } + #[inline(always)] + fn neg_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64GeneralReg) { + mov_reg64_reg64(buf, dst, src); + neg_reg64(buf, dst); + } #[inline(always)] fn sub_reg64_reg64_imm32( buf: &mut Vec<'_, u8>, diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 611a83d2ad..185e5d991b 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -368,6 +368,18 @@ where ); self.build_num_mul(sym, &args[0], &args[1], ret_layout) } + LowLevel::NumNeg => { + debug_assert_eq!( + 1, + args.len(), + "NumNeg: expected to have exactly one argument" + ); + debug_assert_eq!( + arg_layouts[0], *ret_layout, + "NumNeg: expected to have the same argument and return layout" + ); + self.build_num_neg(sym, &args[0], ret_layout) + } LowLevel::NumPowInt => self.build_fn_call( sym, bitcode::NUM_POW_INT[IntWidth::I64].to_string(), @@ -459,6 +471,14 @@ where layout: &Layout<'a>, ) -> Result<(), String>; + /// build_num_neg stores the negated value of src into dst. + fn build_num_neg( + &mut self, + dst: &Symbol, + src: &Symbol, + layout: &Layout<'a>, + ) -> Result<(), String>; + /// build_num_sub stores the `src1 - src2` difference into dst. fn build_num_sub( &mut self, diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index 538b928fec..ed3b1bbd7d 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -1214,7 +1214,18 @@ fn tail_call_elimination() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-wasm"))] +#[cfg(any(feature = "gen-dev"))] +fn int_negate_dev() { + // Dev backend yet to have `Num.maxInt` or `Num.minInt`. + // TODO Remove this test and add "gen-dev" feature the below + // after implementing the both. + assert_evals_to!("Num.neg 123", -123, i64); + assert_evals_to!("Num.neg -123", 123, i64); + assert_evals_to!("Num.neg 0", 0, i64); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn int_negate() { assert_evals_to!("Num.neg 123", -123, i64); assert_evals_to!("Num.neg Num.maxInt", -i64::MAX, i64); From 2a4b3d3cd373e5d08c999eaa89241015dd026a5e Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Nov 2021 16:56:05 +0100 Subject: [PATCH 113/223] added cfg to static size check for arm CPUs --- compiler/mono/src/ir.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 32be663338..c622411b77 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -27,9 +27,17 @@ pub const PRETTY_PRINT_IR_SYMBOLS: bool = false; // if your changes cause this number to go down, great! // please change it to the lower number. // if it went up, maybe check that the change is really required + +// i128 alignment is different on arm +#[cfg(target_arch = "aarch64")] +static_assertions::assert_eq_size!([u8; 4 * 8], Literal); +#[cfg(not(target_arch = "aarch64"))] static_assertions::assert_eq_size!([u8; 3 * 8], Literal); static_assertions::assert_eq_size!([u8; 10 * 8], Expr); +#[cfg(not(target_arch = "aarch64"))] static_assertions::assert_eq_size!([u8; 19 * 8], Stmt); +#[cfg(target_arch = "aarch64")] +static_assertions::assert_eq_size!([u8; 20 * 8], Stmt); static_assertions::assert_eq_size!([u8; 6 * 8], ProcLayout); static_assertions::assert_eq_size!([u8; 8 * 8], Call); static_assertions::assert_eq_size!([u8; 6 * 8], CallType); From b824302ab31fa7a1c2013a23fc08e17d309ceeb8 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Tue, 16 Nov 2021 11:44:34 -0500 Subject: [PATCH 114/223] Name resolved type variables during Expr2 constrain testing Prior to this patch we would not explicitly name solved type variables, causing the elaborated type to appear unconstrained even when the internal representation was constrained. For example, given a definition like ``` \a, b -> Pair a b ``` we would generate distinct, fresh type variables for `a` and `b` but not name them after solution. So even though the compiler knows they are distinct, printing to the surface syntax would emit ``` *, * -> [ Pair * * ]* ``` which is incorrect, as the result type is constrained on the input type. Instead, we now properly emit ``` a, b -> [ Pair a b ]* ``` naming variables where dependencies do exist. Where type variables are don't constrain anything else, we can and do continue to emit the wildcard type. --- ast/src/constrain.rs | 101 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index 013c505705..ff53020294 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -1765,7 +1765,7 @@ pub mod test_constrain { use roc_parse::parser::SyntaxError; use roc_region::all::Region; use roc_types::{ - pretty_print::content_to_string, + pretty_print::{content_to_string, name_all_type_vars}, solved_types::Solved, subs::{Subs, VarStore, Variable}, }; @@ -1876,6 +1876,9 @@ pub mod test_constrain { let subs = solved.inner_mut(); + // name type vars + name_all_type_vars(var, subs); + let content = subs.get_content_without_compacting(var); // Connect the ModuleId to it's IdentIds @@ -2132,6 +2135,102 @@ pub mod test_constrain { ) } + #[test] + fn dual_arity_lambda() { + infer_eq( + indoc!( + r#" + \a, b -> Pair a b + "# + ), + "a, b -> [ Pair a b ]*", + ); + } + + #[test] + fn anonymous_identity() { + infer_eq( + indoc!( + r#" + (\a -> a) 3.14 + "# + ), + "Float *", + ); + } + + #[test] + fn identity_of_identity() { + infer_eq( + indoc!( + r#" + (\val -> val) (\val -> val) + "# + ), + "a -> a", + ); + } + + #[test] + fn identity_function() { + infer_eq( + indoc!( + r#" + \val -> val + "# + ), + "a -> a", + ); + } + + #[test] + fn apply_function() { + infer_eq( + indoc!( + r#" + \f, x -> f x + "# + ), + "(a -> b), a -> b", + ); + } + + #[test] + fn flip_function() { + infer_eq( + indoc!( + r#" + \f -> (\a, b -> f b a) + "# + ), + "(a, b -> c) -> (b, a -> c)", + ); + } + + #[test] + fn always_function() { + infer_eq( + indoc!( + r#" + \val -> \_ -> val + "# + ), + "a -> (* -> a)", + ); + } + + #[test] + fn pass_a_function() { + infer_eq( + indoc!( + r#" + \f -> f {} + "# + ), + "({} -> a) -> a", + ); + } + #[test] fn constrain_closure() { infer_eq( From f972098e70a1132e6605c9f56002afeba32a3cec Mon Sep 17 00:00:00 2001 From: Callum Dunster Date: Tue, 16 Nov 2021 19:22:43 +0100 Subject: [PATCH 115/223] Move reporting module into root. --- Cargo.toml | 2 +- Earthfile | 2 +- cli/Cargo.toml | 2 +- compiler/build/Cargo.toml | 2 +- compiler/load/Cargo.toml | 2 +- compiler/reporting/Cargo.toml | 28 ------------------- compiler/test_gen/Cargo.toml | 2 +- editor/Cargo.toml | 2 +- reporting/Cargo.toml | 28 +++++++++++++++++++ .../src/error/canonicalize.rs | 0 .../reporting => reporting}/src/error/mod.rs | 0 .../reporting => reporting}/src/error/mono.rs | 0 .../src/error/parse.rs | 0 .../reporting => reporting}/src/error/type.rs | 0 {compiler/reporting => reporting}/src/lib.rs | 0 .../reporting => reporting}/src/report.rs | 0 .../tests/helpers/mod.rs | 0 .../tests/test_reporting.rs | 0 18 files changed, 35 insertions(+), 35 deletions(-) delete mode 100644 compiler/reporting/Cargo.toml create mode 100644 reporting/Cargo.toml rename {compiler/reporting => reporting}/src/error/canonicalize.rs (100%) rename {compiler/reporting => reporting}/src/error/mod.rs (100%) rename {compiler/reporting => reporting}/src/error/mono.rs (100%) rename {compiler/reporting => reporting}/src/error/parse.rs (100%) rename {compiler/reporting => reporting}/src/error/type.rs (100%) rename {compiler/reporting => reporting}/src/lib.rs (100%) rename {compiler/reporting => reporting}/src/report.rs (100%) rename {compiler/reporting => reporting}/tests/helpers/mod.rs (100%) rename {compiler/reporting => reporting}/tests/test_reporting.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index da159d2754..4839856ae9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ members = [ "compiler/constrain", "compiler/unify", "compiler/solve", - "compiler/reporting", "compiler/fmt", "compiler/mono", "compiler/test_mono", @@ -31,6 +30,7 @@ members = [ "ast", "cli", "code_markup", + "reporting", "roc_std", "utils", "docs", diff --git a/Earthfile b/Earthfile index 407477acf2..6dfbd03652 100644 --- a/Earthfile +++ b/Earthfile @@ -47,7 +47,7 @@ install-zig-llvm-valgrind-clippy-rustfmt: copy-dirs: FROM +install-zig-llvm-valgrind-clippy-rustfmt - COPY --dir cli cli_utils compiler docs editor ast code_markup utils roc_std vendor examples linker Cargo.toml Cargo.lock version.txt ./ + COPY --dir cli cli_utils compiler docs editor ast code_markup utils reporting roc_std vendor examples linker Cargo.toml Cargo.lock version.txt ./ test-zig: FROM +install-zig-llvm-valgrind-clippy-rustfmt diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0d8ac9ce0e..e85bb427bb 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -61,7 +61,7 @@ roc_load = { path = "../compiler/load" } roc_gen_llvm = { path = "../compiler/gen_llvm", optional = true } roc_build = { path = "../compiler/build", default-features = false } roc_fmt = { path = "../compiler/fmt" } -roc_reporting = { path = "../compiler/reporting" } +roc_reporting = { path = "../reporting" } roc_editor = { path = "../editor", optional = true } roc_linker = { path = "../linker" } clap = { version = "= 3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] } diff --git a/compiler/build/Cargo.toml b/compiler/build/Cargo.toml index 3a9e19187f..80aaa3dd00 100644 --- a/compiler/build/Cargo.toml +++ b/compiler/build/Cargo.toml @@ -22,7 +22,7 @@ roc_load = { path = "../load" } roc_gen_llvm = { path = "../gen_llvm", optional = true } roc_gen_wasm = { path = "../gen_wasm", optional = true } roc_gen_dev = { path = "../gen_dev", default-features = false } -roc_reporting = { path = "../reporting" } +roc_reporting = { path = "../../reporting" } roc_std = { path = "../../roc_std" } bumpalo = { version = "3.8.0", features = ["collections"] } libloading = "0.7.1" diff --git a/compiler/load/Cargo.toml b/compiler/load/Cargo.toml index 2fef36c603..ac6505b016 100644 --- a/compiler/load/Cargo.toml +++ b/compiler/load/Cargo.toml @@ -18,7 +18,7 @@ roc_unify = { path = "../unify" } roc_parse = { path = "../parse" } roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } -roc_reporting = { path = "../reporting" } +roc_reporting = { path = "../../reporting" } morphic_lib = { path = "../../vendor/morphic_lib" } ven_pretty = { path = "../../vendor/pretty" } bumpalo = { version = "3.8.0", features = ["collections"] } diff --git a/compiler/reporting/Cargo.toml b/compiler/reporting/Cargo.toml deleted file mode 100644 index 35df3f33ae..0000000000 --- a/compiler/reporting/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "roc_reporting" -version = "0.1.0" -authors = ["The Roc Contributors"] -license = "UPL-1.0" -edition = "2018" - -[dependencies] -roc_collections = { path = "../collections" } -roc_region = { path = "../region" } -roc_module = { path = "../module" } -roc_parse = { path = "../parse" } -roc_problem = { path = "../problem" } -roc_types = { path = "../types" } -roc_can = { path = "../can" } -roc_solve = { path = "../solve" } -roc_mono = { path = "../mono" } -ven_pretty = { path = "../../vendor/pretty" } -distance = "0.4.0" -bumpalo = { version = "3.8.0", features = ["collections"] } - -[dev-dependencies] -roc_constrain = { path = "../constrain" } -roc_builtins = { path = "../builtins" } -roc_problem = { path = "../problem" } -roc_parse = { path = "../parse" } -pretty_assertions = "1.0.0" -indoc = "1.0.3" diff --git a/compiler/test_gen/Cargo.toml b/compiler/test_gen/Cargo.toml index 9e1a5d5aba..bd6ddfd5d1 100644 --- a/compiler/test_gen/Cargo.toml +++ b/compiler/test_gen/Cargo.toml @@ -23,7 +23,7 @@ roc_constrain = { path = "../constrain" } roc_unify = { path = "../unify" } roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } -roc_reporting = { path = "../reporting" } +roc_reporting = { path = "../../reporting" } roc_load = { path = "../load" } roc_can = { path = "../can" } roc_parse = { path = "../parse" } diff --git a/editor/Cargo.toml b/editor/Cargo.toml index 69c00607c2..8cf82eec86 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -29,7 +29,7 @@ roc_module = { path = "../compiler/module" } roc_problem = { path = "../compiler/problem" } roc_types = { path = "../compiler/types" } roc_unify = { path = "../compiler/unify" } -roc_reporting = { path = "../compiler/reporting" } +roc_reporting = { path = "../reporting" } roc_solve = { path = "../compiler/solve" } ven_graph = { path = "../vendor/pathfinding" } bumpalo = { version = "3.8.0", features = ["collections"] } diff --git a/reporting/Cargo.toml b/reporting/Cargo.toml new file mode 100644 index 0000000000..7fa1d2cfee --- /dev/null +++ b/reporting/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "roc_reporting" +version = "0.1.0" +authors = ["The Roc Contributors"] +license = "UPL-1.0" +edition = "2018" + +[dependencies] +roc_collections = { path = "../compiler/collections" } +roc_region = { path = "../compiler/region" } +roc_module = { path = "../compiler/module" } +roc_parse = { path = "../compiler/parse" } +roc_problem = { path = "../compiler/problem" } +roc_types = { path = "../compiler/types" } +roc_can = { path = "../compiler/can" } +roc_solve = { path = "../compiler/solve" } +roc_mono = { path = "../compiler/mono" } +ven_pretty = { path = "../vendor/pretty" } +distance = "0.4.0" +bumpalo = { version = "3.8.0", features = ["collections"] } + +[dev-dependencies] +roc_constrain = { path = "../compiler/constrain" } +roc_builtins = { path = "../compiler/builtins" } +roc_problem = { path = "../compiler/problem" } +roc_parse = { path = "../compiler/parse" } +pretty_assertions = "1.0.0" +indoc = "1.0.3" diff --git a/compiler/reporting/src/error/canonicalize.rs b/reporting/src/error/canonicalize.rs similarity index 100% rename from compiler/reporting/src/error/canonicalize.rs rename to reporting/src/error/canonicalize.rs diff --git a/compiler/reporting/src/error/mod.rs b/reporting/src/error/mod.rs similarity index 100% rename from compiler/reporting/src/error/mod.rs rename to reporting/src/error/mod.rs diff --git a/compiler/reporting/src/error/mono.rs b/reporting/src/error/mono.rs similarity index 100% rename from compiler/reporting/src/error/mono.rs rename to reporting/src/error/mono.rs diff --git a/compiler/reporting/src/error/parse.rs b/reporting/src/error/parse.rs similarity index 100% rename from compiler/reporting/src/error/parse.rs rename to reporting/src/error/parse.rs diff --git a/compiler/reporting/src/error/type.rs b/reporting/src/error/type.rs similarity index 100% rename from compiler/reporting/src/error/type.rs rename to reporting/src/error/type.rs diff --git a/compiler/reporting/src/lib.rs b/reporting/src/lib.rs similarity index 100% rename from compiler/reporting/src/lib.rs rename to reporting/src/lib.rs diff --git a/compiler/reporting/src/report.rs b/reporting/src/report.rs similarity index 100% rename from compiler/reporting/src/report.rs rename to reporting/src/report.rs diff --git a/compiler/reporting/tests/helpers/mod.rs b/reporting/tests/helpers/mod.rs similarity index 100% rename from compiler/reporting/tests/helpers/mod.rs rename to reporting/tests/helpers/mod.rs diff --git a/compiler/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs similarity index 100% rename from compiler/reporting/tests/test_reporting.rs rename to reporting/tests/test_reporting.rs From 3fe29c99498ec296e6bbcef738bee38cc4b1d7e3 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Tue, 16 Nov 2021 15:25:42 -0500 Subject: [PATCH 116/223] Implement constraint generation for Expr2::LetFunction We do this by treating function definition bodies as equivalent to closures, and piggy-backing on existing work to generate constraints over closures. Then, we just bind the function name with the resolved type of the function body. Support for constraint generation in the presence of annotated functions will be added later. --- ast/src/constrain.rs | 147 ++++++++++++++++++++++++++++++++++- ast/src/lang/core/def/def.rs | 4 +- ast/src/lang/core/fun_def.rs | 2 +- ast/src/lang/core/mod.rs | 2 +- 4 files changed, 150 insertions(+), 5 deletions(-) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index ff53020294..05cd1908fc 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -20,6 +20,7 @@ use crate::{ expr2::{ClosureExtra, Expr2, ExprId, WhenBranch}, record_field::RecordField, }, + fun_def::FunctionDef, pattern::{DestructType, Pattern2, PatternId, PatternState2, RecordDestruct}, types::{Type2, TypeId}, val_def::ValueDef, @@ -818,6 +819,89 @@ pub fn constrain_expr<'a>( } } } + // In an expression like + // id = \x -> x + // + // id 1 + // The `def_id` refers to the definition `id = \x -> x`, + // and the body refers to `id 1`. + Expr2::LetFunction { + def_id, + body_id, + body_var, + } => { + let body = env.pool.get(*body_id); + let body_con = constrain_expr(arena, env, body, expected.shallow_clone(), region); + + let function_def = env.pool.get(*def_id); + + match function_def { + FunctionDef::WithAnnotation { .. } => { + todo!("implement constraint generation for {:?}", function_def) + } + FunctionDef::NoAnnotation { + name, + arguments, + body_id: expr_id, + return_var, + } => { + // A function definition is equivalent to a named value definition, where the + // value is a closure. So, we create a closure definition in correspondence + // with the function definition, generate type constraints for it, and demand + // that type of the function is just the type of the resolved closure. + let fn_var = env.var_store.fresh(); + let fn_ty = Type2::Variable(fn_var); + + let clos_var = env.var_store.fresh(); + let clos_ty = Type2::Variable(clos_var); + let extra = ClosureExtra { + return_type: env.var_store.fresh(), + captured_symbols: PoolVec::empty(env.pool), + closure_type: env.var_store.fresh(), + closure_ext_var: env.var_store.fresh(), + }; + let clos = Expr2::Closure { + args: arguments.shallow_clone(), + uniq_symbol: *name, + body_id: *expr_id, + function_type: clos_var, + extra: env.pool.add(extra), + recursive: roc_can::expr::Recursive::Recursive, + }; + let clos_con = constrain_expr( + arena, + env, + &clos, + Expected::NoExpectation(fn_ty.shallow_clone()), + region, + ); + + // This is the `foo` part in `foo = \...`. We want to bind the name of the + // function with its type, whose constraints we generated above. + let mut def_pattern_state = PatternState2 { + headers: BumpMap::new_in(arena), + vars: BumpVec::new_in(arena), + constraints: BumpVec::new_in(arena), + }; + def_pattern_state.headers.insert(*name, fn_ty); + def_pattern_state.vars.push(fn_var); + + Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), // The function def is unannotated, so there are no rigid type vars + flex_vars: def_pattern_state.vars, + def_types: def_pattern_state.headers, // Binding function name -> its type + defs_constraint: Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), // always empty + flex_vars: BumpVec::new_in(arena), // empty, because our functions have no arguments + def_types: BumpMap::new_in(arena), // empty, because our functions have no arguments + defs_constraint: And(def_pattern_state.constraints), + ret_constraint: clos_con, + })), + ret_constraint: body_con, + })) + } + } + } Expr2::Update { symbol, updates, @@ -1031,7 +1115,6 @@ pub fn constrain_expr<'a>( exists(arena, vars, And(and_constraints)) } Expr2::LetRec { .. } => todo!(), - Expr2::LetFunction { .. } => todo!(), } } @@ -2244,4 +2327,66 @@ pub mod test_constrain { "{}* -> Num *", ) } + + #[test] + fn recursive_identity() { + infer_eq( + indoc!( + r#" + identity = \val -> val + + identity + "# + ), + "a -> a", + ); + } + + #[test] + fn use_apply() { + infer_eq( + indoc!( + r#" + identity = \a -> a + apply = \f, x -> f x + + apply identity 5 + "# + ), + "Num *", + ); + } + + #[test] + fn nested_let_function() { + infer_eq( + indoc!( + r#" + curryPair = \a -> + getB = \b -> Pair a b + getB + + curryPair + "# + ), + "a -> (b -> [ Pair a b ]*)", + ); + } + + #[test] + fn record_with_bound_var() { + infer_eq( + indoc!( + r#" + fn = \rec -> + x = rec.x + + rec + + fn + "# + ), + "{ x : a }b -> { x : a }b", + ); + } } diff --git a/ast/src/lang/core/def/def.rs b/ast/src/lang/core/def/def.rs index 00e75c296e..850c20383e 100644 --- a/ast/src/lang/core/def/def.rs +++ b/ast/src/lang/core/def/def.rs @@ -689,14 +689,14 @@ fn canonicalize_pending_def<'a>( // parent commit for the bug this fixed! let refs = References::new(); - let arguments: PoolVec<(PatternId, Variable)> = + let arguments: PoolVec<(Variable, PatternId)> = PoolVec::with_capacity(closure_args.len() as u32, env.pool); let it: Vec<_> = closure_args.iter(env.pool).map(|(x, y)| (*x, *y)).collect(); for (node_id, (_, pattern_id)) in arguments.iter_node_ids().zip(it.into_iter()) { - env.pool[node_id] = (pattern_id, env.var_store.fresh()); + env.pool[node_id] = (env.var_store.fresh(), pattern_id); } let function_def = FunctionDef::NoAnnotation { diff --git a/ast/src/lang/core/fun_def.rs b/ast/src/lang/core/fun_def.rs index 02d3bdbab4..1cc1d78aaa 100644 --- a/ast/src/lang/core/fun_def.rs +++ b/ast/src/lang/core/fun_def.rs @@ -22,7 +22,7 @@ pub enum FunctionDef { }, NoAnnotation { name: Symbol, // 8B - arguments: PoolVec<(PatternId, Variable)>, // 8B + arguments: PoolVec<(Variable, PatternId)>, // 8B return_var: Variable, // 4B body_id: ExprId, // 4B }, diff --git a/ast/src/lang/core/mod.rs b/ast/src/lang/core/mod.rs index 74300dab4f..801f6afa18 100644 --- a/ast/src/lang/core/mod.rs +++ b/ast/src/lang/core/mod.rs @@ -2,7 +2,7 @@ pub mod ast; mod declaration; pub mod def; pub mod expr; -mod fun_def; +pub mod fun_def; pub mod header; pub mod pattern; pub mod str; From f342bb03aff9b6cfa12c5b604d872927413c8a80 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Tue, 16 Nov 2021 16:20:40 -0500 Subject: [PATCH 117/223] Resolve clippy lints --- ast/src/constrain.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index 05cd1908fc..57ed0d8068 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -828,7 +828,7 @@ pub fn constrain_expr<'a>( Expr2::LetFunction { def_id, body_id, - body_var, + body_var: _, } => { let body = env.pool.get(*body_id); let body_con = constrain_expr(arena, env, body, expected.shallow_clone(), region); @@ -843,7 +843,7 @@ pub fn constrain_expr<'a>( name, arguments, body_id: expr_id, - return_var, + return_var: _, } => { // A function definition is equivalent to a named value definition, where the // value is a closure. So, we create a closure definition in correspondence @@ -852,8 +852,6 @@ pub fn constrain_expr<'a>( let fn_var = env.var_store.fresh(); let fn_ty = Type2::Variable(fn_var); - let clos_var = env.var_store.fresh(); - let clos_ty = Type2::Variable(clos_var); let extra = ClosureExtra { return_type: env.var_store.fresh(), captured_symbols: PoolVec::empty(env.pool), @@ -864,7 +862,7 @@ pub fn constrain_expr<'a>( args: arguments.shallow_clone(), uniq_symbol: *name, body_id: *expr_id, - function_type: clos_var, + function_type: env.var_store.fresh(), extra: env.pool.add(extra), recursive: roc_can::expr::Recursive::Recursive, }; From d946b84e63f7af56e8df800f1fc73b800dfe22e4 Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Tue, 16 Nov 2021 16:34:36 -0500 Subject: [PATCH 118/223] adding initial List.all --- compiler/builtins/bitcode/src/list.zig | 30 ++++++++++++++++++++++++ compiler/builtins/bitcode/src/main.zig | 1 + compiler/builtins/docs/List.roc | 4 ++++ compiler/builtins/src/bitcode.rs | 1 + compiler/builtins/src/std.rs | 10 ++++++++ compiler/can/src/builtins.rs | 6 +++++ compiler/gen_llvm/src/llvm/build.rs | 29 +++++++++++++++++++++-- compiler/gen_llvm/src/llvm/build_list.rs | 21 +++++++++++++++++ compiler/gen_wasm/src/low_level.rs | 2 +- compiler/module/src/low_level.rs | 4 ++++ compiler/module/src/symbol.rs | 1 + compiler/mono/src/alias_analysis.rs | 19 +++++++++++++++ compiler/mono/src/borrow.rs | 3 ++- compiler/mono/src/inc_dec.rs | 1 + compiler/mono/src/ir.rs | 6 +++++ compiler/mono/src/low_level.rs | 4 ++++ compiler/test_gen/src/gen_list.rs | 22 +++++++++++++++++ 17 files changed, 160 insertions(+), 4 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index d012e92e26..e4a994e79b 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -1109,6 +1109,36 @@ pub fn listAny( return false; } +pub fn listAll( + list: RocList, + caller: Caller1, + data: Opaque, + inc_n_data: IncN, + data_is_owned: bool, + element_width: usize, +) callconv(.C) bool { + if (list.bytes) |source_ptr| { + const size = list.len(); + + if (data_is_owned) { + inc_n_data(data, size); + } + + var i: usize = 0; + while (i < size) : (i += 1) { + var satisfied = false; + const element = source_ptr + i * element_width; + caller(data, element, @ptrCast(?[*]u8, &satisfied)); + + if (!satisfied) { + return false; + } + } + return true; + } + return false; +} + // SWAP ELEMENTS inline fn swapHelp(width: usize, temporary: [*]u8, ptr1: [*]u8, ptr2: [*]u8) void { diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index 345b63e48e..8b081cd1cf 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -51,6 +51,7 @@ comptime { exportListFn(list.listSetInPlace, "set_in_place"); exportListFn(list.listSwap, "swap"); exportListFn(list.listAny, "any"); + exportListFn(list.listAll, "all"); exportListFn(list.listFindUnsafe, "find_unsafe"); } diff --git a/compiler/builtins/docs/List.roc b/compiler/builtins/docs/List.roc index be4f8891c1..e30c0bfe45 100644 --- a/compiler/builtins/docs/List.roc +++ b/compiler/builtins/docs/List.roc @@ -691,6 +691,10 @@ all : List elem, (elem -> Bool) -> Bool ## any of the elements satisfy it. any : List elem, (elem -> Bool) -> Bool +## Run the given predicate on each element of the list, returning `True` if +## all of the elements satisfy it. +all : List elem, (elem -> Bool) -> Bool + ## Returns the first element of the list satisfying a predicate function. ## If no satisfying element is found, an `Err NotFound` is returned. find : List elem, (elem -> Bool) -> Result elem [ NotFound ]* diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index d00ab60bae..46ee44bf3f 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -196,6 +196,7 @@ pub const LIST_CONCAT: &str = "roc_builtins.list.concat"; pub const LIST_SET: &str = "roc_builtins.list.set"; pub const LIST_SET_IN_PLACE: &str = "roc_builtins.list.set_in_place"; pub const LIST_ANY: &str = "roc_builtins.list.any"; +pub const LIST_ALL: &str = "roc_builtins.list.all"; pub const LIST_FIND_UNSAFE: &str = "roc_builtins.list.find_unsafe"; pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64"; diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 0f8d1fe154..8e018a6f95 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -1109,6 +1109,16 @@ pub fn types() -> MutMap { Box::new(bool_type()), ); + // all: List elem, (elem -> Bool) -> Bool + add_top_level_function_type!( + Symbol::LIST_ALL, + vec![ + list_type(flex(TVAR1)), + closure(vec![flex(TVAR1)], TVAR2, Box::new(bool_type())), + ], + Box::new(bool_type()), + ); + // sortWith : List a, (a, a -> Ordering) -> List a add_top_level_function_type!( Symbol::LIST_SORT_WITH, diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 6e2342ca3e..604374f90f 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -111,6 +111,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option LIST_WALK_UNTIL => list_walk_until, LIST_SORT_WITH => list_sort_with, LIST_ANY => list_any, + LIST_ALL => list_all, LIST_FIND => list_find, DICT_LEN => dict_len, DICT_EMPTY => dict_empty, @@ -2855,6 +2856,11 @@ fn list_any(symbol: Symbol, var_store: &mut VarStore) -> Def { lowlevel_2(symbol, LowLevel::ListAny, var_store) } +/// List.all: List elem, (elem -> Bool) -> Bool +fn list_all(symbol: Symbol, var_store: &mut VarStore) -> Def { + lowlevel_2(symbol, LowLevel::ListAll, var_store) +} + /// List.find : List elem, (elem -> Bool) -> Result elem [ NotFound ]* fn list_find(symbol: Symbol, var_store: &mut VarStore) -> Def { let list = Symbol::ARG_1; diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index c0c3401c20..4258b04330 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -8,7 +8,7 @@ use crate::llvm::build_dict::{ }; use crate::llvm::build_hash::generic_hash; use crate::llvm::build_list::{ - self, allocate_list, empty_list, empty_polymorphic_list, list_any, list_append, list_concat, + self, allocate_list, empty_list, empty_polymorphic_list, list_any, list_all, list_append, list_concat, list_contains, list_drop_at, list_find_trivial_not_found, list_find_unsafe, list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, @@ -5141,6 +5141,31 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( _ => unreachable!("invalid list layout"), } } + ListAll { xs } => { + let (list, list_layout) = load_symbol_and_layout(scope, xs); + let (function, closure, closure_layout) = function_details!(); + + match list_layout { + Layout::Builtin(Builtin::EmptyList) => env.context.bool_type().const_zero().into(), + Layout::Builtin(Builtin::List(element_layout)) => { + let argument_layouts = &[**element_layout]; + + let roc_function_call = roc_function_call( + env, + layout_ids, + function, + closure, + closure_layout, + function_owns_closure_data, + argument_layouts, + Layout::Builtin(Builtin::Int1), + ); + + list_all(env, roc_function_call, list, element_layout) + } + _ => unreachable!("invalid list layout"), + } + } ListFindUnsafe { xs } => { let (list, list_layout) = load_symbol_and_layout(scope, xs); @@ -6041,7 +6066,7 @@ fn run_low_level<'a, 'ctx, 'env>( ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith - | ListAny | ListFindUnsafe | DictWalk => { + | ListAny | ListAll | ListFindUnsafe | DictWalk => { unreachable!("these are higher order, and are handled elsewhere") } } diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index 3806bc8b72..a62b7a2f47 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -926,6 +926,27 @@ pub fn list_any<'a, 'ctx, 'env>( ) } +/// List.all : List elem, \(elem -> Bool) -> Bool +pub fn list_all<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + roc_function_call: RocFunctionCall<'ctx>, + list: BasicValueEnum<'ctx>, + element_layout: &Layout<'a>, +) -> BasicValueEnum<'ctx> { + call_bitcode_fn( + env, + &[ + pass_list_cc(env, list), + roc_function_call.caller.into(), + pass_as_opaque(env, roc_function_call.data), + roc_function_call.inc_n_data.into(), + roc_function_call.data_is_owned.into(), + layout_width(env, element_layout), + ], + bitcode::LIST_ALL, + ) +} + /// List.findUnsafe : List elem, (elem -> Bool) -> { value: elem, found: bool } pub fn list_find_unsafe<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index e5b5da9bbb..07109404d1 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -34,7 +34,7 @@ pub fn decode_low_level<'a>( | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith - | ListSublist | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize | DictEmpty + | ListSublist | ListDropAt | ListSwap | ListAny | ListAll | ListFindUnsafe | DictSize | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { return NotImplemented; diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index 77f551b980..9405956fc0 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -50,6 +50,7 @@ pub enum LowLevel { ListDropAt, ListSwap, ListAny, + ListAll, ListFindUnsafe, DictSize, DictEmpty, @@ -131,6 +132,7 @@ macro_rules! higher_order { | ListKeepErrs | ListSortWith | ListAny + | ListAll | ListFindUnsafe | DictWalk }; @@ -162,6 +164,7 @@ impl LowLevel { ListKeepErrs => 1, ListSortWith => 1, ListAny => 1, + ListAll => 1, ListFindUnsafe => 1, DictWalk => 2, _ => unreachable!(), @@ -220,6 +223,7 @@ impl LowLevel { Symbol::LIST_DROP_AT => Some(ListDropAt), Symbol::LIST_SWAP => Some(ListSwap), Symbol::LIST_ANY => Some(ListAny), + Symbol::LIST_ALL => Some(ListAll), Symbol::LIST_FIND => None, Symbol::DICT_LEN => Some(DictSize), Symbol::DICT_EMPTY => Some(DictEmpty), diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 44bf51012a..499d6d84ee 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1072,6 +1072,7 @@ define_builtins! { 47 LIST_FIND: "find" 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" + 50 LIST_ALL: "all" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 6acb90d50d..306b2a52ae 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -1093,6 +1093,25 @@ fn call_spec( add_loop(builder, block, state_type, init_state, loop_body) } + ListAll { xs } => { + let list = env.symbols[xs]; + + let loop_body = |builder: &mut FuncDefBuilder, block, _state| { + let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?; + let element = builder.add_bag_get(block, bag)?; + + let new_state = call_function!(builder, block, [element]); + + Ok(new_state) + }; + + let state_layout = Layout::Builtin(Builtin::Int1); + let state_type = layout_spec(builder, &state_layout)?; + + let init_state = new_num(builder, block)?; + + add_loop(builder, block, state_type, init_state, loop_body) + } ListFindUnsafe { xs } => { let list = env.symbols[xs]; diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index bef854f20b..bc5492c8bf 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -619,6 +619,7 @@ impl<'a> BorrowInfState<'a> { | ListKeepOks { xs } | ListKeepErrs { xs } | ListAny { xs } + | ListAll { xs } | ListFindUnsafe { xs } => { // own the list if the function wants to own the element if !function_ps[0].borrow { @@ -953,7 +954,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] { ListMap2 => arena.alloc_slice_copy(&[owned, owned, function, closure_data]), ListMap3 => arena.alloc_slice_copy(&[owned, owned, owned, function, closure_data]), ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]), - ListKeepIf | ListKeepOks | ListKeepErrs | ListAny => { + ListKeepIf | ListKeepOks | ListKeepErrs | ListAny | ListAll => { arena.alloc_slice_copy(&[owned, function, closure_data]) } ListContains => arena.alloc_slice_copy(&[borrowed, irrelevant]), diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index 63604bf205..c6dfd67314 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -536,6 +536,7 @@ impl<'a> Context<'a> { | ListKeepOks { xs } | ListKeepErrs { xs } | ListAny { xs } + | ListAll { xs } | ListFindUnsafe { xs } => { let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA]; diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 32be663338..d70ae54b46 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -4086,6 +4086,12 @@ pub fn with_hole<'a>( let xs = arg_symbols[0]; match_on_closure_argument!(ListAny, [xs]) } + ListAll => { + debug_assert_eq!(arg_symbols.len(), 2); + let xs = arg_symbols[0]; + match_on_closure_argument!(ListAll, [xs]) + } + ListKeepOks => { debug_assert_eq!(arg_symbols.len(), 2); let xs = arg_symbols[0]; diff --git a/compiler/mono/src/low_level.rs b/compiler/mono/src/low_level.rs index 058a2958eb..7053ef87ae 100644 --- a/compiler/mono/src/low_level.rs +++ b/compiler/mono/src/low_level.rs @@ -50,6 +50,9 @@ pub enum HigherOrder { ListAny { xs: Symbol, }, + ListAll { + xs: Symbol, + }, ListFindUnsafe { xs: Symbol, }, @@ -77,6 +80,7 @@ impl HigherOrder { HigherOrder::ListFindUnsafe { .. } => 1, HigherOrder::DictWalk { .. } => 2, HigherOrder::ListAny { .. } => 1, + HigherOrder::ListAll { .. } => 1, } } } diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 5e0f737e72..97840d8ce1 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -2352,6 +2352,28 @@ fn list_any_empty_with_unknown_element_type() { assert_evals_to!("List.any [] (\\_ -> True)", false, bool); } +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn list_all() { + assert_evals_to!("List.all [] (\\e -> e > 3)", false, bool); + assert_evals_to!("List.all [ 1, 2, 3 ] (\\e -> e > 3)", false, bool); + assert_evals_to!("List.all [ 1, 2, 4 ] (\\e -> e > 3)", false, bool); + assert_evals_to!("List.all [ 1, 2, 3 ] (\\e -> e >= 1", true, bool); +} + +#[test] +#[cfg(any(feature = "gen-llvm"))] +#[should_panic(expected = r#"Roc failed with message: "UnresolvedTypeVar"#)] +fn list_all_empty_with_unknown_element_type() { + // Segfaults with invalid memory reference. Running this as a stand-alone + // Roc program, generates the following error message: + // + // Application crashed with message + // UnresolvedTypeVar compiler/mono/src/ir.rs line 3775 + // Shutting down + assert_evals_to!("List.all [] (\\_ -> True)", false, bool); +} + #[test] #[cfg(any(feature = "gen-llvm"))] #[should_panic(expected = r#"Roc failed with message: "invalid ret_layout""#)] From 51ad326d1167054399b735d86384006c2804abd0 Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Tue, 16 Nov 2021 17:30:04 -0500 Subject: [PATCH 119/223] fmt --- compiler/gen_llvm/src/llvm/build.rs | 10 +++++----- compiler/gen_wasm/src/low_level.rs | 6 +++--- compiler/mono/src/ir.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 4258b04330..d1b61f06ce 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -8,11 +8,11 @@ use crate::llvm::build_dict::{ }; use crate::llvm::build_hash::generic_hash; use crate::llvm::build_list::{ - self, allocate_list, empty_list, empty_polymorphic_list, list_any, list_all, list_append, list_concat, - list_contains, list_drop_at, list_find_trivial_not_found, list_find_unsafe, list_get_unsafe, - list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, list_map2, - list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, - list_set, list_single, list_sort_with, list_sublist, list_swap, + self, allocate_list, empty_list, empty_polymorphic_list, list_all, list_any, list_append, + list_concat, list_contains, list_drop_at, list_find_trivial_not_found, list_find_unsafe, + list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, + list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, + list_reverse, list_set, list_single, list_sort_with, list_sublist, list_swap, }; use crate::llvm::build_str::{ empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 07109404d1..7567426a1d 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -34,9 +34,9 @@ pub fn decode_low_level<'a>( | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith - | ListSublist | ListDropAt | ListSwap | ListAny | ListAll | ListFindUnsafe | DictSize | DictEmpty - | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues - | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { + | ListSublist | ListDropAt | ListSwap | ListAny | ListAll | ListFindUnsafe | DictSize + | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys + | DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { return NotImplemented; } diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index d70ae54b46..cc901141dd 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -4091,7 +4091,7 @@ pub fn with_hole<'a>( let xs = arg_symbols[0]; match_on_closure_argument!(ListAll, [xs]) } - + ListKeepOks => { debug_assert_eq!(arg_symbols.len(), 2); let xs = arg_symbols[0]; From 849510c42ce6f4a229cc87411969ae0cc380f80e Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Nov 2021 23:55:11 +0100 Subject: [PATCH 120/223] WIP --- compiler/mono/src/ir.rs | 187 ++++++++++++++++++++++++------------ compiler/solve/src/solve.rs | 136 +++++++++++++++++++------- compiler/types/src/subs.rs | 20 ++-- 3 files changed, 240 insertions(+), 103 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index fa2b0b7cbf..f98296b6bf 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -447,6 +447,15 @@ pub struct Suspended<'a> { } impl<'a> Suspended<'a> { + fn new_in(arena: &'a Bump) -> Self { + Self { + store: Subs::new(Default::default()), + symbols: Vec::new_in(arena), + layouts: Vec::new_in(arena), + variables: Vec::new_in(arena), + } + } + fn specialization( &mut self, subs: &mut Subs, @@ -469,6 +478,7 @@ impl<'a> Suspended<'a> { self.layouts.push(proc_layout); let variable = roc_solve::solve::deep_copy_var_to(subs, &mut self.store, variable); + self.variables.push(variable); } } @@ -478,22 +488,11 @@ enum PendingSpecializations<'a> { /// We are finding specializations we need. This is a separate step so /// that we can give specializations we need to modules higher up in the dependency chain, so /// that they can start making specializations too - Finding(BumpMap, PendingSpecialization<'a>>>), + Finding(Suspended<'a>), /// We are making specializations. If any new one comes up, we can just make it immediately Making, } -impl<'a> PendingSpecializations<'a> { - fn into_option( - self, - ) -> Option, PendingSpecialization<'a>>>> { - match self { - PendingSpecializations::Finding(x) => Some(x), - PendingSpecializations::Making => None, - } - } -} - #[derive(Clone, Debug)] pub struct Procs<'a> { pub partial_procs: PartialProcs<'a>, @@ -511,7 +510,7 @@ impl<'a> Procs<'a> { partial_procs: PartialProcs::new_in(arena), imported_module_thunks: &[], module_thunks: &[], - pending_specializations: PendingSpecializations::Finding(BumpMap::new_in(arena)), + pending_specializations: PendingSpecializations::Finding(Suspended::new_in(arena)), specialized: BumpMap::new_in(arena), runtime_errors: BumpMap::new_in(arena), externals_we_need: BumpMap::new_in(arena), @@ -603,16 +602,14 @@ impl<'a> Procs<'a> { // if we've already specialized this one, no further work is needed. if !already_specialized { - let pending = PendingSpecialization::from_var(env.arena, env.subs, annotation); - if self.is_module_thunk(symbol) { debug_assert!(layout.arguments.is_empty()); } match &mut self.pending_specializations { - PendingSpecializations::Finding(pending_specializations) => { + PendingSpecializations::Finding(suspended) => { // register the pending specialization, so this gets code genned later - add_pending(pending_specializations, symbol, layout, pending); + suspended.specialization(env.subs, symbol, layout, annotation); match self.partial_procs.symbol_to_id(symbol) { Some(occupied) => { @@ -679,12 +676,13 @@ impl<'a> Procs<'a> { self.partial_procs.insert(symbol, partial_proc) }; - match specialize( + match specialize_variable( env, self, symbol, layout_cache, - pending, + annotation, + BumpMap::new_in(env.arena), partial_proc_id, ) { Ok((proc, layout)) => { @@ -743,10 +741,8 @@ impl<'a> Procs<'a> { // This should only be called when pending_specializations is Some. // Otherwise, it's being called in the wrong pass! match &mut self.pending_specializations { - PendingSpecializations::Finding(pending_specializations) => { - let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); - - add_pending(pending_specializations, name, layout, pending) + PendingSpecializations::Finding(suspended) => { + suspended.specialization(env.subs, name, layout, fn_var); } PendingSpecializations::Making => { let symbol = name; @@ -1796,15 +1792,93 @@ pub fn specialize_all<'a>( // When calling from_can, pending_specializations should be unavailable. // This must be a single pass, and we must not add any more entries to it! - let opt_pending_specializations = std::mem::replace( + let pending_specializations = std::mem::replace( &mut procs.pending_specializations, PendingSpecializations::Making, - ) - .into_option(); + ); - let it = specializations_for_host - .into_iter() - .chain(opt_pending_specializations.into_iter().flatten()); + match pending_specializations { + PendingSpecializations::Making => {} + PendingSpecializations::Finding(mut suspended) => { + // TODO can we copy everything over in one pass (bumping variables by however many + // variables are in the env's subs? + for var in suspended.variables.iter_mut() { + debug_assert!((var.index() as usize) < suspended.store.len()); + + *var = roc_solve::solve::deep_copy_var_to(&mut suspended.store, env.subs, *var); + } + + for (i, symbol) in suspended.symbols.iter().enumerate() { + let name = *symbol; + let var = suspended.variables[i]; + let outside_layout = suspended.layouts[i]; + + let key = (name, outside_layout); + + let partial_proc = match procs.specialized.entry(key) { + Entry::Occupied(_) => { + // already specialized, just continue + continue; + } + Entry::Vacant(vacant) => { + match procs.partial_procs.symbol_to_id(name) { + Some(v) => { + // Mark this proc as in-progress, so if we're dealing with + // mutually recursive functions, we don't loop forever. + // (We had a bug around this before this system existed!) + vacant.insert(InProgress); + + v + } + None => { + // TODO this assumes the specialization is done by another module + // make sure this does not become a problem down the road! + continue; + } + } + } + }; + + match specialize_variable( + env, + &mut procs, + name, + layout_cache, + var, + BumpMap::new_in(env.arena), + partial_proc, + ) { + Ok((proc, layout)) => { + // TODO thiscode is duplicated elsewhere + let top_level = ProcLayout::from_raw(env.arena, layout); + + if procs.is_module_thunk(proc.name) { + debug_assert!( + top_level.arguments.is_empty(), + "{:?} from {:?}", + name, + layout + ); + } + + debug_assert_eq!(outside_layout, top_level, " in {:?}", name); + procs.specialized.insert((name, top_level), Done(proc)); + } + Err(SpecializeFailure { + attempted_layout, .. + }) => { + let proc = generate_runtime_error_function(env, name, attempted_layout); + + let top_level = ProcLayout::from_raw(env.arena, attempted_layout); + + procs.specialized.insert((name, top_level), Done(proc)); + } + } + } + } + } + + let it = specializations_for_host.into_iter(); for (name, by_layout) in it { for (outside_layout, pending) in by_layout.into_iter() { @@ -6690,8 +6764,6 @@ fn call_by_name_help<'a>( assign_to_symbols(env, procs, layout_cache, iter, result) } } else { - let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); - // When requested (that is, when procs.pending_specializations is `Some`), // store a pending specialization rather than specializing immediately. // @@ -6708,16 +6780,11 @@ fn call_by_name_help<'a>( } match &mut procs.pending_specializations { - PendingSpecializations::Finding(pending_specializations) => { + PendingSpecializations::Finding(suspended) => { debug_assert!(!env.is_imported_symbol(proc_name)); // register the pending specialization, so this gets code genned later - add_pending( - pending_specializations, - proc_name, - top_level_layout, - pending, - ); + suspended.specialization(env.subs, proc_name, top_level_layout, fn_var); debug_assert_eq!( argument_layouts.len(), @@ -6746,17 +6813,6 @@ fn call_by_name_help<'a>( PendingSpecializations::Making => { let opt_partial_proc = procs.partial_procs.symbol_to_id(proc_name); - /* - debug_assert_eq!( - argument_layouts.len(), - field_symbols.len(), - "Function {:?} is called with {} arguments, but the layout expects {}", - proc_name, - field_symbols.len(), - argument_layouts.len(), - ); - */ - let field_symbols = field_symbols.into_bump_slice(); match opt_partial_proc { @@ -6768,8 +6824,15 @@ fn call_by_name_help<'a>( .specialized .insert((proc_name, top_level_layout), InProgress); - match specialize(env, procs, proc_name, layout_cache, pending, partial_proc) - { + match specialize_variable( + env, + procs, + proc_name, + layout_cache, + fn_var, + BumpMap::new_in(env.arena), + partial_proc, + ) { Ok((proc, layout)) => { // now we just call our freshly-specialized function call_specialized_proc( @@ -6847,8 +6910,6 @@ fn call_by_name_module_thunk<'a>( if already_specialized { force_thunk(env, proc_name, inner_layout, assigned, hole) } else { - let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var); - // When requested (that is, when procs.pending_specializations is `Some`), // store a pending specialization rather than specializing immediately. // @@ -6865,16 +6926,11 @@ fn call_by_name_module_thunk<'a>( } match &mut procs.pending_specializations { - PendingSpecializations::Finding(pending_specializations) => { + PendingSpecializations::Finding(suspended) => { debug_assert!(!env.is_imported_symbol(proc_name)); // register the pending specialization, so this gets code genned later - add_pending( - pending_specializations, - proc_name, - top_level_layout, - pending, - ); + suspended.specialization(env.subs, proc_name, top_level_layout, fn_var); force_thunk(env, proc_name, inner_layout, assigned, hole) } @@ -6890,8 +6946,15 @@ fn call_by_name_module_thunk<'a>( .specialized .insert((proc_name, top_level_layout), InProgress); - match specialize(env, procs, proc_name, layout_cache, pending, partial_proc) - { + match specialize_variable( + env, + procs, + proc_name, + layout_cache, + fn_var, + BumpMap::new_in(env.arena), + partial_proc, + ) { Ok((proc, raw_layout)) => { debug_assert!( raw_layout.is_zero_argument_thunk(), diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index ba9af2bc38..659bbdc25a 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1248,6 +1248,8 @@ pub fn instantiate_rigids(subs: &mut Subs, var: Variable) { let mut pools = Pools::default(); instantiate_rigids_help(subs, rank, &mut pools, var); + + subs.restore(var); } fn instantiate_rigids_help( @@ -1389,14 +1391,22 @@ pub fn deep_copy_var_to( let mut pools = Pools::default(); let rank = Rank::toplevel(); - deep_copy_var_to_help(source, target, rank, &mut pools, var) + let mut mapping = Vec::with_capacity(100); + + let copy = deep_copy_var_to_help(source, target, rank, &mut pools, &mut mapping, var); + + source.restore(var); + + copy } fn deep_copy_var_to_help( - source: &mut Subs, // mut to set the copy + // source: &mut Subs, // mut to set the copy + source: &mut Subs, target: &mut Subs, max_rank: Rank, pools: &mut Pools, + mapping: &mut Vec, // maps copies in the source to copies in the target var: Variable, ) -> Variable { use roc_types::subs::Content::*; @@ -1407,10 +1417,13 @@ fn deep_copy_var_to_help( if let Some(copy) = desc.copy.into_variable() { return copy; } else if desc.rank != Rank::NONE { - panic!( - "about to return a variable in source, but should only return variables from target" - ); - return var; + // DO NOTHING + // + // The original deep_copy_var can do + // return var; + // + // but we cannot, because this `var` is in the source, not the target, and we + // should only return variables in the target } let make_descriptor = |content| Descriptor { @@ -1421,14 +1434,16 @@ fn deep_copy_var_to_help( }; let content = desc.content; - let copy = target.fresh(make_descriptor(content.clone())); + // let copy = target.fresh(make_descriptor(content.clone())); + let copy = target.fresh_unnamed_flex_var(); - pools.get_mut(max_rank).push(copy); + // pools.get_mut(max_rank).push(copy); // Link the original variable to the new variable. This lets us // avoid making multiple copies of the variable we are instantiating. // // Need to do this before recursively copying to avoid looping. + source.set( var, Descriptor { @@ -1450,7 +1465,8 @@ fn deep_copy_var_to_help( for index in args.into_iter() { let var = source[index]; - let copy_var = deep_copy_var_to_help(source, target, max_rank, pools, var); + let copy_var = + deep_copy_var_to_help(source, target, max_rank, pools, mapping, var); new_arg_vars.push(copy_var); } @@ -1461,15 +1477,22 @@ fn deep_copy_var_to_help( Func(arg_vars, closure_var, ret_var) => { let new_ret_var = - deep_copy_var_to_help(source, target, max_rank, pools, ret_var); - let new_closure_var = - deep_copy_var_to_help(source, target, max_rank, pools, closure_var); + deep_copy_var_to_help(source, target, max_rank, pools, mapping, ret_var); + let new_closure_var = deep_copy_var_to_help( + source, + target, + max_rank, + pools, + mapping, + closure_var, + ); let mut new_arg_vars = Vec::with_capacity(arg_vars.len()); for index in arg_vars.into_iter() { let var = source[index]; - let copy_var = deep_copy_var_to_help(source, target, max_rank, pools, var); + let copy_var = + deep_copy_var_to_help(source, target, max_rank, pools, mapping, var); new_arg_vars.push(copy_var); } @@ -1486,8 +1509,9 @@ fn deep_copy_var_to_help( for index in fields.iter_variables() { let var = source[index]; - let copy_var = - deep_copy_var_to_help(source, target, max_rank, pools, var); + let copy_var = deep_copy_var_to_help( + source, target, max_rank, pools, mapping, var, + ); new_vars.push(copy_var); } @@ -1518,11 +1542,14 @@ fn deep_copy_var_to_help( Record( record_fields, - deep_copy_var_to_help(source, target, max_rank, pools, ext_var), + deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var), ) } TagUnion(tags, ext_var) => { + let new_ext = + deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var); + let mut new_variable_slices = Vec::with_capacity(tags.len()); let mut new_variables = Vec::new(); @@ -1530,8 +1557,9 @@ fn deep_copy_var_to_help( let slice = source[index]; for var_index in slice { let var = source[var_index]; - let new_var = - deep_copy_var_to_help(source, target, max_rank, pools, var); + let new_var = deep_copy_var_to_help( + source, target, max_rank, pools, mapping, var, + ); new_variables.push(new_var); } @@ -1549,17 +1577,35 @@ fn deep_copy_var_to_help( SubsSlice::new(start, length) }; - let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables); + let new_tag_names = { + let tag_names = tags.tag_names(); + let slice = &source.tag_names[tag_names.start as usize..] + [..tag_names.length as usize]; + + let start = target.tag_names.len() as u32; + let length = tag_names.len() as u16; + + target.tag_names.extend(slice.iter().cloned()); + + SubsSlice::new(start, length) + }; + + let union_tags = UnionTags::from_slices(new_tag_names, new_variables); - let new_ext = deep_copy_var_to_help(source, target, max_rank, pools, ext_var); TagUnion(union_tags, new_ext) } - FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion( - tag_name, - symbol, - deep_copy_var_to_help(source, target, max_rank, pools, ext_var), - ), + FunctionOrTagUnion(tag_name, symbol, ext_var) => { + let new_tag_name = SubsIndex::new(target.tag_names.len() as u32); + + target.tag_names.push(source[tag_name].clone()); + + FunctionOrTagUnion( + new_tag_name, + symbol, + deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var), + ) + } RecursiveTagUnion(rec_var, tags, ext_var) => { let mut new_variable_slices = Vec::with_capacity(tags.len()); @@ -1569,8 +1615,9 @@ fn deep_copy_var_to_help( let slice = source[index]; for var_index in slice { let var = source[var_index]; - let new_var = - deep_copy_var_to_help(source, target, max_rank, pools, var); + let new_var = deep_copy_var_to_help( + source, target, max_rank, pools, mapping, var, + ); new_variables.push(new_var); } @@ -1588,11 +1635,25 @@ fn deep_copy_var_to_help( SubsSlice::new(start, length) }; - let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables); + let new_tag_names = { + let tag_names = tags.tag_names(); + let slice = &source.tag_names[tag_names.start as usize..] + [..tag_names.length as usize]; - let new_ext = deep_copy_var_to_help(source, target, max_rank, pools, ext_var); + let start = target.tag_names.len() as u32; + let length = tag_names.len() as u16; + + target.tag_names.extend(slice.iter().cloned()); + + SubsSlice::new(start, length) + }; + + let union_tags = UnionTags::from_slices(new_tag_names, new_variables); + + let new_ext = + deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var); let new_rec_var = - deep_copy_var_to_help(source, target, max_rank, pools, rec_var); + deep_copy_var_to_help(source, target, max_rank, pools, mapping, rec_var); RecursiveTagUnion(new_rec_var, union_tags, new_ext) } @@ -1609,7 +1670,10 @@ fn deep_copy_var_to_help( opt_name, structure, } => { - let new_structure = deep_copy_var_to_help(source, target, max_rank, pools, structure); + let new_structure = + deep_copy_var_to_help(source, target, max_rank, pools, mapping, structure); + + debug_assert!((new_structure.index() as usize) < target.len()); target.set( copy, @@ -1633,15 +1697,21 @@ fn deep_copy_var_to_help( for var_index in args.variables() { let var = source[var_index]; - let new_var = deep_copy_var_to_help(source, target, max_rank, pools, var); + let new_var = deep_copy_var_to_help(source, target, max_rank, pools, mapping, var); new_vars.push(new_var); } args.replace_variables(target, new_vars); + let lowercases = &source.field_names[args.lowercases_start as usize..] + [..args.lowercases_len as usize]; + + args.lowercases_start = target.field_names.len() as u32; + target.field_names.extend(lowercases.iter().cloned()); + let new_real_type_var = - deep_copy_var_to_help(source, target, max_rank, pools, real_type_var); + deep_copy_var_to_help(source, target, max_rank, pools, mapping, real_type_var); let new_content = Alias(symbol, args, new_real_type_var); target.set(copy, make_descriptor(new_content)); diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 55d1b51c05..da6f60fdc4 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -81,8 +81,8 @@ impl Default for Subs { /// The starting position is a u32 which should be plenty /// We limit slices to u16::MAX = 65535 elements pub struct SubsSlice { - start: u32, - length: u16, + pub start: u32, + pub length: u16, _marker: std::marker::PhantomData, } @@ -681,7 +681,7 @@ impl Variable { /// /// This should only ever be called from tests! pub unsafe fn unsafe_test_debug_variable(v: u32) -> Self { - debug_assert!(v <= Self::NUM_RESERVED_VARS as u32); + debug_assert!(v >= Self::NUM_RESERVED_VARS as u32); Variable(v) } @@ -1355,10 +1355,10 @@ pub enum Content { #[derive(Clone, Copy, Debug, Default)] pub struct AliasVariables { - lowercases_start: u32, - variables_start: u32, - lowercases_len: u16, - variables_len: u16, + pub lowercases_start: u32, + pub variables_start: u32, + pub lowercases_len: u16, + pub variables_len: u16, } impl AliasVariables { @@ -2716,7 +2716,11 @@ fn restore_content(subs: &mut Subs, content: &Content) { use FlatType::*; match content { - FlexVar(_) | RigidVar(_) | RecursionVar { .. } | Error => (), + FlexVar(_) | RigidVar(_) | Error => (), + + RecursionVar { structure, .. } => { + subs.restore(*structure); + } Structure(flat_type) => match flat_type { Apply(_, args) => { From 81f0f4613204d5488756e6328fe033d0c9992c5c Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Tue, 16 Nov 2021 18:25:16 -0500 Subject: [PATCH 121/223] fixing test --- compiler/test_gen/src/gen_list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 97840d8ce1..5332a98c90 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -2358,7 +2358,7 @@ fn list_all() { assert_evals_to!("List.all [] (\\e -> e > 3)", false, bool); assert_evals_to!("List.all [ 1, 2, 3 ] (\\e -> e > 3)", false, bool); assert_evals_to!("List.all [ 1, 2, 4 ] (\\e -> e > 3)", false, bool); - assert_evals_to!("List.all [ 1, 2, 3 ] (\\e -> e >= 1", true, bool); + assert_evals_to!("List.all [ 1, 2, 3 ] (\\e -> e >= 1)", true, bool); } #[test] From 36f2ef301f03d6e89be19639cce8aee61b1482de Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Tue, 16 Nov 2021 23:41:15 +0000 Subject: [PATCH 122/223] Only enable wasm_str tests for gen-wasm feature --- compiler/test_gen/src/wasm_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/test_gen/src/wasm_str.rs b/compiler/test_gen/src/wasm_str.rs index fcba6143c1..8780a1a5bf 100644 --- a/compiler/test_gen/src/wasm_str.rs +++ b/compiler/test_gen/src/wasm_str.rs @@ -1,6 +1,6 @@ // Wasm pointers are only 32bit. This effects RocStr. // These are versions of the str tests assuming 32bit pointers. -#![cfg(not(feature = "gen-dev"))] +#![cfg(feature = "gen-wasm")] // TODO: We need to make these tests work with the llvm wasm backend. From af896e5d337ca81d6e26d2a5a23a692c9aa20a83 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 09:39:16 +0000 Subject: [PATCH 123/223] Comments --- compiler/gen_wasm/src/backend.rs | 17 ++++++++++------- compiler/gen_wasm/src/storage.rs | 8 ++++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index c094a9cf3c..e1af157a72 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -565,6 +565,9 @@ impl<'a> WasmBackend<'a> { arguments: &'a [Symbol], return_layout: WasmLayout, ) -> Result<(), String> { + // Load symbols using the "fast calling convention" that Zig uses instead of the C ABI we normally use. + // It's only different from the C ABI for small structs, and we are using Zig for all of those cases. + // This is a workaround for a bug in Zig. If later versions fix it, we can change to the C ABI. self.storage .load_symbols_fastcc(&mut self.code_builder, arguments, &return_layout); @@ -580,7 +583,7 @@ impl<'a> WasmBackend<'a> { match build_result { Done => Ok(()), BuiltinCall(name) => { - self.call_imported_builtin(name, arguments, &return_layout); + self.call_zig_builtin(name, arguments, &return_layout); Ok(()) } NotImplemented => Err(format!( @@ -757,12 +760,10 @@ impl<'a> WasmBackend<'a> { Ok(()) } - fn call_imported_builtin( - &mut self, - name: &'a str, - arguments: &[Symbol], - ret_layout: &WasmLayout, - ) { + /// Generate a call instruction to a Zig builtin function. + /// And if we haven't seen it before, add an Import and linker data for it. + /// Zig calls use LLVM's "fast" calling convention rather than our usual C ABI. + fn call_zig_builtin(&mut self, name: &'a str, arguments: &[Symbol], ret_layout: &WasmLayout) { let (fn_index, linker_symbol_index) = match self.builtin_sym_index_map.get(name) { Some(sym_idx) => match &self.linker_symbols[*sym_idx] { SymInfo::Function(WasmObjectSymbol::Imported { index, .. }) => { @@ -781,6 +782,8 @@ impl<'a> WasmBackend<'a> { Some(ret_layout.value_type()) }; + // Zig's "fast calling convention" packs structs into CPU registers (stack machine slots) if possible. + // If they're small enough they can go into an I32 or I64. If they're big, they're pointers (I32). for arg in arguments { param_types.push(match self.storage.get(arg) { StoredValue::StackMemory { size, .. } if *size > 4 && *size <= 8 => { diff --git a/compiler/gen_wasm/src/storage.rs b/compiler/gen_wasm/src/storage.rs index 64565bc9a4..e4125a6bdb 100644 --- a/compiler/gen_wasm/src/storage.rs +++ b/compiler/gen_wasm/src/storage.rs @@ -194,7 +194,8 @@ impl<'a> Storage<'a> { }) } - /// Load a symbol using the C Calling Convention + /// Load a single symbol using the C Calling Convention + /// *Private* because external code should always load symbols in bulk (see load_symbols) fn load_symbol_ccc(&mut self, code_builder: &mut CodeBuilder, sym: Symbol) { let storage = self.get(&sym).to_owned(); match storage { @@ -274,13 +275,16 @@ impl<'a> Storage<'a> { /// It squashes small structs into primitive values where possible, avoiding stack memory /// in favour of CPU registers (or VM stack values, which eventually become CPU registers). /// We need to convert some of our structs from our internal C-like representation to work with Zig. - /// Why not just always use the fastcc representation? Because of non-Zig platforms. + /// We are sticking to C ABI for better compatibility on the platform side. pub fn load_symbols_fastcc( &mut self, code_builder: &mut CodeBuilder, symbols: &[Symbol], return_layout: &WasmLayout, ) { + // Note: we are not doing verify_stack_match in this case so we may generate more code. + // We would need more bookkeeping in CodeBuilder to track which representation is on the stack! + if return_layout.is_stack_memory() { // Load the address where the return value should be written self.load_symbol_ccc(code_builder, symbols[0]); From d3528a3ed39dd5bafaf1f59fb52e568f789f98cc Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 13:21:58 +0100 Subject: [PATCH 124/223] refactor ExternalSpecializations to use Vec --- compiler/mono/src/ir.rs | 60 +++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 030abf0671..0130fab10b 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -419,41 +419,55 @@ impl<'a> Proc<'a> { #[derive(Clone, Debug)] pub struct ExternalSpecializations<'a> { /// Not a bumpalo vec because bumpalo is not thread safe - pub specs: BumpMap>, + /// Separate array so we can search for membership quickly + symbols: std::vec::Vec, + /// For each symbol, what types to specialize it for + types_to_specialize: std::vec::Vec>, _lifetime: std::marker::PhantomData<&'a u8>, } impl<'a> ExternalSpecializations<'a> { - pub fn new_in(arena: &'a Bump) -> Self { + pub fn new_in(_arena: &'a Bump) -> Self { Self { - specs: BumpMap::new_in(arena), + symbols: std::vec::Vec::new(), + types_to_specialize: std::vec::Vec::new(), _lifetime: std::marker::PhantomData, } } pub fn insert(&mut self, symbol: Symbol, typ: SolvedType) { - use hashbrown::hash_map::Entry::{Occupied, Vacant}; - - let existing = match self.specs.entry(symbol) { - Vacant(entry) => entry.insert(std::vec::Vec::new()), - Occupied(entry) => entry.into_mut(), - }; - - existing.push(typ); + match self.symbols.iter().position(|s| *s == symbol) { + None => { + self.symbols.push(symbol); + self.types_to_specialize.push(vec![typ]); + } + Some(index) => { + let types_to_specialize = &mut self.types_to_specialize[index]; + types_to_specialize.push(typ); + } + } } pub fn extend(&mut self, other: Self) { - use hashbrown::hash_map::Entry::{Occupied, Vacant}; - - for (symbol, solved_types) in other.specs { - let existing = match self.specs.entry(symbol) { - Vacant(entry) => entry.insert(std::vec::Vec::new()), - Occupied(entry) => entry.into_mut(), - }; - - existing.extend(solved_types); + for (symbol, tts) in other.into_iter() { + match self.symbols.iter().position(|s| *s == symbol) { + None => { + self.symbols.push(symbol); + self.types_to_specialize.push(tts); + } + Some(index) => { + let types_to_specialize = &mut self.types_to_specialize[index]; + types_to_specialize.extend(tts); + } + } } } + + pub fn into_iter(self) -> impl Iterator)> { + self.symbols + .into_iter() + .zip(self.types_to_specialize.into_iter()) + } } #[derive(Clone, Debug)] @@ -1970,14 +1984,14 @@ fn specialize_externals_others_need<'a>( externals_others_need: ExternalSpecializations<'a>, layout_cache: &mut LayoutCache<'a>, ) { - for (symbol, solved_types) in externals_others_need.specs.iter() { + for (symbol, solved_types) in externals_others_need.into_iter() { for solved_type in solved_types { // historical note: we used to deduplicate with a hash here, // but the cost of that hash is very high. So for now we make // duplicate specializations, and the insertion into a hash map // below will deduplicate them. - let name = *symbol; + let name = symbol; let partial_proc_id = match procs.partial_procs.symbol_to_id(name) { Some(v) => v, @@ -1992,7 +2006,7 @@ fn specialize_externals_others_need<'a>( procs, name, layout_cache, - solved_type, + &solved_type, BumpMap::new_in(env.arena), partial_proc_id, ) { From aa4ee812fe4cc1052428aa0cdc832aa8c361fcbe Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 13:23:46 +0100 Subject: [PATCH 125/223] remove dead `add_pending` function --- compiler/mono/src/ir.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 0130fab10b..7e558d7a9b 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -837,22 +837,6 @@ impl<'a> Procs<'a> { } } -fn add_pending<'a>( - pending_specializations: &mut BumpMap< - Symbol, - MutMap, PendingSpecialization<'a>>, - >, - symbol: Symbol, - layout: ProcLayout<'a>, - pending: PendingSpecialization<'a>, -) { - let all_pending = pending_specializations - .entry(symbol) - .or_insert_with(|| HashMap::with_capacity_and_hasher(1, default_hasher())); - - all_pending.insert(layout, pending); -} - #[derive(Default)] pub struct Specializations<'a> { by_symbol: MutMap, Proc<'a>>>, From 4aaa6d92a1680b8488f64c6f236ea22a5384c969 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 12:52:48 +0000 Subject: [PATCH 126/223] For now, commit a binary archive of Wasm libc --- compiler/gen_wasm/lib/libc.a | Bin 0 -> 947756 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 compiler/gen_wasm/lib/libc.a diff --git a/compiler/gen_wasm/lib/libc.a b/compiler/gen_wasm/lib/libc.a new file mode 100644 index 0000000000000000000000000000000000000000..de6e3c2aa4f27dd9f6a2eee27f25ada31039d4e5 GIT binary patch literal 947756 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
! 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 (iU|pT`ambRz-31 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%0A)r5IeD^0#z+0KFEGGf3{X@;Yav2 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
  • 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

    1p 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%0DeNI=#x2GDspf^v zXrEE0n<>Wgy2;ok-NVKjDQuyU%9a}`#^**FGrlp>QrJ$z%N{g6>;==ye#CQ*CxyM{ z@w2x*scfGo#hB{_fNat@Et(u3h}{s8=h_kszbqmv$QOhv3V zZC+J%z+&?fm~T{M`a8z#wJh*M7G@cGz7C5R!I!>W!Fj%R6Il5CSZ1kUz&XstMOoNn z;FnO}1uVniBYG@PWDzBcAe~A}(BDxGc9fk!cCw~vf)TOHz)0GhJNM+Mo zyy+>H?5t=74{DfZbL5tT3vC@e zQ*Jr>BH$y7{z;wa0a94M9Ll&rEBeaJ*|M+H&4fc=Ip$2b^V_%2X~_DnL#KK;HAlsR zlYBQ?s4H$9pF&{o#~S+fY84tEv9-}+tR^`Szu5SSEXKzN&1TN&!FehCs2Q<@a+qj* zT+nGK2@3!ax*Wx65Ogu*0*WDrjumD+9a4Sc<7nk*Zl{babev^CDOP9kgGPP)J2biC z-*Mi6d->1#cXw;-dF?ph_q5Mx$QQeVI>NH95u}{zwm$xyV%ecvIIKL?FZkhi+T$9Q z+uD5=bB`!cx0Rm^I;JT=IRFk5b+oYB=t-FT|n{g0OE83xYu)u1bPb}Xn3NM z8R7xqf#mne)|W#-ecV23eZ}od()?|}?bFz-W8eJX-{Js0$;ZJ5xUOLz=r@fr4A7g%>n}ydP_TSO)`woz4IISiP z1CUqo`>Kp1^83Wc%F=Ddfs5D2EG;g==JaXAjdQX398L%lC|(II%WESwUft5z*(;;ctsKweTP}7JQ z8*j5Ps|5!sOoc-lfy{0#V)LlNR0+sxJsZ3|hx3;0wb?wyD6Yry+N>3%kcC6loNLTA zvV8OeD-%2na4Yq!R6SqM52CUP=(`h+2F7Qnac6bKpRcoQ=QXEuUMaD9Qt|pJmd`E~ zv2Q30_`=ixHk-y~9f1`?u|qg_%4XVRQ=(KGC>iUeS@yJgA&fkN_Bs=2|*qZGxI!shl-NCH1m z_1r2jtyB?hN7B}<6uD83cBMoGYps%UL%e9q_}Ui`VI9?px>qphA*q(f#zXA9TBV>; z6T>YChMd4`zj;JpjZ!SiAoHcSq!7Z!>DqyJ)vv0lN`a$F<0YedP@GZViO?HGRB3HI z#Uf3FazPoKd@Csg7!&dZya*BPU94q!iS&reN4*P7a2xeHMyz~vK~3~@>g}P4==ac; z5#v)n?Lb5i5qv&f@cF8Yqu}%5JL`OA9cErFJ|B2{PAph`Z_--BJ^emU^7$^&Sx>_l z2EN<9V7pD!JnSj3_$oCY+YPgZ&x5(QUQcB^@Vp=Fymt&A`^5k&&rD-W%v3hb<6+Nv zyzB#y*Vqfzo^inAPhn%dKI49H@r>DC6Z@^a9`=pb$60z$`BIEmeaLLJ54n8^2H$ot z_@;uP_d<%-SOq4Z@h|K?W?NExY&uwcWvO1a3D3!CKDIQ?=lkW@v-fDW*sfCpG>SUs zsHvrE&LC~?>Z3^{Ombnp4826i?;!gf*nd!;p2ND|(dUlA!>})z%lyoqBYF;ka~uI` ztPxri3DO<|6)!fLz4cZMyNv}{}l5Gwn z5V4ws#a6wb3xs(3P|!3Ohk8L^%93GO5Mt3EB3*ilKBVSpvr-V{J;5{#of(QXl^W&j z3|NQ71+7N#vH)x|BP{j=#UmjvON{KkT0SZkIYCT8Lm8}XV=xIS<7syqTKRP6c_+|^Vd9x&9sj#;q8!VnM z6b6Z8T!b5JaVOEOLF@uEn0e>0EDsSFCo*qX@QebK}bdv2xy{Qb7(M z^nuU-s6#z)GjtCvHdoT2$@8aZix*`FzJMkXVlp_2)UO5(hARs*AW49;r%3|zDgyMJ zAPLa>0N9Es6-Jf9wkwynFPTXMCY-#qs0qx%sS;2K-SRjFqFd`2EO=V_IC}xdBLND+ zM5Ny@ESD1@W+00I?uu>ioScsvgqPvZpkm?*Q~tQ4?6I*(>k!&ogo+5w%gKqj8=8Jf zGBW8)1eKxbCnb%9QjCWat$t>G#MD=3nf1oE%>_x-*0^WL`v*-kU(=y+zfnIfsI7zj z8N~8htg7o-XXh$@oQv8x56MuPG(D7N4cD;JAEt&%O-^|AX;h_k?>=(S;9=07k*YP$ zYMLjD*R@hR#d+|+tZ47Qc1A* zTv{3yl{}2B$9TvK8ICC!u;|uev5Q$JEp~lEqXO~vbf1>qe4;?9vA*W`FjEM_d#=$O zq=-ibPl;6WtDj=YPd=7vlmOV6jYY$PP8X8_E0u;1jA2AzSTL*kKE@{7X`;YRanF&; zEy&bDrufc!pn_vV+YY<@5Hrg8v?rM7B+d~f7H=xc21OziRcRk(rJ?Mm?alUM@Y94{ z`83<9=hGj(2FTaISJ^`odAk(0!zm7`bAqV7pqSo^8q7y|AhP%H<)C`^WXZwrQ0YJ6 z%L9?VE7F^kzN+5rt6bS*NToLC4cG(8c_YwLx9;q#Vy^6KTF=Ug_TBM9UBvgr(7jg>n*Ph;NVFCO{td#Qo`luQ$r6e6shNPS`!Ov52@}DwM6J! z^Q2C%7ROz&sp?gb2LYDrSw8hyOFe-I1^wOYE*q+olK?I2Rh86TowU?GGE_Adv_4vg zf;mDZwHN4;MT0&D2*iS+;Bhe&5K^rn1nK3HcM{s1Mh(Eb$C)b85{RgDwPfAJjyeUx znp&h1Yk8GH`BCACh+;#jK%@^4LoOx>m=2)M z=%qP`?MvRHXtC}}?`Qv}l+F}kIeB3r%O|D?&T3s~;y9~vTCc2# z)$@FQ&3B5%+UTr{!3LP@UJonROk*P!>c&@^H--JE8OC%SzPUPlPwPG`+D+pzEZB`D z20~sle8v~#`<8tB;agzB_k;=GtESKRoP6JquLiz1u%I{I^T4;+V;Es*;uurC@Xg1v z{zEv7pAp2KhE~q|K94aI8ac*eDTseM#V}q=NoB?xDbUKPOflHrlr&bFnr8ePnmWeE zsR;cl)nMb((u|Tcq*{=MR8OTD?9;R~-~E2gnBzz2<9=_7@8AC8K#!-rBmO;#IZNku zN!Izit7~F~U*9glTFd(T@ws5yWK!qRLqeS=xiU{gN%?NWZa=X=bgzYJTEClb5VZJo zo$KwuhL#c3vUFluvU#>lF&2A=oAAO=OUdSN4@k$6C09hCIm5)2A1TWM>164+4f;H& z7;G7F+}P>|C=C!o>l1h%42z8g5>br{yat;H1$Npah=e*%sKP2NMu7&l08z$7*3dt~ zz+ajTH5c($bpF5re=J&7T2Wf`$e}NZ~05)9C~ug!*2~;LC!aJ z&Yd@J-rI0uw|NRYaq=ZgJe^N&;rs3_t4 zfLMMBba&$D7_0TLjHP{ph>fG)-I9I*7L{PpfZAjTU_rASiNz>&9KFsWdYwh|T6js* z&sNSVocr%9SC!0C1Xy_1v!gGXRha%u6Kr5CeCp|^@u)>jC9{YrU|{8MQxlf=f|{`H zQI|(mA&fRW@=b|SUqMoniw}_3>&GtGMHsks?!5u3YR(7f-|5-hep%V=mo;wIo;F&t z&*G`2R8fmy=eWoPOMXr|L@pWs6}h~lgIu;?1%Ir`g*e_9=V} z5-#SWNIi@7TDnrRX?d@e97$ISJ>9J>b%<|e)Pq}~-lU^@ut+v!pKfg^47Ozvp#^1s zzCdk@%4h^e1U@lh8D1nlOW4BA1MT72&mN8M8V~Y!Q@q%^?Cjok%%?ZJRc-Y)jBiI8 z1=}BKXY}JoYSr4RPBBUXerKJUPIBmqxs)Og>asCQL}QAP2XsEWL^dQ1J!r(4v#Ajg zXg4Avu(??_psm5QAie<~QVl3Rfn0;Bn8MuRGmZ5*E?Tfthj#MQbQCSvIhm#8>HKx& zZZ)+_t%g@gJp@|E{zQj)rcq*eC5udXB~MIwCC7|=MelI$JKK$=HPe1DOqg*dlNm}E zC8F87D3+STy$?~7O~h&LEHF}fc-;4>aN&w;*#xW z`#2EBo-j$Bz@)MH6=1OOIDE``95$38JxR2HO0H26&_g7XOH{!sFoG6sL-A39xUFVD z#c^3`0gH|A#4wX;9>ukG@R+uWK^TimA33-A=M6qEF-(LvORD3qC3A-MM zktBGF9M=#MRFi%Vf7c13e1rztIA9~%wL!Wgs+L^IS)803-~9r5MSdxPxR8Bg&EATF zv2cEt9?rZ}5GOM|f*KQ-)3k(MMJe3GneI#1e5Y#cR-KL447N}+*?P^xc0&I2m~OJD z?qT2JyE+Xk;-?J5_Z{Y?$J`=K`#hUCkAjjr2KFZLz?FEWO~>@t;4r{>81!CctDgUw-Of4F^+3SbD)Z zv{_XfIt;@@#etYSzLaZr(PY|#2`?DfLZ>Hwgz*7~C-}l)o`$=(92Dt|V8lmsLSu%{ zriNmKfm9-(c8V9oWz$WRIJ1gy%0+TJG8~RdWAH?<0#7mF0ZxI3FqcyZl1g${;}PH` zA%g>omjPthM@mfg*3yLB;)+sPE7GCws3=Jlh%UBT0FR`?F9H;_a{6;Z-plLZ!h;TAm_?)oL%jte0;4 zJ*p6f_o((}Q)vJp@`h$pid%(EKvjA1g+eRXP-z8`SDyam<2~!QA7TXu-}^kgYsaL6 zP9;S}vP%AuQ;7;TPuTMOrf+_Fpl89Zr{4YKp`SiP3RPLC<<(a27i_Ba{jl5^#nE&SHuMw8Z(!6R-a| zZpOR+SrsaHaL&@|U9q2CNUJ?|LBo^`C=!rX0fK6lYczTk(z4GNO?-XAg0f)+yJt*a zzhKI^L(a=rIykE+6)+^=j0&8U6boos(5JrN7yjbV*bQ&8f_*Pe{d~fY(_Bc)9i&l8 z1{4WMBLZnT#R6I)oj>RCMU|T$T>WgQ;D;YpKf7+?JQvbp2WfTir;jDCUR#7ToNWd8tI4da@&=TjvJAYZaxx8}P7p&mt(mAicKkW+_(sBoB zl#&5O0@8>;T28TmmPofw`eyvwi%Z^aRY1RsOQs%n+P>Jq8KG3bkbpBRa28W6pe4@t zpZ-|$FEA+3heEXbJZEKJFOA^~X?AV6;g&+gqmY3`?Uw@(Ze#J(Q;*{sd84pfBf zL81~+z)?ktyhtIl{^r-U#q*}_nEzs^;HzJr+x*hMRvkndMafZtnbMK|v10(h#wxXw zqZA8hiFMPjQ#Ks>B=*V%R`AiB3G-(^UggFbaj?c~F56g1Q5bnf2rHl^*4=A<9((_W zoo^mw1qaG@JhXnzE;rV&gSD8_0Y^eTRSV_VFvS8|V*UD|Z{B`n{?5buS;5+8U*11< z`aw6=Dx{HPSv4tz0!ISYN`bYCVgW6&zB|8a*@h3Ief7%>H`a)QwVcucM?zVP1=a|~0$O67 zz5JaWd*{x1vxXHceRl2xlh!VBV+}i4Aq7Oes&sZ)tFext-bt~5mRQRtJzVuhY|(pD z(6iP~p8nX1SKU~vxS%hM(m|5wR`ONfh)RLAiedpRu@VJRWbX~S08=ol7c<>{nyuf+(;u1(sD`$6e5|8 zv{)dGP%NM&(#M|Kwtn7A->#n*D&UWoo;d940bvJg9cwQ@2uxY@xvp0IHH+6-SQ9Gp z)ds1^TP8^j_!2SIO5+OHih}tn4Bs{^2{}M~(Pzuens8qI&rlFzc>UZ*9DXE$yFq z&dQv9hZEvs;2lSqKmUu*x88I{)%>;F%Ezs_BQiD6`}^fq{=Y^)F{P?ianlXc0t09K z;raEaw_NzyBX9TpX6Lku`1l6`><4-~X9>KFys20M3+UOth3Lsgq{d3nNr*zVEJ4OjfQ7&e{PuU3DaO}VA|maJRkL# z>@(c=L*Kg`_jcU#dS&!*g0A4_np9U{!dQq#JBmI&k7S^#o{(tl&i6az1G-ZoAI2Ex_B`Iy5@LJ zZsK9fn;7g1JZCgD*h@{37SE|Cdf3Vn4Ymc(l4ii!4B>cAJqh6_Aso-gPd3;aCwo}c z$zC?)6oWl=ipSh=ijSF}o&u5g*Qa>dgyvpzMsu8QwV*jnQoP#S>pRr^n6nUwpPSdI zAzb>rJa8K5a`6z{T>AQ?T8>iN{nT}|$vPKQlU3W~V(OUMVGMog;LJUTK7y1;&j&OK zv;tWCQQ$iWv_;2V3riD?<3iPoWWIXP7-Sg(o-42>#qF^eKcRvPgDvc9FOwqS(o)M) zwCTrfAF=W^5a)h+&GuFA6z!;h`C3Sziq>qr?D8Ia_9Mb-Rb5hb&S69pm3-T?@wdj| zKqLaevaqm_GMbMrqhYWW$x2B&;8{c%A{MM0A_OkZR<6eyYOmXdjW`bYOr1M4#Il{e zIWkEfIeJ?OFVhgKErqUK$mBi5y{9>dLF%CD9Z>EK?tSTv58S;&s3Aa_u5p27_=;Ih z@+_UemjWCeV>z{c1TCZyP8%fZ<7mf}C#7a<3}7XXDx49Mp3-K5CUY%h8R zxhdkGvN`LtXF$z)9N07Hkkb&pVXnP(-PN8E)D`o@O8~gV!uzD%LT<9~acaZgpkQ0S zNWd{@I2;PNoQ3EFk&Q!xSe6NP4NWOqa7z!6jV)Wih=lIO(w>6pFQz@=^TK)}zYrOW`+80d>)0}NNYB{ywI;j>mtvs|1dHv83M7k_mhOQGY0)`W~ zJSYdL1@Rd-fjckaup>RFm@y*lC$6-WNbBcW@D||vBx#mTnewGTcAAwI$@W{R$|xxY zazX9`K%tGSMy2@APLGfy9e-&=p^YrRg(!rTW;X(blA9um7{9EGBK8!L=J$Aq__@9F z0t?U*y!G*R$tU_u)$oFR8Nw6yFJ5yuV>e$a{uo8%R-o@PY z7tCEJW0T1?h<&D;I(rTG7R+16dVFlQM`y3YJlSSEr(mz*60gDD^6G4#*YK73j)%Ej zhn$AY?ec8FzH6MXS3dL|)uK1Ke2B^5WEN@T?UFi!y^;pm;vWp-fE_qOY_#A51cvC% z7#EoKi4gHZ3qVPNs#)Cd4APdE*gZ>Ss5b+`3d#8GZ)U?a%2q?N- zR4R^7=%M7cN4E%r01af+kvYSw*aAZ{2(+P6hTuap{InkstFG}AAbt0nX4`jCiyT+Yazn6M55DL6D35VaYG;};x`^>h zn$ybGrJv69FcxK-PPDnmG8W+@%KwUrPkQIni1urj(xSVrS$*=r)!k@?c_mjAejJLz z1jUbK;jW^O@}{i%?$;+*LN)otWh)=smDL5%&t3ay`06nwt0JX<$Iw^0C=#jXw1e*5 zkAq`3c#GvVKsV`vWL7ZwXkkjb>3plaKAKK+H%8+zTK|N4{co_M?h#eQ)gGYVFs#oV z+*+zwejpM?7F@Q|4`ASgH5_h^ORXMYK3x+doSu)-nXPp1jn{(*)-L9YR=ZPxt)T}W zTm1-W-)lC9gURoiqa06jd$kl^B!ejj$^*ta_z)g6hJy2jwKS&Mq(hD$ITb_#cVJLj zAbAAgSOg>hQz*^W6$%ASD`^cHKjQT)!_Ug%hwxdv)?ww{KtCg9WHbD0teMXEffVl1 zJC(SIh`Ui|lQ3jQupD_sGuZ|_ztK$JPug)Yv%)qH8iU1k#F53`#_AebCh_5y`svZ0 z4`UnThuJ^qqh_U})$D>~$=Z8E6vBh_|ZGR=E&pakD< z&#SzLejf$}{R`eNf71+B)D0gGP*Wg()D-vmozbB$h6gokeV@---!%*{7GV3cC2|H! zA#qTkz54W>B?B12&lWEJmDKN{f*KC+i7C>M^1cSXl~`-4DXkHFf60&I#U7dET=(4w zZkw~2oAXnaC8Ekf3{;rnv^)`kS2%s1#5!H>V5 zGMO?54$Pi6S4^bM2r|K`D&JF8zHGV7I6mJZVb7vz6mRF`fKdqMPgRstAel32#AXD} zl(pfEepuLw>2Ul2sK!21j(sVQ*e@goJqbV+BgVTF1rRsTnSQpIn$cN+&L*!11D%Qf z(Kl|SdyAsnBVA+Kqj$2#uGHBKjBZOY+P#hYeyly8!6bDppQxH_Dt5m-0@=yacrM4J z_3dLnX{9f9hlYHqJ9JVLv7{s5Xnh4$4(HL;wq(PXlAb=JhTM_MxZ8kRxM(FgYRKSr z@F_Z5%0Im?xU~M=+P>MEV$es=|lfO*eo5aq)x!#GO;Ha`h| zZoGzLn;@uAbQlcMDhcEZ5$VAMkoJ&@u1OzHd@&crccc>rFV3OkeU3I(efS)A+|A8G(G3V#5et)HFmq0CmjbZ ze?dc5TODkXl50fZZ)nzW{?S)dFTY{t9xof?Quqg zS=?&rj5Lf0w$;*VSS|ImLfwZk6CzbPOT&sAx1fK7RU!-~5ULE41QLW&C@G*+bQOmR z%HR27RY~=MP4eg>07gYJXwq>MA`uvCrSE_BZRF9lpWEs|uuuR{+UWQ%5;2@1qGN4F68Wu>QKgXdHkmeUW6#3!B znhB45<0@%2)Wc*+!;}mt5|CB_f(%CJhy}Dny5`5{-ui6Yh7bQw@BQM9ny=q4D0q8%`A0wRUHqe~pydwIC?x}m1f&sx zw47oAEs;L*(&N8uUG?LW2Ux+>`G@y?^2OvmPDzU$q!CI66bVSf0%?&zBgh#4MDH%{CAguxfRjGzpKue@6x0W1^y%c^h5-J$G z43F_U_Bkc3bdXk2GN4F68Wl(@DHhNY>D<>2y}bIl@@YS?0{$4c`Bzs_%N?vyN(USX zSR(>!ImH56VqKT0@jCmEQ`BMyX@rsiMFLXrim8TdhB<8|qOQ*gHetgR>S+k{;!#mb z&Xt`iw?N@NYXkSlP6Mzl6wCJ8z{Jl7wyuaqI#DD@?;LDlr{Kj@aJ)!D!NK*X!311# zySx@h8YXz8mspWa4gzdR8=t`-0IYgM<->)-IItE1Y_S_AIaCo=ngt_4BzmJ{vK%6g zs)@7XX(JUp=hAt76bLOtG4R!MOdsb8#DA#xyvqHd%9fg7=jyBn_Do@7`Wz;x#DO1& z#m&oD*lfacDi$@*U{UiWo?!^qUV>olV?3vLu-Ji6?F&3(c)kR|+Q$&AO@Tt#(>|TO zh5IL;iSvC-wi@@>DLVTP?y^*qy$9tmD2VwUI`&3CF&FOC(Z#HAIVBH6geZ#vojWGs zKQE!iOw_Yb`?QQPV~Dfq<;Mhum_8ZJ%TgN7&2YYq8YQ+xZaVo8DZipT(kt4(7OP{R z(7Hf0nVZFgMoqf+jYpxhpVfv;TUuA_Y{;bbx}_uxV1BUi*<2KXjaI@C7YK&P2Dc;| zdCFv#Mv^O7^$>DBY)iDiz~PYG*R@#5ptyhv8F_*as>Ag_PL#$aA(O;z1e=o*slcBB z{Ftd5ATbFpMPZcrIReHK!Zg|#$>sV&y@1Qgq-85!)UcMtRX;`%HwOcgGN8qa1s*LK z(IVSoTs{w_B6?}1M|-Z3C-TZcUbJSUF#y9L2LdN{BBy&`z0_3+6Gf7I^$HlcR1yd8 zjkObW74IWNp-J-SC-C+lr4wdBL6+eGDLrjK!my`Ck>{vP&eDck9fS^~mnPuxV+a%~ zo0+T`R5K}wdoWSryvubK!TQaUgB1^xeR4bew>)?+_p2!4(GZ>`g&ye9j<2}-`#B#TO9m^udFOpN0 z1vN{P#{F)8MX@z-urFtlpq~w~JnahAbR!Q~)UHMU&P zU(vHCv!)xruUS=Ew5?y?mNQE4BFWa(r*7JOP3r~ZJn^+N`ro(VBXaiR=%V0g%fv`- z^(-wYe6$kDGfq1r`|ZDH1pwIi_7C64t{g$m*WbP1`YRtVCui#CpKZANu20FSUM^C` zc{q3{JBaj2`5SHF_DSq;(4FMYK%xRtvkYlj$NzyxOXZb`YIx6P9EE@VXf5`3&r=9+ z05*hl>aQr^dpIqxq9^$DJ7>?i>4Mg!RIDG)>2lHBUfib8HtU-3zq@}#p?lW8dLaLU zO%-td&r2oGu?Ih+(7ciRR=s*tFIYXYky?7unJ0C;;ks#4pox0M7uVdr=ErFSn%S|} z_8w=W-b#y>e7Eq^TY4=eXZyiBOR6vbikvOK-qpNsm*wPiY6g~uY@dZ5P+Eq8N}HFZ z>G`N37X0C#^MwT$v!IA;y=jQH~X9kFJ9T3oDY`0vn?&>YI2^v zy*y~PIE$P;hQGe;2d+OdY6cxN?=diXkOIw7NNsE;75#Om|qtr@8UG3 zk0~}&n1Qs=s1)yK+`f?Wt>h+R$ZW9DXBgy2x(AP5WTqQ)E0f$p2gCiPH1S2$*knwF zAH_Z6*qg&6esEr11MJ@Cw(l&VlY9-yV74A24f3)heGL^O*!dj3g`Gjnn4ojBF*Kw( z`rr@(03Vkk6*6uGW_A!mpfHbp`%+;=n|jC=E{&7T9h)Y;fk?uF#1Q^y67qK8 zJYIPu7JWPlU+ng;S7sGXZMJeb3{*|O_PZ5$?7aO6*sww}qe}?^iNC_rwodrxtisE7 zrFBN+$zz}RGakKKPrL|^cbC6I2Ck@#C9{DZhHCh6dJqm8s#Ft+_sl_@{x(y7!<6-! zX{MG+_QDz7DaNgR6@Ij&MHfq(MhPoQ+~2Ok=>GKOvkG6jrU{i`%^6>>#N)cdrBslV zl2!Buo_-&Z@2w4|EiZ8o{DozIE4px2;faH~Ux;X5dySyBpEi>aO}rs3fJg36pOR0! z5$tn`f}`?h&8F|qG}rfM^H|PR$GBHGCv+EVfQ=4(kdL&P7k^q%lK9Oj9OFB4^{m1+ zGfUS1Wcwp|Yw>uXPc}Vn2;WVC+12N)#^aSpZUr7QBUvj-vdqGFJ1z)jc?x?ynOd0T zEgXF5r-fO*!nbeCD#}VJ^pD+GD8CD&;lmW~&wL(p7fb-fatom6kXL0>qD1V?-ni9b}CwL5c*|WeAK@SpR zZI;egQlxm7EstOZwi@udlzPIPDC;KdZWhsKMAvQP$3SJMg=JN+7vJjrG*?WaX-gQa zB-;0b({F01cw{0LChbU_=V%h@MMKN(PQ7|&T7IeM{0XQ^fy zDH$=MFpUM7zeYQ`+xEv^Fh00&ew#&;=1=fmH15vJ`mH(Z!i$=Gf8N-6bB10tyZ7B+ zg$_M_(ejm>KHV~U^F^~ap1s50wn>*iJ&?2Yp}Q~ca_I{z9@)F;o-Pmm_;O_5TjgE$ z^!s|s%Qf4&oL6|p&aD@m7C89So)7-#wyuGDn>~NYSNBW^JOYEf^X9!4K#k$5md{rC z+{wK3=t{XcViUHer*dCggfLd4;lK~F z^6fD^=w!J$9a*RPNT^BgH)&oI^~p52${B1Ce`($R(9i)3lR1BZA^<(RnrR+OU@n zI=`59pmE<&nrAEhIGxWmZc&s?Q*L(k-#Jx3S&ORm5kbBVq?2e| zR9#;py>Qec*X7T$so9MJW-N*Q0ew1$>iM9?cdo`0^ct#MPS6+5uGrXqWv59UpMCQW zolbe>{k*|V$Nwp9Q_BlCtY3c-%`ibGpp|u?gL{ft{uzH^UDsa1T8+3Y{BZLt7#HR{ z-!!pd3p7EBJGnVrMJ@we?=;~RRB@qA6kbjgeLY-HLTegF6@3X9WWg8CuJ50lEbcbW zU@w9wR%md13Yyq)e9%O0L$suFJE()CTwlJ$yz@(4851I)5VMcB(Z_(D(?e|si4kNS zVxjuJg`7+V3P}%SLWBCyHZ0DAPVL^kZ~svv`VQ|eq&|+~1y|wYG(|=^X)1;Wbcur+ zftJv%(#CVCP#BCSnCP@=s><2HCB+*W=HYycllY2?kJ`D$jSvt45w0kSi{vM?Vl4lJ zl4PYTtsKdbpUnj>mu7n)=3#;=XuB6Au)OD!84_=>hDcmWe7r$U@Z9GJejtc1*z(U` zcOU-u;=?Buyt3@e3GY4ebU12Df=D!r>@1Ylmc&j#`CM6Lc`?@njC(VrS2ivD+uTUFKctH8)Rx}7%R!2ShmQ(Eqtd&9QC2Pr>TeeM}G@#lX(b8hIl z?Sb(VXLbl(dHaW--0Ht)aHE}pZGB(W7H0k>W%>mV-8k*)U4aGRv)4>oa>Kvdz42n( zL1lXaw`JVedD*%_n@{89Iv>h^ct`1u)b|6WgP%jFLbnmnSV z%Wqx&)ca?<{MWsk+OoCF|6OqX?dLiE{9e~qyp@yBzNHT8jLrNQk~E0t#Mm6S;!q>> zKrupB!-fo*k%7H(=JASAdSKE~nkO(BTTgkpM`^D9e2T`-!&dCAtx5YmO2F4ixc1J4c9 z8Z>g&A?U+m_>P_<`gI@NcOVueeEe2HBV`aD*dPMj&j;E67#`y8!^{d717cXjIh}5c z=dX+!5DbvMKI2z4xQUh?d>ea;Gyv~5rYH~hS*IMd7G(pgOu~1*knGV80mIXYL^MX@QadCeG7BSW!FiJ~9H$JE z*%}`p-Vsgb+2Y7Tg$_W6ws(J;r;rJjq z0TJxI1q>tu5m%_?!w$ZPN(K2BR$wYk2IK1FmL{{88s&8e6m&7ot{cyw` z+sHxp=?Ol zS75TXb9l2wy8jrC-#h~#q?pb1Ke@Y;r)Fmtj+0>k^#l9i9xzTv%k4!q5+nJDN;Px}|fd8WPL zhoLe1w1_I~0WezO{V_SisEl!$8$_@zJp~`+hUIxUS0FHh4+&HAT$*67%)(fmirEj= zg~9>`7J;;iqeD26+|h8v0@6-KcGWEn3pzetBdO3vgl%e?*A9zcF7R3%`5rHXI>Ue*J} z(v?%NXX&BoA1(gzC#Slj0xPAeq*TBlQrS4m15xjBDIWjr_+8W>;9U_Ne4bK{IBC}1dn6DJsWi&897 z%Q!czT(dEKg?(2a>#0*&&TY;ua2~GU%mRempo0Je1O-r%Juq6kGa`{z#&~s-WAnWS zSC&Ou=kDF^+=&CSZj25IAeVYISLszk(E}A_pyf5_26HhqGZvU`|DJS)_J>?(w&l9J=UAKAJA0LD? zEIsA7`vddDhO2WwDq8bco%_2desw=QPaK>+{_6anPkvIe-T3(rBlETyg z*n8dA=Y5kW&QBO)Q>`q0@A&UelXOG##4-o^iK@?r_b-)Rx4~=QBmbd^^{OTQ^#1F< zuV=nJEKmG=THBNlGPMC$@AeC>@?)N8tu?cIuM3^ard$mD#%jwGD>PdBX#9ia6)ql3 zn$d1#p7?3lo@srn{C@EJkgoH?N9T!s+U)c>Z7H(vqekmyOo+}C9iLYI%^uieYVU>9 zhcAyo`S&EGv>CQ#z28z(>%-&o#P4@^Ir`?(JKGz!?i=t|T%LI5cEp#1M{e#K*>>`c zGLzuDbi=*g>$;3@_oUqB^m>!?#Opq-@9YxlHUH|I?+=lQd1BtR2_O-cG{*x99^2E3QYPWjLZ+D`r8-g#+Sd=HGwsLL@T~qh&*?Dc(UtN+X z#`G?h)^oGp?3&`!tu>bCiMBT*OE!(Xe)8iLQyz|6nI|@Tyyv&&R#GdBzY*=f z@$Wt%2h7vE`}?RnV3zgETwAZ`mIkJ`?3x=p?0I6QZ|QdjO)$q~g>QTJ!;Cy}%NyR6 zR{NTER%~->+l(D~;?3cI8Xq)0x={brx!&ieJn_9sMUO?jp1Q91@ZXC??LmIKv@t&& zDD&A51I(xI?aLE=<|MtnEu_U{-NVCv5eM?bV$GLNn(`oQws@}1`rJc#VnWT7fGT$~ zH%%Lwd?F$+10srXtwHijQ^qKN3ChNzS_RQ_HqlZ z<%#Rg{9Wqf`|YOtHLCQe@y$H3#hj$a#nflLqOP7AdG{8^&$7x(0-lC{n_A-P_LQ7F z@tsNCb`9)(eeja4L)NyulP50hQejAw2ZMF3uWaa{|2t0{x-BBF$tRO*T|995Oa?q@ zckZ@k@Q*$>M*7_-U252)JW-eV!P@y9rumncd*UHhFL@`m3rMr`RWM!^GCZR))51SJiKp z)+xUI!>J|epZcHc|J$53I=xf;yh2jPJJsWC_V!~x8|>v2ziishSNC?yYPAL~zjfIg z;$&;7jR~<8@5N6)65Yn&6fc}j+@#&89~|}0M$^x}PBH2J_~suCHX6&+sl2Oh5vMr! zjq&Fv8_Tb%dfVA&Ls6&rX3*)Ce{OB&v;JM-t-#mdzjI*IpcNl%&UkZ|?%c9sPH|$p zHKC>bt35uSaC2$J;!bg8*OPVH`ZX-}d%N**OG-G!uB(ge-gp1dijpVyj{2aaQ=I)? z$V|iit+Oudi%DEn$|=?|R_;Bi_kmU$pKRD(y^K>VGQzqp;_YR%57je!Z7=H-uN!7m zuywF4ni=~>WW%?d;`VaIx;RV69GHBlit6OsPVru1i;C&lo4OsU5WT6J5qF!}lM;?q zY18%R^Cf584RDH%_B&RuDAzB#{O8vejxCS!OqqLOW2JU~b*uFF%A4;x#jgY3st~!b z?Xg4efA#sg_ncz#ypY^4|Lo^o>+^DXO)EG>Q;XEUOLW{>Ec@wazul-Q!k`FMR3jrIC?kY6AY`_S5OJzi1cTG4tyFT23)9C2K~4J!OEieY3U0 zKX!__aqBDG5zGxIeq8ljP>55^{`K{`CQFC%*77^L->if7|G~0UxNq1Z>}%X&zUUP9 zZ>ck>L(u4XmmmJ}2Hv%winv;5xZkRv#!j)uM?d9# zU;9LOYS&gPo;JbwD?PVNPK{4~$vi)=;(?}4G0w2GcWj;GefA&g{r;@xPO)d_ru$k} zdF{>a_dZZ==%!%RYUpU1RKlUC`w#l1= z`X(*-I^j#FSZq#hE8y#h*jILjHpqR%$;`AM5Bpt?XBwo#M^Y#|9=BE!U*o z0`(sax?((BZ1!pRgCS3<9{jXhweC(a^`p%d=MFE{$kg)PnDRX_f9`F5KVtWYz-jx# zI+pmFJnP&14K@v{@X-WjTREOJ-0RDdE5@ zRrh7K=CO=*^=0vc@H;D(#W#y%?1VRC3w@Yv|9EDrW?v)zM z@57990Gk}k0zZvq$t%aPO%unn^w$lHK7Ym=Sp5EREPmN|<~4sjW1WyU1N^daEU*vK z2gb5eX$H3Vb6+;dVqkNN_%U0c4=Z&K@DIINveuUc&hll~`}wl3QQlf;udH(hmc`;& z?!Y*fKEc2mx1GR}XT-8wr+t~RW-O~!HjX7{8JN-6kF}#VKZg2ELY}qa*r0`YZ{))| zS3$9?M#2&>tDTtn+I~zj-_x`oNbh`lbjQ)XkUu0ba{Pro#`I`7(`{q^5rMY6R%C zAo1=oC{n<&RCtTU%iym47_<2^f4!D_K2#YL!4G0I%=HE!4Py(qJS3t=zk%I83T+-% zPxGF99`;K(@qmnSx1eEH1l%$JW!6vl=Hi>6)@xR&y-;|yH@k+HN07d2Vl+NpY$?vf z9>&+E)v;6G+C>NJg8h5&V% z0K_QmdZm}P#`h@4UtcEhH6%hmh@+8u0O*agJihvp&@%< zhK3BeYm&og&B7-NiY=AdGY!|GY3QN`RFBE&a>YWmXh`$FrbXjr;C7V;wlx3h!M){a zpt;}&E{l^J!~9CLpDDek*20%f5(G8_tH^xJeK;CddujFyq)59Us7tA@3u=G$NEPH( z6IAL7>Uk=4pn9oFT}!j|zo1AXNpf}9!St7yp+VIYn_l+}eK~!`{dhDS*JtGVOLF>N zWgR_1bGA zWYT}1HK#VgT@~N?X{2)-^a1Pd`u^(Gce!}5Mg3#T){GKIf81u9rcE5ATzFFUts<$^soN+w3!4%MsuE2pUP4mN5bHqE>%1!^Efi2|xuuDDaeUKx5lAxCWd;CRQ{=O=|Y z-{`)^>q)k#=`isVTUxaJ&v^-*cHheuzi!dw;O)i+ir#H}?+V{{ zE|zG2)3#hw?@YGXVO+_ElNPnJSNiCFfX^@4V%eFEdd>Q9n0?yf7N`F{nk~Mzd}rs| z-9keYeO*p>-6!5Xr-rm;Z{4=+&lbN^r<}QXa6m|A$d2`?d$PsAVnxM?&cu)l$A8VO zv@2UoU-kXg!|_8x6g}U!S*`!r_Eutu-}$FA*4VSfiD}`iTGAx@q7UZ`S+hA?Y?PLG z?%;*7c5BZgsb@B1i=Ao}-L~h#P`jcZy!Yh~x9S&*wiiw4xPSg?!2kNRl(u?e$eH)o z*J!XRThz`PUuEO;A3~n)opz$wifqxl^_!P2c8d>D^olq4lx{I*Z?%w(_1lksZ%MXT z-O>Gnt3gR24Fgt`7`P}~oHt}fm&RA(?B3^wY`zHn;^L+`pX?5fvn%?@l{Y>ZH?-Ag zyK&dSYW35y#dhsJAA0_9qWxV{n~}9rv&HVEf3z+2ZyOT10`YI!5ZK7S# zV~*ThZS0C-ee4-$4Br%kUNd`1|4li)y4kCg=@GI9`pwT`vRcg&1_Q4|-G@Oa}@mJft9aK8n{&O$u=YQb+_zCZ?4$O`Z5j$RJ z-W&MeTF`X!xu75Hir%!ZqgU&vw~|7Fb_5EyQNA|)epz<$j~*din;og~7s_uvvbM_Z zlo)%lGId+O5B+PknxFi+p?9KP(YLfR3_HNGt|VEh9=lsG`lcwHL*;Nn5hqPN8`1;(_+2YzSA_t7_Jvt=g>341VLa)7U&ctblej923{;%U1 zeKG&W1|LZHwoF`zqKAHT`e@@xKg8R6ZkSL}pPemkS$XdB)4ST(AD3vpDfO>x(R^=V zog(w&?H{-QeL}=Tw147?T6cf>+OFuYtB-Hj_fqy`dt+TnV7fL(JaoR3&#%tGA;)$! ziGLgG&GP99j~;KEZ1;Zq*A6?e9L%z>+c3Ngc`u5&O zCuNNeX>zpfM}NMbBlarOtk$YS-9px1(FX>UlQuX+(X$sd znT>NNkF-x8_46B-J0t&u9Vc6SF)?IJ&{_4>-Z^5EzQXeMACC^{yiWKlATmcRS9hI0 z;N(cVqM!fSufZpqD~+>PO!>Qb{pcL=c+AJ0H5&$p+!JH3eH5P~hDXf#?AGp4A)`Ls z`}nh&Ib!bQSei!Rw^x8#UH ze=OOR^ug$mXhbZ;{w=aKkWlPP8_Tt-TuXuVkN1StLa??-7 zeH(Hre(s1J*K)*h2RmDKXj_H+89wQQoqxf8U|W7Fj~^?7-rv(YiskwjG;nm=PW?A@ z{xyPL;XGA!7vtro)C7f>`X91+`ja?gA^U|kPs?7x=BZ@FYHJ}jPwW0Xva@3Wnq*>H9&pG$Q4;?(`a35NDaKtwQ zx()70w}f$<6VAo)GYu}Ik?yk5h#~=Sxn2L?dUlk}&%ffh9Y@0gE}!K!QoRLC(!G3l5i{i0&HWo)WFgd6N+$im=MNya#N2IvyUFYPY-^z5hriT{g1u?9#cV z4;Lq=H)Go5;p&nv$hpv6|JU$Ip-`z7@I_^Jr63(o(tm zde~S~Nf2U$SvU0y05mBO4y7PKI{U98S((rWH(RI#UU0R73=Xzsv{@OlA-4RUnbD1J z45*E(W5r|zjyWVtYBgF2LNFNy1?N5Q)Z_lpYS9@18lH1)X(YKarTTe5VZ5Nw5GA33 zz3P`$a8Y@b-=f8-H>&z_q-Y5wR~xm-DS#;6(4;C$?@Gzwn@d$T8R)p-_Y1Ca!SVq= z>Hq%O?pi^waFa`|pcnXuCyy^Lw;G%tZL=}q7Y&@eXyD+){a3)<%TKw##PM~2#y&j1 zG?CT<3v0%$t!;cA2(^XF#D!qw*40tu)~p#7WZp z<{2gdvplyGO>k79k*-3Zp=YyA&o{SuHc2LJlH`;v)IadZ$4Q}I$9R!r7e=mSOgcQx ze1aw=nzV^{bC@v}wMmInlJZZ^B%?Y}^7VnqnFyyOi3oV!dpkTcDOAa=1L-;4^KHCdSL;|Gp%MdII4nT~WBx(hrep!m7 ze0d_?@37VEyB!szc?NeWiAY#dnRgN{%((<$kmuY?+Me9T!JJkWn1(4n=>O$ON3z;l zwLMfQ9zP2`Yh9@K{TEVRm#78)_fTG>eZxZauh3o#^LHe#vQ|Em+`sDonbcQp#jiSu zuYc5|1qUjN^K+=LRB9pKH_thSCi|OIh-9uM5h`Hjg~gsPQ=+GFsw2PKIY(4#7$!bG z_yzrP{vMdbvtt?oX5JVVxX{BN&J`%olkOGhSops@$*Kg`2z0q9c!`z{s{MkNekEUK zN>lTu6W&BqhuSa0qm^VEi&c$%&)3%PlME8e;9jYCORCVkFqG%b+w(c?>-(Q*-`a`` zh?i;K>V=%#8cQQbkj}=xByFDppO!TB>ozOFvuqFYF4z zue7!mCR2>2cHz>csF&On_?Q!lVzSK$WBijF)y=@3%LnxAJ)rmC9{={zMf0s%utIjc z%uW#e0$Ch99=&91P2lYddp}0}t1YVI3+|SbTIye4n$S{kLWd@jKmWAK7ixdT*$1`a ziRVXrJe=>`pho#$@OemtaJc8#{k#a|0qt4?yWwPXMP9qCvyjUES+uz1o^ zD=o8Fw6zxLj&!5SDvq_HukfMMm!lLnJF;6JD2&t=qkMV^Cj|+Iv~a)N<>&$lhiE@g zxsE|nHm(DnuW&p15){#6dFP7}-Hxt<_m6=Q`PX-U_4DsjDExZ#-&AULTcu@bxM}i; z`d?r8X)UYnGWx_U{ihjPHMoYX1NGo+CsLEC=n81E5vBW}hpG53`63QiC!H9Eo=D-m z_TqFXP6~VJ$z_!a_Ml`Fs)pYNQZ=Zp)nZJVMci?NmW0<~(vFc8nkq%gQ5H)d*rgk_ zWdpQi+9+%@=?D^MT*>8w7twj1kQ6CJdCQRAWdpnjQnk(GLy;x}hx7)d$`g`DN>Oe| zZ$JVT!@g)^0C*w3A)KBYkt+n%B#;A7NT%f*mmF1Y7H^9!R*enz#Dy67lVkspyl2F5Fn_Z3X9 z{&AS8C@#r10`SLSM*NJ1%u;78f^Z~ny<%8^A1|h_QET+-W0^h>XN3Ejyeu@?P)RR~ zNOklvdaa0t<*g5n9~!;-u80ZnAx(_8B@Xo@9gvsB+{c9G!=Y)q^qPk_aZH+7g#aA_ z{p1LG82uniBrK*P@C{@1USTR4Gn&d2ZDlQ2j0WN6XDk{M;0Lt~;i2pU)ByBB0MMy9 zatp-Fau`Y_7YYSLNpM0Eg)Ks{ST67+q;yhT`om#L&6q`~B3j?%Z8VVA9Ur6LFr?MF z8in7{jRqP{;!$MiXY?74BBH^DW0Xd<1&js-^$svlq3|*sZ(bI|5GY0h4Av+LLdInY z14)%z&;Wt*=R1?nB1;sSYK2LI%3F6J@8P`m8oBmr3@p?jK+CI-taUA5upAZOZPa~- zQey<6%VX%@DAbDU!;H$fqatwR=qoCfdN}ell-*2@Q_;WPxRlSb>sxdvz2XG$dUfVj8=vyT(^xjDS6`!vPk4#0Q6pFpxxB=BTrF5JN%2^ZdEG!U4JXF9GXuEODvAiH2nNWJNHV^xO6^{@=2 zz+V?y-i=yZuU?p>Q_VCg4f>gj;ULrGSH61owTg8WSU=T&fs?2i=&|K`{47)o5?q+4 z%GGE|rthrh*OdMEBUsA(G_veQ#5E2&bN7|1E7Xfco@W3cIY^5f+@)LJPJ;&a9x%8^ z1TI#m)X#AC&ydpcC7}u_?MYc9t>ovDqtf+^fVfn?+RStCX(%I?OA$U~J%=LKkQ5-& zeFpRxI=D+ul(U~CSl9LLH?SAZ73o~`MH(Gm7m|zXFdIN&5OtyXu{;e#X0hq}n)L7R z-||*~RZjMM$v0V(mj`93cpb5@21aaG`C~ZUS}%fDNG$ZUbMp^wT`Mdh7H@Sy47?ci zu!XV);j}sE$@?YBLkK0(8XJ|KJY7|2Nf_fMJhBOe%K4!lH@Fl@fED+Zw3B%@6STB?hevT)jLQ3?Twy)^*c6yQT= zlt47wSQ+3;20jmuDGsJU&W7`tk(3IF;-y4X@MN7yD}hPl#iaA+GGc_;lqy$L$5X`t zB|DY?-^=mjY9-GXz+;o}0OlDySx5!WPAN#?Maq;C@qW>QxIph|6;vu$ksL@xQvexe zQn3M5ph)R%JPrvDVB{jX@z{`xdK0)@jgl;f0e89SI9JP?E!UMI zKdvk}6=4B{ls|87-q;G1YpP~S>1|q2LTGp;-c*FQhsIPCp};BE!`}tx0G!ImQ)Oy+ zs{xaoO6_X3bfhY3#5#d-%Ez*j#)T(duDizQu4%GVrg$nb;@x#f=WX*W4x|?_lQ5cH zcx^Hc4R5V@1qPf2Qo72A8&RdXg<+(TTELZ3<4OewBpg3#k&Bs0_ozx`a-|>_OUNB9 z;)Ze{j7AGVAl_YzED8Zm8HX~YQEMrL)(8urOGXw_ zc^Q2uWv&XmD0)e8Ut=ob?kA)|B`8%EjdwuFy`bQ6AO%&`&*+9qmrCFu2*gVegd>we zGL;ai;#gx5ldj@(0+4cP!6ka`TV9JSLO5TB zxw7)-8X(GMu_}O9Iavjv0pe{)Pn`l7S2rL`DucB5*l>UqWkf1}ZsB6|?PD2fqx}K! zxdjJLMfFgrj|M4Slq*OLL#A!yinLCdD9a7~d)&Gz8?t4aqUp@zk&wQQ{#r_I$Gb{FnB zXKM7!f$uLGFE&l<&5mk)a8g~v=IBsnotFKM=Xkw_rRxnit*&Jc@QlL^&TH^Jg>Q_v zmO1df>J9G+K3X>0N5c-{nT2n(!N8W|dl=tK_$K&j*M-}mAON(e(W)TCshwt>FfXDY-Q7y|Ws%8t(F1!7G*-bP~+-rVp@oV1f&}#2j z|LbGk(Q>T9HH{{SOi7qgS5m!7-_w=l z|3~zF?N^b;)O4xLJ?6b)lR~PHmsIS|8BNo9rbeUYQVE*Wd|C@65Q73k1v$P6Vq!*m z5RFS=0e_wFV*wTsiBduB2x;7zgN9N=9NiA-RZ8LjJ;w>fi3I`yVAoiEfs^0Pss=Fv z(Qts4B)AkvZZHgV=@piOz9icxKGY@2fD{&M7=64H(YaC2@gfi82)x+taqBDa>Ip9# z6!Ib|cvZlwC%oKGs!Pa{4=+~}fc=1$KuwK-FbWCV?3RDXucYoBk+g}aviZ80YH%i6E9 zU)Bs%j;|FmZ(hNc>vwQ&Ot_>LbkdB0Z+BRj!?(K-Zc^hv?QWPBF!C}AcKBHl2Aj0< zd`Y7DGDW_n65%ii!Zno`@)CG}P8tk+SQE9bvUmfSpFzL`Qe#Bmq(L7(*a$1`wB$p8 zhPJxzV2MC^2&+lr#%JKCQr=Q>aD=q7 zpuT9dAzT+`)JAM4qeiLJMjHRx`WXMux4`2U3jWJR%h00N415);p=xk-*#_5R25_y- zvlL?t5qrmb%!iie0<2|&GUjLXR-=ifSvG0a>&J@~#xMt4R* zCO~<{7^yJQ^M{Cz;$-HMB)Dps+m_AxWMe*s;>CWm!WtNDRQ4JXx zvdK{bA4#SS>p-ref|wr=K9Ve%#4`f0L(i?{JUdFsD=C-K@<0+wbDP3Jaxu^rdIb=3 zS!*FlQ9kX#R+pewYq>5t&GsS&*%HIIQB=J%ye0t;86#-9TnR;T^UI#_rzChE7rZw$ zT??9JKJp$XDmyvJlS$Gn?R@!yy{ObiZ+VHqiixQ}e5m%$&l2EK}R4gp-G65r(g&JFk#?X*=dIxLGmpZyA zM-?96je=qMMM=>)q^i((G&N!{D2(0_G|EHs;g#j z!50S+#cu)};0bz`0MWz=e3KxSSfGKpL91bVbsGId{lCt-(@I?RRcQF&!p@JlXm~PY zdby*K3A9QJlLQrC4b4QUyNGWhMv8(M!SIk=v$@GuPT^Zv4Hf#5_PsF1Ke?f)M%fj9 z0Hcyos@KBK05$&)csRgy8Lx0g zCAj8`=t;U+=;iuwH1ER^f`FSU(1Q{+$tg*?7J<`~2-onAlqeKVT6%OJ$QD~CT>CCt zqCBVTu*+FSMoHaAbk(S#oJf42j@T~u+Vd@-sn>cI)@}9w^=_lN7Zj`ML(jKS;5#-5n(Mstf2YouNf~2blSW!p(d!b4 z!mksdi_t)$ND~^gE@G9v4$COC;0)7~rZkZUT#Dje?P-TbMmAzKK-_4^d{!gTF`!{2 z>H&eJK)~SPA3(wuHBEj{0E7{{BxrZi7x3YOg&!La+1T=J1*KHB@X^vPK?kdh@-Csl zuB>blX;cRHCXqz18p!Eniww8Z)?|wD+!=K82?n!@^}w})On*uEPptaEfy!WdnUPn! z5Q}`*s{itmn|tUnCj6yR!%8(uGYqS~B0eCyOcTVX`2!$^0OeHHq`~rxVZ&uP;2!zz z!0B8>e_qz4$_NlBx&s}-2PI+GG{FE?Hlp;tp1|~`00$PQt0Kr!8^R|qBS2DN zF)2f;7)!RKntbr?lag%mNik78$V8u1qjw5DlkuLMOwg3QoSxQ8hV(3j*z;75)aaE$ zPb5WpeCDA**eGAX5`O*Npn-$`eVIs2@PrtO^2g(6p_X0Ms=sItd-?NiH~BJlO;Cd` z8!li(+G&Sz>ceR;x_F;!|Gb3&8lRHZnY7FqzpYo9D4O zltDP+%Ps53ZeMU))+IwIrF{p5v|*^xAj!8x>WDuDf2VNX7^}2!@=z~w_Y8XrsII(? zq{1SrEwFh;y~Hnq14ocIUVX3}0<{nA%Ve{S@$H$5d;cZfJ}*i=3|&A_LYHuY1~*3` zZSAlp>1(;emsbo`BiZRGhf)fN86>lIUI52-68Ksf_-RN6)WidNyR*Mv%EjzuAx_Gj z$^)~5{BaUZKynPXwM&4vRZcth8Vi6`K8z^TB!eWg7=@4ZvTWbMjqBy4PBFljiUZO? zE){HX@|OzOT*V@@oqWYA5b04amrakmT=z>!#j=sL42l)6AurF6RLBh>mC06^9T+%f zDG|YCs<8oZFj>Z} z%FDQc-xUUX6Uxg*dD#>^yo_Y!f-)-B9k6m4h58Zip9>f&BjLe%%)_!IJh{9_6&S*k ztmfh@lv*yMyFBRxyn@K&?QRB`V9>llDjQ`6r~;Wub}NYEb}J;+%XQg|xbcu(2#Q2s zcelv6J*x^K2w`&2(19h3ySd^8KAeC@3WKGi(pBjmc$BV6mhhw#9>lxxWC@U*qv4e> zle;`*xI^_M7?i^elT0DND22F&LniVlSSOMP0!Jo6Al{8*5CV`vK@?K*WNKRUvO9Ta z1OQio;F$yvl)>nVN?=Ajk{3W=olD3z89UMg@{@ z4?J2zC5dJIWrZS^2ycl?kxd9>Sr+W@r0oI*B{X^5Yzn^{LeDf>9pBvx6J{+!C+6c< z-j}Uz77Hq7$M<&uwkZ%^?ZkJRTEouZyGf&A7c^RC(;`l*Wm~iwb{OB0u&J4*Q?oOJjZ!y*)lIRJBsJ;u&sHB?+Vz~?C@5zzr7(C^TF9b*wly^oC=0|2S!hifii;UWz#AV-#~^%GVXUf1ZAR}F%JY0FqIHcA^dvsDtPo`a!5oAs^=*#CucfCL}@U zsKcecA^F${0s(VT_(3j#X_$1r<3B;+*KoN*c!?fzcc;fJk|}(CGRH;V%k;kL3{5e9 z=H-=zULJ>So}u?$$8`8I4H4L{ywgtzf<_U6`S&%cq_vo|-k3ICeWXK=YMQj%c#}x( zaFdp3XD%IU;HQ#?f!woT0OiRCy^@R6#_=ubf?kTIP-IP#GYOPOV#AjrX`FyQb}P5k zTptFtADwOyj4FCCU(z{iEh8WqBc4%(JxMCL5jyWa2DT75Jhl?v;M^yfbWF%C@$y%( z6iQo|(5s7zeXC}31T5dee?sczHl=upkrxzH>shU{3q91Su@^4>QG?qu+Hik0~t}CLkau6kqp0-Bsx^!g6 zsGp}zi?TXqPMGExv-&Ph`Ev-QB3c)>n1ZtPxP;f5vh&L7WoM&rPl&RvKK0w2Q&(bf zB`zOtNCvudl80G$f_SrDYMRWvm;g-`z9wX4-_$t<#pBx%=DZRNP;yl$2A9ApHr# zMS5y=Oe)PD8*BZa^(t!=*=0u-n)|}Djri|IYBhRCx=@N{CU;tl8{gb5>poTr} z;kBOLJa62pk<-_`Z9N||V%(vPDY(N{DQUa}kxUSPE(E7dN)b;fkXo+&xxK$!zOZB2 z)B51V#&ZfAZK}ZJt3PO7YSVl-@ml9TTD|4(J&rSzqpXJy-#+v3 z&Pk7wf(Ryv&L{?e3n?h5U`mkh@?GnWbM_Gjc24-aqSd}>>Mr}$IiAG?6%7DL7Tgqc zzCwbEM!e^Ryw(HjPcG$u%qsnuf-8oV#sq1N^hV%Q$m)FPGQqFY#29h&(xroEXPg`x zWxbobY>jQt;)fm+!$DjKVLYht~kXlBXuy)I|q^XC-FO0G-zdAl`%8`dpJ%(Gn1d~iKfG-5AO-d0@ zDUe#mnw@rP^7>!S&5wz)p1nPJ#MH-2JbEz~Y%dC8BM^WWf;3A?kqc#tTbyG3Y444T z@v9eQ&xx{5KYsu0*|fzrv#b7@5=a(-0K5>S4k<+@r9f)Aq<>y_?2eDmT)aBUdi?0N zQHTF{3~`4GYq|vEAQ-?Gf;Cx6kxnU)TE@C;Tg>USODkd%qO1#ZuP$1@d*%ptQR5|$ zWC8(rAxLdfig-$a)H2fTJLhgZeEz2tjdlF!^h4?ACynqZX|A*|+6V;Tg&@t6Qb3~N zaaFZ7>G;O6yO+(G+t2!N)RpO5_8jtTQwbuAAOKwmPKT5tlTu_VDctficc)W_`y-KJ z1w`)-f&vB!uPiEH2;<&gq{ALa#z-fI0=U>r!!p`&pk!kP|4l;4-Erf3k3MP*TVF1L zF1hqK_;K+_kbaTBYOAh*Quo^Ng-&w zJ9Qe=dtgwfuX{7tz`I`i4TRTC?Gj#q*OW^ST}d^pU|7F_8pc*&l6ul7nu?^9dtG3) zRjeP_RIs@_!RB7UbE*ogr%J_c;W<&QVh**MUBYv!2H_eNyNPEkE<4-?*7rP~6Ts#! z*Wt25e8+&*U4#n{&*J$M&vdZ6$Gi{@7I%?1!ts2HXF6EiV?GE6d%MV>VyE$ZjOPMh zH9G=U_s+l1>XID3X02E7L={}Mn(X1rgG!&kyNUbH2f@VM+-#tr=P0B((WCA*Fp@E% znbeWJ2gtv0G9AB06ResEOrnDPeQw}D7*j7$srWUEW>O~_xq%v2;E-Ephf@#jN*LoG z_$+5oqrvPO4%E0G4@zRQao5|}6mU40XTg<)JnA7_RYQRz!^4ZaN%;-u>Tay66sTHA zp@)CcU)W*sm&j`;gW;IIbnOrC#FcY$TB@h}b|X%v$Z?rsYARki zpO~R;QZ~gfQ>)SpQ%AXsEpT#0T4o`SRL?YmTPbT&Cv#(WM!ZNK*I)@oL3W%wQ#SHN zYNY^-b(5Ue>x>9ZF{#reOI}Eu)5vg+Zi8Fl^Gol+l>XuNFWRrOJ9oBp5sh1`nzx9#l;{sA=%t^ZvcNwUO*{#hEo#0lv!c<_?Rx1SRId$kJlWs$(11Q^ zjyl~B)-a4&=U|pVLxsS+O>ln zzs9Cj$XWOevWOQ96)xRJ$NhWAW3X-h$~E=Wj^fQWf7`x$>NT6O!c@oziS-QL-Kwd;G1qSq#^ z8gaoJd1R^#723Ctjqg#bhI!K1>qX}3x|nC_Z(5_T4Kh0)ZTMIn(#`B$s&?4g7L}2Q zP3`WE56Sgf#v1XLYHK^R9QVHY-BN)iy7eDn?tiyb-5E`Hn0uCpFLI*TB|xPE%3ixe zjgv#Wo4aZIHfxufVHV?#w{F=}u!MfFVAPpW6)bfO7b^5!SkbaOaLR}MpBCSNegV|! zxPuiZ)mc~P)AWd=l-Kb(Q#Pl!Eor_HGu9{Ja%c01pZ3jp=o@cdczI8&8ztuIFtNIvbq1;?SDAd>zFyBeAcwf>;Et(xBk9dsmT}3-h0k&Z+nvl zi~~?34_xS@J`_~f>NTNAHuCy=cJVGx96sjrD=SZ(-n^c<+|#cvoo(O4oE7kB#IRqx zBd=UQEeyS!Vd~P*ytY~E=uwrU&E1|fz0xFixw%50y}$Mg*=%;KZhm^{;xu#7yKfr* zSkx7HC2I|VXZzl7{Yll)b*t5lsk?jo8gcfw?_Zntz$yMd@Zr*oryrUdpL<+!;!@GP zuE~h-)#gCtl?kZZ-#hM4?O4}rZgTX>|t$@48=e&PA@3(uDys+kWiUk|jqW zt5li;(8g(wtF=t?2hP1~{=%VmO)O5kYZ5iyOfy&G!!!#u2Bz7k#SQbBT0f?_uEojx zTy0UNiP8BpO}y?krkSNH#x!ZV*BM(2mu?#kCD;*s|K&qM;6Q3sdj;#*pc++WldwWK z5c2D$jv7w3&6}xFU&MiEz=8B+oCVQ<1yO#22ce&%3EYzj*$w9wO#M65bA%oAi_2<^ zvk*^+0SRR=;4*^3NWvL9_#=KP<|9*LJ^+hbYD_AQBSFHXN~Eh~SdyFJ2n|^^cXd)| z%*4N|q;tL>5a1yl~l!(5|lrL zdjnj05DeZp{~*EO&0k5XbdA(Q{JJBIF^OT2SsRJPaWMq$3d`|X{OO8!S6F5!l3fgk z#UTe}NkKBhAQknMs;81*@ZkKGR6V>=liy~x^;lRh!X;n zrx<=y;~p)wG{vA>1*O5wG^N=k^9IV5Sq_OWcxDDlM_75V!uIE92zb;!g&~kHr9z?c z7y3s)m6b`MTU3jKFk?dgj@p1n?@AkL<59m?S34el*Q?dVWBq&6wk1eF0NZK1Qza?1 zUqEa%L}m4uN7HUhVhi`QlLxlSf)VPmTwpTrljK+~a3mDs2}DbUCJPo>R>6}fvC@j6 z#aN*ggPyp4ivKriv10IA@S40}v5*tJ%woawmeCt|ZnR!#QBrgbUoU75gX5G%i|VA% zQ4dWbtujiO6d*O2!El6z9VhThp$hoKZ;Ngw>?j^%+cl(B+1+1Mn7^A@jE3UVU%O%b zW7fcWXQ#Z~V3^mH23rgtHvqxL45h~JZn(nfoU|>b>=?%n?Z@t%HD|%D?`p2t#Yy_& zUYbbj>tBxw`{~y$_4f66qkeYhH|l|a6%3`ydR1Ay32;*?mvOY*vT8@M&%WN-W6EQY zoXLWrcv8Qj*8Mxyg+>NX3A^fy3)_@bIg}Idr8Z9AzP8xoN!t#t-kdS7?OjKWlEFLt z?luESmj$@WyH;Crt9gY6g^Ud?lT|u&=9oSf&4Ntrs)~J1O(?-4jShNp$BKEsmDV3ehDRrW^Z868csSiEW z%NEuo<3SkmL~Qbe1y=oepeygMjBkVOEf=BTK&Y20`}NeSg8+M3|G9bh zuu9h74p$1jvh_XGCK<7Bc!yfw>{m6c)5u=+dR_jxUfX(a)oU-7K zaIT@Xln73BpTM5aqc}?`6lZaT;*>%_aY`YeoTLy?oKgrVPALQwCxvi|lR`Mf$$t>V zDTRRIltMspN+F;)r4Ue@QV1x{QlL21-=UcQ-yu1l&@Smoa+YHC1a=3K@h6awr-9@g zMI>je8YE{Lk(|qjYN1$uB`A#|tg;T=|9!*Dcf zSQH(M+(1qHBEr){;O!QIKS%WaC#O2|1b)#hkb~~r25T-4(JJj1&k=ts`-QTbuo)II z9f5-*MKorF`HGUtq3njPt5?HL8}`?Kw6qUI)n8A2W6Pf1xg-zk@?nGN^ZeSng;(hr zkZ!v+ov>3sZa#9P(lQ9YK6DQMIc9lv5`Ik|Ee1cxSW7><-#fJV^G+2AzSWQ2iW%l4 zx>1qblr|G}n6xouiOG<+8|LPhX`3`NvE6_K)wpEa+7zNVjRhszScE|A>A6fzYlIX^ zLd#fpNuaGa0+lw!q)C$;kH9BO8cD7^B-)ypv@HX7eu*|**h>;^?`I|2=zpzIL1L>v1riEa7AUwV|19!BZmA+|+; z4~csDgJAGRFnACQ9{(uOMr)&rQsrf8GM_}-v+{C$K8d!M#a;Q)a^?Ax2-s&O+E6v{ zTBCHYR85GhshW6DHSwTo;z8BKgPH~pkET(Eh=&CK6b2!eXp=XZnP`4>*#dIy!)h+q z_MD&pgK}+!CgdVlslJZY!6h)x~r2+xxE37RV7tsIPwMCvZ z(z4?2YP492(tHq57b=22{De4>ZQ|jmsOodRuVjv2@KKKwj_=F|gBGL>ueZ{Ce&qYR zzQ4I0@;Zp1m-p*2vEGC)&CTC$I`!O`<>siZyQf7PE}6HMoV4b{6Zg%P4d3^Et;7W+ z&VmSf`2LG$dg)fw31vGjQ5Kg=bQ_?lQPzB0^9%U|&9tUwp_i^~jmHzsk2mPrhTT|aF0pmNru6yS&7XZWP#tKShSUy-pwG`; zu_)k4#kxNn4e0PU@)*D3tLye5Ma>nDE}YYFlEqxJ)Q3&S?E2jNd)>toCpBmYC=x-> z)>TVs)Wc%#wCGQLu1ZBVwfCOEQyg;^J&n2i^?c+-BIq@*ec@d5S!;9c2R~e^ zT5g`X;^FRo<%%9PPdmD0Y5%s@%}r_yJECcF)~rc(KKW?i8bFZPbDVjjHpKM^R zn_boMN0Bk+nZqWAHT!z0d133f7H(O#-rVH36Mo;@=a|b?^{F`MYG*)^2>RH2d&1uP zbL@8i^oEls*4>hErrFlsqcu85RQ%UFE-eXmEN$$6A+2IPN6P_6YS-vg9Z)2Kc6MJm zbbL%5^OiS9p8a~>K=b|NMu)Y_$C@iTPBeVC>{#=OQ*}eW`mvk2@Ab0RqJMe)MIvb2 z+W4#pIzkaaM=B!d2t@=PsfeH>zz}dTb)+JKj!;ChnDkA6zMFbtGh@c}B z5p<*?f{su`(2*_?bk)N6fe23_@Sw=9PWiFB1^IzDSSx|WLIgbrBIqqDwI-GLfu+O`>?D3* zKk);Xh#$B~{J`JD4?HD)U>=E}7m)}$gZP2H#1H&N{J=Hh2ksC*@QC<<1n>fTz5g40 zfa^-qm*4|}sw-D+ddQy@K7i!U8pxktP5|v8b@q@&KTiNXowEY_1xUwa0kns73`~Hh zOo>S%Xi#V>ig7UjvBUsa$_-KIe@Jzh=w<<)6^Ml%YuhF`DYV8%(HkModfIQ($9OPi z!>#RZl0Wpv&)ZjqaIE`^s)*g`oI`@=4UeoOF>8N)wp#+mvy<zbS)uH;3T2Oz%_$@}GjfvLL(a@e`>ih8UZ?El9<;p{#9E3;3yK~zCC=o7%7+O& zMq*$0kFHOq(s4&hD2bQFEqmqR*e&wMyJfF3T`vinIbEM$*bKU! zNLxUU4{8%UJle!V+U%%H z(&nwOO96YwM;WMijQ-BDb;{(eX&Vfi{>Mbm`Dk`7)SgB(JIO^suXAk?>3L)>I#k_x z_u8b;H{0#5i78ZR)uSzVgv@PL2al?|8bWaHVz)z&j7Y%T`{Th$ntLZy8))t|>E4>= zUY`nS?zso_FBU-m!(yRGfw5j_m88;op%nUmVyVD<)l$g|3Yf73QM)C`lIB8W%DHuJ zo@ixB(;W`I{Xs;%Us~OV2pBTu5BprP{{B(-dey)5Z_qPkdxO};x%EMTL8dGQe+_wS zPMz}Ur_KB4oU(5GS_s=ySwr$xW+>jKTz~88)8B@bZ@j2p^t*r8vk7*@*dSB(yV$(y zGQeG1|AV>S_rBIjZ*H&-3$a>3Ye6>Lw35L(z02az%V$T1-Cp}uSii(0hyg`jYH_n` z!EZduspFVZ(rmvNYOze1U}^eAsu}qK?$+>SmKjNptb6N!9r|mBKdkX5p$o9sTr%Zj z+a`QCa>uBvb$E~~jKc;T|2-fU1FQe%=SPoI!#o%HZQ*n^=l_4{wNHh8bynfgP& zOO$2G&4;gC-2t%0q7xkxyY<>Rvu^iY2dZ~~)HoS(;kTF6wSM(&g|G-~t9mCpuBexJ z`F7ZdV7)9;4jLz}`{wS^ZROtybiC1g&W>_TEACwLaH&LRmuek$%hKTSu+Wb>*9oh1 zx>neoJ7q&_uABQJnR3-aWy(ZCl2jLTnIOrFiG-9w6qzy+MpB3(QzjBp3Q=UrL_$&s z=q+#Q2a%9ch$2%a5>g6LWXeQBN+B+pGKyJC_5e>PKXvm#JL+&RU@*>HUZ;(uR1ksS=h=xod8gdEIkn4zs zv=a@v6*A?&K}S0O6Le&)z+l-j0c7MqdNiq8Tk(I=*@tzB>@Q$55^&th##EhEQ6x|% zsj_s)@kMS<$)JZ@RIB<_m40y3YRSl&Osl0|Bwv=2!L&yHLFutwBS*%3PLh$eYP6SD z_z@%-jxFm*+RWW-dq|t1)?EarZ;+|=jQ|}P0qPRMXY6E1OCG*tLJpcgVWv?4ttGj} zhqMsCqax`aj?0&Y!(sTa_2)DkX$gVK$o=mlMRFEC{ZxYN=)fxlE>p0#$T29g z6hXnTqgC8pc!YwGED)MZSDbj|mk3JWioZLZLd+s(cmu}Gr#Lps)Sx8EHIzl@V`3Xk zUPiBE5;KBiMKbRIF7brZ7LYyY5fh1N4KywUj@hw zHuu0r&2Ch2mjiO?9z>yyX!63nkQ~I|aNlEU143Fq#?XR9YXUm5+>mgzwtL~A<)o~M z!ATL%f-ejOXFT(q@$$r_c@4hB#$c6B(_Icm0pxI_mSQmD+cS)2F@tb>>E)l?F65X#&cJgKo~!W8 zR0-@1L`UbfTDA{c^l==L8s)8L$GkQCaMTSv|H2`uQ9c?Li$hW~@JzvTr;i@@?s&1i z2CsixJzOQYR@GPWoLIG5uWZYUp;K!o+fOzD;G+ZJi z1(KD5{EJ7sw(m8#?~tih=~S91J=spdvp=`bA=@dMCy)*mvP;vfb8X8syG$BsZx-T= z7^?r?SxwNqM6arkH#ZOnNSc$Vf0Do%zlBk|`u+K5Za$i3VZDiw;`^ ze7I41qk$^t8-UGG0-ZOxOWcc<>!i<+%fbq==Q) zz@$)H_-boMT9T*{Ja#{h80(CV7YjYaE2KAh!7y(Mm5Cf-@}18MMf2E(u=BZLu}|~W z8Sn<9A;F010NN|j#M5-7PNy9Y&gzT??r0NRoqd{2ogr2kJ0>Bv zvox%LHOZ)#Itp0`Nk%Wcph@HKrjd8LJQAmJW5YrwOo0uJ4|Ej35ry>_9$w@g!Eb4P zN$&BaU5w95k6lbfog$OJG|!}6429+ivD(Y0m1I#T-!U|HK9PVHgGG&jqQU4_uQ5R# zDop`xA{9j1Ce$>D$Q2+q4hfEiDnwmz*huIg9Dee>VKmJ!6QAEI> ze7EU!Y`&N7zp$>?P@LQv|Cvh*s;M}F@>ti$QUeH`Rs5vu0(w!sU`f|ScI(owD;;s= zBnTYJOyuys%*fE~_-$hbHk%&qewaY7Xm>%|uRA#;M^D64kY}?C46N_JY(|BB@|ApB z2h~&>zmWFicKZu?&0o--dZ|5o{zHRGPSN`H9?-YfHzLI4=+=ftEQY5zrFX%7aVbiZym;U{`bcz5qs4Oc9 z)P#aRmKEAJU}4Sw<4Q?-akunLdX-w5;}HDegCVkauK{>t#TnyH&pn$Qx_W^@4)GsY zYpT79ge^F*khMl>Z6e84e8E{t?eU@o+@Q2}&zEX$j?dlPvy|r6OI_CU|D^V=?rK7e z@P8WJRclq1=Yq%Rmgcq8)SL$*vF30Uze@HwMzV}Xz6a9-4{eZRc8A2DBJc)fIe$|I zemaRRg%t*^DoO=kev|>U+yX8JP=UIBmJuRn5BS6FUx+8cnsX6x40w^58F=R7cZ$RX zFbE=~c@#&fr6joZ2gE;rW1t6FMiS9v6B9XQW+MK`X2!XUSc+@jk%(RGVu@eCSg_&Z zV$fpnM-OLBs{SV38VNqK$w7tu;kz z2S^#Hz)Vsm@&-WzK32P!z$ZWaKjgg!TolLKI6k|3$591)*8_WO2&j;p&YfUOG}hP? zu`4$07*S5KS5%BW6pb25~CtE5PQA<^UUtvEd~|8-}n9L`}rSI={0J< zy7={CYyX z@C(2ReYaN%ynMF#chP}s2cCuZ1zt}N!a|h;9F6d`t4eYFLhPM2hrJut9P0`bC@>@f zn+-|w4}O;jN@?Md6`mY2>e9kvEE~uIu&>-KZ^#?t$f{BcO%RbG!@ z(pX^HRanoNMuz0lf{!*wV2i-cB^qZTZ1HETahBdOT1lC+q>Q!{%qb3@rKRQ^K)RH=8ExWf&tK0*Gfl&j;dEveWeg1V6;-8a!}F zzb=EjckS*Y$r;t8COd!KI(F<9Hn>~Au3ftihC+g(LDV?^IU3%|H~TPeAR#1h2v88n zQ+9kKil_sTDNKWkRro1Oi$ZCrY(`Zer$nP~vZpCP5W# z$G<)u2g{RA+BTD1VIZ6KslV zEhGB~Lpu14u2O=H*SP@vJmJpfVtOhb^i*)Ci=E`dOXfgn?IlqcAOXjlTqGwc-0R^| zWFBZ5^qjb&5PnQs1x-kV-vSlkw?HBM>O{0w5q?3i&B7-|jQ0Y)%_6Wf)N5nCwDMyQ zBSh<&uaq%$K_bv$B@=ftYz@O(g5WAznF!R$MBt8C6%nXa9SwNlqCx~J?;r%M%Ggo@ z%~gkZ5h?raaq#E8Z?=2ilr!G5XA$-Yz)?C`7s zvr4UtZ6GjA2*xH8j}DA%W)0xvh*m~7q5w6~3UnhBCK~-MqoFf z^2=>qBLrd`Gb(`Hn)7c`Qe!$ce*=50oPi5G9c7S!x*Sd<)812yu>k7YQjTp#vJtu* z^yWpoX`QBA6;THW(AAjsq&>7ENoj+ptsNjOfv5xBf}Suu&}-E(;+nsjT4!+REAXOg ze9Pm({me?}9P=~npF4VT3;cN}ea7Y{#!>ildFP*sklO3;=b?m=|Mb|m0e&LNDt|#W z+boTmK2AsDgLJP)&YRe@7?vfAwoN*)*@!=T&)RbA!s;IQb41Hoe|hDdgFjchFWc8> z$r<<=YnwR0+}KzE9`sye+Lw01Dv_f>bXTh`7dk)3ajQlu4UdfrMrj*f(DNO+`t)7v z2mN_eq_Q~uT`Lh@7xYi)KPhj*@XdL*RKLFBa4bHJ_kVb(;`3|xwB+2$OOG6EYEgy- z;P#)o_kQUJKM}&`t>~2Qdc6^rJD)FYgSAROtbPBb^W4<#v+$|Y{sYs>-P{8%O3)SQ zFX+kXJ$Guqtq%RTpE78X$1)Sv$$vP1mD6K7W1W!uGq=Z-9EVRAn$AYonUVlcW8>rE zg6d4(YuQ#<6d5p(w3SBKc8pb+O=rM9{kxh zCU27&7ZLS>!W?hZm@@V#{#1cM-L7%;hCiNfzXnUC{hy{Imqs?kvO~^P8GN@O^Aat0 z{q?a29E-Yk<;v;Vg^HwNfx)ZxbzWZg8UD1x1SU_le`Y1Em4Ov9#^Ssx$$Z9GW)@?A z;_fr-l-)NG0bQk1*m;xHT$=*QzqH zELRS&R8M~QBDU2T$cP1!;O{gAt<>8~iu^q-a%`qapV zyHTJxGRIJ4>Nlj3JqR*MtR1VFB$y)_Ky(JdFMeePK+wOsf?7F% zpl^UuScQj@;xHH)!%;Ff$c#=jA5kZKfE&~zUiFdKKu{5M?-d4oVJ~9WW9|p!BwSz? z_KYu$7)$g#Y%;QPlifrCTt5ppEfcIzz@`h*gZh(gG4{EcgKcPthL`6?Q3ruGnkh=v zyua4YVR;L>T3>uS!Ico;Bi~jC)A&ibxoB|XA%|`1KSbNV}Y0C37!I8o2G$Q?Rx{iLlJOua1v7)W(u@d1gr-A2+_tM2F7QZ4hr`P8nar82@=oAaq_f9~vJIBSs z5FO+6x;PxFTo?Ee=iXXXK4upTzyuUm@5a8pjpmz>VlIk|0X*O#C zt$uU17WTmbLb%<$Y>+6e1XN$MScTH%1!#gOEdjtNjEgAgbQ#)X%uyZ|hh&cn6FEB& z7X{Pw;;%;07EjJ}XB3Mm55-Vx3+sS`JLNoiR@4&~8;alFprRH`cOf8Ow488_+faRQx z${*+#mNCvk6_W;&vXTkD0w1Q$tQ{S=a^*LmA!8-W{vHMo@}4*b3ba}9A8PDab3)+d zaxJT~W@iOnysOy?*`Rci(2H5P*mq_|N+F@|z|iX}pz{NKY(`r-z%M^rcw7~J&1J`p zMBy`PU-B1YS|I)gX8zCUf3(t)%wF}QkUYuwKCVd?Mj#tK&F5-pmSMB@d1OOIF@!Xa zs`C|;GmMH-vjq-zwxE|6&kZn#|q&4uJxd!Ia+ z(aszGfy#Ws5>oT(Q_-?2I z$cD!`9Lck#lR6TSoM(Zyvpu;1r#0)@t-s(IQjM9zfSYe%^7Dc2 z9>Udmo%;0ZO6-Ey3FDwWZmd?rjdH-_d=%^j>_CV2n4|8Vn`jJYmkYABIC?*`241%X*9hTe4K#~4Sb8{`LPJa`R*rf9!!y_yrH?Ei zFv+rLCK#SG?P7v9f4BeftiBXP8oR3HvGd34P^TY74Pp2yg!2)G>{S=?g@Mn zr=+JD!@Zp9RDrAMfZ5j!hECyYNC?Itb*kexVL7<0+o1rHp)SBd5iAa$u*i|3Ixj9u z0+{)%^9FwKDgegAhK#cWWC+GtLJ9!VAD&q7rBLz&EWfHCubL622bI`g|h z(LGvl`*8WtoDY64iQdrTm}&?aoh_cq;i~@6EZn&B1aNHyLcOdj4Tznd7Q8Vbc~w) z0vE+;{)T^@G!NmilMn@RRbi8c^AHj>Tp{7OhSLidG+cS%u7>j#o@zM%uYeM&;jJik za=;__`1$?o_UeyH960G(Mb2d|*ya-s7P(7QZbJ0k>gRt>Nql;hH`>%%0g)9Uoht6q ze0#;|;5GWXYG~K``Ok|D8VODN3_C?Fv+kDPaPWj!OY%XB_M-;I&VKNqC(G#u0C z#hdLjSovEshF*1o@-)A2NE=;h?0oi9yH+~9sHtQgy%&u zX+(qRTaP?}_68(0_P!uKY~s5yU=E~H{(L#fbYARrcJ1|}!I)ooQ^lXoi7mF>{IPpw zNP8@dFV*|3xa>ml+}!KO@cxeO-6GG3HQKmtnR6J^&uXSEJ}rL#cJuee=0iGoT8p^t zr^HS3Q(UL_g0%67G4f)vxIQ)Sn48~1I>q?yxK~Nyx}D<+7j}cRcdE~#;z{E90qc*H zNy&uzui{6JJ0Xrap7*3?Bc#o>x*R%vOl*2Iyi&qMNXO=DB$PcW-fA4(#p@SHr!=Wr zEc~#zF8}yit^6Pj6eWM|pyXPGcAKrKb`K{BQM(-2716P1m(}H=d4t^z3xEAV{0t z|2|eMjz)NljnN%@2WtpCKa#VgZh6?xi2zE%3w&|~_>8O$87EQlEqqnu$Jl6o};J<(3R$QcB9tW)2C#g{XbiYEoE6F+t znMs%FRO|0Auk?VlQLMEz5^-TJjF9 zdiakL_4u)ty>DJsCc$@T$pxA5PoDQRH0?e0xi#hveLJV2Qwz;>OZWUe0!YdoT6e_3 zU5_=BEp-cuH>@Sos6n60==W-vB{`A*(`g5;Xt=T%%(xd+N??`MK6-M3Px9>%$ z;g8DOQmxn1C|_@C{fiOP4Qt<4Id3g_myTLEiQ2hP5jejifxFt{0XTD8UV}%&h;6C;EpprE|JdRr4gng=Obkli-K+)pOT2LtI8# zToWIZBe4%@?s;{cBF9d(gdcs{hon5DPlo27Q_eiYa%^P9FrrVVGg=HDcyaU$i*sGq zvLra2Ua^)dM+O)zzGtW2vBsp+gcWc9zEZS}Wzu-}v)1eBwBPiZM~l3iVCYe*f`;fb z=;(Sr-5y6QH1s_8&p+0V8Fa*)HCG*9jW@JjKF*oMX3&|hPn)mZXl*%0I~E}+88lzU zey#7AnU<&9*S@fpd_?zbH+SFhYKmp`%*MB@9Usy3)S3nJL@c)aUE{CZB=!-tJ}sbi zCW{OW>KrOeQXbLRpD*2fJtoT1@0WM(M4w3mUoUEu^md|U=7kvOe@T81W##~ zVeR;s-m7-JQ7hqh%ds`Ns*u>nblB3$hQvOhrz}mPI=q@>c^p_B>OY|sS`>Ux zCU=;{J%T@GE%}sQX*q1{g~)k^{u?H|wRU_;b>)+)r8-TpY=2%n(;D-X@*@WJjCnr6 zFxv0UJ?r(Sw04?zl_>K}3lXzYm9sI)ahfdDB#FwcWkO*tul|}Rh=O^DFLC(DdA43-J zi3e^{Ry&1BmVAZP*(9cBC!C%q$lK<`~U z;)9@J_#jWKVSEqBRe^c2)r`0Ovi$(jE9x#c%PJ#gD`S_AGHn7fF(@7N=`QgtTt4uR zVQGn(VGc}cHpY2CNI?)wr+-jRMA1?$NH+H(q2&7pve*La!aiCeL zUy<*T28}VSo&68cpxbXv&On;7!?ZB*DA1J4;r<&6G~$Vl^*1jD8c{|Xpz);7U-cKf zoeF16t*519j`)M+eF$H21JGpKXZpAN6KJyAZ$erljdkkgzVBUt#;UwBt_#vk#kw8H zs0%dH15=oA8)%>xF-0pO4b-_oi>FA_92>FjN2F;Qk8*y#InQ}9#iwUO@yIoL?VndM z$YX6iRJ|kPy>=sZ+mVnt;=`Vo73)YWua(q3`Lb?$-5FMX9lM@?wa?&S{cNbHlA(Q6 zzxg);>VHPR$)prtMtGW?0THS<*`D)%Q+Dd_uNd{_;I#A2PP?g`c5(pJ2!1Kf^~Wsm zw7pt6Q3ON|Okgu&QT(*le=I5zfd4~=k-lFZ{(j!xpR)tjtdWgfWIWsC zWD5_?DEM#@!CLU|1rJ|l@eu*W9uVDU{%AmVr_VQ*gg_eI2A~TshjqcVV@SXL1H0ND zI06wlq|e~)zS81@(*3%rGeK2h%akU*k3^ILiQc_W|4xGk^%~qAb~7LVkOFXC$0&g{ zsA@$sgi`R>OiYQSx0hlm0wkSUZttb3L+W5D^bNEs{_9%a2*?DkdRa3824+$hNxu3h z#uuOjm@k2YFnhgTkc`hgLE2kEAj|@awZcOyM2f+NwM_bue^vAdQN2lwzy|cJq-@VV z7T*jHJVMm(@Q|#m1d}&w(E}7V;PE_OF6$qHy&^1q>hy9d)wxH}rqz-j)afdkl2 zk~MJFm_4Y0%c^#R`Bn~~SQ9ABKm!&B+8{pO#+@*I94LzrGh*?dIItIq2ZauppU4Uw zRO#?wK4PnrRolkfp2x=mMrEtw(f>DvPzU#KJ)FaTr-ySe$$B^k(|@Ul)77aAdN?a# zia2Z*<_j4|J0x^WBL|QMrctjd0Xu+B-ghKToGLF)T`&$bacYGgOb(k9`zwTacm`Uy zI52&MU#bcI&}3zK&cG`(sM$r8LIxH6<+*(5nAg9DTE`ZJr-FI|C?x#E`3sXcE|Cb) z9BSF(n1XE$Q?PAg3bq4G!FHM{*sd`J+dZaWd%+ZJn?b>L9~5k>n1XF9D%g%Q1zQ^Y zn_Ke?9_JP&qi$^>YS}iUf^D}3cDWO%V7mwkwl6J^fxV@gqAdfm=#%z$etwEaiG6R$ z8Q(iM4!|$z);x(n1{}Xly?Y#--THAA@KC}}irC(}8Q4*urBQY7fv)9F$t?YEv2lQ-^nX}Av4 z=BS^3J|}K>t?FBUCZtKBp-KEXu~Z$eLNNm%9TheH$cnS##S(waZ_*snO@&s0P0ot@ zO3zr?$`{hc-g|34J0s@1vbgt#e3-xD?efKE#6}$sH1GNhbZsjp1TJ1vHE?9PHEjHks3t?K1zWrno5Uiyu+ zQ{w5~sVC-kfpm(uf6?eu;_Qg!H_Ft9^u$Y3_t!opM%HzxWBmrwQROQ9ot7+K-?{#> zmpi0iG^p5jPO^CZnqU1Hk3o0$V%vfqrex7r{@TgF3y_|d9-Z_cNj$V9EV1@Z)a_j^ z^v8lEadMfIy%F({-rA-4?fOZg-`F#ywG$zoF}|+Xy_2F#<-$cz^o4Xn!6Dz*KPk2> z6ma@t3rKr=)CyX9LTop7V^FzoF+VNHjXxp2ev#j_Nssl1RfrEhF0Ol0`_dR4q@(6& zxWr@PjCZYnp79WLe;$)sRnQ+3(;B(NUObEG(bEc!J}Oq+?U5L~6Vgeij~%{oMBI95 zNX62BKsqW<6=U5aBA*m<+-n-7Gm7^dw&Ji@?ANjT+Yf=XcY|JiT@Q;lYOHQ};%7)F z)?KC_a7Z+sX*_RuJT-hgn^LERMm%C8+ zc&b^Ydi%sxMO}X__9vzzEt3=Wir$;@1rMB!>4v@M7u_p9jceWd)ksJimqxXmutyZX zE52|;Pe{iOf3fZHZgJ<+8Ig-yV7gM7L&3Yn?;H=W+)^9T`sb}9P9%z(jel0;zQO!= z4X+pyMIY0#--hRhwD||i&eo#1@Xe{>dJfV?<8O{NcZn_y8aI4$A9R(*m$l~=+$r|z zHlz8|3y_Yz@MDjcJH+r&t#g;!59#2l`r%i$i)m$#4h~<3y3O*bdlR>bn~PL(<$i~B z;=m2{mTeVxhHf5_Fd5S1uMOO^E#hWNdYQ??FzsLW(csPErD~0;PwR^HC-lwr%O>$^ z$8u5Inn5}x?plWi8^uPae3s^-kd6&$e9?DQgs`V7htpM?WnP zE4{q`$HTUm9(}TNt>46`O3B9?HiR@;IrVkm6oGY%Z^$Mj46h-y>CKYfPh?N*-U z|6INBSh2yNyX8t3!u0(;LY^>j&boXK8b?f*9`2+G7K^+p`@Ccd>UN{XK2GmX2jA_q zr&t`OYgIR0nLw+|AD!UQ1$Di9_ANOvn;u{N(D1Ab=10O`cm6WTg# zri-urva(V+%nzwP^b+jrm3r6imkGM!;9@@puG&WV;mhOu?!vU&j)P%4XkW*gealWk zU2>{V-oTwy)8^-$(QPpQ+JI`#BAptu!*^3zNE>HX%-+aE}Hx zA#MJ(ca81)==a{mJ%4b5bVhRdfZ6-$sPxQncP@kOIipbN;~@uVe68SW#n(bQs{8#H z#)EWuo74367|bv7G%^1nI%SYky0JB+&Cgm^NIOK!{je(Pn@W&2zTj)@I82i>XXlOO zAWbS2dobk)Eo!)2I_5m;s<{r$+8?D+>kewmtbuf*FKOCOZ9ek}f`Po!wqMhYwxa0iSr>HI{x?GXOigaf~8iL8;tos_)e&i zOdS_&_=_}wbc0eo+~y_IpK5oz)9@Qen~$YfUnJ9D{>dE90n$CYobTB76s@o%rAwI` zpc`M2&&him=;}9J8Ma{;q=N%J1{OL^_mr92W933f7rNiK?6A|cwL`&7-Ec^IuYKL* z>}l$n_uSR8e`lR>o4(D}wo$oJ;TFsOE;^EM zn{t<~H0Zf|vgO(C4kbv^ZJK*_!^OpDq@ngR?LBMyZQ7#pjUpQJD2sXS_*}#zl{O#l zG@!e6gdtB_k2lt;skHQjon>#3sfLi;qpw?=q|#H|qkc2_ewL_3J={rXDjmG2a&h1CiPH>smMqc`k2}=2(XD2uA|@GTRGM9oc;BI;AA4_3dpFs#XppZ1 zX?llRs(0%xijxcnCe_iC&^vUhv=bA+M4?%{1~lQdeTv-M)es2P^zJceu5{%Lf(f7#zwjtRB6 zO|JXIIwOsyujo3nsCj~=c9nTot!vY0&DrfHrx+(#y1#A+<462mxZCjrH8flFNKZ1- zsB`;?W<&=K#uv{2uQlUMDUY8YO8t_Nv)mwFEm zyL#l^L_>orPm7b#yY%v^3$=!tW>}j0wk<}Y?$SI%_l)Jm>6RaAH~EGn+@&3<)u4IX z%aUAT&3Ws|yL4k{RG!q@V=Q5sW)H3Dcj=OAxl(F7gc#bpb-QeJzel$@m-Ij6(9Y2M z$jW!ts`qGdL#e?fxZ##7+vi-gHn~S*z8T-s!#dousN3(QN$5RVyUF;Zy4J}CV}S`T ztuyY?mwWg8Htb!vp~+FrDeKyMbYI2HhvlqYEOk4WPFYXhqn>xad$`5g$8z1N%L{Az zJ=(#g%3SdFw6qwy>2It1eOfqVOLW)WQw;yKe)Y&&^*()Yz-yihiH4_9LAR{w z59p+0%@3R+{S491RvovxKcuI6Rn{9LBP>@BHNR}F`jB>YEP7-&8DU5-P$$#cb)X^lFO%@ccrfz^sKeT&H8(867`UBhg^P{W*%z^D)`5B>)MBOlRogQ z0|_(4MdT?$k{;4o9a;sy;G0_ZS+?s)2H0xcuKsh7ah!#p_Ulutdpgz5Ob@8`x{2lB zOZIVs{51v0`qLU518~ypl+CQBR37c2!3E$ab+V}Er z>x^{zL+Y?6$s>muM*Wil^Pf(uEeT&xnCox({pPS@Bq^P)`|HFH4@VC$RNI^K+?t+F z+f4}NYHIsg`UQ7;Vs+1;mz;|=Ts>;CrOmJ7A6u(t(3JIW_V$XHYbogV=B>3!25ldG z)bE`**D$8>ae;(p(4(zxCPtDmhC4?y0sk^+ks&pAUAOkNbi3pV)~6ZtUfJ7gBIrzu z|LLV1Ny?zlV;T&9HPUQ&`}Wc+YkCGv?0qg&s~Kkb?d^6K;_--fcIi9zjCs1@=O?#b zS*wC=NR78$Ux|wi7Z;p`{r3@F(=<=$FtWg~;3rSm{~pnY*Z#Tj^6fN3*_P$rSZ6$< zg9d(g#hc7Dv^CVqLlPcQP&=E4N6a^D`Mtsm>&Zv7$JCfrJ}VznZ;^tl1T?vsWK{+8)~@d zS>dU*eBu-hyDKv4QzI0;B79_&}HMCRBMwbwB4ljTYFh28B&I50RNxR zmYI7Nu1lO_N!{H)-8$n59r(?+nNG%q2F>zax2$WQ(7Get#4Xln%e8VI1xeBqS}Wwr zfUb%2EjMasxRZ=0v{;LAE|VhW8j^pwl81Oar8SmzAJ9z`Z1}aDwgB;dN}YU4oj4)> zW@!|9`M$NuQ+hs5s~yNsvi#YyW4g8fQ<|si;as=Hg@!yHw+oV}r!*>k?dbiZCK_hd zJ}i)gr!>)3baphwSS*Db7AHwhX@&Y_UVk%so@LUnTT`v+PpPKY1M`+q(H6q)1F*}K zrMU5&MlD1lQJz{B(SXa7Ma%rv=$QSyeX1!+lN?BLYIrM(NxLM6%c9}>|C42nT|&uB zY?y@DCLsm+Co|vqw`mP}6nwU2&BxpWY=$+GS(jwNAO!|ii!QU+)y#oij@SGl+tp0u z(XM75v#W{v@^&?VmHwY)SECfRV`a|di`m)LTw6KS{Cvb&n_bQ2zKP2-cAc`>)%5tb zS;U$WNjAHhw9;diU8r`{W>?c@SfX>2)(32MHDvUngB4fqw%OJEl56UTp+9c7+0`5? z)~TIg?mC-YO$pb({hu_C7nyjIAiphr6uX+SZ8Lvf`Nv9|UCqWSHCDFx#bUFoalEV_ zcB|}un_W$4eJ{81dyd-dYW^M-duWO_*=ASc^l)=)Z_ODhUFdk5`bBPSuq0QK7~+!R z(!TXsTFT^{`ObP>{J1TljC5#LlbtQ$*JD)!{;|~+^S~VJcz%A_#5ek=RZR-&Nd9N6 zYFHHCFA_6gDGtJZwy{8BXjFp+8(Gz*%*Ic>&3u&+1N^-GY@v2?FzY_ml`DwtI||3t z&KyPzi1_I4VmAn7P~^M_Z_FB-Pzq#BR=Ud(^*`oT{&hqp1o-)X2A$xeD3jGO*A@7o z5lqe^F2o`hawQo2l&FNtg#>okeK<}D!tTp^LHl`E|GapF%J!tfJymqCi2sFngoCn+ zN60JIC2%c2g}IU1Cty0xhje}0*B*xu;2oeG zy*YxnVk(;rykW=rkK+(Bb3LvU+k+H$Fa&*J5H|nFGcg-4~5vvOv zGGI>dqk?ued({7E1j7HVO)5KD2RA956sz<9*e>PoqmV8zJE|#_e@jnl_(^AsPxWke zDdn6-gRh*O(<~?sSC9n3vVc#9RrwL2ClCjlS=-q+A;}4eXowP-K?&FJg#%cl&0N4| z`HWXr;Hz2%cIf3aVjcL81C`^BR=j2_{v$yxyR#E)g^1#SBtz|Mpl<>`$I{TpFPptX zfm+UEUb3T%W4FJ;Z4qEIw&c@@ri1|b!iZMY53DUeCsMl2*eV-5%XyS0HN@c3F1Vg5 zdjd_3WHv9iFAOqRo7JlMDo1<{b~eB4uuO`>EZc(1HsJhmTz;C*H~a?6?mV3O`Y|Mc{P*+;u<28RS-P9z|_xX1`YPCXnqY=h>(x= z(JcBmnm0oNte?@|Spa+M(yRp+@*y#yvT4ZknUgcEG*5yAUH30;$_z8_W4ppD2Q%;M zt&okX)iM%q09C82RfW|fE^I3Nf1Sq6NwvdLKVIy#NVmSFRhZhL9Wrwud z??pKo^~}S?2Ii$Wb#{7!O$dTnX@`NC3B|L4v&&ZjXWtqMl75vK?U7TA9`e;=wBP5P z8b1GTG1>;^Phm6z^Vf~h)vGDQa1Jm!TN-czE^AKSo^!@{umha~#}ICTo&#P(&&6kd zB|6eH$}TKz=wFzifxWi6zar?%5yZ0L)NByTIT2`w*i;!}(Jln6?A05pq{#+|DH|$- z*cWFs@O-La6U^rTW`4feXsZ>N;cbdJWN(wv34}YrL3n*0yzVeYAYaE1{bJlP(!%Jl z5R9428-Wtr;0Pfe5U>FPfd@8EJY8f{cnN2a5W7?Hj4_)dB1Ps)E12Fv7;&td zC6hU{u>!nav)W5LUh(bIMY53n^1HHDf)?%J^uqMo33@)#OZJW9#W>j)hAlDsF*=DY zKbUn*-~Mnf_?KTFHGMvV-p}?HA7!rD1@$@GQC6|JhH!ZTaN&68dBLG32xW-V46!zp zY5ol(BqHejd4kg{MRLd6DPf8^X^Kq%PjlFSUCQhdd3NRJ>}GUjVh2kN*xG~^ZM9i+ z4|BL)GeplrKUh7zuxqwFiysU~jI;Q~rxDj|%>ZQ?=3vbR_$rLCil$^!Cn&e|zURct zGfdTegpvp5XVBnIU3zy6?GFl}ZUcpg5BlnM>I$yAvahb4!DGa0R@Yrf^%yKU@{W-f zj`O6kxJ`_Qi>D)ayK8O|xaMj~<7@(^uq^=sZNhW|PH9c)W`;=MXUiBl^j~$MxaBxE+*=FNz8AYiqFCx+#bx=*B;)0mR%F2{_) zv~RCW!=)n{tri!iiUEhH`;yD?W*mW1mIAR7n3#=itsjS4pD&GAaLW4F{P*FI{iNQnZ*&V9#ZHIOnnEed0fp!@vSQ99rDp-68Nz?#4=?8?H_N(TXVpI0D&E!4;$bFpq zb?Y>+^KiUoQNC%O5k=~)RAalwL`T1Z-4XC`%`gIE% z+^IXzZ(n-3!D_2!6BOlS{%n^ZWHWywbI!X@XY)4&<}X5;zxFtP?dAEK#h3}?S@fL6 z3+|r66@{+ux&g}6$w@CQO!6iUe!=%H zdA72%dBE9%H7U>5*Knrz_}Hc(2lG|aM#`w>i^-ySTjU^_3E^J?!ju15=7S(BlQpc+ zzj%*6@9`cfz=RO)D$m)Bwm{XSEsd*@@J7HEAa7wtHPU8_jH=f52(ZcwX^H0bgg6^O z@WM4hxEke3jKhISN=sQNcx6MNkq}J?U&uZYkz+kIbvV`zyq>Q^f$QN0*_s>+r67t( zgZffLOxOgx;529n9pgPUc##X+7c>m#5Pdt(+=tq%Fy&Q^4+A|oX2S5aqSV2*tVSr7&z@#pE4VJWLxsU|xwEX~z zV@V+C?Z~biKpx;4s?haov6%WWa@OfMT^^2rh7DfSRzvz}$zKpZXf!YAM4r=K;=lM2 zg%pLaEudgd){M=3NVR5|34=CR2#26s;V9T8!S6Be(w%GkESNds`1vgSdl$8E*n&C) z7h~LkkC)kcM$dp4c<{g>{kp&{%n-GUDSmCsOJVe-<;B~gZf#)83$8}sB7{+L%&qrz zxpHVN*i&sWtl+vSz%ox3Yzt5rj#-G4$Cd!6aGP~8xT^rGQG?HwI9rIkGC3rL)$$~; z5}*mC99uq8TUiSzybxg_`8dKp<{8(C~FOldQS&clPtCtyY&zrI^a1?@GD$| z(y$&KV2R>S)(u;>@=PfSW3eqIyrObL))li9la55=z*fxQ{=+&A>?)IN>JWX7z0N zJ7vv`gf+u7sM)WXk^lXg8Pweth%V=AW>AjT%%5z{EMu2~*~MZ1(W-&ahX2c}26$t_ zA}GQ_F$dym$+A)`A6Y5VMWGHrBJGk_3eZUSQ(7rXw(?9bmwbPvuuyaMvxS+R;!1Hr zLP}aG-E+KDAV^&Sj+Ej_bAfc%kl|V~9hS-hSSn{>slt+A~SY2jqIR(xw_ z!{4|rD9@lEWE>j7+y3(CT{YD>dIGtdhR9c}cK9-hcjLiWp1A{^|T zE1OOG8zqg(a38W0OMy zz<%CyLL^QXPl)ql+>Q9999#>`t4?rbLh;b{g!?3AB3Q?at2`YAqeNgj>LmfOGW(2p zMAB0hD?8wU?I0x-xwO=xLRRY}vKr*muu*tv+z8T{fF}gLbnnrbM>wD}Y`yfh5%P={ zWj#|mifE`vt?_+;k;tk64R4dT!>FLQdQY7)79GgOvD$~mf@Wn(`&rvo#==@8p1Le! zfkEI{9Hg;$+bq)7;|$nQUpn51hIi@+>X<&=hW1eq9|!=A0CN{w4Ilp7ebq%L5dbEh zbQg3Gbx*ez{@>1V1Omg8X%JO!J8&yC0j0N0*YZY`8abdw+)D@OXL{=n@&gkpW3-?R#p?^82=H^`y_|raRAfs1 zf!Pa!gBCs+)YBO#NW@6^yr9iMG~omyCEf@Xf$$s;txI|4P!uFN)j>`VKA|ny-3WRV zUfCPSz#Hj!xov`^0~ZhPmpM>dQ&6mBy`oHNg70{*YkI)ucu!~60Y(dJP|>Af1e7ZDCRc3@G9!s_B9n-=wSMiv$-D*ecydgmqJD*|9qw`qktAp|x~ z4YUT0t6D{9Nv*m8Ak7{CP$z60c?N99MX$rzfQ1N=_mmF^>KquSz(Ah`!Wz>qcpGT0 z6ksw)LvI9=*`pymmZAEBwgl;sNoHuU&(b~sFxJ87l{VQOe#&csw^mxk`}|lJm^RM{ z*CHx&lW_LZRJh!aw*?i|4hAJCPUL$*MFH2~nm;dB2rBA^NTihTf(-`1ifQ=31%F-+ zqC6bOaP}B)VRVL&qPbxHoZ}Vzf*UQIV=>IAJIC2^X6!q zR7dG7fWq$fj@y2Dxy5?rg16)1)(kdfu;q{7S8fn-iG%U$UG;hN1mFk2fPXm{crLwL zoR@0Is@4I%06LfugkHQCXM0%|5J4NbbU&2o2?8FI<3JfZ*a@t6TpeDg@_4{M9!_pH zTAg&23LuVxHZP3fq8IE4T&xT#5+R4Px0lJF;ec9D%F7wbdD#Qt(=H&zf<<6!jal&6 z)iFMI_X)!;_z-k02W_LL_$Nl^i-z)n${!tS%+Z~c8V__0loZCZS zQak5qBn^74^?kE;#;CY$wYPR^_*;TX5LWvtr+- zo6j!oTuRC}s`6h{p0K*eS@CR-gx_zDy=`Ij^{V`^VRJg}IwPjkt}we-QH@lesPco0 z?U~Z)jCgEpqXtzke^XPNh(Y23Dqly6q$>;K+<2?KnO7KzT&+D~&-l1es(=xTEWo=0* zpQ!RztXkEfN3xi)VvO&Bk|m}0!(Cwtcu0daFCngn*u9lQu?|F(!!-m7n~+wMK?Cf1k=XtLhtn>04;qNpXT<{;F?UyGi{E zR^dv-W37VUXt z$IR`XQhlPzk6m!^`HW)_Cpe~Oli}rZmJfHe+29vdc`(FD5oc_fQZ3=f!czT2ReqxR z$HR}0h~1-((=I=5m+&uEm7j2n$OuI zI_?`#(0f{G>HWc~{NSo*zuB@|{B23@LQBn6a+YsY)sIRFA9X%aeA52T#NT>3Oa1>; zzFt*7<#M%|_eC+&cS(nqLuC9Rs(exr*2gZ3<)_%= zI}vl?0axp+5*vk{yY=gsVp9E2_P65Em^w{Vcr1b?JQiRK8wa-=p_8DG}mL<0UtGqp;Ner}BxqzHKF` zetaT75#wDepGiaVdzk5+ii_v>J}B?6W>vmKj%0DVGCg-Vy0r=eQ>4{FMD&onLOu^n$x-rmpgduyjwUe{h$u?fn_0MnN1o>Nnp% zX!>#)KC!BN^LW=z$$Mzr#?eRnEEc5tW>tPv{)9K(_R>iMe<-!0>H!HpMpb@-Z)B~R z`)Jtaw=IW9%KN`woga7eR=NH3;K*LL?)b{%Pr-QM^2cN9t{+<;pkY-Em8P6j=qFWv z=#VLSG7iwcJr~`YmRp&BResZ;anmLpq}srlp&s28{zH{d0`9Hdb%-WcN?X~omQIGR zI{*2VcI^(+{?^zw?5?7XRD@x1LgfC1>!p^pQQG!A&wti`S)Kx zPOC1{$BC-^l<)i}Bps!j^R#Tc?+1B);qGarI`POj@VfsodaB}Y`v=~CB<)YZs{E)k z3ANT8r_~ekKmW!muV14o-y_wUtHlZG{lpYpF3%ome)Ot*a`oowrzdFc={vgR_dFuC zPgMB{8~PNRf0BA%cRh0dXi;hWi4gx>`Lt;q>^~rh&iwH~fy;|tNbSd}@`F3|sJt(U zrrk9Zm{LflpUtZLJBXjjv{=R;U2=KK>n~W9|KhKs9eO9z(FOi^etdyKf2#6(w(Bxq zOr~3Q)^GM;nT)@BRsPmoee32sMelB}xBc1#nSO%1#Fg%os4L+Rhmk(fH2wb7BANb4 zROJVs{`*nB({!uB^YpJb`}t;e!1oKq00C69oBr$Y1(0@ z!{(OX6_WCURrz<$mfBeO3|*WOb-%_ z_XEiTy=&{9mOb2#>oX;c(1NZGBN=}(krvSTiL z_FjyI?r`JZ7zS73JYzhp3tOl`6f^K_zI0FjYyk9?U%lnMw{-G8@WD5^N0BJJO3mYzg;Idg|C)BEE;# zZN73^^p!Ie#5aPg%~TU-`i;|Tdt*-`LcocwC_L8Ux2F!2BxoRkZ#PrDZVpqBFyXCa zH(_fN#!Kv)lHWK43Tsyb?V{2X+GAQ04MGYNOh@8?Lqr_~7{O}g-vV}wMHIkWw53cG zBI9M+T2P(X;Eg#uOkSs9rcd!UQT)^xOUFT)}HMLWP+9f z)Gvr9>_To0yQ~|XmuwmY5EFAd;=LT1IsgiyYeJ-~t4Um&NI;JUli(OM;A}DsrlYZ| zETOhZ^&Nw7Zb@S2#BNF!;DMRI{6qI_Z}M^iEs5SKF3t-(ZF_9{A$8VXK3-}TNMz`t z^G?+Afb_lUc)iPVQ^^4)VX!%&2S?ITB=&Bv2#*pOO;?JoQ!a1hgYlfapI%}IeH!Z-~F;f<$jxF}x3 z?p0f-;bM96NW+t@Ng-wevS@eqk-`_Rv(y!s+0z*&HUk?n4?N#`^cy;^oKF$ZP(L>L6HNZQ^ zD{lR!8@qG-a8_KF{4qGqzi}A7_n0dnS18MAtHSfI2UvF?#9 zePw$F9!!Dx6olFTP@rT~croMM_bh@1+Yx*j-^R85usN4(5MwjylGLNJMJ|COz~&PQ z3E0!n-UUs7N<+hV#q3i2vTtYhkjcjdhUd-Ts-TxFqJc-tQ9!0t7N+syyVIqRcZVkg-W zYiwU)cF!Wc%?=iJ!ea75lMEd>SbnfeGD}!kh|*@MIN4;sS)xI#eKwUX^Mk9dEU#<$ zRjfL2eOKl%2ey8S@xOW&qY%WnM@F!_=_B9+2A~J<>3^{9fan19?-<&vzfZ?Lod)*k zrkcz@C*yv(%-I32kLM$R6$NkmQt%=(F@d3}ymcb)h<|9;C)Ck{T_0mNfr$bZ?$w!{ zW(~4X_>2xPz1~~8o*M^+wWc@gr?4zY2;gS|WjJQcVr==^^Cj3|k)Uc_Iv44*F==P4 zmjgt|!EC)loc(El;ArB&{|i_(RZXg@Su5L`wPLYm1k}`^?c2Xz?v!Y6A|>0G!&7Vm zozKv_%+_ruqpD`MFHezPJ_>3IlHuKssgD#eXib*a=Ou6isRglVfuOHIn z!BcEa^FE{st00x}UO(iT5~RR?4<#6YNqcWj0!(6#hQN^rMIJib*Sq6Q8XrX1$3HMu z`L!3O9ezuQ1Xh7y@~B`=F4rRNKw)q zRzf#GMu4~<1|Ed~40Ma-KsJGI3Pv=ArXjX0n5G5|3KgnMF1+Nsc*u5+10ybAlBJhI zy{vEa`4O6N_S8Y+&>B{T!AO;{HEe!&Lw%VAks|`)AzPQFHLRk8=Jk$o0A$I91m!o0 zXeTPI7ifbGmct-Zz>TwEu+?gF*M`_oI4t-i>?UJHyZM?tcJkiX!Oc^%1y`hpwCZt9 zLZ{&qY61|v2e}W{E(Gnc^{lEJ0B*!afRSR;1~zUWx#2yX5IjhbfdwB}C&B{(010v& zPba+wE|~Yk{RIPSWv%HVRe~4cT$}C=3xP^ph)KSa0E+XhGQ3fcT-Z20Ss-mSkmCqH z0c2pb%b=!*OnV+=Ve5+Nx?b~*Ach_(28K zhCSG~{?q4F4VxpIiaJ!zDIg0YfadsLJg1g0Aw(=MfDJmFQSu38zlcJ@DR6U_<#%vE zU5Z)ykey2~sXM&1dhI9n6D^{6Q#_bJOs5TE2a`v$UGcGi5r970_pn}zYlgS&7t+#X za=$nBr8#>CRF;<{E-Jubh#z)$REU>@so>z=yCB;UP|OjemEbPIDJIqm+G-JPCBY{M zOc8Cf;HnlLNcb;vIDnxa^enPtD5HzBM^VX7>?X(S7V=*lMZwpuxN zD$~y@9AyE31RHijuxBKu7;P2KGcnBvWc{4%ewDMDPl6m7uY^@$jaRA*Moo0ViO$G?DKi z{FJF@ALbVTJE0;rEzc7;%K#k!c|s&3W=MvBrvw}!y+O(iPD;J8IJ;FP#1l`{L_WmR zRWP#E0WHHxghN$(1{=;^9=F=?;?KuPq1a>jQ$gNqW% zhoQw>u*ZVa1@;s>$&i$50LPI4LSE^uA-GrbfcegXQT0ka>MaClna6H{&AbEb&U#n) zCqC8_QuuZU=mb>8PQYtj&@)O4T@VI`NL|F`;>p8F=~$2T4Y~-2DnuiI)reyTH!74h zJId@w5f^OVX#+06wiCQ!Qfp@Tmvsh7=Au|LF_(j6vpU^gJuwl!1jvJ; zwr;1;?x4kh`3Gz(3Ylztj#8Qx1{ZO8P5`x-4yoC97K^hST%Ni(hCCnOEaV1|X5;2zXtu#ahCGpwjr~z3lll8Y+Ewq=2+HSWuZ7;j z&}7VHQ=)en2x$jIdj&`IPN2MlodI9NP+6)f6>;~>1xvscAOH)Lt*czD9eX2K4_GF2 zNOIBVfmU5Td8oqUsCYn6SiJB;oB&w0@_V5Q!UZ=Q=(2#*jPHisOE2hMLvZcOzL)sO z6?Q#*q;~*PTo-~{9wS6TpwTU`iODb{usYd(;|N`aJqJ4RAMH1e*kwo9fv|geXK2h> z&qD{;mU)}QSb15QAxg71omU-x_v*!jUmg3utyRou-6K9$q+(lc)6-x z#38!j1e*%M2Bs`tWs5N38UUana(T)HmAvdX9S2-TfbziXFr_GLgnAd48|fu_hb>C= z59~h9_WIz40*)xSoY@?@DvL0iJuB;50h@5g##dv@r6+JB*^ zatC1vBb-mvy7M!F9DTdwhM0Puwf}VQ=M(5ST00Q7(%ln z*ctl@ryH&@#3#Wiy1c1aQ*i(trmu(I~KhE)-+nV=IV(4*`sCVB_#& zjRO|5vkN*3J2L$ADy|2ou0j&PfEabt7uOexL&6uv!H$nY057S}CXQ_nFkiSx|94)& zfBY4m4)Q$WaA6R|*dSs(;alph+*8&JjK87~%R&E(f+Yke(GZ-z7%;bxg1i+R5aCQz zBO%_uiKKrIQr!bYI%#839k+517;YgC@3sKS6fFu6g&l)U9iaIC@|&cAvxCEq6AT%U zu949cW?$+yY;s6>!O`Z5NT%*H3mc1LK!gC$!M6=|$Uq~CC1^rQ<8DIW{L&3@aajrG zMFja37YJrbh(`XOIV+hwTn^=rd>K!Ie(XoyRLD<~TbCnO{hpG}mlKI${v2Y83M5^c zy(2rWts+}G?I+*%D@{%{u0t9+q!6dORYd(~ccj9)V&qQk<>YDgF(hb56|yL8 zEZJB#^#5b;O~A7#lK=6VnfJ)S5fx8#ee>#it{Rd6L3bqy@!WOQUGLR}$bFxl9C^7x zU=0uy@OlZS2O1T@3wRMkQ53upM5B1%NfZ9N)1-ggLBDnXijIH0 zEv4KrfwG*dXyA_Xsp{eG6nTCPwb(YDHa&P8{kwP~r8NDVMo#NU@g{9)LVg#Dt=ml} z_rHWfp=R{TRfp56dHreNC+(>F_yirj;sScD^Kwev`~h7%{4^SO^9q`C>|Ip!*hV_~ z>NjZixj_nscT>)g*7QR5W}15GhxFXwY&z*L%jpl@x6lJW|C^d0e>Ro;@CtoD`ZyX? znhBq?gXo=Jzf#s2x6t9|w4tY(tfb{f-$(OTyg+}tq<|XG4K!--`LwC;8FbIe>6CLL z(SkPz(So^mQ_Cygq4&=HiDqUTMVH*XgF4)I8ufYaVQN3@KcWYk?WRtD=tk47E~ZC*yMTt2tfOeh zMU=gHEPcMT9c@|h8ue(AN;kBAn~wPKJ-X(c59z~uCefSGQ|OdYo9UBlE}@mLWK+tf zBdBult8`@IGTM6FTso@qUv%bSxitLH8)^837XA32f6@Gk68giJKhT92x1o&AZ_z^= z*U_VG3#nW2>y&oNEP89&0t(Iffv&%$gl4`loQnTEhVJNpD?K*;I_mx2Vmf0^d)l`2 zRhlq#3!SvAGhO-0dGyNrE$EbaZ_*3J6X?)Yw@~1uCUofe_t1)KSJ2BZ7SSb7Oe8vT zE4|%jKAn2eXSDMjD1Mggpg)wYrarHKM~9vJBYpFIjGp{rIlc7rDKt4)M$7u1OJ}A& zN$KZpr7?%zOAki|(wR>^Ko?AUfd*!uMGda(N&V)QQui;8r)IC-MYkPsF%{hQ32pmm zENw2kn?Ct`1WjvpH;wtWJGE`wf}Y#ih%TJIfI83WL4Erb(u5nb>4C$arsqFPr3uac zNZSXrqO9Pt1W}Lvn$m^-^xZXd!9%4q;0v1;zk4EWA3TS8UD%HvIARO^r)&-_nD`UD z@z2X?P1+9>nVLgC{&fgF(Y_09Jhv_7-{8>5u_binKTf5V9TL=YT?S=em`(rs+fDTM zzHifcSM;Lv)Ma$qk6o!rr+4V&@O^Yc;4)fp&IbDG<`-%7FGtcv-3QZgCqGMfbv>0< zu6~5(H@SjJKj}te-XBYU>US9hW-Xyx!ez8Is}IqRlj*Cz^QhAc7g2}GztG(qhttf~ zcT=0Poz!sDcxqPgAx&y^A8qV2o{n7f1*Lp+4jta|bhJfX4 zHthZ@<&`$3Ymd5_Zk&BM6~Fo%y)^b2%E(_#Z~hRVi*7oZzFznfZHPWcX-yuYu_v8H z9fsdbspsTSqq1Y@^0ObJ<7U1#4&fo#@-(B09BW7F~VSQo3OG+0^ZqXXvISTj`X^ zA7Q&Xi#m<}i2|=4PQOM&^!}&E(O;gNMOQbylUlr%N`Ei>k`7xki*inQimDzuhA!F(Lt^KekmA-U5owi{i z&HUrpM2}6U`Tv|u3$G5)sb?&pzs82p`tV%3`JqNM@Y)%4#G$9r2aC?2Uq9PPV>j%g zu}gN+r#JVY(1SbZ+*ltP+3RrHIeIspa&DN4JLk}8M~$LO7Jr5L^cdaQvlmV2+=`kl z{TGdR??TG@=m>i0j5hSg;^wrf&+C-+>eIBe$4;6>oaf0YI=Sxfh9SVj-y z)Z#1ULn)=(^>pTyN7Bi3C6zR(qL0I)s7ZPUx~pIUjb8F0t>1YXb^qf+8aOtWf?Idd zGfVHMF5NDri%*+Jm#(;u&iMIxdhfcawC$xS)bNrC6ghhi&APfRHEI1g#qy@m>WD>s zH;$rJA1jdO`u-g zKB0=8D`|4dG8%Nl0O~&f33{#9eROWWfwc0FZnS;PgLG>DkLamY&(b2goIZJ?Aq{x; zMEY!SI~uU=4r+M#pJ?b&4QNQGGO|uRf*!d2X4<)P30-yG7J46R_c!k!M&q7+hF09Y zgPP4dnZEC}oXTEoLF?vSMGNLVMQc_!qC>}?LA|fer9WLYmZrVFiQbJoL*4)V5S@G4 zy>v+1)wDDHV)}U7Z}gvYdeSGO{zPBCJ%V;Dc#yVy_XeHWd=;J5s+jUJi>T@QFVoN+ zY4qF0-RP`i*U>*0jG(_y8&6k6SJP=%en5$p?^62FchNC@o~Eu-I?zeiwWHSm_>M{r zX-wOmI)rw-`Xl8&e+Ita(dHXg)5d?dqt5@ihbHB0p;bpdO~u#TLmyxLJY7C~C9OL* zgEscPkj^-EBRzK149fh|`E>2p_vroGr_%jbBB09JQP<#w)bWWbDj74E#{BJW`sIxllsV~18aV7? znz|;F@*ntsKDgjY`gp+E)cNZ|+I8PY^zXOZ(!kEM=-EeZrz?Ldr_;xrKn2fUN!RvD zq0G}pQL77v)7VX)(`Wa;O&9%^PrI-Bl8$Zs3cYyk9aQ$~>GamJ7pd`!YiPrDkJ1G% zj-rumZlugn=g^;SE2E6!(RAA122$)#$55N4htimnO6k@=kEMAlKBdn#45Srjzd$E# z`---A1`bSGN*!mOPJfyFI4vH8t(eO{pp!SYr>-Awr0Hcx)4WrsP?y(Fq10~|P|*Vs z`uo&ZsL!zWG-S{T)cBcfn)~B_sL54dQ0Dh3^b~lS-a{^-*+*YaPyO;R4g2U_x@%)G z9Rcxk#n}(g@bVed@7tc#YQpU_?CA%od-nBo{>lF$%Ket!q+4jmwku&eb_rGXjS&@8 z9-f{L_BJ0|2V$ImM$v$CaUYv{z8tD(clqjD&*A&wO{-dQzQ`YM&*S^(uuU!SOUG^P z+MLD=1;6ZBi!EbT8qoplJvQ&LzXbJs*Ir!*wC&cND8sUYU3qKYqL&XRupk+hWd|<1 zsCTwa`9X2EIM=MDG{?f4wjxfnL<<+ppmMSx*d=ojRwW68b&Jn1x@xedo@v#_oFXw8AmZ{IIZM z$;92Qm0B(06s$!aI3=ru3WoDTJqPPcHxx+aqJ#-r;wXLFsm@x?ieh_YHDODfg17>j zu%kibg`Q63bsbGrE*Mc#_{PYI55ZVsH-e2QS=T8jRSo6_#km&1Q6-g13Mm!H5rlu3 ztxw)D@##sWvvUhae;2#^jwi=&^j;~ZYA>~;yomysx_0q9S7E~dU*PD}RBeRH^`WFr zg-sQ!i_nmm9ZeGhE5uzH&NF!~tM#z^=nX>mf?QVLI0aQu4RP!EePXeiTep@KRJ^@( zs#9e}Emca_nxfl+q0o>f-ZS@`$G_S>%qo0#^_mA)RIYm3d(VUiX{`nICPoFD^)i6b zhAyNESBc!a#V5-)T?tKrGisXUZuDYOOYQtTwEq@NpAvzuGin2 z$fr}i-Ym7GH}~kkpILtcwID?rD&r0e2CDHo^XD47pc27%bW>ugGf_%c>b+nUaxtXR z72kYx@9Q7`_EbsXqt8v=^!n3xmHChl(Pa#*c7izou0e&}cTXS_-up7{Z1Xs&GZEPb z&->sxYE{KKffey6s}fvj5f>G*q#v_Ph5l}gm_)A^Bhrab6!TsPpT1##r- zCRJg!@iY;@NM?`>4?5g*z=VRADG@gpc5TD;42g|P(1>VIg%^sZLvz2D2}V2!?RmyX zOd*-TxWfhpzf4>|t=5e(<{PkDj zPS;-rhf4gkTK#L01Ar^}DRQf)d#!(MKD?Y&mep@>AsANBvdsXvIbJON`=Sjy7uL zRKY;Q&W|)IBK;}G-eDlKv0zWZ<{CW1N77mE-UyRGwj+|tLFI}G%4ktg zf&YPmuXYdVhH@YdPR3}iQKn3c8-BX;bTC6g8F3kvlJHUz`sKLQ$gf(>ue+90kYB$C z7!yI)N(G_9gHWL$BpkIGniAN~WTbImv<9?sQ?=(fq{UUa3P8Jv7J4T=oy2z9W6dAs^mGcOf~PWewZ=HPn$z-(5H$%? zMhbn%JfM%CcA6`Gn!3T^n&r?^e79RRO+y&3#kNg9g1vsg3DO3~rlElV&Bn2`SMmET zzV`(Kv>e}gA)8(g1!x<7r-cLbEWTghdq+xuUcz@1z7M1ZXnSgi#;1kp(X;@)pJvnc zG~B1-J{|YzxKGD@1Kc;jeFNM#zIa{nXB?^k8TWlEa5j|R|91V$u?n#5Aw1R6c^O_`U}JBf{BLV zBb5q@G7+8#Zw_PQu<6zCRShkFXJK;lCvXL-k*-VO2Jmh_E52hYuLt!LtN7q*7DfjFQ_!k?bEM!hnw1W?APCFfXntB`}gnI;fxz^vx4n=6!+?UU9;>n zv(9W5Ii+*g0r~iLx#`9;+xPBy_U&Ce^W(Gdd&Z5udk^S8pkHyHGm#;Z*S>vrUdybG zS*>!ivx;+CWwkHv)G@bXc20}z+>Uu2JLG2F*deDyPWw~Y-miJCIWiX6_YBT!VVp7g zBy}@`)mf$e3xpMu8N3rtsBs)WVtaEJNADdI@fF7#5Xn`#RpJluseIM>deWBhq{WGK zo-z6funr@uLdNRp8W2Qu=FD}69T|O?W`L}!w>iny>JB?6={wq+0p0_i-3fxrBoQGo`;3~~4#Rm#nlnTnca z`ZACxybKrIDCV}9Q0Q|$vG4CL^oD&Aj3uPw(z!yOu(%L{_jgPn*m;3S;I#wYZ#FX% zr3Nvhb>slp0yaHIuUHY9 ztfptGnVx|Hz~~NA=Wq-yGd;%xQKUYZo?8!b#v_uO1Pn4c}0)j^Zita&qi zq|i4%g$OzA%*nLs0f6i|!Yb8WUFHv2VsY{0h*_RCO^yZQwnNvO{h@vRk$zFs1oKsZ zdUbR|qoAZ#yt($iX)zETvUY}ptOSFRuNU5=in>QbCt@UHObD1Khy;M2wz8WAl7nDF z?9$R+0bSrGpc`UzUO!-&?WxWfpCIG{)j}*hLnVUzM%0Hb4}@nBA%3PAZ;l?EqLe^L z7TFo|gu@d^&|rQl)vMYV(cQ{qZB9iJOqrlUu+R=BcOnauX08*@K~Pmpd#GSDiGZCV z5XOK>Nac#!VJ6@`v4jE;D=hepYX`JW0Sdc-(iBIM8cBo7Md%NDz%1deXb!;~#(60o zaPIb4jFUlSwPhP%fCfgaOg3uaRK9fbWv;_uZ!mh)x?=v|XhU^gtsyuNPExD|0PzwG zlSx_Ib4k^e~@Xfz-owf$n6c;yGxXA3QTOx=nyz2rUv;>S&{;gE4>& zk+)IPXvzp-TgH?qLhZg8T;7BFS*RK9(Pv~Vu9wdWaRWwx5i&0iZy;Di&}#5Rx*H4F zED58*njs4Sex`2o3$yT^Zr6?QQ~}Fdy94~PjElmbe1$(=kw_}T7{OlXIn0`>9{)>5 z;*NQcu=Fwdgy|_$%19d1(-23NW<+L09f1O98RAF7E;&??CkWL*a2!i?3}eqNH(XIe z@I{RNB9E&{0reEa;#85DIWKcep@LHwmTG&1iE|K-7!AQYiNRlYG+V+^3UP+VlcZN* z*ZnYd7v`KrMHrd0x;4ZqGc~=_X(6}Jqu+D+HjM%)nttzHM$8D)3d!8BV~^hL&unvP z(RoheaAPan)S`23y40b80lLQu(qf2-zgPi!0pj8MV1QPHLiAB6OuvRws5G1!{xy8i z#W3)2EzJH&1fPAL*=S`J6yF-5&umEKS@$fniLfY+8xFut1PHgL@n(5YRNbrx?q-Y7 zGmFw*!Ub6?Y)7^>%$XyO-|na(7lgJoo=7-BgEQEJxJIZ9a4Iv%!~#k%O+;PVxhUW0 z_;?CH8Nz&{t8w*aAa7^@Juoqx0>N*)=4V(C03;&06sh;+bL$fQDhFt1lt%PJ@L@i6 ztAnPfvWSEjg}8*JN!A9u4dOAP5T{5Fp_p1vz|`>60vCtnLro4SXn4y42u@qzi!oa|k4ltfXm_?0E8VVp}k(xQLcG#W~hnfM|k4h@I0WQrXKFSF|d z*0*e47yl^kL4P0C3mLQ8Nm!TtlUtTxXvlibax8Eh2nLhS8U@Sf2jEcb363CwWV>J| zyAAW5oslAi(hExnI$*{KJfh%Ltlk-Ms ze8dvLNqIG!#E)N{1gRwI@MY_NyTizjVoN8vLx`)0yRhO(BeE7%Tbeu(!>m+F8j+O>vPln-Mm+Ij z%m|({BLhGdHyUZo@-0&!+rHiR?_wH#0tGvF3;uYN9q$tZ258DIyUC%BwQ4 zuG6#y_5rfhtR0zVn@(LTlo4F+uXu7Fd7+zIxmSR$a<^_e5R%|HF96^FnE3K_oTI?a8 z$o&s3-y{6v5!CzS7D0(aLQresLM3dBf5C0Yq19lzbG}Uzz;Z6c_dP2>!|WhU$D;cJ zzTe_I!U@r0#|aM$9P|a4b%(87r(>YL`=Zmit&Ecv-&~)-ePwIkRP23akUd+HYMJ5Y z^snWb#k?!D`z^~-D{_R2G2T|O4$H1W3t7{mb`eN1K2;^{g_v9Vp2%HgEfw#_ny$72 ztos3m*~*ADgLREMRh3)3#W;GTg3Z4=0q4Dw|#Eiv98BGyCZ zX@m;U0kK=veL9J&IuE&2hf%-^${A?p;RN6O$P}QVmPO_GCh%R0@4?q&Mo{d=D~WoRyoK)kU zL$X`eAiIj%!P5Q(_M3WmoS*cZ)j)dN%sO#y=FPf01<%mA3ZHuP;@&OgM1SvElu{ph zv{_xE!)E81KKIQu)1!5qW3_kb1KeF+mrC#1=+YFKqCI*E#@5$9%{K8t_XkUJT$hc$ zKGnNq0r-deJ>KCIJ?lYUU$5YPg)-9bqa|=65@S#ffV6?7R9Fpa5`fx3aWS|OeHu(d zT|TBfd4wkOExUv>BV;(4y*h+D-VUEzA7(&~YiO_^GzBXY4=O&s(K0ij4n_%&%ewNY zMZ!B<1+f(D3A*xsWl4D^ojw!_Ee*f>mLiH7N@oRCSSm*chDD7+GZDD%c%{{yBHl((+ois1>Hw zgB8MaYKk#3)QZPTU911bsb7vOe%3IWLeKV3(KAyU#8!6bCgs zoNi0X(v{mQkF0uon1=H?$V)urgxuU5vuwMg#^YD>2)1li1MjC+i*|~78U?j2Vw70h z!}I?E8u|}oDhJ*3NC>lJ4Rbs?%6ex_NR>DY#$2!%a{qzR!}P&K^ZWa zIt2F6c*k0~&GO`9DVwj`wJj#-=M+rX4g7PM*aVck>}!{S;uLHiIvB0Oe_-VFT|h~0 zl~G`;R*4ub3lFx~_{G&;m$wF~?qMm~TaW^N&Gn4rbx1s{@;aoMd9w^X#M%7(S4uc+ zg%7jn&(KsuTm2Tk(_q^7fo+F(*9VPtZu2Z-KI7uPOoJLJS$2y(^_sQnGA-o=%SzW8 z-2#HWA%BEJ@JNIR4z?A*iIx6cJNN2b+!NjctYFx?2}+k+jn2HWfB!SxTy}kkLIOYM zhCJ*?ALcYO%1Ga8preqm)}K}X#xvRD!tT_fcL;Xv(Yy1Fd+|V)CR$7DaIDb<_$qAI zPGk1!BhF6eKJVJ8Yx`m--qm)Da9w_^wkge`L+pdS5HlTbQ5RdWoa`F-D%1B80A?`v zy{ySk?yK)Z()TRJvw4VF+B}79t-UW=0uTR{ewhMx17Gip^Z{ey`r7^I{g&B=AnXt3 z=he{r#!{~?wzl^PBQ)KzoI#-12o(uqQ;>FRZ` zCk~HXD<9kHyR4D!w{RB;AI%bxD z(TIobd-um_M#Cai2`YSRS+?1lhdWT~MARK4;gI0=SDi5wBM%#Hj%SJGV8jONl=#6x zuq0Q6A<#)hC1ooNOp;_$UUq?KGjuWo#zU~wN@ri-^ljvjWy2EK!r2b~2anY*B!9Bn z$^aZNTYKc4u6E$ubd?#YENvN?I0EhdOnyBNyUL`iv5)Qmw|EyFem$F5gdjNc`H7!$ zr!qfss7069G|-{D!Hzrvo&IwCzHbG>o2`Q`Dl<*bYi`u?`$1K_VC+8JlugM1(2~#N zDm#9kLcip{f}9!`Wk1f3s2*~z0+y1s(&qhJe>FgCf11@?3y#fXIEt~#>#H9j? zvezYd&+X^d(3l7c)quN_)0eJr6scgO1uXDhp|lMY#?HR>cFaG_YlB19SPGiR=!}0p zboSB|VC6|$CPaWILVza%W2|m-gdNnfwLP}Gbko>{ly1FvlfqFPNkZkwq?5QgY%yc- zKAmb>Gue711gr;DNJ9J?7;)@oVN&$4X&830o&wgd0@iP^obd94&xkYDx2nrp+AOPu zCfYu%S5iqkXE0+u*vP@c%9Pj}g+A26MnY7r$-ymlnbEb_!#6w7=w)-~JNMMdb9$RL zZX~1p7zED(%3Fg^K+Q2KsE+i{`$Gr7Mf0zW<-kp`LVwkue4Y)I2bGTPa9}d45$3sQ zND)?finGmF0Ahq2h26n|H|BmjT+Wfxb8>DaSg`5t4dQHH1F<^Q9@ur|OmG4Yj-`O-~baGoi z+OTvar^rN=mclr)=*`R=js^f<`ri9`O%aGP!Q7ni*Kgj+R4z^7x_RZ%jXm15`sh7d zZOT>eUmg$fZ7tMea#Xs-lHSqO1H!Z>AmE}vJIq3;ZUmmP1C;>@RwEj!-Y~aR-ifd9 zt|V{CZC95_3hS;!l3a2wWKJd;a~VCnrBXC)Of(=`GSM(@u+?(;4rlf+mxr;@*%20e zI#5rC9tYug72l6QIPQQHkJxdv5#O(HJ=%dC8V>3u@O=%}!vg^-#eu#1P}RubL0?vx zzSLz`t67%W8u!tcdE7lgHr8hX6O^zr~6<9h^JgoR+ZjBOyP{NbVqq zZL)b7*!q+yh^-R9WAGb7$WxCk-x%Pqu=JA$soFynGf=BN;lA){sP@oT8*1Qj@LA|o zaKCwkX$Ie>P#~lUlhG)u!^BM-Y7(F(L1kXtPhF17!i!Qdo%{#EH2+(dAiO;b^ z^qL)}?XcFF?S#U+>V`n5<85I2`Rm zSV@Qt81&UjxPQ*@AByX8k~qWwsEOm_5W#S&eG8Wlj4KY4xkFHsfJtAf(?ygwyq{sG zQu75)(?}pby?X6_o=?^8n!U^~%vJig|Ow`7He%fJak#tfa};S?*0d;dF%^26;iuxqXW$BK(tJQqEp2j|#eD6l*S zz>OudVk`NPpU^dCb40LdZIl2v9mH-K_^=rGueFO9e_EaO=aM}X5;rMm?f@o z>H+W7yjiO{>=5Ld04Dz3e~<1BvXw)(S~#m9LLv8T27?TJ0`k^Ay|aDh8S|MlvmUYn z5Yfb4R}smlvUP;!U~PuZjHi@*!2Q@uGaW$@TSt9c_QBK<%2k)fFFeNLwtM$drCQ?v zIHFo(DhuUnod2Y|7J7dbm46ZV1}r{ z{3v77`4-Ipk{o1m4C%gkb_=8Y-VdD?fLH)RLtYkf02c=brc7q@L_OR(X_88^kW&pcj1QoEN~fBPvUsS2Jk+u$QuA0h zw`ffL80(yDv&DxIG%G8Qrn*-Djdcht5%>{4zOk15Am}e4Vi|ven5%=@Nr>c+g=*F^ z_PDM?Kqk*umY`17=wZwSU*>KP$;+8hkB6|of&P=lyt5isEXEp&bN6f;&gebHx#+Dx{Rw5WV0>i$~oXd8Dzg zEgaY_4MY)!%JZ}Z7Z5IfAic`z7U8qWcp3ThDIB-q!(9)|T=R}`4j5vGQVa>swj{s8 zBDch4g*()m_kgXBot71zLMP4fVL}q_Q7G_|7Xz$ zADS~5p@IqzW`aurLN%Ci1+#*mB6l^IS%tgi-#_!7FUM{2HMG4^C+-d9q1*Oc*3zchRH7hX%*&mB6I-#*600HPYuO61@!<>+$At$|Ls zXZ=s}Kl|*}>kEf&U%hqfnuovkwREiqw33SfL^YrZ1#~SxMQ#mr>?=RMv1Vx1CwG?= zuAT7J*p;)UZt+@L;Q>u>F@UHBG_HVF@Kfa0Kqqf}^VK<<@7mPhA zE%kuLxfnoH0~%96OZh2sYoNQiAcgI(Z znOMGJ%pryRe`5KF9bQXauXXHZ!E=+DnI`BE$i$gFU2#i%imt8QMh~scNEGhn4D6|DJY>*^kRe|!l^AY zpqvBcbq-StG+A7}4;~`328brPAmXYSx--xvUcY#4#ZhO5(hg7n&}&wlD+L5ysp*OY zvNI(`k;{+)rF8}&#z;X1l>!$J$OIJ_Z_kM;3f^g0p9Qcc=1MIaWJ*h#biVpt=KuU_ z>L2xSuT$Y`z^48-&4GmVGBZ^8y%*Be8c12+<98OMtCf(he!=fO&~U#VaHtBuGlLGj z7=-IM{7wr&3m$T43w~#W9oig*-CK%7Pp8=QHhxE>LVJ$y%c%kS3cusvmaYPB={|xN z=~#LoT#REjcSJ+ZT5`<~?P7nX9rDtPU!{hAxhw3U|t zHXyh2k;m^ML_1ba)`VkA@TJ|vMj8%lz5x+Lf|b~6ih!{^N&(e|r#zkH^r+G{Lv;+F zugYVI)ZGUH4hnT)dml_x<&MkFM`M!qp`3yUW-=80fLCDr$D+U~sxny6vM$77t5luK zsLP>AS9xG_%DQ(s1!^++L0#xFHSmt2iogJt^~vHg!4&b}UbAO`%e475^VZPli-Oy) zW0qZTPu-$?OW_nKv;9668-^lE!7L8W{Y1g1T`ocFGANgqL%Dn>^ej(8!Mq;7X82!md@HY#B?|(ZD>ifP(2U`|<@($XbM7H@g}gy*k)ZsN16 zpGkY>;-|+iTD$Pbh3%fArMyUc2qu<_mK9(+)4y-O0c{5q-v|YO9aOfEhnWBazQ=+3 zV8PqGMO{wkG;3+j82cnQbsR65(%YN3dk(+`4g!47;sIUScI|a@agVMY_-K`q-u5QU z2{nXPXA=w!$*N3)^p=LV==cRUZ@bh&AG}h87b(OQxue9oE9ql0k|t zgT8VljYnalv)LGU+SUcpoh2iT3&lcfID5uImd4tXX|S+0muNH!+4VcoaCX-fDzwIM zfJ`odXZ0qTuWw;YQKGe%+SC(+RRbnxQ&b^=2g1fC4_Kroh=MHzmz$3WgF*L2uDN=3@i}3O1V+Z0U?a9vp~FLv(ef zB>-spCe;)(O|l~mxLQErZqdUt2$-cCp$eiuF!*RhAtu9MjFTXk!cXpQ42iA+H~gv? zz7&Q6A9wsLz^?8>g$)@kLxnk`kThrzZb$Ht590pieE9JIMbWp?T|@A~8ZC|=jy}bE z%g}Srj&g?rGZ?QF2}ws`yrZMo#U8(t#T{#n;x5uN=lJ1_^Nc<4j)5*kMX;C{EN#Sy zN76@dGJC3n7mktc433oyAA#1l9>eXGm*c+YPT@{se}!N+&tl5JpUU0G57L+U!$%lq z60rqXC>2H#{G^;qOk%CF+;gdNI>1}_W&tLJM0<&4PgtuaaAsv$O_G+v44XtE@UvK9 zy|0BpFp#(cZ-S?yC(?r9jW}Xa5B4ouw5Y>5IWMzsWjqiI|K~&qdD?+bE4Z_PPb;iO z@M`6#G2`*1;e{+lSB?1Wht^j_16T;aI_sU#FR_!s9;VpMax~aK08r~zk28ukI9@@TlIy;%Rh13Q0A41BSWMDPHZtNx1m|FhkO zS8v+71Sbh5wTzD$(xi2~yvXYK!w>6<+VJHm&Q+_TJ$v$H%XdQ~wsp9RFK^$)rw*32 zjsu(r>+Rc@4(M~*Z?Hr7a&A?2ypM}l0IKM-DMl@wQ5`s;| zK?p|_*L_j7G?FrtiNs>*?>@tqM#FGj?%t%7n~d@fVHgq50Pr}#qjtEzto8iEfZ}>^ z{-JrxoaQXmtIxh<``lJW5#YmXVRoH8&p+6!nHU7>zCQzla_$@1nDHBw+wP`aoRv1# zeFu2jA$B0A9e_IelmqCZdoqDBtFKbgiE*sEufrR7aejY~Hi{idfC9FIxATm&XK*e* zAq;s(6Z$)J2jZJewGKK7gcc|-%ZDDm%Nlp{a&is1^kK?qepL$x5ZH~|{+;y}%5U8Y zqopE6o-ikcFxgC9hG~@mG6KCLD^18xp6qs|Gw>;9rJJKqUcA|o{7R%)7mYZFp3=x zx?49Mmlk!{Wo?;l3^07-qV46e0}e}h9vp2izlO)_046XrZ>n=-3j368ehc|+!x$N$ zNd0|AO;CZMl`+yrJP>XChVKD8A1TK0-L+XV7p*aWm4Og6QU;7`NaVL=ck}I0-QMk( zjJbNkTtJenr8>V6x|?s0>d?w+mP<^TpdDBH&Y6%vVTpv7-aB0qisR8G8GWWp0SubY z_(-g4{Ddh@b7<$;G#>i!1^E7k?@Z{zSKAJKh_l?^*!6)@wW`aS<{kX@&4^KqQkJY~ zw(zuK8n72n2CkJ6FdC&OtxA@sZ{e>Jo=BA!QfAfUqwI)CI5`#_=0=@@ujh{14U-Wh zV%&zt)(#Eerby8{ibZIqzJ|e&GPBd9u(ipP4;&zErN zyM-26bD>gV@$z2OP=^y z4}T+kj-Yw?W7xFEJmq6tk#hN~tS)OuZu1tJo${?6@}_}y?lBn>TWgp=varaxF`#0lC52nYKDqeud3PCWh5`u|>LC7rCBYmDi9-<- ztWE1y`1J4(=BT-z*N4yW#q8U zk1v^1QaEPWfBm)07>qzWs`bt%#iOIs+G}RDgZotL{2~Gh_ZIS?mOpMJj zkYAf5h}}X3!dl=puqO~IhyxU~(frlBmaxT8;Nxkm{^J~~Fk!k}n`ZcA0Fv^~Zx1qfBhEs}tR#+wzZcg+5(O1lL{wn`Ln z5LyE-Sj8qY0HKPxK-VgumHZUBs{utjMy*-6VARyv-+Mq49?-R13?Qljtx!M{{1myX z0gV*SxnthYmnJOo!Hjz_E4UOORD)TnV8;0=a#w>1?3=Oj<#jWDob!X%(3l6bl#2mG zHK0`~s!RDPa%-SFh7X%}=hop5PA@6EW78X>r+xnFRu5<;ikL2yU>GUYfv#0REBPsM zYoME!el%?8quWO|DxCW6tT$%Q-nz|$nebq)l__FMxx-YUU?%t}a%-4hjEH@B=k(XN z99B5-*_Yp&|KZ)R>N1!c_h43VDL|<9@}&x9oS!1MhPn3FuYcPz`IiY77QR#Y#g|Wf z^1^lxX3T?G%B29I8qBJ&>QH`)+#2RL(^r17bHmzi@a}gleevTppZ)B?tV9XZpU^lK z075mGYZc5&eu~^0=B~w)p8Vnd-Ai7g!foHgW(|9I!ml3Cga>pj7XyfDKr0l`1V2S? z4Rp~@W9M#u{I|yj7H)iO(+p70r(Pl;|<^e6`VgOMMXjMq{C_hDR4fLtS)vV-pc`z$c0zK+d2F#7= zTfYBnRC!qyY}yPpS*zeyLdRQx5*jW@jrx>elFs;G)9d5DM;X)Fgo4cEWG$BijB2f| zP*4;66uGNGt)#-|7O$Va<^3qtA+dKk@$V>2A1+4Pmx>0 z{O-l^kH2^Sx4&LkICI@E4{dsFjDPlfFiW`IS`RvIJ zBLp`3#1w)8kNe5aY-s1(h^8&!E4gNvz{1*qH?lHD0uoPvO4!Xd~z2!6j z>4RuSs-V~!N6pD|AT}}~Lpue-8`5O!TTx~p3yk}8*XQF7WmN%};f7UMHOxH-WO($aHv9XwJEA2v8ZPz=V+=UPT9B}TcqbRc>n+gWm00wQtU;r{i z1L^Bn;!Z@1GVQ2PBb(rHL`Kz0U)Fp#=UQ!6ZA%BDoXU%xKxXNO>E2I>CA3VZWJ`57 zN8I+TY!V2nAp>Q4wNxXT9pwfgtF8oML`|)asqEFP_r0uM>#NW%-JvmCdL3mo@P;m) zRH}EZLdW|o_g#1p)!cqVPECjtoEz`0pt-PM(apnG$xi`SJ>`^S!*mxS4AU`Vz*-~Z zIhR5CY7k>yoz+a)O{H3eqw}tlNs;Dd7;k6b{mt_`N3uk?m4Kv<1Ht z5v+VgYLGt1@6@y)J)0JyZ}EF4f|M^y57HO-y{7^4BS`u8_?_G^L@OHxX)}KBX@vAf zfP>$OjRB`I;NW)}Uh6r$*LV0WJtRcS4++v|_`UnkAU$(vh`z?}gu_CVI4nq?;P)qd z=QIh@`X(XTf#3TN$Fsvx2ES8|04#jhA7RtPBf~WNNW9;XLHhZ~6q!nBI{qVi>m;gPF@9W2;(9UCmG`DGxUTYen?f9K`Y=~AJ8>FxCJK?xsc*$`GT@?te zaCVkCm>7xd)B3%I8+5&08Ws2NX%UfCC+qjG88bt5*9>{uA5jLmsv*(#Xe?JpWqliR zewQ%Q7}Kr0IKm%CP&)zbfXk{qBmBuW2LG#f=I&YD6p6`XYj>E|dfGHOqj^`lMEnc85&x3>T*i!(KeKgJRRRa5;H>!2_R>%J z&~_2#C_YuNmQq24=w2+Fh%ryd27AV9-7G(suL+{}P1C6+Y|ulQHW(A^ zrXgNXCeAhMA-boJkU zys6KQ6V%Ny3-1`3JtLxTPTCxOsv<+(Y@RXu$z>%!sajiaee1`g2E3zgPHX$jzy=S` zS2t5v-|)-LKMz(nf7=$j?91=ZQ#W6a9({b_!jQTNth*-VkQ?ogM~P3ls*PhCp4%BAXVxm3d- zmuh(AQVpA2s^OGNl3`Yt+z#&Iy|fu!@4jAnk^9=^MQ(S%IkD-c@*=nU%8T4?EiZDr zyS&I9hVmkJc*={8F~f#SGo0l`?l6~o!_RT2LlGG4Hr2?^?XO%Khh2O?du{g!u|E{llWct&37%g;kW-Q-z;g-hDy6+J!21SL)R57 zdGg~#o5;$izC7oYP*IPnYm5JJ%ioLWCGKZ$*)Qi?UiL!+;GDl_v1JE36}KNigjdV} zITCNf8BVa2^H~kdK_AW&Agb<-H4qLU+Sjf05{`pzPjzSlj(^U<(a-1cyA_PSSihzA z>DRl%P3=4O>u)u{W&4i(`*-Yc#*MdG!S+3hdv(69S@xM(XEuwR(z)w^e0;mybmN)r zd-pv1_O6}z@mcsiKSDd z_wZggF47%elcU=jJfoPg5HaHaZ~FofoV>{=Ja-TliF$~AZ1?|=g+Xr1I#^tL?&+(K zy_0;#&bS}7zv8h!F!^zBr|Q(1yJ}~vO%z@;MaK_Ez1CRAu}j$O?F2Lf;$x*hKzxKx zx8X3^ZmTaGAAjdX-rZG~$h)lJw4gt-3%LsUKqbh*V55PiQQK3W`A^re#uKvMWe@^U zUTKbeIrG(eil{858X+_ z0Y8GLVT8bqhMOYYXhp%Egqyl8FcffW7R_DPQJ|6gvP{p;Gta)vjeR>b@tx;uM!a9^9#LnXJPx}k3#WJ#e@s0iW z60Wk*L0_hL^>2|?2itNm6|zbtty5mlvQ_#1*+ojvcB-*!PqWdrr`drFp7&IXp&@te z-dKQo(zkVrmgG9E_F=7XMK+wFd0wdP=eb{M^N6<>r)VMRbaonT2>Lp~=c|(Zo!KW! zzk~W(I3Xx@=km*YH|2XIq z1oNY1T_{g(j&XhH8^cl3%QA-ca|bwf=rcI7fCkMB-58O)M#2Eya~O-`@9yYf9IymJ z$;D>{I2Z*VXu^?m8>zhf$+*EWb}I}kRv(Nm52VeDpZ0Rc<9oVu3Sv~GK%g`+1UM}+ zg8|xD92KtAI@It}uD$Wd>g4Ct1NyYVHFkKIRUgJWubFRY@miwF_w(%ju|D8= zDr4QrH`t$O4D$J?iTK7EGu5UjHpF-+Wnaw3M3tfTrs`?-u?Qjnf9`EIG+u>MF{jx_ zO_q2A7;-a=ajwT>CzM-c$XlWI#U_9NB;XpRY>GtwYhj14Kj_2AYg(QgsCqxR1q4>x zb4~M)!d<3UZ+`KV}MJhXNWG-4NGjAd@~v_2L@ z-@!2rq$q-JX7`Nb*)4~{;BD3l%k1tV=fY~6-fisgtp|O2pOxD(tC?Z%_hXEk*W~a0 zzcN#G8P393X}IK*9z# zDS{!HP+bCow0MeOx{;LCYRdK(HXA7ICw>`@Ph4~D!3G>|(Kwug-c}!|NXx7|Lm2i4 z!&(^u%E$B7#J9hSem;=1wpe}Hi5aL#H7$+d1^~_!`U_SVefh5<5L{@U}WTf*JyQ! zpl3TlR6$SC;t2Bj5zkN-@RFvIU(%#+lsN9xEe~djKb36)R(K5g|t&;EaBB z3~KL?WtL6PA!gbb`=Ap&@H8!(H8-Nge&FPPO#@O4(}!%I#OT+6pzk457%^R@wb$WF zDS*`_(7w1|=lZMxX_?*3I5OC;p8YRrK%{5)rU3z)4ko~K?Y+skJb`a{8w5gOzs~hq z1Jcq%#Qo^ood0tTh;(|LG$5|hBS{_NiB$)x0qNJ-(4ZQ`sgM;u#G-nl0fGCNI#8bG zwM6ugW05Nvdk?_lM6f-(SyYQ)pgm%N`?%}xg!B43Nw7-hyqJ+O>JSo38RAc(T=XN+ zV7U^AL}}uwM~Wm9n+*jb!5RE7UJl(yK9)KxT*6fCx!N%chpH@OhpyzBxPlC=3v+wC ze4+5^So(s16j6{OlFSQqp;I**(-W&AQQ@TAbc=il) z_^ue|7vS3vLV$?;#)>x<=>n5sY!R4L22~4>wey@tDaO3ObL9*3>=RuSV0QYHB()6+ zL?F@qX_68Qad}E408pN62<#AM$wM0mfGqgo0W>_K@$oC_YGI4OV;T_{le@4*%| zv8ba>cL8e_TJ?e}%5^s+_5*8jvkf8J3)cJ&O;56R)`}O15P9YlNHS?X!JVOX@|!E zreJ8bjAufl&0?5|@R`7f`X*nYs48fbJraQgHMyDLeAlcR}v3;ROxJARb!;#9z z*ktEQcxdp;QH1_551^<*;Yd`1g4lAT40&}1K469n>KPzGm!&2mo{s^?%|)}gXpC== zI1eU2oIQ@;f;f)e2}FH>jkQ-?A};0TL9uFrp`#FYBc4^@85cx@(NM2b(GYnBA00qf ztLC8?q!0Z{D#>?;Vp_S2e4-*wa3e+Yrl2A7%bbL4G5*E<7;b+hAGa&OfjNC(4_(HG z^|aQPAFEcn)S^maHIuaTRA+Ow5W(Ez3ES1BJ(A2xz+ntjYly9&6_cK<0TVrSux>GD z@pF$2wNkB(O;5AVnQxj;l zfXFyMJ#&fN^h%u9to@DMo-b!tX1TkBx(KG+iMf)0|gtIU;VMZlfJ zm{rDMF9UqPRNqfgSj9=_mSH#2VALcf6+4p|o606DY(g5fE{obQMz|<{N|XUnYyP)X zfD*N9Iw=|$$0?WIz*rNQw+GhP&oSDB6m~@fZS>88OP2y|LPgW2o)5c~5x^k`+Q6GQ zcaNu|HX;#k3IK0JlUg(4oMTb(K}Q_sck=2Ick%yH-sO4bDMsqKyo<*E&&a#2>Jo|T z|5DzS8Q~4_=R9`~zP!sr`M)CX=4H7e?0!fm|CjPEdd)9f{6Be@9A)^z==47%@4`UQ zu$lXTQO)wQG@s$)9Ola!sCd%qVfySLIM$&Lo$&QwWE)KOdgcon9*{Wf7kF!zjukt? zdvnUlK|89HTh}F~SnH?4uVvR;2XyM+)pd5@`MDIuJ##ti_W+Q*^G^LcWvc^I?h&W{ zodzH+rW9mkm?`cwf5!DkRlaxpf)0BBD{uVk?h#kK5>0TTJS3i;6-{<<=C9Bl@S zDlUQN9*nh|f*Ldo9PSYqah4?^`l8NLoq3KY#~a_CC?)P)kjLVHP9ljb`7~`$Q;%7( z1Zk;M%Bk8i1$wC^IyA_w+-6@*@Ii*w@CSw>>Jeo?BZA{bbfNJBDoOzAB`Kab`upYnKNOfA@^+|QGFC$$?jO#$DYIQ(+!7ZrbQATd{lvCoIA8pk6 zN9eIztMXTJew5WuB{mOI66)z%eu|vxsn<#H6Q+lcYk=0C&7RcQgE|1O5Oz*5q(Z?- zFdV?FArG*R{UiA-novgNV-1izmJMNCnPk@b!oAvw(uQ`i^jbo(+d+ zT{w+~;o$Rhgvp7gG@vE;U6IltJSw#w=y&p(we%^BeV1B~tWsL!sx1p|d)l{_3Z=1R zE&UxQJ76l@#V1Sc z)EZBPh+5ZK42H#XdX$Ny9dmVXP*DMg_48;7j$TVViB$G|v^xynNAQJZF75mXmfC(u z!&&9>%(O^YEq0mda3_L?T6J*h+_WDphLb1m8+3Wp;=T(O z7>`pLC`o@pUmi^_pMzde`Q2PzpN9brpm>m4_l+o>3+S?H82H8=+K4-Xst33c}nq^JGsh-`Ft zgh=R83I#$zCPYRf=jUFU1WByq{p?Cc_%JK{2aAS-QMnJ_*T3-gmnnWk#+T;M~(wC5(J#yB`N6+pQdNw{70zDhdUr@6ePCAKE9F8n0DwP?q z^D!TgNYUW)(U4A#hWX+*AzlIZ5*ZQd5tGR&gGZ{Mrd+9t262g{V}u6jCuRbdWg^yW zGUY;fQ|j(dU!0;!jnkAX)f9}R>P?Ci24SccYM$yV|M{k2)1^H2WR;O#aNJ&uef%^^ zPHFLpEzl^K=|xl7WY0l;FdsDVBSEgeq>KrnnwIk3*m^N7M7tEN38P;Epf@UR7#EX% zia3*_sby2~wnCA@ZVug%K>$FnO1C?GO^l)7ROw;#kO36LUXLG)Z*WYVJS?g@sSURp zxUW*T9v(@rEvlsIQwHO`t2-3xMHwjXI^nGV9HFD74yHdT>hPQNqU~dZL|*dfPh4gT z=ub%KkKu%>5ujH%S26)Q#0np4QBRvjgZ|tJdNUpLryMkA3FyzuxZjBDIOxxMY-E20 z=NT*E3id5Hu^C%G=ud7=UG^JmI@j#yq*yZu9~vct$o_=;Dp+?;%G1hqfCkQD0BTJD zn~ZB$L)SqxbRO5VX(;NmD#g&-Xz18|seK|E5>rA9L}^yfvGAVcuYlPAZ77q8i3g4% zll5|!L3=uy%-SI42STl3FbD<_Q%CN#!9k}8? z4%y2&JWt$5n+xwQ(Ta1{5Cmb`zTWai%&*(m6>zJA*QD(j*IG>Bq&kXNvSxH3mL0q z+h8vqfy9likSm|8r$j-KjSv}fj^NNt%duIkL)dqi=oHOr`0UY}22M`IHP_-`(GtNf zps5K2yr2oL6&_xQcJQZaH;q^dejCIlSeQFzZnuK5LvXT0JWCcd8Gto3vD@i3AMxjx zMngEt60y5iPY$zj4{9^}0RV=aoJ#3bllv%~A#sw0R%K2D4Py-f{f@EdbeqaRVh*w+ zLvYzGay8$~Lv6;}yH3{UwXDfUlz){Ido9IfS7Im*#NS#i*rIl(JXYGrNl(W{3|V(O z0UR;`3OUBln(v?q<5Z@jcxSQtV(jtM12}sWoXe6bhFy)mqwo%cu2?}qH;zo|vD_#U zP0@uEQYImeThtP)3yVWz8?r2_VID8BJA8gaZOj#z!OklL>$sSx7D5P%%PlHY8gDFs za)pOzr3m_HY$Sj)QJPx~6)c(g#cu<<6_ihTfmkD9^a2*Y6yGKtsR9Tn>qTd;XdZ9A z6qwKu$PTrDY7;93)Z1{)s$;+~=$WXei@Sj)69tew4ub3kXqE7cHf;mnIKl~p%ba?#Mz_o|2VM7LHr41uC7HgmU$AGm zH)^A=0Z-Coy_%6fwS;O&>^LE@V_*Y0SY*dG&u@w@*P%@_g|y1iD??hJ2gQWQ;`9ZY z#(oa>TM~83fGSqOkvDfM=;_kaBblDYb~xRZK)g`2)Rz=ulQtlXOGnFC5aU$PQE~d} zaci=CG99fZExUyDuIgCf(4iKcVAE~&fsVrPm8qus?30c*Gedc!3V5zfH#pQeKtDlvzSFj88VKNQ zI}l!FA9Ml;ZX&NPe&3qA$58e%3w$#3$J`f)KMc}?eBOSyX-W%tE=@Or2QmQ!{Ibk`cuk zMzpZ(=Wq4lBgIlCJVAL@GCEC>jsiM~?|~#XubdzGDO^Y!SX^(@6i7zpP`o^D)d!l^ zsxB+L=fv7a)2d<7VDb5Gzj=UI6l5&YOdhV;nTbLvIi=ts(kMYBYyiQtRt=j9;xbL# zrya|D9q%S!?SdyF76*<}M=4Vbwg9(`sveoV)l&>|6k@1#Pj4DjU;Xw@X1LKwh!L+5 zF>r>yz^0B4^$Ub!2Oll4Kh-L$E^A#2*SWb5FEp<&erlbPAw%f*;e1LAHI3I7 zrSoG)4e2C6JSJLf3oU}s*uHnKZU2tnZqq|jo!kCkK((|QI->m4-S?L!iVg)(G>?Gk|{q_ zLJHL3{toSP!2d!cp(HcU)A}rs1+r$?V1+}56=oNWj-tGX5TQ)Mqu80$4!fbJOvwbd z!n)p&;)`LR12WHw&ww6a$m^|OQI1Vz!HoXF2NBwlCT{H!Hf4=GxO)W<} zEE^h$2-1R))bbh8v`AVp6caG<;U7n~IysIO_Sp3rgOV3Q%YmQ#%ruw=6)1)qC+V56 zIou?(kBP{=%y3JSgyD90eRABz2{7Q;inYVI%2LI#NUDxVr&&A}-X!<&-3Snv#9ozi z&YJjcobhFg=3U^s@2?NKgjP9qp{31h;;(AL-NE>f{q6zcu6AzaL*D)dd6gmuthiar zDuw^vXi41Akm0~tlymVHY!RQ_?;ITm9jACN(VVn~8-EVj*oUo64O2rNL3MU839 z{R;vL_s`fWIO^db{7A6Xtf0EVyuC9&z`SJ6z6R8D1F1{^>a76kt*;-veQsUWBv{ez zd16fTeZge9IRqav0g2kBg5y^ovdb7(QtNIKqCKGa@NqyVO-#LmV?tYTTil_8`!ua> z+najz?uUeIbskKS;sL;B*=kVwA0IY9F%m7b9%I)k4UFW#u2o!ImNO_|%tdkl_6kFt z!6?l}BcR3n!?ZZ2Bn-)dJDf!ER#@YvM0o(>V^YF$!|2vCLQxP!7LYBT) zrd~*p)kOCyrY743GT{6uLQjhPC4Codj1{S|veOfv03ZbjTj(XADxAvUSK)W&i1z$S z7;dH&1wUK-+B|T4m?#s9cJ_Rd*_eMTt;`f&*5XMc%6AwYaWTV7Dw8sX-WL%b6tg3oh3L879 zJ&Op}CzLOqzj0E0%9lvDnbxJnh2su6A)3l{6A-A_m&hueebL9_kTCp*_ktE zX3m^B)6dNQ5$(6zwS;TIyj#je0r%bEPG&m%6uczlpKuRM!G{+?tUiIf)#1f|!mX#Z zYSb`3Dscz(ziO@9tR($;4OuGRP9X(+oFwJ{=oXlQRaHqfsNjW65yl6C<{3|9yZZp?j(u{D#n{B5TgMJEzG zh*7z5k}rYh8$rGG`Fqp`RsVOfBgF8b+3KSv> zG~&D>rHLsaMFC7*-;}0VoUNg%odus)q&gF}_$X#rh0H9U<3i%R;vl*x9d{;RhP6Oa z*mB9tzK|^JYrKyF_9>1Fy@sQTQ!(2*kK;nuaa?HAKVp_u>yL~r606kEZzL+H#R}^G z{pr(+q8H*V5uL%-wFJTrF;bTx+Nuz3!Cd;6!FKEVa6j6uE6RWVw4&ZZ1r8h*d`ywf zG={ZM(8d!jlvT@nOcBcqdJ7deC8yeG&VySOF*c?%inQz#634&ks3OkV;lLeDz6v<1 z$lIWhql&x@B09t&L^LMB!+&Curk@=QJ7b6@`Z_6@(@{lZDu?Q5$9I&_1)_jfCogZa0 zn}@b$1=^b5lz)ImQmtAw|G=4zYJb;$!~D+B;;fwaVdNm^1n^b zvRaiY$$wzpRjsNaydizxNaD|5KAFgQ88Yws|JjX=x19PJGIq;TipQkCy?Jv~u2uyb zYP4!6ez#l4!#xo?W{5oLJHK4BPNwU_+Zb94eB{Zuxbo9OLSt3Xstx}RycjHnsx9!r z2Tm|vMvu*;UrnT0XXq+;f{Jyt#2q|*hQ+>yVqU~pJ9O8kP*=ci9EmVZ_L+6y`5{0L z*bM}nhu|s*G;YV>eYVkgE0c|jo*56wNA_MbrVIGS@sL(DPM~#l^xTuh!3y-&aAM3s zM=bPYaML+1g-$wmee%Fz2ZnUghNP?J5T}&h2L~{)c!`8VLI7l(0zrC|qV9?7%{3{V z@{BahSvnNc!x=sd0J3I#EtEXYlg|wG;&fuqdomFQB(oDyO0=kH_A07H&}=Y?F;d&G zWMxs#5GTlI`VVRwL1q!pa7Hxfof5#)ckj413GVtMZ4!REgI|#Yw$ap*ln0H0$*l19 zJ>HqxP({HQ0)u;-ApLA(ov4jOeX6E(?6pI*8Br2rPZqCvyv97+sbR8JcoEB z-(rv3Y*evfyf98kkB`g_+|zl;XX@+XxRAMkbe0!enYx{2vGRI z)9`?#(hdj|oyYrNOyo=AkSBe2gvSU!v7fq59KnPTO!7j1^)*DoPau&~49-nF)i%0R zuZ0-PYjIsE^5BPfhD-P=h$LxaK+so-m3Wf~V4#Ody?K?M>RKa+iAKlRkD)_#bi~NX z#CIjSckS7&YtPQIO>AH=`uaRc9>1NPYXgM}os4UMB=#eozx(`gwJJ%~jNt%U@!Pfa zf8SU(@D;`X-Lmlx33mQtS#Zf1XZ&}b8LC#LYT)9GJCMiZ|J)uC-LV}ql>KM#5rNo( zcNPK{T>b<0h)}+PD-7|m-%q01@gAR*Uzq0tOk zpqOD?Mad7{-?a9@iD_e{pKx$|8h0Nm^U`R@i>{x>pEQEOuw<4hH#CN~ZR4OF` zkfA@OGa!MvX?RXK*f&(69;VRpNqxAPi2Me#scEsJkX+9b?{24J81c;=eIi^ zR$u69iX1A4Th*6*?xP?*e>(E6R}^Y-gf(!FqA~nG%7_1lWs}VBMhr{<$bu@P-%vr7 zCAc;Yxzq2h&})h~4#R5-?yulO^=INRfJQChR}J_FrFtb2@t`VHuG%p{)D8(Zf2%Z+ zU=YDcJceMf=Zso`8HE^~a}87^BqIzH;awqcmpIa;EybPIO{BNzCnXqiaJ9|UM{u|cHYXq*X zxC41gOstwHRAfU&!F)5y#80Z=J4OmFdmm!FnfxhrE=v9*Vy;?Hz;d~zN5>xRd+67! za7XWfkT%{|nV2NI_@=Pkad0u>H|_NqG8olWhzdJYaV^y9)m<}FAig{ z@+^x;t055t`u=pp4?x~~iSq{A1ll-`hB2p!{Q2?M8m4Tqj)>2KXv@f7UyDO~5CM_AJ!@SPhH`OxhdaFizRXd|e4X~7SpIn`+j1RLE z8kWi0x)nbk8cfLpZ356v2*Mo3hu@witCWa-Pe07+U>I0(|9%@~r3$yl)mLvXe0 zH*dzM=6;Y1WG5^NQ|?$RGDT~ViYo)9&=^S2%mlY;_HcM5W(ki%lc0oU(Hz}VGw5K? z!+``Lq1IHaCo9@~Zz>MxDB2{vEv6JXMKw|W+NApI+PBPzU)S5qo`s?$srEUv`eA-1 zP2$piyKwfh z95BW#oN5NKORt;oM(sLJP|dIE(+&&A)|51_3-XNZH-z;@P*ix6Y~^@TacC6pqN!d7 zP)w#2B5RsgHKluzCQ+!G(-Abn8!7yt(v$8rX)ochn9FMh%nY7`vj{<(AY@}?GiinU zY2YyTqZ5LW0VjP>%%oWY?sU}w_f53Nat5KNru$fUXqGE9%N3f1g@y!}DW_)D4Kek( zwMZ;ifOF;K=72@2rs}eSml=fm%v9bcD9?bb{8365db!_d&t;F0NBW0h>Sx7fQ{@$$v8p)*vMXjjPD5m8`)Jd zP7nY#vd5Egh5)dUy&M_m2>=_}E0S@M0I-q03K^FP02|qp$+%7c*vMX!48Iou*vMX& zjNt@;jqJ#DIe8QT^z1hzz-R)%M)sy;WD)>2vNtDV0s)#s>KOQm;)*00B^D9`140&& zTga>dAtR{@5i*jwKQCk!_5V)DNU9)@BB#hMH3R8BceuDr^ZFPV6e=)TUY{ADP?4GA z^+f_iLW52NVgm;W40sBWfrEqvH6P*vhYCj|IpX1nH^P*Ig9LK4j!f{93%idOmjH$DSY?;dnFHU=#7gL zohNbMMkj5(bOEswn&TLX;Obz}vh!v}J8|UGYl_!~&zF zK%EK?T~I@9p@!O`H`G|RPKVB}XqCa8NKsqRY@=gRR9kiGm8i*}R>Py6IXn{#iXv`B zXuH3kINQRzI_l#%U%(&E7x2fe^N0E}ml}mW4jq|Q_0RxIwdgEyVEizMcUxxanZmjv zJDj0yj5}8jBjFC~$jqVK1>19lHiz*CeNtFxl)8oTh+!A;#~R=dTE{4rdh`gAo(RDo zR$ZP${E5QIJjkDDZS#dsr&_#L;*UqWxOvYt3nCQq!}$XKaK3;)sONkv5W)FlMaK{R z*wtvS6#y&o2P|=e8o?h6Il^*?4;@H#;P-#xX=X$FarJc4FV6B7<;sVI9>&Wm5Ak(PP3Yh^i3qgim zM~0VyjHUu;wh%Pfbu@SZ%?A-c)xb2Q1Vmm&l*RjL=V$68#oCNZ2SpMU5((^jBvB#~ z42d8=Sa{az_X!P6UBqpN&puI0u~4o>_sbPQ8AQs5+u`xXb4oqAu~iO6abo}{hh?KA zd>mSqG3C*!gpo-XAM!>DQz1-Ym{zDCFw#PE;^R?6@G$DT0 z@E#FtF3|uoF+s>fW&%*Gg1dRcSB9sZDCNOXig|)3q0(Y;q^?M40r4Z8@?_z&5Cf)M zlvjg~g(A1)3Q|)9Swd_G&ulIDkeDFHd5Ntmg1yU2i^@7w(CP@!MS6kd$BF7dp;j(m zPS$`YXM!~!Ce-FSYgm!dr)U@;p#6_1CoAaJ&|cF(BRHD+e`c~qb2Kr2;=?NRS#E0I zk#83!ei3NLy%8?P=l#pPsqtd1Om==|k|KZVqSV@mTTTIGoo` z?4z$T;N%cwg^wT5w$fPKAx7!;iVz_ufj9#9L8I!^y&dS0u(-ukSDcR!(hLtLA@OjE z>Qs3wuC$PdFvmorkxxVsw~r_yG$M56`9~Ca`-mb#BXX;fYQd5NdVimXX3LP*RMi8a zozK@G0LM_CAvcb6)tbgTW1e+)9EJ{&xEZJqN`*`pH*INYX<)Ji%Lb@}+Za{|sdtuX zbYarm)Wg{`=mQ0~&juP2Xhf}=r(aq(4(dZmIi2s#MxSP98gn{owo`L9e7SS`KE^bM zvs8Ri+xRL~;@h@s-=Slt&Rx2ucI)1wXRqFU($X{f_6156XTz?E4Qo`X)vr_A9(}ua z?a{qS`#x3r^r_maU*A@3)B81Q%UZF=Tcx$=@npm5eJb~Syk*PYHF`hPu*-dq)~Zq? z@%~QtKiUx(SY(l$#jzin-%kQqn<6<~H)mH(#(^xD)c|=%a>^C(o-aAKsiRWs$M3ey z9+B{`VlfTVdz*YU?Q?PxXOy3GHNp03_lM3L_m*qaKPIQ<&Q6c5@9sL8yt@42>~C5O z`gG-<;q{Byo2=Zwr|`JAYXe_>$Cf>wm%5K#@!bWQjwxNIQ*JYa}esrMn(gAIrZPV(PGOdnJSk!7^yGc!-NGWupeQK@GTCMUd zs*wEb_V;(3(4v-(d~D|UlWBvZ3Y}e1VO_8G&waAsp5GFSW)!aX?2c07Uzu8U&EBQY z?u_p~v}Mu@{YOqLH>v5EI!ixn)-CSD$D7A{%XQjr-`95R0`Ijpiw8AL@}GI`x#xzT zTi$oXN%^k34~>fJczS5PSMT~{@teDU>D9wstHH&Whc$F2DC+Pz51ilD_4%o#r#I-b z#XF_@$=}*eb9FvHYWJcqvmQz9Qu(oc<>tBHoL%*iMctj}dVXK$g_suS>#Uhn;o3_j zJN`VgpR}}Ay{A6wG%E7GVZ}zC9sT}{UX3=*9X@#d^RLy}*SFV^balgs84Zi4ypy`& z@pcP$KV<1&zk1rYzsKDxPi+wYbxw_@(T<$mr`!jpX8(Nur)e#%FUC#w?;H44nM;RH z{8qfh@5kyiAGqqHBi-LxW64%lJ-lGU<~B1@Hco%``S$Ut#g_KE)@5bO?)6T;S1YF1 znMdoCe&l+OiW93$ZP;k&cKb)qFI94mt-tX=)x*|u?oKP3B@}yN{^!~5jBSl-wRV1a z@Y?PVKgu51%8}Hj_!c&E@4&Q*DZiJQ(Rusq($_AZocqRQU(&&E3-_%X+pX=5ZKYaN zUi7GW$<>wjCbfCxt{Y8XOl&#qTUKxF6VFc18r|!&gvVbgez0qiZ-1NLV9%zTFO}Pp z)Om4wtA|G~EBj2>ZBKr-_PNDcJ< zs&)6j@nz;)*P0!;@XgVxFMU2oi@DbB#Fp=O9QaHJ9jPFFn>i+U**dEi$t#fy;9#(GfT^_xwmKia3Z7E%DulVE;{+US9ctF zc>epVkHp*A9XG3;#+#;gD0j|?+{<=L;LxXW81e{_|CUa zy?Wn<0Yh3oy?@p-gVj$y{6X$#y8Gn?J14g5Qfyn4_CWeWpH*tI;(-N)UVM~25*J&( z<&^qQxc7d)W$Lj*=voh^vSpB~3Hm8%yk-`w6eCFZHDdbNvwKV{Nm^*g@Z;F-PO zkLk9z{-w#*Xrr#dX{&2kTP!Rw+*M2!QrmqoZ* zoL5ShIDc~mlZ*fAdiTAIm35zd;pH+PdF_X;#EjkbTjd3V(wihrkedAJ8~Vc!wGSQG zSR=XL%5C$$`DIGuwhb3VnsVIrwr)G4mFhcZ@)tF~s~mZ%&djy`q{J2Viq?GXv4?CQ z_ITJ7(V*AIisQG;=npCm9Q0Ov+OmOwG|2VcOEL87Tqeo zPq&2Q-xP20$``|D6m9b43q=mtGS*F*v2OI>W+!W(dEv~}k|Pdwy3gMJ%S|0NHz``; zoNa$>QjI$IeN%YN#`yaloEiPd=8n)+n$Y5#?`y|Qzx-{VRu3h5_V!;qbZW7v);~X9 zP3g9E_SbcaM%A^?jeqK=<6|ydz4r546+d1xy=UFnQoS1;8@asK$y1K!BS)^NQ19sy zKbG!))pGAcA0Fyh-d*y?$$MX|=P$FZ)1w1EZJv<2!ZU46WbBp!r@ouevhMY{7b`hR z&3ow5g?sNQS>1hitzvBkZY*Y-ch{qOZ}c~+S%T;F!R~;m9=K|Ztk2ueNUmo3qM~sa{JkN72CC0^z5Q( zJ%|7D-qKR9b@=T3N5wwudRJD9wNH0Udb&%>iuWtj-E(q!;-wF~*~OfXO`V+8`jwX^ zUz#|7@V)J(jH+?Df2Ct@wI2Ud)X?ZIh0Bks7P+_d@vSqzJ^be6HBSzhJN(xt+Nb&A zZf<&c>YI%>7C-G+@x^0R5?X%WbpM!giR*ftyKwr+Q#ZFHxBaQy@9A|1o!wvPf#;5` z?r@^ebDjoAV(O`@zB}9K)S`v6V;}B*Fz4aVuQs^YVC%}Yspm@8dAOt5`-L`rV5xmu z9~?08h1Xes`k?O*MC0KdhfwHzV1)e zI6SCL#@Wy3T^NzlGpYZM;eP8o(_36F)@t9m6V=|@-*(}=t_wC=T%TNDq&$7-Gp9e{ zg@)6ICpX$;?!4#5r_)PC?mn1)@QYEcJOdB3?woR8=VKj{H-ECPX1zYsFPFPlz1idE zAHDTrAGmkfn0sa%JAP@&%LltWeecOjDMKfexV!mp$>qCFxTMBvm%ftwC3L&Et_z#> zRiAjmyT6kHtfj5uYcnD0})%t=5fJ$D5QnFvaoNqA~+ol)G47X?b8|MaQ)s zt4_8nbf^pK+Vtx=*^yn&zCN?;tl#TDJbKA1CoD%suUxhF;tPXH?O1rGb&cJVXAjuX zphCBlYSVvLKOFJP{zYHcI{Vr~(RD6e{j}ucMSC<$>@@rC_ue{oD&uO;+DZ34^Ub9n zwJz7x0iQketK-^RD}LX%`07kMCt!F>IVs)2Rv^fKtq!j5n>bcX8v`*TUJ$28R4eKs+s1~Iq4|uUmn`sr= z%sz4X+qmxSOK*HXI&yl_QF+(HotDN9-Syd#iFb87I<8*TcFy=Zz7N-*jhyw~h{+La zj*oVw9WHliR;5M*qH}IcSUs_wZE%P4zi$7r*X;WryV`W{D`juIy{Xje^?uRXH*sX# zOqjf=XRq2dZd|_D=1}zf%io-y+5BkSH{BInT7i1I(r zzR9+abJtqw{K?(*+Kd-FO&ff0hjZuHtl7`U?jKb-W^MeEXCC=@;Di@X@2%5sMMA9_ z1D}f8{?>PQ`zs|TT%5P0L6Xyl-@gpA!buXb_$H<0Io%A74Au(xUyfW<@>S zieLTdv#5O^mAUuRO-H|bs&IpbBV(c+J&7=1YM#ruxbdS`U)gk}Q_GAuR%~l^q3`=2 z?!Vr+?cJwe82)X^*9JzW4*zaq>#=V<)w6N$C*D`bw%Rkg`C<9fql=v%=9q`AZQ5>r z)bs@zeODD5vf6%V!I7EvN}Z}UPTDM&e)`1d_2=znvL-*^`Mqb!lJ|aC{M$Kmo$d=G zXLkL$OSzX1tUmO+rPdQucYHVV(IH{PLXq=FM*f<;@X0o;-QYu2zMg(Os{N^&cTMWwzXT_=+%ufXL{E!@A=;QJ*%fyUexr7fjuXz`?BBcE!#HU-|_5a zcgw+tUvFH}k-lfkgE`F)uB}zRMdLLKPTW0lv2yJB_2>6oojK)^N~zzCKG)uNcI1=~ zHoltuTSEMO3r(fw&dIqjZB5(kmmf?$IkiRX4`cQ|(_zh(S$CH^TD$hVkrNj*JK3() zx!va~Z#{77(Mw%>DfORnT|Dj%;r*CAQeCzAv>HAloulUGo z_sF#u?|F0ZJA*$mS84E|on>Z}p8COsC28;PeY*Ltqn_@wxcrghbBi6hv3OaN zsaMDU^!n!AC$>LPr(F3?doGtth#5FmYCWJ;o4!9ajC}Lb=;wDI`>KaIc1@3qqsp|M zY5M4V2XpN7)0<{Jky-al@v?7Ku-0BMwMYH9U%l;1UF$UM*J8gMy1U%|s(pXG(Q5gy z#q4%RR2fHUEc55*!hv|i&~Fcvi*@FCmwv`P?ehPo_xE;*emMzjhQc;+VNt& zYaMoYA4yvOaQ~N%t(xEX-twEewmjU_e>|px$M){5`1g8zbEDFTuARJAyQA@x72jkx z>ag>0_b1=ork42T()wpoUVk!fi1g+5wa4D?_EPGsZyMcvs&+$1wR(HLcz@me9jDUP z4)1XF-RMrQH|bUP^@zxfCt{xYu}|T&%g+sNxzzS~ zO3L={-hU{y@t4WNm&Quvlx0Ut)}A!+{TUxvnr8LfF|1DgUc(lt)tZ$oE?q90R(5%t z*tUo2kN@$Wfwk9uRHjk#(ORRjnho6X$m&m%Du24BbkkKHmT@yhED-?RM4>Zhh(s=fBt`)(H7b75Me z{beiq-uk%0_2aR9u8(z>iJdUD?f4(Ao}RX9$5S2VZ`?J1P4x5D4Xa$K=3^aOeCcU0 z$Mkt*&of8r9Gp~meb%Jr9Zn8NN}5=D#<$~kAGs$vYj>#&eO}cv9C4$QXE#&(tp8+R zQol{FloLgmR*oAh!XFZuH^_hSc||1fsnfl@mMw%gI`rFvgPO`E>zL%)AMV&Cg0 z{z`z%(Bqm{HqI!**wXiCY?Q^zC3HvdLylU5}dvCq^x`%9n2D#N{cQ{=Uk#0{^ zbWEYx!bOS}D;_5hN|Y>BTJ`$wiZ63_*>dG8+*7eqLS>N(_h)P9#7s~teIG3#xtSt+ zTDNYWHn4X_>vr97zj)Vle!-M%vNdQd;F4@hXr7Rsk(Q7su~L#;A~$|QM#uDw)?M1B zcj=fevxbuF>D0Y#=k(U?2DVP`+b&~ZZ+v8^xFlOdEQ~prhXo@|QkaX$iUY}|cg$$r zt>eI;UsW@cCD{(Iwi&&;R!_FEHj*3xXV;!xGg_x-w9V*<58tcIBMGdo8NJ$8Pqs46 z`~~IC9+{BVt3%t2wh2bko^U`yB4hCe=vLWMSWyElcit41JJKX51{v5o=c+OmYkons>Q!F6mm>JX=JrZ))f|znpwlMayEaOgPE1P7pDzi*B##Wi^$~v-aH`&=_#mW{dR_i)NQZ_3NrhEaz zdPtG1Cjj}$;$+HPD~xMo?8M!r%3+6@u@erva?#=1#@G!oF-$$T`;DT@c|iMl5viVaq%#glCg`7 z3uKHg17j{3ACqy2j4NbJyBo%bWbB1ueWko)omgH{zPrc8{t2guY6K1jskc9`oqX#% zcA;iW--^Z^yZr1`0e1s%HDkLW?`b$JgmXcDCNZHyEIIgPA5t{K8ah--$xmpmI-Rdj zy~3BnnA0!ixBU8l3foMS1zR+Ja9^mLQ+tLcfwyZ3?fT+aD9A0u%v^O@icDyio}Li! zR2btK4y{|VVnhBS|Nc96t5vC4{SVy140ZIX;v&2@4%Rlk2NjaU8Ka0(nO4$9$B!B6 z>A2Aa;&Q92S#PP8j(&l((oLojR2T{xc3l%a#<7MriIsOOl52>{DlwB!roFwoeXzBd zO=85=Jm4W?Lr8cSs+F`I0S^g#6v6`v6coJ?g86K^2VLJ7;-QGmQfvhJA<`T_Esdfw z`eaKmoH zPBZOXW*d++>&+EUC1|LmLIFi=;AcXqpDVbg`tU&tb3bfnVW&jCjP}1I70NCBV1$v$ zbHQcFATtD_lNkch$qa$$Wa8$PJY>U$PB|Jrzji=52MR_^o@ROj_2S6jlp_RHEddD2n-rKs9<(22gf!H zJO_t4w9F6~G$erM)N*hIwSfnn5x`tpW(bU{U-%-l9Nd&|;6bkicudO-z$DUj0W4C> zoTlSJrX``g0Tq&*FsMk!qh+F9;&F0ZK~a>J69yHuM{Ak5PCJMzav7uLgh2&A3Tc@* zW)j5ZS_8gVEhhj)34oEfQAlJ63=G)8ICK#L4u%EnU=*%D7H}{qUg^c2Z!G<3)7~(?4aInbmLxut_FV~u;gCM39hzxX^u*WNL zJp_i+DMk9Dkvwnhg933v+vtcJn)i|x(ND`R&24Vd{z2^q&PxfS~HsA{A=jxxKBz5PsT{zZ$8J!G8lFaefjKKUfQAO~s)gW}HD2$0xjuT0JfEedJb~%gxPXqBr`MHTKDI zffL#MsFR{C`m1ar3FloYSME zD1*REDL^4A5UETvp+bV81C+MnFc5)Sg++x9rpB7k(GQK{FX-`wc{ysckfg%AoV6KFqURgRRhvQE9)uv>2!2Qn!V9~#Hbd7E5`=47MUt1f zHiL38vX9RXW8~%M92b2JWramLO_K4$#SMs~cH;;V{BNl`Xl4yZ`ztaDEjg(KVr-`Q zUrK}i+>i(206W4Sh|{9s%!WmEr=phmJlYZBK5FR41rIQ61tP7gUc( zz1Wrk?JZc+Ak^gcWTZiZsVGdB;m`H7X?$$>JGj3|8;v?@(nd+C8b(e++A-KiOTy2e zjg~Mjg8r=?X`ol*2hd>ehq(klf(Fliz6cybgUIp#qa-LWB0z4nV+@ga08%{mIVb>5 zU!Y&Y0RcO`tjHj58hCp}#|fnjH6oo?R^cU4-@H+t&YG^bR3L4`B+j<%aQJ*=11U|bsTdzjx*gy?U2B+=s1>e99O!J z8YF>Z)p2l&GBhnSj(SlG1kGxApcxKni8!ZtN9%!*pfe8D71wpaAtKby$)t8lU$C>| zcp1Mb5UHYhM=|AYz|6b>6PNAe847iD2?Ty`A4x~=w?KQ zv6~*3gt4HA$^@H;2@@G3BG^PcnBnQsVDzYygu$aA2xCVPM^ryeM1eVzASJe+CL$<; zp(O8mL}f$|S{p)u?hOakBybTUk3a)UrDO)hP>aV{Ed-1X4`2+I!ohS!3)eCa2TLM) z)L;xwxMFZfRPDH%;^ z!@&?afHABJ2V;6ox1pLed@DYlk7rcH>3nmQ-_K$oKu*8H^q&WBdbk0LM}G`}2Ojii zczA$7kMUDsp@$o=sQP07RCv&z;h_S79^;n+3q9O`B}IP>KngtQ&+x$31FUfCKR@2| za03?PkUs{%4-fh?JirWC;l@wW4N1311c3u17w$tY`Xdl|kd@F%=d( z0VizyPk`YC7asa?UjBtQkA$V*g-3s}6tbrTov`sg0frY`c<9GV?=QT0B+QQ&9{t7q zWcLT1u<<_uh8J9TLVgnLc=Q*EIu~~V1z7(RV5$cE2}U5pibsEusB>`_P=NJ60j6re zpI~?eRy_KPM4gMffC8-l2{2Uy{shAl8@a>_jzYw_xCLxKObPmkD~B^Q3e;uu1A{!AVu305B*Z`gt`gf2h5)$sDaxC zw+(J^!{zkL@Dz~&;=x0S@WfK^#={^PxKbAAc;jIb;CQeu12+*xKR-yOjQB-vWViv4 z@g^QImIXf*PZof1%W&f@zj6d8XTaN}*jjkid(Kwq7zTljNc!C!xaX(UU; zK>jx1#@m1!Z$jih{x+b-+X!X64Y={e?Rvt$XACK6k5wH z8fXS69!Y=5PQQR#w@{N{G!Nt%aED`a*B=c{fn@#BBM7>657Es85d&@>;IDZx=R#8`z2+Mc1l=J`g3&w}O@z@*{MFEuC{<>oLWj9^kHEw- zx0{gvVrYs%)gQ9cPt_m8q5?oq9ydS%Ah(CPRpEK-&=ev?f5=Y16#X$QDFD!u#|=;b z$n9b76ybU6&=kV2KV+w$Uw;gX9{_stxB&_PxjoG77oG)%)-qM6-@}Fx9)5mQMA&8E z%fm#a-u^;KGaJ!VNI}cm*ar!0Df-%bjpg zIt1h%@bkk?PT(73PZ>@gH^G3<;{_gv0XYyq`Eg`Kz>)M9!qJc7_N3TSnD`?*pf+8k zZ7CQlr$FZMCLBDl^S=-rz=4m4e8i92^tce7$0z&9%QG;DGnY5#VOJj=}>s`5dNGFauTv0M$p0W zIGkwUbWyZ|Hdyo?3LfOgaRjYo=K&~AN*nE0iXTi94T ztupZ=xCARbWXFrgO*r%;xC)r$7ygJV0OMg1hG6squ8|JK!{hT(SaRU4!k{qB4_rKO zb3A}44xWaJ+JO>LJ>+Xs@#fR5fSp2l07n>=Y7;BHaMZ zh+3j)s={RQCKi!hQjnxVaGKKcEC7$DwEQQgw!}^y7jXzXaDXrKusj^ud7Oxs!zmv6 z5l+Y(bnv*0X)~WX6Ky&Uk5{LO;-mC9-GVMbrx7PlL(s0{a++Z0=~CKc2m8h15+_Hs z$-LMIrc$b4ol40v+~7feHrVloofnQu801GT3d2LojKbg{d;#NljKhMsJYJ+P-h_)d zfFtm@U8KWl;o*2%f<~k(XeWG1ho?!Qcs!IYQN#TZH_=V_;^BFMKc%T=n)Zr!0{I-Mlp z2T3Afw(i|Atw-w~ZPUATN2%go>~LV3#QYXXb`WNIm#&>MaE8Sr$^V@>X?pE$J_fBuuYk-~k zk-Dvu!0he-#keipX(;O>9{Mhntiop=3|jg!S97USHG zi#dX>s*%hTbR|WEVkWy;Bx-TcyPAg~qeev4qsV1#o8G=FPUA#FGw63>d`w~E3`;n> z6_&q8n!=((LkPAjEXDu^c;6ko&kLmz$qVhCm>)C^(7< z6m}=)i2{k~%uhm7Xv7>m4U`*{oEHn%*5t;5YKq&4OD_b4v2RD93_=et440I`QnsX2 zmi&^^RLW*bTa14PNPbxvD@ob1vQU!zCS?=sCgn>>hW#*1S;5Cf5aKrpayv?v5e{F9 z^ef6z*d=8nOhwrXQ&vs_ZdPu~Wn~-elJXVol5zxgrkt_kY}91{6lJ8t zf#@eV9Eg4v>}F*d>=tD`>=tD^>{jIf>{jI}_Jw5S4Hr&L&BES{qO62zQTD^MDL=t< zC_^KhewQ)WRWJEl)IKTL9Ya ziDAlq54Iw{^TaB@dJ5yrm!}A`j*E)4X5m>J70Jc|J%^FoYR;g7rsY=_bwW_pl+o@x6$E2#& zlaf2u?ARf>O1lnKt5iL%BxPYWk-)+XTLpkyV^05BJ zZ$em+t)AUG>fcM_u6({1fsaMe$0N`|GG?6F!C*j~{IWO}Ed?dY3qjT0Y!=jv-9%)1 zF~w3Pd|hcIcVS1C-r6`ap{XmNlANM)eOyVUuMlWFB*K}rERKDb(Atd?S})lwsP(d^ zxLFw@za-zz zh$ts%g5MdLxrFm zoVkQRmjG8Vdw*U6z^)J;;zCDao`nkBy@az+LKfY6xeFFL0_E-qlshSZtBydqOR77J zg;FjSM(X7bII+~6yT77&+CZt$+GL);R0OyrJGeDKp$Quc?lBzL79B~gM zC5U7+l5AYd%{7Vhroa`Gp^hpNAr)WZZ2pPBi!MV)YeQv=PXq+Y7B`Xh^Vvm-5?MwS zr%UO*(ZrNn)pbs)0~e+GqBuKMUh@Nu+MlWQLihr50a*u!NUBXtjTRyeo2dc1pQ6Nh zhi2+6(&qB$Qk}f;0=ACuZTaeCs zgdpj+>k$mn|5}d_M!%^3qK=?yBRjeXxQy0I#ntM(su)cUNh)u+f<@pF4Hr%s=?#~- zdN04e()m;5mRQ_U=S$LS>aq#HSnfRh%RDZQts;{^TFL+4sIQ#ac*9WC)h5M_;Q+;u% zm<$!C!=EUE2w)XYSL6Dq#nKU7slulqi@J?<+wmyK<+zZ~3t879(XjB;}>&#vd5KQ^sdGB$Tj` z^77T-4|1!sK?XrG2wK1Nm(PHYgozE9-cWK1uv90Qg?tt#uBbAIn>8!@kVq4ZkvT=g z31sTn(e6f)aY(Yb&V@H#`C)~~EN2hA^h9T7=6nJ6AW@=*+BBqRQ^9Pr8po3jB>LTF zmzROXW=;4c*~f`)+XxIB!-b2Ag8d(MLqF@(}Irs%cp^%YP zH)YjMNn@TK$PUlyH(BeJgI!3KXBCBx$f;m=&(DkwOBC!OHV*ybl}`{LZ=%~S?OY$4 zXf!42phUxxR7<34$EUtB288ELbnlo$lf$#Br~1m&uigQ3@}~OJf)fkD;6PTRC{-(^ zilPnA>WDAL>_j2uP4)8D^_}y}>i!Yy)wSM?}LtvD8WhNP!a?UK>LrfQov&zT8kSakU> z#(hct-@3VIGPvl_ORG5dpb9W=YtA9?+pX6+nR`%k`eF8t4yjtKQCxN^+~~ZCI#abx zD}GvtlFpmxxXCLnLqzf>dgH{$pfYcoyVj0fi~xZ|ZImd!rjR?Qu2gO3^_e&FP4vhY zEBfS@=7fA`YEDED9<82=rwg8J)et-HT zN)5XDitUdz}R_H4?#{q7fU59 z=Qfk943Sr3v6&|SN@%dETbVMxSj8tJp}G*k=CY6IkfcQjg{3Q0Qvl z7cD}e3xFd=grcsN4{}5(G@QXuXy4#hScF0w1V<4O%I$P6!Xh}cFdPz%esW-y#FV?R zg*W78gkz{(^)jU8jEGOA;Qa}6DhL2u4*PfP+#jPISz-~ATqw6E-B&5IyO1`v`-5BD*e=G_ zFOswxJ50D1vwb(_0Ub6glEj^sJtW!Gu6nW=T=yvEal8cLjD6YM>3}+gl`hCvCy}ud z1z`}KceeBFG@<})3KREzhHeXYwpt`>w4@Z38N1u0Bp|2A1FLIN9>s?5vlhlWSgje7 z^m4q(-Qi?E(%b1`hwz+oI@#;k zBwgxqv61+W&$<788#ob010 z7n>OEVsr7Vh<37rcy7SHJjTT?;TciL$=)i2^zfX)a~1Acu}-!**2Q+mMzEh^UCP+P zxGQoA8K08z0~xOufw7Q`FUdGZ#^j?-lc6)HK;`pZYZ!?BJ?i8 zqJ-uQAZUF2Ok$3CRB5F-bVrfQcLz_-ze!6ZPiz;`i@Fcl zgNSf{E?-UN7!RdJnsE&xng+Dx*l{FWbgdj0i4m@d0PQyia#9SS5i8$;15lvw4%W$5 zQ}AGuiHon`M3WhEg(tS_3rVby%nF%UA%&UER&l3q8p9Q7{!r}@lbPKsv92 z3Y#gJ|87xpRIZj-rN$rFU9Xi?Q(SVXhR9lhyX$XIS=&h%+^t)8@7l9t+qBl$0`HYJ z5NCyTFzym=->r4;UR`@;bWAf1;b7V)5A2}dYImLdGJ5redKtxLP4AtCXgUcOkEAy` zDDopoaWou)&uhrPDr#q$`SZLPl%_1-=!Vs1!WeX4A*hV(^R~n^Arz{yiT!=;fASk{ur;F~!a%z&kCyD@)FLwYS z^Bc587+gIXM3(bI4vX0oL^jS8Ap_sycl z87e3esh~(f6_ojsmo~e3H8024raaJQ^wR~FCagc&m-t+Rd=WfBE1DlWC5G~KhU#)q zI#{tNC#I}?4;&gOlF&fG=ZQs(x&{iSXS!Rb(56#JYh#pxie{H?!$o^?N4Y>VLrZFb zNXvsc-U!;jk5C=hD+Q|pYy#yG1ygRQq3D#;rX%NtPC1&lKq8#C2IcS|$}uJF=B4dz zG(LZpe7z{Z8gvXE+=S~#V;Lqq+aLsCl9Nq4bW~9~K%g zIE3xUJ+YfqCBSYgqO*H#Tu=&NH>3#rCfQu;$3}vJP+@{XZd*9J4N-;%UE*t3ZQXEn zTsWsCU6}ZF%0RM_xZ8xdWB7+;j7Xs~g4?9cL?-y)rQXY|wSm5hI!M4t_*87$qQ7$j zNI9b%0bK~cgb=)#yppDRBZW2yRRwgIs0xul#4WDW4f73tzXVkk+O9*VTHZ8DcacT{ z6*bmu^bKNcSQ#*Ul$&e2(7rOMWDs69Sk=wv&Yv?9GC&$cgo%3~A&flBkvcZM6WgE- z<<15?a76`ihNcVUQjNG}E_3J5jT{pHiJ(X-L${u?!D6D@fEhFZCA3)*q()MC+DHTJ zFO(-Q8m{$X_PVL?c+qkBqrw2OZYXjHRf>o}fvT9wf=Pn8s?I2}ksoZ(K65)CO_cd(|7+nfa zgJ85gD1HfJMPB@&&A-kiUd z4%TJ8ZWIcmlH!f(e_2NXsX^P;80`e3`3zcpF~mT7h+7nmK7-~rREKEqUgsf6A_iWl zOVGeW7o+Q&g$@O`QC}T84$LONZF+OP8=~gS7eftNbcDpKfd@lEvzG}b2bwtE_6fO1 zpQWj&*(MDI?X~4@(Wx)g`z#Fq%A49ymu1tNxh}%NTRDUd_EtB^nF*V#6Jq?p`z<5=&;SOkzW{ zJ0{SnSg^%3O>+^mEX%lwX=*@r?(6@;I|CUi4&y!Fy436ibAqAd09>rBHG;PAzyXLuutw1KlMV~55yTb3%N9eXJF5|pbH41PWB-9MT-Z1j z>3W59@K!1~Mm0uoj7D%Yb_8Z%Twshm31-v|poESU^twjUf_m`RM{vABGX~xv)n$kQ&{f*w*V=iZwx`V!>z!h;(`!T5 zEMstu1rBK0@hH*4?;xC1tf|t2-i>q}u@4bYc%{CGW^{^{6NV|&U&AmpD32J(J42C4 z8`6w!FGNi=JRssXhv>D2dfK3qi1i@S&ZYasNpTlh;L5tXawMf%iOrCZFI?*!Mm$(j ziA~3vF;~+JjTYCklgb&UQP8y&7dVH7G_GWpQ^oo>u4JC7NJWg5aX(hZW#NN?mWgu~ zOa-$@mlEXR=6DRg=n`&z)jaI|#J%zG>W5q7q19mu)wV<|T+xzw%{($)5tA5NlfGYq z%#o&t7SSJSQMjiX8jxB%d4O|-q;MpYRty@D(9I%mQ@?bs6=L$5K?@?pGMq$GgS0UJ z62W~IuN8Kc2glMZ>?OFJukfLvqO@J;&PYFj?2#B&QWryZ55|_Hx=HqEZ;VjKEaZ(v z4x)U8)fg0dtk0Cz2Zd|GRpchE6j2w$sdMyCCzZ4aP*uD?=!*puiq{0S`--SeUs1S8 z$&(s2A$mxL6vHG+4@c5cy|I{PVSpc@7C|P8lFlqfYlT6e8HAZY5F~=c-7oXX!k}(r z0ZZalrWS=1RhL!Ra2N-+60l)B0vpbaK`|#1wnDI(RS#?)*i33PY%bVh)k3gA_Z1QA z;^E9PL#ak4rJ8boT&bp9K&gfwpcG0qeCd?-0-;ny2tujGK+t}qUQsC3K;^|M)M}0c zXlY<5#QeZrhO*4}++`@z9OEuS$>uxmG8Ax*a+jf;bA-Ee#T`0>!a$R3EOjBny21>` z6>#XPG}yu6(!kYaxLys{y%9<^x~`1E1L#^bLZwDmx8b2I@D}PBriX&0!LPIkRfs!EiBPfJQ6eN%VL(J$MY!KxA`}i>a)hK~6lGCPB0M}cX3 z^x1hWd*$4ND^EVN@$p(eNB#WNoMH9H?Rmb$qDc#_`=n=Hj$S_^F@DovSF4QY)~Efx z{IGwX<~(?(H*O@x3aZth8`=#sh~IEPM9As4M**eWc!` z9$OOUZ!2qBwspu;AOGS!vZcw`d3zpd|Cyz8`SOKEI98Xf>5WUc-lO7!F%dOeK9=t2 zxYm){FX7XTLq}9h8#nXB$FrJsDn7sWYt1&!ex&=>VkgG!inmPOJEB_T#ok$|p28dE z6ti`&QL1_Wre#;ITb8`SRif4d3->+r@MqJW`K4Dvm$SphWb|r3cR-;5+lJfZt)s8r zT%UQmdy6@jW?xxUG)C`xo$mVM_4sw<{pkx;O2y*VcE6i??-%Me-6w#)V#DprM z4V7-IiPq6-?JHSdgC^QrlEkv1iIzi}X!|6Ga#nIO_M7BjlVq22RE}Wmj2y{!+udxq z!^8ICIgaO7hnr1yy4hN%hh@4vEDO(4mz(Xwa~1YCBBI!+NH=>g(!*}z8RPb_>25dl z%G}T^^RNX`9`-?$n|+P<)@Tp($UN*+w405KakKYhJj`DRY2Xt<78J?to+pYiw$ zyV(LfpBMJ9lZB($n4%sw1JAof5f`2-u+J?P#fBG;V)NsW2A-{PZgv{a>m@vFTZt%k zuoTiNsys2>s&m`D@)3hq{7U)s;b0ZPL5@7;HsfHcrU4j@}Pajzw>U7#6;t^4i&%K zX}TpQCe=(N#8B-ceCN~8PBf7MG2e+MQULi*G?44obbvnU5RNvU_bwK@$%fD!jhH+*rM~hFD^a1ZgpJ| z-6Vk4?pXNFK3$IqwXVUaalgEMbNiLyrw~;pwmKVNo_TL5+sOn>Yn) zU!4a|k;qvX?HSA#80MO`)-`grSh1 zlnLnsy<>?lVvsMAr-}Q2uv9DYijPD8H(4M0q9nBslor0Ji3qr=qXWsQZe6{}g7qth zuEc1WpbJPSs9h%$9z-P?4^nU9S-QilKnp8KI-=zni=^!@ockWksSj`q%~s^C zs3&HIP!Fz#QIAeXcjuxW9z;F1GjT*|2p0RDyzTz;+0e@c$z(&(N$9AV!enzBNkxcY zW|KQqDnB4Vs7Nj&K&U*c6gD}%9#l_Ul;I`qA4S_h8=k6X$^X~hl|aW)oayT7o*8LoG&-!) zhukxkZTXNa%hFi33}kL*4qWGSC+v&BOl zoO6X1OwM}LDGS_aPu7x?HTtr~oXquQZcZl4c+^)&-=QqHAcQzcxF|_T((*m0I!%4C zn&F*pISWidVkWxgF~v%`a7^P(th89BrFf^}ZekB9XDDaT=r83l(GWYj`|%(^BQq2ut>oZ@53z@fguyrJExfRKUohV9%f>#fh=XWKkC@VWxJ@raDr1 zpSAOTl>810RBx)>qmZE&ge`kQ@@84z?>>hAA#y!}!TqgA(1Zyv(%8z8L5evXmPRg= z--Iiv%R+nWeX)%CO}KC^_SA&?)m%ZnOo9>0Xq5a4>^fq1INNtDY{KD>I$7n_$-Y{4 z+KOFd3>10}h|xYtXOf3G!#1XnoZ-fXWp-L zM384c(Gj7nup>fQVMm0r!j1@Kg&h&f3Ogc{4WfD{CtSuh{$ z?mM%A40j@P*^Lm1n*(E5U7@dHTwQL zv}B^~xke8R7g)Imh6`U5qQ9dZ{C{4Eym~y?{Wrq|*BIl3$#FwtjONoAGfCJR%sgxs zOUz11QlVmoX$8)<+Fq-P2J}Z{BJ^U>gcnLYXpGlkr7Dlch|-BWf1GzGYzv=SaHpX$ znwzf+-b@-JrX~V3#{3{iDa0hD&nL|DRA8bd+0tXhDa_HSyh0dZ85@sbJ`A$r$5_N6 zA2ILYFxGJjqX~=k9JD-Q_cmZwc@U~&&pBEzsXk|n;LKoXuN1`zNFt}J<9yfYYCOM- zw+{{ueXN!)gP_(EY@fRnsK}tVM=xDQ&!P)?_pVZU)zZB?A`dmf{gF*+$A!z5Ei*Ik zplPxzk!2ie%#?ZTMvM?mFT>8jP9<4vPFK?kJZ`U8j=$jxm*dsYYk<#LXg~mpyu0S| zt`4~?a^Z3`EtqRS>%;ju&TKngXg0deLq@Y9ILbU-$`Bl-TbwckN9hiG1V`xxdjv=6 z{(1yQ>Gm3eBW&lUf&@p{qD(ot91oh$!17HT{V;z zr)oiPtOH)^)&kp^>m;Aa>ta?|-W$sUhTzCeleHi?)?vsL@(7MK7!x@lI5J_Flp&Ac zSnGz7CKx!t@LmyI9dLzYCvpp1X2V4zTp&2Y*M$of$lxOB(Qzx_BGnNDN4SLG81k}L zY+I2}aKv}<&4zKM!sZyDz;4*vGBXR6y)v&s!(n(TgB~Y_hKu~Y2c!{-HH#QSmu@0x zj=SJKDSJ!iK{n;gA!6Fg<2gRSlAPr^ZWiS895)H_d5-rB@_CN;3G#W4_X_fPj#A)# z17$g$qeKvc1)BJp3VTV4qY0Hs^n%LJsf6cuk>f~8u!KaKV>Tqx9J3*j=9mph7>*K>VK|OAAsL3_ zI1^Hi;pm4%hNH?fn2<Tp`9J3*j-$>A@M#H5tQ%p#%fMyd?QUF-F@)W;Q zN+gp_NMiuRhpE@#1E$_sA29XCd7x8`hf8Iqn~)j>q)kW@1hfP~nkbSs6VfDrY)F%R zz>u1Jz>u0f(5a@th5n)msYSpX6Vg-x9f6QqMbc?Png);!sm%ursoe(*DeZwyH61P- z;HFGa9fBTECaf8PP?_cuaHfbhDHGZ(ploQJK456GeZbJ>c%W0wjm0iPu~IR$H^X)0 zqNe{U7j^7ZaB7aw`@0S6v_(A3QQQx7|`tM#x$(|uD<=$J9} z&~G2y+tGab^!aBTa$57j-#F>iQ`7%)M)#DHPM&sDOYcD~y{&D%N40pjn{IF~%vj=K(hhg{dXM?&k#cfI=Xx?9P4tv&bT zXUTi*()Lftecib5l!M5BUA6Aje=S>< z{ED2}yN)PdO5W_67mt67+}X0$JDbR#otym2mE_RAn%KFKJlgv%Sv{Lv+Oao9FC(9J z;d%CUa%xZMOGL@5-96>8gUPKOw{_gVkzf0ViJQJjj_r$gTz)Niwl8$wx{_Sm)$300 zB;WRTYyWTvIk&Ug&#NTw_Bi{G^U1xnTDtBb|Mq)7*!2iGxGfvM5hf3}_Uk*JA{V#p z=AM5hA9tdA>c5hcyW!Dawvv~-<&noWkehqNn#|Y8&%Nr+i(e#1clDuHzeJvH_cyn0 zCRcacMVVK~*Io2V_vz&9{$#_tr^wsgy>92X$lX19O3eY}@Aj{G`^V()?wE1haPoK? z>$}I0%lrFZo%aIyyj5pDu#TMGNk{a*LSFAR$BcX9H*>~66uECG`QV20AFY3L`@>J2 z{p=fOJlglxlEcq_@9u>){XaY5?eL9PZn=K*+1=5#CGT%^uAEyw;*gQU+GD4VSa!BE z=DpLOYrL%C!Fk_V^HA$O8@E1cp>hlaU3aV)BehDu(*Kk&59Z z@8Xe)=LSf{A&*oX+6SrFkN93m#r_TZBo+HNeR}JYg$&}qiBz2T?)xMaU&ibbBo#0D zY@A}}ZL3JBT~@Jkv5qQrg)UYbbj&#yCN9+~yF}d|O{o6?hj<$}#LwY+BbHDX#}jHD z_`@qoz%9nLx+DSHlnM1d+}{O*A_}T94~laENaMXZX)GrD{2hNL~$|@GH39!F3)CNZyL;@jCE+>&n#2 z;0gZ;*SRATYAvqEMwY6Nz#IM%IKvl!8~g)YH@XS+5U#i2z6m_x$H51Fxgnv>9ShDc zt`Bfs3_kF+;}U8cuAOk-06y@=6H3+fxNe`2P|x7{5bi5rjq--c3AG9T?`kSlTX8+z zlu(1s3H8(FQuQLP8(P4LZb6v%|6D85sx_fjOhY)h$n(9nEul8!`aRqqwv{<++sl<& z-(KQ8)?P8!d959%3GQyMxK}xsq~W|dT`{DbEp)!dKi5ykpY`|?`OS1I@&c|mrd!VU zW>u-k&pR#kac8BvXm&zfKf6+`ne(|H6i8c!t*yo+rpuqd#wMQD*5+A0JUVw$;P)}c zR`$`>5+w%&9vxX?ew2QcKF((+73Up{Ys?;IPo`Dc778lNA;yItYejFl9KqZ=3lYm9msmNltbPkmib{qTVL5drlh1L{Ww)Yk{pk2dOMM_ZF} zJ@v_;`cy#un1K3*fcmik_2UBS#~bw=I^rufdg>H2SP|L z#-t)pHK#3!iixUx6eX(kQH)5oLGsQxQHAeULR9Xf1W}ofN{M9CC7&xJO89=|L?u3| zAd35F7?JGmIHhWmt!`5;tgb5x07+jARllt4Dvzq<(;qQ300%MhXQUb&>5iJ27T3_>kOJqG(q1zdQGlsuo4ylW&+=Onv~cc!!F8~Wf{1~GI*apxD0O}(HMhFNQz%BU>*Jb!j9e^BMg-XOo#)`L> zI5aPiP0;ZIyaXL5!21Xj1b82TbMmO^jkZYwybm`~fcLSR1b82NvH&knGz;)@%M<}# zK57x*<*=y&yu8;cz{{1>1bE5XCcsPZb^z~ny^k|pyuFW;rZ*47GhdM_4%w8Nk@NFX zb(VO0sX8;~?R}2f;_ZEoPI~izFnl^B`&{w!KH?k{x=VfY)v?$G=(#G3^NE9&`n-Q$ zV0Dq3%(#OPhuiBg2HhB#%Opn0f(1Q&#!5RxN+H^n3SIk%Cxt=x&=q{ps%SoT(W2(O z+qF`g_`<;va6=>_=Q~^;hVRv3J91;#imb!6F>E={MYXbbM)kYOUKZ0klzml9zpCt? z#dN2=A*OdL`+*qNot}v4Hv6@ho^1a)rW@>)alKvH*T(hp%Dy$OpH}w0as7m{ACK!t zl>Jg%kF5^IUS6;#1#0qbY^ zEkmDuD`wV`~)d z!b&7pV0k}WhI8YP>dcB6{SRrH*~1C3#e_gwb|b*Kr4UFrzzBHM&;)%Q<3<5Hm`0U` z+}?ngKrt67fo?O1?JSP+#OZ`(648uuBV;lvXb?przrgJ;QRGW#pCF9T^0rntO2 zQW{pcnJ)k5Nts#Al=q{Gg;@kTL{T;=DcN8oURqLen~`{lNr@<$Zem=Z^>yBy4P!Mc zwJdr)53S~uaLz9et;PgKz%LIW-f5F-*&pITt0oG)l0{wYJLbY`cmIk~XmbrF>t%fC;bCOse=HZt(X`GJE zREXc2?OO!9gW(vNDo$bwfhTHm7a|-TsS+@W;V4R#V)GLmwW)IOpy6mp4NGDPmM3&p zC9&elGdgRMSYzcWopnj9rZ#FfH6n?{Qy$7WDv7mHSb|B7PP%lIrIN{%J&+>`Tx<_6DyxC_%dwQjY*YFJoGRpJOhMkMEh+r?)rJ^ffpOb`k@6Xr4a zL{3kpa1>g#JBE>jS1yuxfv7~ygv1y2qb?Cf3?v*$3iv=()U9_LvTpzd6%tudP;cJe ze=~Urq$X74e4wJj9n06jv%^h_`)McX;=ibT3qQiX51t;5T26y?k*PqP%4wkbwB~}a z%R!mtra1Vs+>tbBWx2y?xyo{@)0#`awPaLTZY9lLS#AaGTUl;`Lo3TIBk9U=<7v%x z>?o~ZSv)R-i?|?UaYD#RYxXlkG@PZ_AuFM2EX7`4m0JxLyNaXSdbrrpw2>NV#V4?O z30EUr!)Pu`u~$3-`75p1@5gELaIwE#PP1Cl_s3C@aIr_9bW?C~07P@^X^6>bjiiJjAw-jT9Mc0xl~_7=hze#cl_`TR&6H)lli6t!DW0?-^Cxgz zEA}lbd+bSWvJ=&<*7Ix8Nh?wCh-GGuk7i zp(D21QD6LgkpiD41v0lev9g{sPC2IUIColW)3Ij`^tdOfH`p%bh8J=IT@*uy#4-Kd zZT+}+;mHe*U3|O@Givi?&Ha5REWl|;13gM1A97i~#_3bhoMJ4~R^-rv#eF9pzp(%0(EV)t^e7p<1iTTmTr70% zY`knh`O!dOd5vv-aH#VY4t0iEc0D38P8X?W+n$GE#n&*(xCE=P_I0q&WZ!OKWOAQ{ zQO&cKQ)ItxLDL6T$X=--x<t3-8LTlt^*Y}IM8~BgJbmWade~F?sI(kUiPto@!M|aq-JGl8BN4MA?ICyq> zNH^N6Lb}NLPq@^7g+dOj2EL9j0oU4)UTvxMaNPr$r8dF!5M)|C2G`S&X|)}$-$7=p zx8QmgGF$Bqh3pH$+Ho-MYgB8)VS5A7Mxw3Zi2Wpx{Sy8}KE_yZSBVu_ny}QRIC<{+ zgcZ3J*WJL|fd@-J_pz9|mU*Uh;Fx}ldKMhtbIicv{+>lv6W7f9dyZ?ukzCRL1w?3m ABme*a literal 0 HcmV?d00001 From 9de989c0d5e300ff3b234787febdfa34d0137bb1 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 12:54:39 +0000 Subject: [PATCH 127/223] Link wasm test binaries with libc.a --- compiler/test_gen/src/helpers/wasm.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index d2d7fa8a99..649aac8421 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -122,7 +122,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( ); // We can either generate the test platform or write an external source file, whatever works - // generate_test_platform(&mut wasm_module, arena); + generate_test_platform(&mut wasm_module, arena); let mut module_bytes = std::vec::Vec::with_capacity(4096); wasm_module.serialize_mut(&mut module_bytes); @@ -140,7 +140,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( let tmp_dir: TempDir; // directory for normal test runs, deleted when dropped let debug_dir: String; // persistent directory for debugging - let dirpath: &Path = if DEBUG_WASM_FILE { + let wasm_build_dir: &Path = if DEBUG_WASM_FILE { // Directory name based on a hash of the Roc source let mut hash_state = DefaultHasher::new(); src.hash(&mut hash_state); @@ -157,8 +157,9 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( tmp_dir.path() }; - let final_wasm_file = dirpath.join("final.wasm"); - let app_o_file = dirpath.join("app.o"); + let final_wasm_file = wasm_build_dir.join("final.wasm"); + let app_o_file = wasm_build_dir.join("app.o"); + let libc_a_file = "../gen_wasm/lib/libc.a"; // write the module to a file so the linker can access it std::fs::write(&app_o_file, &module_bytes).unwrap(); @@ -169,6 +170,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( // input files app_o_file.to_str().unwrap(), bitcode::BUILTINS_WASM32_OBJ_PATH, + libc_a_file, // output "-o", final_wasm_file.to_str().unwrap(), From 03c19b727ac8861a37cec71ec5832282e4b38437 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 13:38:50 +0000 Subject: [PATCH 128/223] String concatenation working in gen_wasm! --- compiler/gen_wasm/src/backend.rs | 13 +++++++++---- compiler/gen_wasm/src/storage.rs | 19 ++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index e1af157a72..b55fe608be 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -479,7 +479,7 @@ impl<'a> WasmBackend<'a> { CallType::ByName { name: func_sym, .. } => { // If this function is just a lowlevel wrapper, then inline it if let Some(lowlevel) = LowLevel::from_inlined_wrapper(*func_sym) { - return self.build_low_level(lowlevel, arguments, wasm_layout); + return self.build_low_level(lowlevel, arguments, *sym, wasm_layout); } let mut wasm_args_tmp: Vec; @@ -524,7 +524,7 @@ impl<'a> WasmBackend<'a> { } CallType::LowLevel { op: lowlevel, .. } => { - self.build_low_level(*lowlevel, arguments, wasm_layout) + self.build_low_level(*lowlevel, arguments, *sym, wasm_layout) } x => Err(format!("the call type, {:?}, is not yet implemented", x)), @@ -563,13 +563,18 @@ impl<'a> WasmBackend<'a> { &mut self, lowlevel: LowLevel, arguments: &'a [Symbol], + return_sym: Symbol, return_layout: WasmLayout, ) -> Result<(), String> { // Load symbols using the "fast calling convention" that Zig uses instead of the C ABI we normally use. // It's only different from the C ABI for small structs, and we are using Zig for all of those cases. // This is a workaround for a bug in Zig. If later versions fix it, we can change to the C ABI. - self.storage - .load_symbols_fastcc(&mut self.code_builder, arguments, &return_layout); + self.storage.load_symbols_fastcc( + &mut self.code_builder, + arguments, + return_sym, + &return_layout, + ); let build_result = decode_low_level( &mut self.code_builder, diff --git a/compiler/gen_wasm/src/storage.rs b/compiler/gen_wasm/src/storage.rs index e4125a6bdb..cf4f336c06 100644 --- a/compiler/gen_wasm/src/storage.rs +++ b/compiler/gen_wasm/src/storage.rs @@ -233,20 +233,15 @@ impl<'a> Storage<'a> { } } } - StoredValue::Local { local_id, .. } - | StoredValue::StackMemory { - location: StackMemoryLocation::PointerArg(local_id), - .. - } => { + + StoredValue::Local { local_id, .. } => { code_builder.get_local(local_id); code_builder.set_top_symbol(sym); } - StoredValue::StackMemory { - location: StackMemoryLocation::FrameOffset(offset), - .. - } => { - code_builder.get_local(self.stack_frame_pointer.unwrap()); + StoredValue::StackMemory { location, .. } => { + let (local_id, offset) = location.local_and_offset(self.stack_frame_pointer); + code_builder.get_local(local_id); if offset != 0 { code_builder.i32_const(offset as i32); code_builder.i32_add(); @@ -280,6 +275,7 @@ impl<'a> Storage<'a> { &mut self, code_builder: &mut CodeBuilder, symbols: &[Symbol], + return_symbol: Symbol, return_layout: &WasmLayout, ) { // Note: we are not doing verify_stack_match in this case so we may generate more code. @@ -287,7 +283,8 @@ impl<'a> Storage<'a> { if return_layout.is_stack_memory() { // Load the address where the return value should be written - self.load_symbol_ccc(code_builder, symbols[0]); + // Apparently for return values we still use a pointer to stack memory + self.load_symbol_ccc(code_builder, return_symbol); }; for sym in symbols { From a3bfee5cd8b030dc3a35d557ceeb4c059453714e Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 13:48:29 +0000 Subject: [PATCH 129/223] Leave other string builtins for later --- compiler/gen_wasm/src/low_level.rs | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 27a99bc7b9..424079e6bd 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -28,24 +28,11 @@ pub fn decode_low_level<'a>( match lowlevel { StrConcat => return BuiltinCall(bitcode::STR_CONCAT), - StrJoinWith => return BuiltinCall(bitcode::STR_JOIN_WITH), - StrIsEmpty => return NotImplemented, - StrStartsWith => return BuiltinCall(bitcode::STR_STARTS_WITH), - StrStartsWithCodePt => return BuiltinCall(bitcode::STR_STARTS_WITH_CODE_PT), - StrEndsWith => return BuiltinCall(bitcode::STR_ENDS_WITH), - StrSplit => return NotImplemented, - StrCountGraphemes => return NotImplemented, - StrFromInt => return NotImplemented, - StrFromUtf8 => return BuiltinCall(bitcode::STR_FROM_UTF8), - StrTrimLeft => return BuiltinCall(bitcode::STR_TRIM_LEFT), - StrTrimRight => return BuiltinCall(bitcode::STR_TRIM_RIGHT), - StrFromUtf8Range => return BuiltinCall(bitcode::STR_FROM_UTF8_RANGE), - StrToUtf8 => return BuiltinCall(bitcode::STR_TO_UTF8), - StrRepeat => return BuiltinCall(bitcode::STR_REPEAT), - StrFromFloat => return BuiltinCall(bitcode::STR_FROM_FLOAT), - StrTrim => return BuiltinCall(bitcode::STR_TRIM), - ListLen | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat + StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt | StrEndsWith | StrSplit + | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft | StrTrimRight + | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim | ListLen + | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListSublist From 16fb04b4fa5399433ff8875062e43c15eb9251a8 Mon Sep 17 00:00:00 2001 From: satotake Date: Wed, 17 Nov 2021 15:18:45 +0000 Subject: [PATCH 130/223] Add builtin `List.intersperse` --- compiler/builtins/src/std.rs | 7 +++ compiler/can/src/builtins.rs | 77 ++++++++++++++++++++++++++++++ compiler/module/src/symbol.rs | 2 + compiler/solve/tests/solve_expr.rs | 11 +++++ compiler/test_gen/src/gen_list.rs | 23 +++++++++ 5 files changed, 120 insertions(+) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 0f8d1fe154..289ae67bbe 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -1140,6 +1140,13 @@ pub fn types() -> MutMap { ) } + // intersperse : List elem, elem -> List elem + add_top_level_function_type!( + Symbol::LIST_INTERSPERSE, + vec![list_type(flex(TVAR1)), flex(TVAR1)], + Box::new(list_type(flex(TVAR1))), + ); + // Dict module // len : Dict * * -> Nat diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 6e2342ca3e..2a247b9e61 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -111,6 +111,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option LIST_WALK_UNTIL => list_walk_until, LIST_SORT_WITH => list_sort_with, LIST_ANY => list_any, + LIST_INTERSPERSE => list_intersperse, LIST_FIND => list_find, DICT_LEN => dict_len, DICT_EMPTY => dict_empty, @@ -2147,6 +2148,82 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +/// List.intersperse : List elem, elem -> List elem +fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def { + let list_var = var_store.fresh(); + let sep_var = var_store.fresh(); + + let list_sym = Symbol::ARG_1; + let sep_sym = Symbol::ARG_2; + + let clos_var = var_store.fresh(); + let clos_acc_var = var_store.fresh(); + + let clos_sym = Symbol::LIST_INTERSPERSE_CLOS; + let clos_acc_sym = Symbol::ARG_3; + let clos_elem_sym = Symbol::ARG_4; + + let int_var = var_store.fresh(); + let zero = int(int_var, Variable::NATURAL, 0); + + // \elem -> [sep, elem] + let clos = Closure(ClosureData { + function_type: clos_var, + closure_type: var_store.fresh(), + closure_ext_var: var_store.fresh(), + return_type: clos_acc_var, + name: clos_sym, + recursive: Recursive::NotRecursive, + captured_symbols: vec![(sep_sym, sep_var)], + arguments: vec![ + (clos_acc_var, no_region(Pattern::Identifier(clos_acc_sym))), + (sep_var, no_region(Pattern::Identifier(clos_elem_sym))), + ], + loc_body: { + let pair = List { + elem_var: sep_var, + loc_elems: vec![no_region(Var(sep_sym)), no_region(Var(clos_elem_sym))], + }; + Box::new(no_region(RunLowLevel { + op: LowLevel::ListConcat, + args: vec![(clos_acc_var, Var(clos_acc_sym)), (clos_acc_var, pair)], + ret_var: clos_acc_var, + })) + }, + }); + + // List.walk [] l (\acc, elem -> List.concat acc [sep, elem]) + let acc = RunLowLevel { + op: LowLevel::ListWalk, + args: vec![ + (list_var, Var(list_sym)), + ( + clos_acc_var, + List { + elem_var: sep_var, + loc_elems: vec![], + }, + ), + (clos_var, clos), + ], + ret_var: clos_acc_var, + }; + + let body = RunLowLevel { + op: LowLevel::ListDropAt, + args: vec![(clos_acc_var, acc), (int_var, zero)], + ret_var: clos_acc_var, + }; + + defn( + symbol, + vec![(list_var, list_sym), (sep_var, sep_sym)], + var_store, + body, + clos_acc_var, + ) +} + /// List.drop : List elem, Nat -> List elem fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 44bf51012a..3783d24b90 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1072,6 +1072,8 @@ define_builtins! { 47 LIST_FIND: "find" 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" + 50 LIST_INTERSPERSE: "intersperse" + 51 LIST_INTERSPERSE_CLOS: "#intersperseClos" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index dcf74d79bb..c38a9b480d 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3805,6 +3805,17 @@ mod solve_expr { ); } + #[test] + fn list_intersperse() { + infer_eq_without_problem( + indoc!( + r#" + List.intersperse + "# + ), + "List a, a -> List a", + ); + } #[test] fn function_that_captures_nothing_is_not_captured() { // we should make sure that a function that doesn't capture anything it not itself captured diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 5e0f737e72..dc482918e3 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -277,6 +277,29 @@ fn list_drop_at() { assert_evals_to!("List.dropAt [0] 0", RocList::from_slice(&[]), RocList); } +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn list_intersperse() { + assert_evals_to!( + indoc!( + r#" + List.intersperse [0, 0, 0] 1 + "# + ), + RocList::from_slice(&[0, 1, 0, 1, 0]), + RocList + ); + assert_evals_to!( + indoc!( + r#" + List.intersperse [] 1 + "# + ), + RocList::from_slice(&[]), + RocList + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn list_drop_at_shared() { From 237d8d1c0b3f4fab8e4a239518399bad17643068 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 16:29:16 +0100 Subject: [PATCH 131/223] fix the Default instance for subs we later rely on some variables always existing (numbers, empty record, empty tag union) but the default instance did not insert those --- ast/src/constrain.rs | 2 +- compiler/mono/src/ir.rs | 2 +- compiler/reporting/tests/test_reporting.rs | 2 +- compiler/solve/src/module.rs | 2 +- compiler/types/src/subs.rs | 37 +++++++++++++--------- editor/src/editor/mvc/ed_update.rs | 2 +- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index 013c505705..200ad57550 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -1799,7 +1799,7 @@ pub mod test_constrain { aliases, }; - let mut subs = Subs::new(var_store); + let mut subs = Subs::new_from_varstore(var_store); for (var, name) in rigid_variables { subs.rigid_var(var, name); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 7e558d7a9b..ba8d1c86c4 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -481,7 +481,7 @@ pub struct Suspended<'a> { impl<'a> Suspended<'a> { fn new_in(arena: &'a Bump) -> Self { Self { - store: Subs::new(Default::default()), + store: Subs::new_from_varstore(Default::default()), symbols: Vec::new_in(arena), layouts: Vec::new_in(arena), variables: Vec::new_in(arena), diff --git a/compiler/reporting/tests/test_reporting.rs b/compiler/reporting/tests/test_reporting.rs index 14fb7279ad..5210c72396 100644 --- a/compiler/reporting/tests/test_reporting.rs +++ b/compiler/reporting/tests/test_reporting.rs @@ -66,7 +66,7 @@ mod test_reporting { problems: can_problems, .. } = can_expr(arena, expr_src)?; - let mut subs = Subs::new(var_store); + let mut subs = Subs::new_from_varstore(var_store); for (var, name) in output.introduced_variables.name_by_var { subs.rigid_var(var, name); diff --git a/compiler/solve/src/module.rs b/compiler/solve/src/module.rs index ebf781e9d4..920cbbdd58 100644 --- a/compiler/solve/src/module.rs +++ b/compiler/solve/src/module.rs @@ -27,7 +27,7 @@ pub fn run_solve( aliases, }; - let mut subs = Subs::new(var_store); + let mut subs = Subs::new_from_varstore(var_store); for (var, name) in rigid_variables { subs.rigid_var(var, name); diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index da6f60fdc4..c0eaa725a5 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -63,16 +63,7 @@ pub struct Subs { impl Default for Subs { fn default() -> Self { - Subs { - utable: Default::default(), - variables: Default::default(), - tag_names: Default::default(), - field_names: Default::default(), - record_fields: Default::default(), - // store an empty slice at the first position - // used for "TagOrFunction" - variable_slices: vec![VariableSubsSlice::default()], - } + Subs::new() } } @@ -987,21 +978,31 @@ fn define_integer_types(subs: &mut Subs) { } impl Subs { - pub fn new(var_store: VarStore) -> Self { - let entries = var_store.next; + pub fn new() -> Self { + Self::with_capacity(0) + } + + pub fn with_capacity(capacity: usize) -> Self { + let capacity = capacity.max(Variable::NUM_RESERVED_VARS); let mut subs = Subs { utable: UnificationTable::default(), - ..Default::default() + variables: Default::default(), + tag_names: Default::default(), + field_names: Default::default(), + record_fields: Default::default(), + // store an empty slice at the first position + // used for "TagOrFunction" + variable_slices: vec![VariableSubsSlice::default()], }; // NOTE the utable does not (currently) have a with_capacity; using this as the next-best thing - subs.utable.reserve(entries as usize); + subs.utable.reserve(capacity); // TODO There are at least these opportunities for performance optimization here: // * Making the default flex_var_descriptor be all 0s, so no init step is needed. - for _ in 0..entries { + for _ in 0..capacity { subs.utable.new_key(flex_var_descriptor()); } @@ -1042,6 +1043,12 @@ impl Subs { subs } + pub fn new_from_varstore(var_store: VarStore) -> Self { + let entries = var_store.next; + + Self::with_capacity(entries as usize) + } + pub fn extend_by(&mut self, entries: usize) { for _ in 0..entries { self.utable.new_key(flex_var_descriptor()); diff --git a/editor/src/editor/mvc/ed_update.rs b/editor/src/editor/mvc/ed_update.rs index fba3cd346b..351d101d2e 100644 --- a/editor/src/editor/mvc/ed_update.rs +++ b/editor/src/editor/mvc/ed_update.rs @@ -501,7 +501,7 @@ impl<'a> EdModel<'a> { }; let arena = Bump::new(); - let mut subs = Subs::new(var_store); + let mut subs = Subs::new_from_varstore(var_store); for (var, name) in rigid_variables { subs.rigid_var(var, name); From fe858011fe5399f46119dcf6feee3c4674e9c06b Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 16:29:58 +0100 Subject: [PATCH 132/223] extend ena to get a mutable handle to a value stored in the UnificationTable --- vendor/ena/src/unify/backing_vec.rs | 14 +++++++++++++- vendor/ena/src/unify/mod.rs | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/vendor/ena/src/unify/backing_vec.rs b/vendor/ena/src/unify/backing_vec.rs index 4b50aafa06..7dcc30cafe 100644 --- a/vendor/ena/src/unify/backing_vec.rs +++ b/vendor/ena/src/unify/backing_vec.rs @@ -15,7 +15,10 @@ type Key = ::Key; /// backing store types. The most common such type is `InPlace`, /// which indicates a standard, mutable unification table. pub trait UnificationStore: - ops::Index>> + Clone + Default + ops::Index>> + + ops::IndexMut>> + + Clone + + Default { type Key: UnifyKey; type Value: Clone + Debug; @@ -141,6 +144,15 @@ where } } +impl ops::IndexMut for InPlace +where + K: UnifyKey, +{ + fn index_mut(&mut self, index: usize) -> &mut VarValue { + &mut self.values[index] + } +} + #[derive(Copy, Clone, Debug)] struct Delegate(PhantomData); diff --git a/vendor/ena/src/unify/mod.rs b/vendor/ena/src/unify/mod.rs index 77f151f2e6..37823da931 100644 --- a/vendor/ena/src/unify/mod.rs +++ b/vendor/ena/src/unify/mod.rs @@ -284,6 +284,12 @@ impl UnificationTable { &self.values[key.index() as usize] } + /// Obtains the current value for a particular key. + /// Not for end-users; they can use `probe_value`. + pub fn value_mut(&mut self, key: S::Key) -> &mut VarValue { + &mut self.values[key.index() as usize] + } + /// Find the root node for `vid`. This uses the standard /// union-find algorithm with path compression: /// . @@ -451,6 +457,17 @@ where self.value(id) } + /// Returns the current value for the given key. If the key has + /// been union'd, this will give the value from the current root. + pub fn probe_value_ref_mut(&mut self, id: K1) -> &mut VarValue + where + K1: Into, + { + let id = id.into(); + let id = self.get_root_key_without_compacting(id); + self.value_mut(id) + } + /// This is for a debug_assert! in solve() only. Do not use it elsewhere! pub fn probe_value_without_compacting(&self, id: K1) -> V where From 3b1e0eeb2446b6941a0b31ec858ab0cab8a44fe8 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 16:31:13 +0100 Subject: [PATCH 133/223] store a subs instead of a solved type in external specializations --- compiler/mono/src/ir.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index ba8d1c86c4..03bdc8e692 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -422,7 +422,7 @@ pub struct ExternalSpecializations<'a> { /// Separate array so we can search for membership quickly symbols: std::vec::Vec, /// For each symbol, what types to specialize it for - types_to_specialize: std::vec::Vec>, + types_to_specialize: std::vec::Vec>, _lifetime: std::marker::PhantomData<&'a u8>, } @@ -435,15 +435,15 @@ impl<'a> ExternalSpecializations<'a> { } } - pub fn insert(&mut self, symbol: Symbol, typ: SolvedType) { + fn insert_external(&mut self, symbol: Symbol, store: Subs, variable: Variable) { match self.symbols.iter().position(|s| *s == symbol) { None => { self.symbols.push(symbol); - self.types_to_specialize.push(vec![typ]); + self.types_to_specialize.push(vec![(store, variable)]); } Some(index) => { let types_to_specialize = &mut self.types_to_specialize[index]; - types_to_specialize.push(typ); + types_to_specialize.push((store, variable)); } } } @@ -463,7 +463,7 @@ impl<'a> ExternalSpecializations<'a> { } } - pub fn into_iter(self) -> impl Iterator)> { + fn into_iter(self) -> impl Iterator)> { self.symbols .into_iter() .zip(self.types_to_specialize.into_iter()) @@ -1969,7 +1969,7 @@ fn specialize_externals_others_need<'a>( layout_cache: &mut LayoutCache<'a>, ) { for (symbol, solved_types) in externals_others_need.into_iter() { - for solved_type in solved_types { + for (mut store, store_variable) in solved_types { // historical note: we used to deduplicate with a hash here, // but the cost of that hash is very high. So for now we make // duplicate specializations, and the insertion into a hash map @@ -1984,13 +1984,15 @@ fn specialize_externals_others_need<'a>( } }; + let variable = roc_solve::solve::deep_copy_var_to(&mut store, env.subs, store_variable); + // TODO I believe this is also duplicated - match specialize_solved_type( + match specialize_variable( env, procs, name, layout_cache, - &solved_type, + variable, BumpMap::new_in(env.arena), partial_proc_id, ) { @@ -6476,8 +6478,10 @@ fn add_needed_external<'a>( Occupied(entry) => entry.into_mut(), }; - let solved_type = SolvedType::from_var(env.subs, fn_var); - existing.insert(name, solved_type); + let mut store = Subs::default(); + let variable = roc_solve::solve::deep_copy_var_to(env.subs, &mut store, fn_var); + + existing.insert_external(name, store, variable); } fn build_call<'a>( From 65e0866d0a737fe511a2c50bc0f4621fa0abf67e Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 16:32:20 +0100 Subject: [PATCH 134/223] add assert; a returned copy must always be in the target subs --- compiler/solve/src/solve.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index 659bbdc25a..a72c36d4a7 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1415,6 +1415,7 @@ fn deep_copy_var_to_help( let desc = source.get_without_compacting(var); if let Some(copy) = desc.copy.into_variable() { + debug_assert!(target.contains(copy)); return copy; } else if desc.rank != Rank::NONE { // DO NOTHING @@ -1478,6 +1479,7 @@ fn deep_copy_var_to_help( Func(arg_vars, closure_var, ret_var) => { let new_ret_var = deep_copy_var_to_help(source, target, max_rank, pools, mapping, ret_var); + let new_closure_var = deep_copy_var_to_help( source, target, From e030cd3da501322d56044f59328e845a13391c93 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 16:33:32 +0100 Subject: [PATCH 135/223] optimize `restore` --- compiler/types/src/subs.rs | 166 +++++++++++++++++++------------------ 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index c0eaa725a5..4d6765afbd 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -317,7 +317,8 @@ fn subs_fmt_desc(this: &Descriptor, subs: &Subs, f: &mut fmt::Formatter) -> fmt: subs_fmt_content(&this.content, subs, f)?; write!(f, " r: {:?}", &this.rank)?; - write!(f, " m: {:?}", &this.mark) + write!(f, " m: {:?}", &this.mark)?; + write!(f, " c: {:?}", &this.copy) } pub struct SubsFmtContent<'a>(pub &'a Content, pub &'a Subs); @@ -1089,6 +1090,10 @@ impl Subs { &self.utable.probe_value_ref(key).value } + pub fn get_ref_mut(&mut self, key: Variable) -> &mut Descriptor { + &mut self.utable.probe_value_ref_mut(key).value + } + pub fn get_rank(&self, key: Variable) -> Rank { self.utable.probe_value_ref(key).value.rank } @@ -1201,22 +1206,7 @@ impl Subs { } pub fn restore(&mut self, var: Variable) { - let desc = self.get(var); - - if desc.copy.is_some() { - let content = desc.content; - - let desc = Descriptor { - content: content.clone(), - rank: Rank::NONE, - mark: Mark::NONE, - copy: OptVariable::NONE, - }; - - self.set(var, desc); - - restore_content(self, &content); - } + restore_help(self, var) } pub fn len(&self) -> usize { @@ -1227,6 +1217,10 @@ impl Subs { self.utable.is_empty() } + pub fn contains(&self, var: Variable) -> bool { + (var.index() as usize) < self.len() + } + pub fn snapshot(&mut self) -> Snapshot> { self.utable.snapshot() } @@ -1830,6 +1824,12 @@ impl RecordFields { } } + fn variables(&self) -> VariableSubsSlice { + let slice = SubsSlice::new(self.variables_start, self.length); + + VariableSubsSlice { slice } + } + pub fn iter_variables(&self) -> impl Iterator> { let slice = SubsSlice::new(self.variables_start, self.length); slice.into_iter() @@ -2718,83 +2718,85 @@ fn get_fresh_var_name(state: &mut ErrorTypeState) -> Lowercase { name } -fn restore_content(subs: &mut Subs, content: &Content) { - use Content::*; - use FlatType::*; +fn restore_help(subs: &mut Subs, initial: Variable) { + let mut stack = vec![initial]; - match content { - FlexVar(_) | RigidVar(_) | Error => (), + let variable_slices = &subs.variable_slices; - RecursionVar { structure, .. } => { - subs.restore(*structure); - } + let variables = &subs.variables; + let var_slice = |variable_subs_slice: VariableSubsSlice| { + &variables[variable_subs_slice.slice.start as usize..] + [..variable_subs_slice.slice.length as usize] + }; - Structure(flat_type) => match flat_type { - Apply(_, args) => { - for index in args.into_iter() { - let var = subs[index]; - subs.restore(var); - } - } + while let Some(var) = stack.pop() { + let desc = &mut subs.utable.probe_value_ref_mut(var).value; - Func(arg_vars, closure_var, ret_var) => { - for index in arg_vars.into_iter() { - let var = subs[index]; - subs.restore(var); + if desc.copy.is_some() { + desc.rank = Rank::NONE; + desc.mark = Mark::NONE; + desc.copy = OptVariable::NONE; + + use Content::*; + use FlatType::*; + + match &desc.content { + FlexVar(_) | RigidVar(_) | Error => (), + + RecursionVar { structure, .. } => { + stack.push(*structure); } - subs.restore(*ret_var); - subs.restore(*closure_var); - } - - EmptyRecord => (), - EmptyTagUnion => (), - - Record(fields, ext_var) => { - for index in fields.iter_variables() { - let var = subs[index]; - subs.restore(var); - } - - subs.restore(*ext_var); - } - TagUnion(tags, ext_var) => { - for slice_index in tags.variables() { - let slice = subs[slice_index]; - for var_index in slice { - let var = subs[var_index]; - subs.restore(var); + Structure(flat_type) => match flat_type { + Apply(_, args) => { + stack.extend(var_slice(*args)); } - } - subs.restore(*ext_var); - } - FunctionOrTagUnion(_, _, ext_var) => { - subs.restore(*ext_var); - } + Func(arg_vars, closure_var, ret_var) => { + stack.extend(var_slice(*arg_vars)); - RecursiveTagUnion(rec_var, tags, ext_var) => { - for slice_index in tags.variables() { - let slice = subs[slice_index]; - for var_index in slice { - let var = subs[var_index]; - subs.restore(var); + stack.push(*ret_var); + stack.push(*closure_var); } + + EmptyRecord => (), + EmptyTagUnion => (), + + Record(fields, ext_var) => { + stack.extend(var_slice(fields.variables())); + + stack.push(*ext_var); + } + TagUnion(tags, ext_var) => { + for slice_index in tags.variables() { + let slice = variable_slices[slice_index.start as usize]; + stack.extend(var_slice(slice)); + } + + stack.push(*ext_var); + } + FunctionOrTagUnion(_, _, ext_var) => { + stack.push(*ext_var); + } + + RecursiveTagUnion(rec_var, tags, ext_var) => { + for slice_index in tags.variables() { + let slice = variable_slices[slice_index.start as usize]; + stack.extend(var_slice(slice)); + } + + stack.push(*ext_var); + stack.push(*rec_var); + } + + Erroneous(_) => (), + }, + Alias(_, args, var) => { + stack.extend(var_slice(args.variables())); + + stack.push(*var); } - - subs.restore(*ext_var); - subs.restore(*rec_var); } - - Erroneous(_) => (), - }, - Alias(_, args, var) => { - for var_index in args.variables().into_iter() { - let var = subs[var_index]; - subs.restore(var); - } - - subs.restore(*var); } } } From 1134b6f45c2a39bb522570fbafc06ff3de283d46 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 16:45:38 +0000 Subject: [PATCH 136/223] Fix test_wrapper linking bug --- compiler/gen_wasm/src/lib.rs | 14 ++++++++------ compiler/test_gen/src/helpers/wasm.rs | 19 ++++++------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 2e40ca9ea3..a8b19213dd 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -37,7 +37,7 @@ pub fn build_module<'a>( env: &'a Env, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, ) -> Result, String> { - let mut wasm_module = build_module_help(env, procedures)?; + let (mut wasm_module, _) = build_module_help(env, procedures)?; let mut buffer = std::vec::Vec::with_capacity(4096); wasm_module.serialize_mut(&mut buffer); Ok(buffer) @@ -46,16 +46,17 @@ pub fn build_module<'a>( pub fn build_module_help<'a>( env: &'a Env, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, -) -> Result, String> { +) -> Result<(WasmModule<'a>, u32), String> { let mut layout_ids = LayoutIds::default(); let mut generated_procs = Vec::with_capacity_in(procedures.len(), env.arena); let mut generated_symbols = Vec::with_capacity_in(procedures.len(), env.arena); let mut linker_symbols = Vec::with_capacity_in(procedures.len() * 2, env.arena); let mut exports = Vec::with_capacity_in(4, env.arena); + let mut main_fn_index = None; // Collect the symbols & names for the procedures, // and filter out procs we're going to inline - let mut fn_index = 0; + let mut fn_index: u32 = 0; for ((sym, layout), proc) in procedures.into_iter() { if LowLevel::from_inlined_wrapper(sym).is_some() { continue; @@ -68,14 +69,15 @@ pub fn build_module_help<'a>( .to_symbol_string(sym, &env.interns); if env.exposed_to_host.contains(&sym) { + main_fn_index = Some(fn_index); exports.push(Export { name: fn_name.clone(), ty: ExportType::Func, - index: fn_index as u32, + index: fn_index, }); } - let linker_sym = SymInfo::for_function(fn_index as u32, fn_name); + let linker_sym = SymInfo::for_function(fn_index, fn_name); linker_symbols.push(linker_sym); fn_index += 1; @@ -100,7 +102,7 @@ pub fn build_module_help<'a>( let symbol_table = LinkingSubSection::SymbolTable(linker_symbols); module.linking.subsections.push(symbol_table); - Ok(module) + Ok((module, main_fn_index.unwrap())) } pub struct CopyMemoryConfig { diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index 649aac8421..762fd4fc7a 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -98,11 +98,6 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( // } debug_assert_eq!(exposed_to_host.len(), 1); - let main_fn_symbol = loaded.entry_point.symbol; - let main_fn_index = procedures - .keys() - .position(|(s, _)| *s == main_fn_symbol) - .unwrap(); let exposed_to_host = exposed_to_host.keys().copied().collect::>(); @@ -112,14 +107,10 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( exposed_to_host, }; - let mut wasm_module = roc_gen_wasm::build_module_help(&env, procedures).unwrap(); + let (mut wasm_module, main_fn_index) = + roc_gen_wasm::build_module_help(&env, procedures).unwrap(); - T::insert_test_wrapper( - arena, - &mut wasm_module, - TEST_WRAPPER_NAME, - main_fn_index as u32, - ); + T::insert_test_wrapper(arena, &mut wasm_module, TEST_WRAPPER_NAME, main_fn_index); // We can either generate the test platform or write an external source file, whatever works generate_test_platform(&mut wasm_module, arena); @@ -164,7 +155,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( // write the module to a file so the linker can access it std::fs::write(&app_o_file, &module_bytes).unwrap(); - std::process::Command::new("zig") + let _linker_output = std::process::Command::new("zig") .args(&[ "wasm-ld", // input files @@ -190,6 +181,8 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( .output() .unwrap(); + // dbg!(_linker_output); + Module::from_file(&store, &final_wasm_file).unwrap() }; From b5b90fb2b7dc534d50e807841d60f6f689fa4666 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 16:45:52 +0000 Subject: [PATCH 137/223] Delete unused file --- .../test_gen/src/helpers/wasm_test_platform.c | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 compiler/test_gen/src/helpers/wasm_test_platform.c diff --git a/compiler/test_gen/src/helpers/wasm_test_platform.c b/compiler/test_gen/src/helpers/wasm_test_platform.c deleted file mode 100644 index a607d38a8c..0000000000 --- a/compiler/test_gen/src/helpers/wasm_test_platform.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -extern void* test_wrapper(); - -void* roc_alloc(size_t size, unsigned int alignment) { - return malloc(size); -} - -void* roc_realloc(void* ptr, size_t old_size, size_t new_size, unsigned int alignment) { - return realloc(ptr, new_size); -} - -void roc_dealloc(void* ptr, unsigned int alignment) { - free(ptr); -} - -// Having a main function seems to make it easier to convince tools -// to include everything in the output binary. -// Using C as the source language makes it easier to convince them -// to include libc for wasm target, not host. -// The returned int is the memory address of the test result -int main(void) { - return test_wrapper(); -} From 3d124b41227fe1494ede979b618d8c395a0ed273 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 17 Nov 2021 16:51:42 +0000 Subject: [PATCH 138/223] Fix builtin calls for primitives --- compiler/gen_wasm/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index b55fe608be..6a516e543d 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -794,7 +794,7 @@ impl<'a> WasmBackend<'a> { StoredValue::StackMemory { size, .. } if *size > 4 && *size <= 8 => { ValueType::I64 } - _ => ValueType::I32, + stored => stored.value_type(), }); } From af8fad2618ec6b6bf70c218ec38e5e35012470e8 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 12:28:27 -0500 Subject: [PATCH 139/223] Update sizes of Type2 variants to be correct These are outdated; the new calculations reflect the current state of the codebase. --- ast/src/lang/core/types.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/ast/src/lang/core/types.rs b/ast/src/lang/core/types.rs index 8cb34c1089..3de8039ed2 100644 --- a/ast/src/lang/core/types.rs +++ b/ast/src/lang/core/types.rs @@ -20,29 +20,34 @@ pub type TypeId = NodeId; #[derive(Debug)] pub enum Type2 { - Variable(Variable), + Variable(Variable), // 4B - Alias(Symbol, PoolVec<(PoolStr, TypeId)>, TypeId), // 24B = 8B + 12B + 4B - AsAlias(Symbol, PoolVec<(PoolStr, TypeId)>, TypeId), // 24B = 8B + 12B + 4B + Alias(Symbol, PoolVec<(PoolStr, TypeId)>, TypeId), // 24B = 8B + 8B + 4B + pad + AsAlias(Symbol, PoolVec<(PoolStr, TypeId)>, TypeId), // 24B = 8B + 8B + 4B + pad - // 32B + // 24B HostExposedAlias { name: Symbol, // 8B - arguments: PoolVec<(PoolStr, TypeId)>, // 12B + arguments: PoolVec<(PoolStr, TypeId)>, // 8B actual_var: Variable, // 4B actual: TypeId, // 4B }, EmptyTagUnion, - TagUnion(PoolVec<(TagName, PoolVec)>, TypeId), // 16B = 12B + 4B - RecursiveTagUnion(Variable, PoolVec<(TagName, PoolVec)>, TypeId), // 20B = 4B + 12B + 4B + TagUnion(PoolVec<(TagName, PoolVec)>, TypeId), // 12B = 8B + 4B + RecursiveTagUnion(Variable, PoolVec<(TagName, PoolVec)>, TypeId), // 16B = 4B + 8B + 4B EmptyRec, - Record(PoolVec<(PoolStr, RecordField)>, TypeId), // 16B = 12B + 4B + Record(PoolVec<(PoolStr, RecordField)>, TypeId), // 12B = 8B + 4B - Function(PoolVec, TypeId, TypeId), // 20B = 12B + 4B + 4B - Apply(Symbol, PoolVec), // 20B = 8B + 12B + Function(PoolVec, TypeId, TypeId), // 16B = 8B + 4B + 4B + Apply(Symbol, PoolVec), // 16B = 8B + 8B - Erroneous(Problem2), + Erroneous(Problem2), // 24B +} + +#[test] +fn type2_size() { + assert_eq!(std::mem::size_of::(), 32); // 24B + pad } #[derive(Debug)] From 506086e3d78781315fcfe0c984e146fcf59b2f9d Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 12:30:45 -0500 Subject: [PATCH 140/223] Make sure Expr2 function annotation arguments fit in a PoolVec slot The size of a `(PatternId, Type2)` tuple is 40 bytes (4 for the `PatternId`, 4 bytes padding, 32 for the `Type2`). This doesn't fit in an item slot allocated by the pool, which has a max of 32 bytes. So, we allocate the Type2 itself on the pool, and then reference its pool ID in the resulting tuple, which lowers the total size of the tuple to 8 bytes. This is a bit wasteful, but I couldn't find a better solution without significantly more rework. We also reorder the Type2 and PatternId fields in the tuple to better align with the typical `(type|type variable, pattern|expression)` tuple structure that exists in e.g. `FunctionDef::NoAnnotation`. --- ast/src/lang/core/def/def.rs | 11 ++++++++--- ast/src/lang/core/fun_def.rs | 10 +++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/ast/src/lang/core/def/def.rs b/ast/src/lang/core/def/def.rs index 850c20383e..012db8b9e8 100644 --- a/ast/src/lang/core/def/def.rs +++ b/ast/src/lang/core/def/def.rs @@ -37,7 +37,11 @@ use crate::{ rigids::Rigids, scope::Scope, }, - mem_pool::{pool::Pool, pool_vec::PoolVec, shallow_clone::ShallowClone}, + mem_pool::{ + pool::{NodeId, Pool}, + pool_vec::PoolVec, + shallow_clone::ShallowClone, + }, }; #[derive(Debug)] @@ -521,7 +525,7 @@ fn canonicalize_pending_def<'a>( // parent commit for the bug this fixed! let refs = References::new(); - let arguments: PoolVec<(PatternId, Type2)> = + let arguments: PoolVec<(NodeId, PatternId)> = PoolVec::with_capacity(closure_args.len() as u32, env.pool); let return_type: TypeId; @@ -558,7 +562,8 @@ fn canonicalize_pending_def<'a>( for (node_id, ((_, pattern_id), typ)) in arguments.iter_node_ids().zip(it.into_iter()) { - env.pool[node_id] = (pattern_id, typ); + let typ = env.pool.add(typ); + env.pool[node_id] = (typ, pattern_id); } return_type = return_type_id; diff --git a/ast/src/lang/core/fun_def.rs b/ast/src/lang/core/fun_def.rs index 1cc1d78aaa..e8aa642a86 100644 --- a/ast/src/lang/core/fun_def.rs +++ b/ast/src/lang/core/fun_def.rs @@ -14,11 +14,11 @@ use super::{ #[derive(Debug)] pub enum FunctionDef { WithAnnotation { - name: Symbol, // 8B - arguments: PoolVec<(PatternId, Type2)>, // 8B - rigids: NodeId, // 4B - return_type: TypeId, // 4B - body_id: ExprId, // 4B + name: Symbol, // 8B + arguments: PoolVec<(NodeId, PatternId)>, // 8B + rigids: NodeId, // 4B + return_type: TypeId, // 4B + body_id: ExprId, // 4B }, NoAnnotation { name: Symbol, // 8B From efe6a8b7c8566a258e51463c03787ddd122a6420 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 12:36:01 -0500 Subject: [PATCH 141/223] Pass down rigids vars for substitution during type reconstruction Rigid vars are added to types after solutions are already found and are only relevant for pretty printing elaborated types, so we don't keep track of/care about their rigid names until the end of solution. Previously we didn't provide this information in tests, though - now we do. --- ast/src/constrain.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index 57ed0d8068..319bf93276 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -1926,7 +1926,7 @@ pub mod test_constrain { let expr2_result = str_to_expr2(&code_arena, actual, &mut env, &mut scope, region); match expr2_result { - Ok((expr, _)) => { + Ok((expr, output)) => { let constraint = constrain_expr( &code_arena, &mut env, @@ -1946,11 +1946,13 @@ pub mod test_constrain { let mut var_store = VarStore::default(); std::mem::swap(ref_var_store, &mut var_store); + let rigids = output.introduced_variables.name_by_var; + let (mut solved, _, _) = run_solve( &code_arena, pool, Default::default(), - Default::default(), + rigids, constraint, var_store, ); From 477ecd6c3b6ec54154bff0279267155dafbcba73 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 12:54:48 -0500 Subject: [PATCH 142/223] Store rigid type and field names as `Lowercase` in Expr2 Moving from storing these as slices to `Lowercase`s makes it easier to transform to shapes we'll need later during type reconstruction, for example a mapping of rigid type variables to their lowercase variable names. --- ast/src/lang/core/def/def.rs | 2 +- ast/src/lang/core/types.rs | 55 +++++++++++++++++------------------- ast/src/lang/rigids.rs | 5 ++-- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/ast/src/lang/core/def/def.rs b/ast/src/lang/core/def/def.rs index 012db8b9e8..7da21a2d54 100644 --- a/ast/src/lang/core/def/def.rs +++ b/ast/src/lang/core/def/def.rs @@ -320,7 +320,7 @@ fn from_pending_alias<'a>( } for loc_lowercase in vars { - if !named_rigids.contains_key(loc_lowercase.value.as_str()) { + if !named_rigids.contains_key(&loc_lowercase.value) { env.problem(Problem::PhantomTypeArgument { alias: symbol, variable_region: loc_lowercase.region, diff --git a/ast/src/lang/core/types.rs b/ast/src/lang/core/types.rs index 3de8039ed2..babdd51f89 100644 --- a/ast/src/lang/core/types.rs +++ b/ast/src/lang/core/types.rs @@ -3,7 +3,7 @@ #![allow(unused_imports)] // use roc_can::expr::Output; use roc_collections::all::{MutMap, MutSet}; -use roc_module::ident::{Ident, TagName}; +use roc_module::ident::{Ident, Lowercase, TagName}; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_types::types::{Problem, RecordField}; @@ -176,9 +176,9 @@ pub enum Signature { }, } -pub enum Annotation2<'a> { +pub enum Annotation2 { Annotation { - named_rigids: MutMap<&'a str, Variable>, + named_rigids: MutMap, unnamed_rigids: MutSet, symbols: MutSet, signature: Signature, @@ -191,7 +191,7 @@ pub fn to_annotation2<'a>( scope: &mut Scope, annotation: &'a roc_parse::ast::TypeAnnotation<'a>, region: Region, -) -> Annotation2<'a> { +) -> Annotation2 { let mut references = References::default(); let annotation = to_type2(env, scope, &mut references, annotation, region); @@ -245,11 +245,7 @@ pub fn to_annotation2<'a>( } } -fn shallow_dealias<'a>( - env: &mut Env, - references: References<'a>, - annotation: Type2, -) -> Annotation2<'a> { +fn shallow_dealias<'a>(env: &mut Env, references: References, annotation: Type2) -> Annotation2 { let References { named, unnamed, @@ -293,8 +289,8 @@ fn shallow_dealias<'a>( } #[derive(Default)] -pub struct References<'a> { - named: MutMap<&'a str, Variable>, +pub struct References { + named: MutMap, unnamed: MutSet, hidden: MutSet, symbols: MutSet, @@ -303,7 +299,7 @@ pub struct References<'a> { pub fn to_type_id<'a>( env: &mut Env, scope: &mut Scope, - rigids: &mut References<'a>, + rigids: &mut References, annotation: &roc_parse::ast::TypeAnnotation<'a>, region: Region, ) -> TypeId { @@ -315,7 +311,7 @@ pub fn to_type_id<'a>( pub fn as_type_id<'a>( env: &mut Env, scope: &mut Scope, - rigids: &mut References<'a>, + rigids: &mut References, type_id: TypeId, annotation: &roc_parse::ast::TypeAnnotation<'a>, region: Region, @@ -329,7 +325,7 @@ pub fn as_type_id<'a>( pub fn to_type2<'a>( env: &mut Env, scope: &mut Scope, - references: &mut References<'a>, + references: &mut References, annotation: &roc_parse::ast::TypeAnnotation<'a>, region: Region, ) -> Type2 { @@ -380,8 +376,9 @@ pub fn to_type2<'a>( Type2::Function(arguments, closure_type_id, return_type_id) } BoundVariable(v) => { - // a rigid type variable - match references.named.get(v) { + // A rigid type variable. The parser should have already ensured that the name is indeed a lowercase. + let v = Lowercase::from(*v); + match references.named.get(&v) { Some(var) => Type2::Variable(*var), None => { let var = env.var_store.fresh(); @@ -406,7 +403,7 @@ pub fn to_type2<'a>( let field_types = PoolVec::with_capacity(field_types_map.len() as u32, env.pool); for (node_id, (label, field)) in field_types.iter_node_ids().zip(field_types_map) { - let poolstr = PoolStr::new(label, env.pool); + let poolstr = PoolStr::new(label.as_str(), env.pool); let rec_field = match field { RecordField::Optional(_) => { @@ -485,10 +482,10 @@ pub fn to_type2<'a>( { match loc_var.value { BoundVariable(ident) => { - let var_name = ident; + let var_name = Lowercase::from(ident); if let Some(var) = references.named.get(&var_name) { - let poolstr = PoolStr::new(var_name, env.pool); + let poolstr = PoolStr::new(var_name.as_str(), env.pool); let type_id = env.pool.add(Type2::Variable(*var)); env.pool[var_id] = (poolstr.shallow_clone(), type_id); @@ -499,7 +496,7 @@ pub fn to_type2<'a>( let var = env.var_store.fresh(); references.named.insert(var_name.clone(), var); - let poolstr = PoolStr::new(var_name, env.pool); + let poolstr = PoolStr::new(var_name.as_str(), env.pool); let type_id = env.pool.add(Type2::Variable(var)); env.pool[var_id] = (poolstr.shallow_clone(), type_id); @@ -581,10 +578,10 @@ pub fn to_type2<'a>( fn can_assigned_fields<'a>( env: &mut Env, scope: &mut Scope, - rigids: &mut References<'a>, + rigids: &mut References, fields: &&[Located>>], region: Region, -) -> MutMap<&'a str, RecordField> { +) -> MutMap> { use roc_parse::ast::AssignedField::*; use roc_types::types::RecordField::*; @@ -607,8 +604,8 @@ fn can_assigned_fields<'a>( let field_type = to_type2(env, scope, rigids, &annotation.value, annotation.region); - let label = field_name.value; - field_types.insert(label, Required(field_type)); + let label = Lowercase::from(field_name.value); + field_types.insert(label.clone(), Required(field_type)); break 'inner label; } @@ -616,20 +613,20 @@ fn can_assigned_fields<'a>( let field_type = to_type2(env, scope, rigids, &annotation.value, annotation.region); - let label = field_name.value; + let label = Lowercase::from(field_name.value); field_types.insert(label.clone(), Optional(field_type)); break 'inner label; } LabelOnly(loc_field_name) => { // Interpret { a, b } as { a : a, b : b } - let field_name = loc_field_name.value; + let field_name = Lowercase::from(loc_field_name.value); let field_type = { if let Some(var) = rigids.named.get(&field_name) { Type2::Variable(*var) } else { let field_var = env.var_store.fresh(); - rigids.named.insert(field_name, field_var); + rigids.named.insert(field_name.clone(), field_var); Type2::Variable(field_var) } }; @@ -669,7 +666,7 @@ fn can_assigned_fields<'a>( fn can_tags<'a>( env: &mut Env, scope: &mut Scope, - rigids: &mut References<'a>, + rigids: &mut References, tags: &'a [Located>], region: Region, ) -> Vec<(TagName, PoolVec)> { @@ -753,7 +750,7 @@ enum TypeApply { fn to_type_apply<'a>( env: &mut Env, scope: &mut Scope, - rigids: &mut References<'a>, + rigids: &mut References, module_name: &str, ident: &str, type_arguments: &[Located>], diff --git a/ast/src/lang/rigids.rs b/ast/src/lang/rigids.rs index a10dce0016..c629904dbd 100644 --- a/ast/src/lang/rigids.rs +++ b/ast/src/lang/rigids.rs @@ -7,6 +7,7 @@ use crate::mem_pool::{ pool::Pool, pool_str::PoolStr, pool_vec::PoolVec, shallow_clone::ShallowClone, }; use roc_collections::all::WyHash; +use roc_module::ident::Lowercase; use roc_types::subs::Variable; #[derive(Debug)] @@ -18,7 +19,7 @@ pub struct Rigids { #[allow(clippy::needless_collect)] impl Rigids { pub fn new( - named: HashMap<&str, Variable, BuildHasherDefault>, + named: HashMap>, unnamed: HashSet>, pool: &mut Pool, ) -> Self { @@ -26,7 +27,7 @@ impl Rigids { let mut temp_names = Vec::new(); - temp_names.extend(named.iter().map(|(name, var)| (Some(*name), *var))); + temp_names.extend(named.iter().map(|(name, var)| (Some(name.as_str()), *var))); temp_names.extend(unnamed.iter().map(|var| (None, *var))); From 9399596d8666c51c4420e653da8d4f7f146dad6a Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 12:56:53 -0500 Subject: [PATCH 143/223] Store rigid var names during translation of closure defs to Expr2 We ened to store the mapping of `rigid type vars -> user-declared names` for presentation later on when we reconstruct the type of an expression and want to pretty-print it for the user. This information is most naturally captured on `output.introduced_variables`, as the main compiler does so there. We don't currently record this mapping while translating `Annotation`s to `Annotation2`s (though we could), so we store it when we hit an annotated expression that now needs to become an `Expr2`. --- ast/src/lang/core/def/def.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ast/src/lang/core/def/def.rs b/ast/src/lang/core/def/def.rs index 7da21a2d54..ce2a273541 100644 --- a/ast/src/lang/core/def/def.rs +++ b/ast/src/lang/core/def/def.rs @@ -458,6 +458,10 @@ fn canonicalize_pending_def<'a>( output.references.referenced_aliases.insert(symbol); } + // Ensure rigid type vars and their names are known in the output. + for (name, &var) in named_rigids.iter() { + output.introduced_variables.insert_named(name.clone(), var); + } let rigids = Rigids::new(named_rigids, unnamed_rigids, env.pool); // bookkeeping for tail-call detection. If we're assigning to an From 539c7371235f1c57fb74232fc3f1b884bc5beba8 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 13:33:05 -0500 Subject: [PATCH 144/223] Implement constraint generation for annotated `Expr2::FunctionDef`s This is mostly the same as the procedure for unannotated `FunctionDef`s. The only differences are that we need to 1. note the rigid type variables that are a part of the FunctionDef 2. generate fresh type variables for the function arguments, and constrain them to the types of the arguments passed to us in the annotation This is enough to get the constraint generation working. There are more interesting cases that properly typecheck in the main compiler but do not typecheck given the current state of the editor AST (see the second test in this commit), but this is a bug due to canonicalization, not type reconstruction. --- ast/src/constrain.rs | 187 ++++++++++++++++++++++++++++++------------- 1 file changed, 130 insertions(+), 57 deletions(-) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index 319bf93276..f40ec6de47 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -835,70 +835,109 @@ pub fn constrain_expr<'a>( let function_def = env.pool.get(*def_id); - match function_def { - FunctionDef::WithAnnotation { .. } => { - todo!("implement constraint generation for {:?}", function_def) + let (name, arguments, body_id, rigid_vars, args_constrs) = match function_def { + FunctionDef::WithAnnotation { + name, + arguments, + body_id, + rigids, + return_type: _, + } => { + // The annotation gives us arguments with proper Type2s, but the constraints we + // generate below args bound to type variables. Create fresh ones and bind them + // to the types we already know. + let mut args_constrs = BumpVec::with_capacity_in(arguments.len(), arena); + let args_vars = PoolVec::with_capacity(arguments.len() as u32, env.pool); + for (arg_ty_node_id, arg_var_node_id) in + arguments.iter_node_ids().zip(args_vars.iter_node_ids()) + { + let (ty, pattern) = env.pool.get(arg_ty_node_id); + let arg_var = env.var_store.fresh(); + let ty = env.pool.get(*ty); + args_constrs.push(Eq( + Type2::Variable(arg_var), + Expected::NoExpectation(ty.shallow_clone()), + Category::Storage(std::file!(), std::line!()), + // TODO: should be the actual region of the argument + region, + )); + env.pool[arg_var_node_id] = (arg_var, *pattern); + } + + let rigids = env.pool.get(*rigids); + let rigid_vars: BumpVec = + BumpVec::from_iter_in(rigids.names.iter(env.pool).map(|&(_, v)| v), arena); + + (name, args_vars, body_id, rigid_vars, args_constrs) } FunctionDef::NoAnnotation { name, arguments, - body_id: expr_id, + body_id, return_var: _, } => { - // A function definition is equivalent to a named value definition, where the - // value is a closure. So, we create a closure definition in correspondence - // with the function definition, generate type constraints for it, and demand - // that type of the function is just the type of the resolved closure. - let fn_var = env.var_store.fresh(); - let fn_ty = Type2::Variable(fn_var); - - let extra = ClosureExtra { - return_type: env.var_store.fresh(), - captured_symbols: PoolVec::empty(env.pool), - closure_type: env.var_store.fresh(), - closure_ext_var: env.var_store.fresh(), - }; - let clos = Expr2::Closure { - args: arguments.shallow_clone(), - uniq_symbol: *name, - body_id: *expr_id, - function_type: env.var_store.fresh(), - extra: env.pool.add(extra), - recursive: roc_can::expr::Recursive::Recursive, - }; - let clos_con = constrain_expr( - arena, - env, - &clos, - Expected::NoExpectation(fn_ty.shallow_clone()), - region, - ); - - // This is the `foo` part in `foo = \...`. We want to bind the name of the - // function with its type, whose constraints we generated above. - let mut def_pattern_state = PatternState2 { - headers: BumpMap::new_in(arena), - vars: BumpVec::new_in(arena), - constraints: BumpVec::new_in(arena), - }; - def_pattern_state.headers.insert(*name, fn_ty); - def_pattern_state.vars.push(fn_var); - - Let(arena.alloc(LetConstraint { - rigid_vars: BumpVec::new_in(arena), // The function def is unannotated, so there are no rigid type vars - flex_vars: def_pattern_state.vars, - def_types: def_pattern_state.headers, // Binding function name -> its type - defs_constraint: Let(arena.alloc(LetConstraint { - rigid_vars: BumpVec::new_in(arena), // always empty - flex_vars: BumpVec::new_in(arena), // empty, because our functions have no arguments - def_types: BumpMap::new_in(arena), // empty, because our functions have no arguments - defs_constraint: And(def_pattern_state.constraints), - ret_constraint: clos_con, - })), - ret_constraint: body_con, - })) + ( + name, + arguments.shallow_clone(), + body_id, + BumpVec::new_in(arena), // The function is unannotated, so there are no rigid type vars + BumpVec::new_in(arena), // No extra constraints to generate for arguments + ) } - } + }; + + // A function definition is equivalent to a named value definition, where the + // value is a closure. So, we create a closure definition in correspondence + // with the function definition, generate type constraints for it, and demand + // that type of the function is just the type of the resolved closure. + let fn_var = env.var_store.fresh(); + let fn_ty = Type2::Variable(fn_var); + + let extra = ClosureExtra { + return_type: env.var_store.fresh(), + captured_symbols: PoolVec::empty(env.pool), + closure_type: env.var_store.fresh(), + closure_ext_var: env.var_store.fresh(), + }; + let clos = Expr2::Closure { + args: arguments.shallow_clone(), + uniq_symbol: *name, + body_id: *body_id, + function_type: env.var_store.fresh(), + extra: env.pool.add(extra), + recursive: roc_can::expr::Recursive::Recursive, + }; + let clos_con = constrain_expr( + arena, + env, + &clos, + Expected::NoExpectation(fn_ty.shallow_clone()), + region, + ); + + // This is the `foo` part in `foo = \...`. We want to bind the name of the + // function with its type, whose constraints we generated above. + let mut def_pattern_state = PatternState2 { + headers: BumpMap::new_in(arena), + vars: BumpVec::new_in(arena), + constraints: args_constrs, + }; + def_pattern_state.headers.insert(*name, fn_ty); + def_pattern_state.vars.push(fn_var); + + Let(arena.alloc(LetConstraint { + rigid_vars, + flex_vars: def_pattern_state.vars, + def_types: def_pattern_state.headers, // Binding function name -> its type + defs_constraint: Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), // always empty + flex_vars: BumpVec::new_in(arena), // empty, because our functions have no arguments + def_types: BumpMap::new_in(arena), // empty, because our functions have no arguments + defs_constraint: And(def_pattern_state.constraints), + ret_constraint: clos_con, + })), + ret_constraint: body_con, + })) } Expr2::Update { symbol, @@ -2389,4 +2428,38 @@ pub mod test_constrain { "{ x : a }b -> { x : a }b", ); } + + #[test] + fn using_type_signature() { + infer_eq( + indoc!( + r#" + bar : custom -> custom + bar = \x -> x + + bar + "# + ), + "custom -> custom", + ); + } + + #[ignore = "Currently panics at 'Invalid Cycle', ast/src/lang/core/def/def.rs:1212:21"] + #[test] + fn using_type_signature2() { + infer_eq( + indoc!( + r#" + id1 : tya -> tya + id1 = \x -> x + + id2 : tyb -> tyb + id2 = id1 + + id2 + "# + ), + "tyb -> tyb", + ); + } } From 111a835b3c46886492eb99aa3491d71132bab6af Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 13:37:02 -0500 Subject: [PATCH 145/223] Add ignored tests for annotation-only declarations in Expr2 These tests fail currently because we have not implemented type reconstruction in the presence of annonation-only declarations, but it's good to keep track of them for later. --- ast/src/constrain.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index f40ec6de47..760155fa39 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -2462,4 +2462,34 @@ pub mod test_constrain { "tyb -> tyb", ); } + + #[ignore = "Implement annotation-only decls"] + #[test] + fn type_signature_without_body() { + infer_eq( + indoc!( + r#" + foo: Str -> {} + + foo "hi" + "# + ), + "{}", + ); + } + + #[ignore = "Implement annotation-only decls"] + #[test] + fn type_signature_without_body_rigid() { + infer_eq( + indoc!( + r#" + foo : Num * -> custom + + foo 2 + "# + ), + "custom", + ); + } } From 46499e4419d51962c415dafaa8bdb709fe4312fa Mon Sep 17 00:00:00 2001 From: MartinSStewart Date: Wed, 17 Nov 2021 20:56:32 +0100 Subject: [PATCH 146/223] Fixed "map literal" used instead of "dict literal" --- roc-for-elm-programmers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roc-for-elm-programmers.md b/roc-for-elm-programmers.md index 5d75c244d1..da0215f5a4 100644 --- a/roc-for-elm-programmers.md +++ b/roc-for-elm-programmers.md @@ -819,7 +819,7 @@ Dict.fromList [ KV "Sam" True, KV "Ali" False KV firstName False This works, but is not nearly as nice to read. -Additionally, map literals can compile directly to efficient initialization code +Additionally, `Dict` literals can compile directly to efficient initialization code without needing to (hopefully be able to) optimize away the intermediate `List` involved in `fromList`. From 75126b09fd9e8a389bf9b4c5d8faeefb5ce830de Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 22:33:24 +0100 Subject: [PATCH 147/223] refactor procs.specialized --- compiler/mono/src/ir.rs | 287 ++++++++++++++++++++++++++-------------- 1 file changed, 187 insertions(+), 100 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 03bdc8e692..f2a30a5120 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1,6 +1,5 @@ #![allow(clippy::manual_map)] -use self::InProgressProc::*; use crate::exhaustive::{Ctor, Guard, RenderAs, TagId}; use crate::layout::{ Builtin, ClosureRepresentation, LambdaSet, Layout, LayoutCache, LayoutProblem, @@ -8,7 +7,6 @@ use crate::layout::{ }; use bumpalo::collections::Vec; use bumpalo::Bump; -use hashbrown::hash_map::Entry; use roc_can::expr::ClosureData; use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; @@ -525,13 +523,123 @@ enum PendingSpecializations<'a> { Making, } +#[derive(Clone, Debug, Default)] +struct Specialized<'a> { + symbols: std::vec::Vec, + proc_layouts: std::vec::Vec>, + procedures: std::vec::Vec>, +} + +impl<'a> Specialized<'a> { + fn len(&self) -> usize { + self.symbols.len() + } + + #[allow(dead_code)] + fn is_empty(&self) -> bool { + self.symbols.is_empty() + } + + fn into_iter_assert_done(self) -> impl Iterator, Proc<'a>)> { + self.symbols + .into_iter() + .zip(self.proc_layouts.into_iter()) + .zip(self.procedures.into_iter()) + .filter_map(|((s, l), in_progress)| { + // we use UNDERSCORE for removed symbols + if let Symbol::UNDERSCORE = s { + None + } else { + match in_progress { + InProgressProc::InProgress => panic!("Function is not done specializing"), + InProgressProc::Done(proc) => Some((s, l, proc)), + } + } + }) + } + + fn is_specialized(&mut self, symbol: Symbol, layout: &ProcLayout<'a>) -> bool { + for (i, s) in self.symbols.iter().enumerate() { + if *s == symbol && &self.proc_layouts[i] == layout { + return true; + } + } + + false + } + + fn mark_in_progress(&mut self, symbol: Symbol, layout: ProcLayout<'a>) { + for (i, s) in self.symbols.iter().enumerate() { + if *s == symbol && self.proc_layouts[i] == layout { + match &self.procedures[i] { + InProgressProc::InProgress => { + return; + } + InProgressProc::Done(_) => { + panic!("marking in progress, but this proc is already done!") + } + } + } + } + + // the key/layout combo was not found; insert it + self.symbols.push(symbol); + self.proc_layouts.push(layout); + self.procedures.push(InProgressProc::InProgress); + } + + fn remove_specialized(&mut self, symbol: Symbol, layout: &ProcLayout<'a>) -> bool { + let mut index = None; + + for (i, s) in self.symbols.iter().enumerate() { + if *s == symbol && &self.proc_layouts[i] == layout { + index = Some(i); + } + } + + if let Some(index) = index { + // we use UNDERSCORE for removed symbols + self.symbols[index] = Symbol::UNDERSCORE; + + true + } else { + false + } + } + + fn insert_specialized(&mut self, symbol: Symbol, layout: ProcLayout<'a>, proc: Proc<'a>) { + for (i, s) in self.symbols.iter().enumerate() { + if *s == symbol && self.proc_layouts[i] == layout { + match &self.procedures[i] { + InProgressProc::InProgress => { + self.procedures[i] = InProgressProc::Done(proc); + return; + } + InProgressProc::Done(_) => { + // overwrite existing! this is important in practice + // TODO investigate why we generate the wrong proc in some cases and then + // correct later + self.procedures[i] = InProgressProc::Done(proc); + return; + } + } + } + } + + // the key/layout combo was not found; insert it + self.symbols.push(symbol); + self.proc_layouts.push(layout); + self.procedures.push(InProgressProc::Done(proc)); + } +} + #[derive(Clone, Debug)] pub struct Procs<'a> { pub partial_procs: PartialProcs<'a>, pub imported_module_thunks: &'a [Symbol], pub module_thunks: &'a [Symbol], pending_specializations: PendingSpecializations<'a>, - pub specialized: BumpMap<(Symbol, ProcLayout<'a>), InProgressProc<'a>>, + specialized: Specialized<'a>, pub runtime_errors: BumpMap, pub externals_we_need: BumpMap>, } @@ -543,7 +651,7 @@ impl<'a> Procs<'a> { imported_module_thunks: &[], module_thunks: &[], pending_specializations: PendingSpecializations::Finding(Suspended::new_in(arena)), - specialized: BumpMap::new_in(arena), + specialized: Specialized::default(), runtime_errors: BumpMap::new_in(arena), externals_we_need: BumpMap::new_in(arena), } @@ -575,23 +683,11 @@ impl<'a> Procs<'a> { ) -> MutMap<(Symbol, ProcLayout<'a>), Proc<'a>> { let mut result = MutMap::with_capacity_and_hasher(self.specialized.len(), default_hasher()); - for (key, in_prog_proc) in self.specialized.into_iter() { - match in_prog_proc { - InProgress => { - let (symbol, layout) = key; - eprintln!( - "The procedure {:?} should have be done by now:\n\n {:?}", - symbol, layout - ); + for (symbol, layout, mut proc) in self.specialized.into_iter_assert_done() { + proc.make_tail_recursive(env); - panic!(); - } - Done(mut proc) => { - proc.make_tail_recursive(env); - - result.insert(key, proc); - } - } + let key = (symbol, layout); + result.insert(key, proc); } result @@ -625,10 +721,7 @@ impl<'a> Procs<'a> { // by the surrounding context, so we can add pending specializations // for them immediately. - let already_specialized = self - .specialized - .keys() - .any(|(s, t)| *s == symbol && *t == top_level); + let already_specialized = self.specialized.is_specialized(symbol, &top_level); let layout = top_level; @@ -676,7 +769,7 @@ impl<'a> Procs<'a> { // Mark this proc as in-progress, so if we're dealing with // mutually recursive functions, we don't loop forever. // (We had a bug around this before this system existed!) - self.specialized.insert((symbol, layout), InProgress); + self.specialized.mark_in_progress(symbol, layout); let outside_layout = layout; @@ -730,7 +823,7 @@ impl<'a> Procs<'a> { debug_assert!(top_level.arguments.is_empty()); } - self.specialized.insert((symbol, top_level), Done(proc)); + self.specialized.insert_specialized(symbol, top_level, proc); } Err(error) => { panic!("TODO generate a RuntimeError message for {:?}", error); @@ -755,7 +848,7 @@ impl<'a> Procs<'a> { layout_cache: &mut LayoutCache<'a>, ) { // If we've already specialized this one, no further work is needed. - if self.specialized.contains_key(&(name, layout)) { + if self.specialized.is_specialized(name, &layout) { return; } @@ -787,7 +880,7 @@ impl<'a> Procs<'a> { // Mark this proc as in-progress, so if we're dealing with // mutually recursive functions, we don't loop forever. // (We had a bug around this before this system existed!) - self.specialized.insert((symbol, layout), InProgress); + self.specialized.mark_in_progress(symbol, layout); // See https://github.com/rtfeldman/roc/issues/1600 // @@ -825,8 +918,9 @@ impl<'a> Procs<'a> { // NOTE: some function are specialized to have a closure, but don't actually // need any closure argument. Here is where we correct this sort of thing, // by trusting the layout of the Proc, not of what we specialize for - self.specialized.remove(&(symbol, layout)); - self.specialized.insert((symbol, proper_layout), Done(proc)); + self.specialized.remove_specialized(symbol, &layout); + self.specialized + .insert_specialized(symbol, proper_layout, proc); } Err(error) => { panic!("TODO generate a RuntimeError message for {:?}", error); @@ -1832,28 +1926,24 @@ pub fn specialize_all<'a>( let var = suspended.variables[i]; let outside_layout = suspended.layouts[i]; - let key = (name, outside_layout); + // TODO define our own Entry for Specialized? + let partial_proc = if procs.specialized.is_specialized(name, &outside_layout) { + // already specialized, just continue + continue; + } else { + match procs.partial_procs.symbol_to_id(name) { + Some(v) => { + // Mark this proc as in-progress, so if we're dealing with + // mutually recursive functions, we don't loop forever. + // (We had a bug around this before this system existed!) + procs.specialized.mark_in_progress(name, outside_layout); - let partial_proc = match procs.specialized.entry(key) { - Entry::Occupied(_) => { - // already specialized, just continue - continue; - } - Entry::Vacant(vacant) => { - match procs.partial_procs.symbol_to_id(name) { - Some(v) => { - // Mark this proc as in-progress, so if we're dealing with - // mutually recursive functions, we don't loop forever. - // (We had a bug around this before this system existed!) - vacant.insert(InProgress); - - v - } - None => { - // TODO this assumes the specialization is done by another module - // make sure this does not become a problem down the road! - continue; - } + v + } + None => { + // TODO this assumes the specialization is done by another module + // make sure this does not become a problem down the road! + continue; } } }; @@ -1881,7 +1971,7 @@ pub fn specialize_all<'a>( } debug_assert_eq!(outside_layout, top_level, " in {:?}", name); - procs.specialized.insert((name, top_level), Done(proc)); + procs.specialized.insert_specialized(name, top_level, proc); } Err(SpecializeFailure { attempted_layout, .. @@ -1890,7 +1980,7 @@ pub fn specialize_all<'a>( let top_level = ProcLayout::from_raw(env.arena, attempted_layout); - procs.specialized.insert((name, top_level), Done(proc)); + procs.specialized.insert_specialized(name, top_level, proc); } } } @@ -1903,28 +1993,24 @@ pub fn specialize_all<'a>( for (outside_layout, pending) in by_layout.into_iter() { // If we've already seen this (Symbol, Layout) combination before, // don't try to specialize it again. If we do, we'll loop forever! - let key = (name, outside_layout); - let partial_proc = match procs.specialized.entry(key) { - Entry::Occupied(_) => { - // already specialized, just continue - continue; - } - Entry::Vacant(vacant) => { - match procs.partial_procs.symbol_to_id(name) { - Some(v) => { - // Mark this proc as in-progress, so if we're dealing with - // mutually recursive functions, we don't loop forever. - // (We had a bug around this before this system existed!) - vacant.insert(InProgress); + let partial_proc = if procs.specialized.is_specialized(name, &outside_layout) { + // already specialized, just continue + continue; + } else { + match procs.partial_procs.symbol_to_id(name) { + Some(v) => { + // Mark this proc as in-progress, so if we're dealing with + // mutually recursive functions, we don't loop forever. + // (We had a bug around this before this system existed!) + procs.specialized.mark_in_progress(name, outside_layout); - v - } - None => { - // TODO this assumes the specialization is done by another module - // make sure this does not become a problem down the road! - continue; - } + v + } + None => { + // TODO this assumes the specialization is done by another module + // make sure this does not become a problem down the road! + continue; } } }; @@ -1944,7 +2030,7 @@ pub fn specialize_all<'a>( } debug_assert_eq!(outside_layout, top_level, " in {:?}", name); - procs.specialized.insert((name, top_level), Done(proc)); + procs.specialized.insert_specialized(name, top_level, proc); } Err(SpecializeFailure { attempted_layout, .. @@ -1953,7 +2039,7 @@ pub fn specialize_all<'a>( let top_level = ProcLayout::from_raw(env.arena, attempted_layout); - procs.specialized.insert((name, top_level), Done(proc)); + procs.specialized.insert_specialized(name, top_level, proc); } } } @@ -2003,7 +2089,7 @@ fn specialize_externals_others_need<'a>( debug_assert!(top_level.arguments.is_empty()); } - procs.specialized.insert((name, top_level), Done(proc)); + procs.specialized.insert_specialized(name, top_level, proc); } Err(SpecializeFailure { problem: _, @@ -2013,7 +2099,7 @@ fn specialize_externals_others_need<'a>( let top_level = ProcLayout::from_raw(env.arena, attempted_layout); - procs.specialized.insert((name, top_level), Done(proc)); + procs.specialized.insert_specialized(name, top_level, proc); } } } @@ -2172,9 +2258,7 @@ fn specialize_external<'a>( *return_layout, ); - procs - .specialized - .insert((name, top_level), InProgressProc::Done(proc)); + procs.specialized.insert_specialized(name, top_level, proc); aliases.insert(*symbol, (name, top_level, layout)); } @@ -6706,8 +6790,7 @@ fn call_by_name_help<'a>( // If we've already specialized this one, no further work is needed. if procs .specialized - .keys() - .any(|x| x == &(proc_name, top_level_layout)) + .is_specialized(proc_name, &top_level_layout) { debug_assert_eq!( argument_layouts.len(), @@ -6833,7 +6916,7 @@ fn call_by_name_help<'a>( // (We had a bug around this before this system existed!) procs .specialized - .insert((proc_name, top_level_layout), InProgress); + .mark_in_progress(proc_name, top_level_layout); match specialize_variable( env, @@ -6916,7 +6999,7 @@ fn call_by_name_module_thunk<'a>( // If we've already specialized this one, no further work is needed. let already_specialized = procs .specialized - .contains_key(&(proc_name, top_level_layout)); + .is_specialized(proc_name, &top_level_layout); if already_specialized { force_thunk(env, proc_name, inner_layout, assigned, hole) @@ -6955,7 +7038,7 @@ fn call_by_name_module_thunk<'a>( // (We had a bug around this before this system existed!) procs .specialized - .insert((proc_name, top_level_layout), InProgress); + .mark_in_progress(proc_name, top_level_layout); match specialize_variable( env, @@ -6973,13 +7056,16 @@ fn call_by_name_module_thunk<'a>( raw_layout ); - let was_present = - procs.specialized.remove(&(proc_name, top_level_layout)); - debug_assert!(was_present.is_some()); - - procs + let was_present = procs .specialized - .insert((proc_name, top_level_layout), Done(proc)); + .remove_specialized(proc_name, &top_level_layout); + debug_assert!(was_present); + + procs.specialized.insert_specialized( + proc_name, + top_level_layout, + proc, + ); force_thunk(env, proc_name, inner_layout, assigned, hole) } @@ -6993,13 +7079,16 @@ fn call_by_name_module_thunk<'a>( attempted_layout, ); - let was_present = - procs.specialized.remove(&(proc_name, top_level_layout)); - debug_assert!(was_present.is_some()); - - procs + let was_present = procs .specialized - .insert((proc_name, top_level_layout), Done(proc)); + .remove_specialized(proc_name, &top_level_layout); + debug_assert!(was_present); + + procs.specialized.insert_specialized( + proc_name, + top_level_layout, + proc, + ); force_thunk(env, proc_name, inner_layout, assigned, hole) } @@ -7031,11 +7120,9 @@ fn call_specialized_proc<'a>( ) -> Stmt<'a> { let function_layout = ProcLayout::from_raw(env.arena, layout); - procs.specialized.remove(&(proc_name, function_layout)); - procs .specialized - .insert((proc_name, function_layout), Done(proc)); + .insert_specialized(proc_name, function_layout, proc); if field_symbols.is_empty() { debug_assert!(loc_args.is_empty()); From f9c81bffe0bf4ee455ed14a4a3a16cb2dd962125 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Nov 2021 23:09:20 +0100 Subject: [PATCH 148/223] make external specializations more efficient - create fewer Subs values - don't merge Subs if not needed --- compiler/load/src/file.rs | 16 ++--- compiler/mono/src/ir.rs | 139 +++++++++++++++++++------------------- 2 files changed, 77 insertions(+), 78 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 17a370d49a..c046e8bd18 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -356,7 +356,7 @@ struct ModuleCache<'a> { constrained: MutMap, typechecked: MutMap>, found_specializations: MutMap>, - external_specializations_requested: MutMap>, + external_specializations_requested: MutMap>>, /// Various information imports: MutMap>, @@ -587,7 +587,7 @@ fn start_phase<'a>( .module_cache .external_specializations_requested .remove(&module_id) - .unwrap_or_else(|| ExternalSpecializations::new_in(arena)); + .unwrap_or_default(); let FoundSpecializationsModule { module_id, @@ -1054,7 +1054,7 @@ enum BuildTask<'a> { subs: Subs, procs_base: ProcsBase<'a>, layout_cache: LayoutCache<'a>, - specializations_we_must_make: ExternalSpecializations<'a>, + specializations_we_must_make: Vec>, module_timing: ModuleTiming, }, } @@ -2171,11 +2171,11 @@ fn update<'a>( .external_specializations_requested .entry(module_id) { - Vacant(entry) => entry.insert(ExternalSpecializations::new_in(arena)), + Vacant(entry) => entry.insert(vec![]), Occupied(entry) => entry.into_mut(), }; - existing.extend(requested); + existing.push(requested); } msg_tx @@ -2198,11 +2198,11 @@ fn update<'a>( .external_specializations_requested .entry(module_id) { - Vacant(entry) => entry.insert(ExternalSpecializations::new_in(arena)), + Vacant(entry) => entry.insert(vec![]), Occupied(entry) => entry.into_mut(), }; - existing.extend(requested); + existing.push(requested); } start_tasks(arena, &mut state, work, injector, worker_listeners)?; @@ -3936,7 +3936,7 @@ fn make_specializations<'a>( mut subs: Subs, procs_base: ProcsBase<'a>, mut layout_cache: LayoutCache<'a>, - specializations_we_must_make: ExternalSpecializations<'a>, + specializations_we_must_make: Vec>, mut module_timing: ModuleTiming, ptr_bytes: u32, ) -> Msg<'a> { diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index f2a30a5120..268ba249f7 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -419,8 +419,9 @@ pub struct ExternalSpecializations<'a> { /// Not a bumpalo vec because bumpalo is not thread safe /// Separate array so we can search for membership quickly symbols: std::vec::Vec, - /// For each symbol, what types to specialize it for - types_to_specialize: std::vec::Vec>, + storage_subs: Subs, + /// For each symbol, what types to specialize it for, points into the storage_subs + types_to_specialize: std::vec::Vec>, _lifetime: std::marker::PhantomData<&'a u8>, } @@ -428,43 +429,40 @@ impl<'a> ExternalSpecializations<'a> { pub fn new_in(_arena: &'a Bump) -> Self { Self { symbols: std::vec::Vec::new(), + storage_subs: Subs::default(), types_to_specialize: std::vec::Vec::new(), _lifetime: std::marker::PhantomData, } } - fn insert_external(&mut self, symbol: Symbol, store: Subs, variable: Variable) { + fn insert_external(&mut self, symbol: Symbol, env_subs: &mut Subs, variable: Variable) { + let variable = + roc_solve::solve::deep_copy_var_to(env_subs, &mut self.storage_subs, variable); + match self.symbols.iter().position(|s| *s == symbol) { None => { self.symbols.push(symbol); - self.types_to_specialize.push(vec![(store, variable)]); + self.types_to_specialize.push(vec![variable]); } Some(index) => { let types_to_specialize = &mut self.types_to_specialize[index]; - types_to_specialize.push((store, variable)); + types_to_specialize.push(variable); } } } - pub fn extend(&mut self, other: Self) { - for (symbol, tts) in other.into_iter() { - match self.symbols.iter().position(|s| *s == symbol) { - None => { - self.symbols.push(symbol); - self.types_to_specialize.push(tts); - } - Some(index) => { - let types_to_specialize = &mut self.types_to_specialize[index]; - types_to_specialize.extend(tts); - } - } - } - } - - fn into_iter(self) -> impl Iterator)> { - self.symbols - .into_iter() - .zip(self.types_to_specialize.into_iter()) + fn decompose( + self, + ) -> ( + Subs, + impl Iterator)>, + ) { + ( + self.storage_subs, + self.symbols + .into_iter() + .zip(self.types_to_specialize.into_iter()), + ) } } @@ -1897,7 +1895,7 @@ fn pattern_to_when<'a>( pub fn specialize_all<'a>( env: &mut Env<'a, '_>, mut procs: Procs<'a>, - externals_others_need: ExternalSpecializations<'a>, + externals_others_need: std::vec::Vec>, specializations_for_host: BumpMap, PendingSpecialization<'a>>>, layout_cache: &mut LayoutCache<'a>, ) -> Procs<'a> { @@ -2051,55 +2049,59 @@ pub fn specialize_all<'a>( fn specialize_externals_others_need<'a>( env: &mut Env<'a, '_>, procs: &mut Procs<'a>, - externals_others_need: ExternalSpecializations<'a>, + all_externals_others_need: std::vec::Vec>, layout_cache: &mut LayoutCache<'a>, ) { - for (symbol, solved_types) in externals_others_need.into_iter() { - for (mut store, store_variable) in solved_types { - // historical note: we used to deduplicate with a hash here, - // but the cost of that hash is very high. So for now we make - // duplicate specializations, and the insertion into a hash map - // below will deduplicate them. + for externals_others_need in all_externals_others_need { + let (mut store, it) = externals_others_need.decompose(); + for (symbol, solved_types) in it { + for store_variable in solved_types { + // historical note: we used to deduplicate with a hash here, + // but the cost of that hash is very high. So for now we make + // duplicate specializations, and the insertion into a hash map + // below will deduplicate them. - let name = symbol; + let name = symbol; - let partial_proc_id = match procs.partial_procs.symbol_to_id(name) { - Some(v) => v, - None => { - panic!("Cannot find a partial proc for {:?}", name); - } - }; - - let variable = roc_solve::solve::deep_copy_var_to(&mut store, env.subs, store_variable); - - // TODO I believe this is also duplicated - match specialize_variable( - env, - procs, - name, - layout_cache, - variable, - BumpMap::new_in(env.arena), - partial_proc_id, - ) { - Ok((proc, layout)) => { - let top_level = ProcLayout::from_raw(env.arena, layout); - - if procs.is_module_thunk(name) { - debug_assert!(top_level.arguments.is_empty()); + let partial_proc_id = match procs.partial_procs.symbol_to_id(name) { + Some(v) => v, + None => { + panic!("Cannot find a partial proc for {:?}", name); } + }; - procs.specialized.insert_specialized(name, top_level, proc); - } - Err(SpecializeFailure { - problem: _, - attempted_layout, - }) => { - let proc = generate_runtime_error_function(env, name, attempted_layout); + let variable = + roc_solve::solve::deep_copy_var_to(&mut store, env.subs, store_variable); - let top_level = ProcLayout::from_raw(env.arena, attempted_layout); + // TODO I believe this is also duplicated + match specialize_variable( + env, + procs, + name, + layout_cache, + variable, + BumpMap::new_in(env.arena), + partial_proc_id, + ) { + Ok((proc, layout)) => { + let top_level = ProcLayout::from_raw(env.arena, layout); - procs.specialized.insert_specialized(name, top_level, proc); + if procs.is_module_thunk(name) { + debug_assert!(top_level.arguments.is_empty()); + } + + procs.specialized.insert_specialized(name, top_level, proc); + } + Err(SpecializeFailure { + problem: _, + attempted_layout, + }) => { + let proc = generate_runtime_error_function(env, name, attempted_layout); + + let top_level = ProcLayout::from_raw(env.arena, attempted_layout); + + procs.specialized.insert_specialized(name, top_level, proc); + } } } } @@ -6562,10 +6564,7 @@ fn add_needed_external<'a>( Occupied(entry) => entry.into_mut(), }; - let mut store = Subs::default(); - let variable = roc_solve::solve::deep_copy_var_to(env.subs, &mut store, fn_var); - - existing.insert_external(name, store, variable); + existing.insert_external(name, env.subs, fn_var); } fn build_call<'a>( From c17b9ffaa32156a82ff7b9590e8f7fb7c722368b Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 17:45:02 -0500 Subject: [PATCH 149/223] Fix compiler builds on macOS `cargo build` is currently failing on trunk. #1986 added an extra parameter to the definition of `build_zig_host_native` active for non-macOS targets, but did not reflect that parameter in the macOS-specific definition. I don't think there is a good way to test against these kinds of things without a dedicated macOS machine on the CI runner (`cargo check --target x86_64-apple-darwin` won't work since some dependencies need arch-specific things to be present during build time). Any suggestions are appreciated! --- compiler/build/src/link.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index e2a8b9a5a4..efc3385800 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -145,6 +145,8 @@ pub fn build_zig_host_native( _target: &str, opt_level: OptLevel, shared_lib_path: Option<&Path>, + // For compatibility with the non-macOS def above. Keep these in sync. + _target_valgrind: bool, ) -> Output { use serde_json::Value; From 712237998fb7e79a5495ae7cba74c919738fbd4c Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 18:02:53 -0500 Subject: [PATCH 150/223] Check for compilation errors against macOS --- Earthfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Earthfile b/Earthfile index 407477acf2..978b29aa00 100644 --- a/Earthfile +++ b/Earthfile @@ -33,6 +33,8 @@ install-zig-llvm-valgrind-clippy-rustfmt: RUN rustup component add clippy # rustfmt RUN rustup component add rustfmt + # macOS target for checking Mac-specific compilations + RUN rustup target add x86_64-apple-darwin # criterion RUN cargo install cargo-criterion # editor @@ -54,6 +56,10 @@ test-zig: COPY --dir compiler/builtins/bitcode ./ RUN cd bitcode && ./run-tests.sh +check-macos: + FROM +copy-dirs + RUN cargo check --target x86_64-apple-darwin + check-clippy: FROM +copy-dirs RUN cargo clippy -V @@ -104,6 +110,7 @@ verify-no-git-changes: test-all: BUILD +test-zig + BUILD +check-macos BUILD +check-rustfmt BUILD +check-clippy BUILD +test-rust From 0c124aa7833c386800498f25168f4873a414a156 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 19:49:14 -0500 Subject: [PATCH 151/223] Revert "Check for compilation errors against macOS" This reverts commit 712237998fb7e79a5495ae7cba74c919738fbd4c. --- Earthfile | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Earthfile b/Earthfile index 978b29aa00..407477acf2 100644 --- a/Earthfile +++ b/Earthfile @@ -33,8 +33,6 @@ install-zig-llvm-valgrind-clippy-rustfmt: RUN rustup component add clippy # rustfmt RUN rustup component add rustfmt - # macOS target for checking Mac-specific compilations - RUN rustup target add x86_64-apple-darwin # criterion RUN cargo install cargo-criterion # editor @@ -56,10 +54,6 @@ test-zig: COPY --dir compiler/builtins/bitcode ./ RUN cd bitcode && ./run-tests.sh -check-macos: - FROM +copy-dirs - RUN cargo check --target x86_64-apple-darwin - check-clippy: FROM +copy-dirs RUN cargo clippy -V @@ -110,7 +104,6 @@ verify-no-git-changes: test-all: BUILD +test-zig - BUILD +check-macos BUILD +check-rustfmt BUILD +check-clippy BUILD +test-rust From d2fec425e301c12579eaf694f93445ef83c8c935 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 17 Nov 2021 19:53:39 -0500 Subject: [PATCH 152/223] Add Callum Dunster and Martin Stewart to AUTHORS --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index a44adf2dcc..0ac6349b9b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -52,3 +52,5 @@ Ayaz Hafiz Johannes Maas Takeshi Sato Joost Baas +Callum Dunster +Martin Stewart From 7f5b873357247d91bc2ff9d4c93d099577dd4d20 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Wed, 17 Nov 2021 17:49:04 -0800 Subject: [PATCH 153/223] Parse _ in type annotations as an 'Inferred' type --- ast/src/lang/core/types.rs | 3 ++ compiler/can/src/annotation.rs | 3 ++ compiler/fmt/src/annotation.rs | 3 +- compiler/parse/src/ast.rs | 3 ++ compiler/parse/src/parser.rs | 1 + compiler/parse/src/type_annotation.rs | 11 ++++++ .../type_decl_with_underscore.expr.result-ast | 38 +++++++++++++++++++ .../pass/type_decl_with_underscore.expr.roc | 2 + compiler/parse/tests/test_parse.rs | 1 + 9 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.result-ast create mode 100644 compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.roc diff --git a/ast/src/lang/core/types.rs b/ast/src/lang/core/types.rs index babdd51f89..4b9c52eabd 100644 --- a/ast/src/lang/core/types.rs +++ b/ast/src/lang/core/types.rs @@ -389,6 +389,9 @@ pub fn to_type2<'a>( } } } + Inferred => { + unimplemented!(); + } Wildcard | Malformed(_) => { let var = env.var_store.fresh(); diff --git a/compiler/can/src/annotation.rs b/compiler/can/src/annotation.rs index a649bb850c..cc4ef8b7ad 100644 --- a/compiler/can/src/annotation.rs +++ b/compiler/can/src/annotation.rs @@ -459,6 +459,9 @@ fn can_annotation_help( Type::Variable(var) } + Inferred => { + unimplemented!(); + } Malformed(string) => { malformed(env, region, string); diff --git a/compiler/fmt/src/annotation.rs b/compiler/fmt/src/annotation.rs index c74636dfa9..98d156415d 100644 --- a/compiler/fmt/src/annotation.rs +++ b/compiler/fmt/src/annotation.rs @@ -180,7 +180,7 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> { true } - Wildcard | BoundVariable(_) | Malformed(_) => false, + Wildcard | Inferred | BoundVariable(_) | Malformed(_) => false, Function(args, result) => { (&result.value).is_multiline() || args.iter().any(|loc_arg| (&loc_arg.value).is_multiline()) @@ -279,6 +279,7 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> { } BoundVariable(v) => buf.push_str(v), Wildcard => buf.push('*'), + Inferred => buf.push('_'), TagUnion { tags, ext } => { format_sequence!(buf, indent, '[', ']', tags, newlines, Tag); diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 4b79be508e..0da46bb4a2 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -240,6 +240,9 @@ pub enum TypeAnnotation<'a> { tags: Collection<'a, Loc>>, }, + /// '_', indicating the compiler should infer the type + Inferred, + /// The `*` type variable, e.g. in (List *) Wildcard, diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 76e1480387..e9726ffb66 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -626,6 +626,7 @@ pub enum EType<'a> { TApply(ETypeApply, Row, Col), TBadTypeVariable(Row, Col), TWildcard(Row, Col), + TInferred(Row, Col), /// TStart(Row, Col), TEnd(Row, Col), diff --git a/compiler/parse/src/type_annotation.rs b/compiler/parse/src/type_annotation.rs index 64b6c69fb0..2bc21e2921 100644 --- a/compiler/parse/src/type_annotation.rs +++ b/compiler/parse/src/type_annotation.rs @@ -55,6 +55,7 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located>, ETy and!( one_of!( loc_wildcard(), + loc_inferred(), specialize(EType::TInParens, loc_type_in_parens(min_indent)), loc!(specialize(EType::TRecord, record_type(min_indent))), loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))), @@ -111,6 +112,15 @@ fn loc_wildcard<'a>() -> impl Parser<'a, Located>, EType<'a>> }) } +/// The `_` indicating an inferred type, e.g. in (List _) +fn loc_inferred<'a>() -> impl Parser<'a, Located>, EType<'a>> { + map!(loc!(word1(b'_', EType::TInferred)), |loc_val: Located< + (), + >| { + loc_val.map(|_| TypeAnnotation::Inferred) + }) +} + fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located>, EType<'a>> { use crate::ast::Spaceable; @@ -119,6 +129,7 @@ fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located Task Str _ +42 \ No newline at end of file diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 9b8b6ab805..b9dae1d201 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -196,6 +196,7 @@ mod test_parse { two_backpassing, two_branch_when, two_spaced_def, + type_decl_with_underscore, unary_negation, unary_negation_access, // Regression test for https://github.com/rtfeldman/roc/issues/509 unary_negation_arg, From c156f61b0fab2f81520905fa544e803a4e379b6c Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 20:57:19 -0500 Subject: [PATCH 154/223] Suggest tags of primitive types when an ident is misspelled With this change, mispellings of things like `true` and `false` will include a hint to the user that they may want to use `True` and `False`, respectively, instead. There are a few ways to implement this, but exposing these common tags (which compose builtin type aliases) seems the easiest, least expensive, and doesn't break anything for now. --- compiler/module/src/symbol.rs | 28 ++++++++++++++----------- reporting/tests/test_reporting.rs | 34 ++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 65b8d366cf..89666dfa12 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -989,12 +989,14 @@ define_builtins! { } 2 BOOL: "Bool" => { 0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias - 1 BOOL_AND: "and" - 2 BOOL_OR: "or" - 3 BOOL_NOT: "not" - 4 BOOL_XOR: "xor" - 5 BOOL_EQ: "isEq" - 6 BOOL_NEQ: "isNotEq" + 1 BOOL_FALSE: "False" imported // Bool.Bool = [ False, True ] + 2 BOOL_TRUE: "True" imported // Bool.Bool = [ False, True ] + 3 BOOL_AND: "and" + 4 BOOL_OR: "or" + 5 BOOL_NOT: "not" + 6 BOOL_XOR: "xor" + 7 BOOL_EQ: "isEq" + 8 BOOL_NEQ: "isNotEq" } 3 STR: "Str" => { 0 STR_STR: "Str" imported // the Str.Str type alias @@ -1077,12 +1079,14 @@ define_builtins! { } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias - 1 RESULT_MAP: "map" - 2 RESULT_MAP_ERR: "mapErr" - 3 RESULT_WITH_DEFAULT: "withDefault" - 4 RESULT_AFTER: "after" - 5 RESULT_IS_OK: "isOk" - 6 RESULT_IS_ERR: "isErr" + 1 RESULT_OK: "Ok" imported // Result.Result = [ Ok a, Err e ] + 2 RESULT_ERR: "Err" imported // Result.Result = [ Ok a, Err e ] + 3 RESULT_MAP: "map" + 4 RESULT_MAP_ERR: "mapErr" + 5 RESULT_WITH_DEFAULT: "withDefault" + 6 RESULT_AFTER: "after" + 7 RESULT_IS_OK: "isOk" + 8 RESULT_IS_ERR: "isErr" } 6 DICT: "Dict" => { 0 DICT_DICT: "Dict" imported // the Dict.Dict type alias diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 14fb7279ad..6e2ce062fa 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -547,7 +547,35 @@ mod test_reporting { baz Nat Str - U8 + Err + "# + ), + ) + } + + #[test] + fn lowercase_primitive_tag_bool() { + report_problem_as( + indoc!( + r#" + if true then 1 else 2 + "# + ), + indoc!( + r#" + ── UNRECOGNIZED NAME ─────────────────────────────────────────────────────────── + + I cannot find a `true` value + + 1β”‚ if true then 1 else 2 + ^^^^ + + Did you mean one of these? + + True + Str + Num + Err "# ), ) @@ -1950,10 +1978,10 @@ mod test_reporting { Did you mean one of these? + Ok U8 f I8 - F64 "# ), ) @@ -5802,8 +5830,8 @@ mod test_reporting { Nat Str + Err U8 - F64 "# ), ) From 214b8a30a9852379b0a9deae8522790cf415ce79 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 22:39:24 -0500 Subject: [PATCH 155/223] Suggest typo fixes for non-existing module values --- compiler/can/src/env.rs | 49 ++++++++++++++++++++--------- compiler/problem/src/can.rs | 1 + reporting/src/error/canonicalize.rs | 27 +++++++++++++--- reporting/tests/test_reporting.rs | 24 +++++++++++--- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/compiler/can/src/env.rs b/compiler/can/src/env.rs index 3054193b65..4ad1bbd058 100644 --- a/compiler/can/src/env.rs +++ b/compiler/can/src/env.rs @@ -1,6 +1,6 @@ use crate::procedure::References; use roc_collections::all::{MutMap, MutSet}; -use roc_module::ident::{Ident, ModuleName}; +use roc_module::ident::{Ident, Lowercase, ModuleName}; use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol}; use roc_problem::can::{Problem, RuntimeError}; use roc_region::all::{Located, Region}; @@ -99,23 +99,42 @@ impl<'a> Env<'a> { )), } } else { - match self - .dep_idents - .get(&module_id) - .and_then(|exposed_ids| exposed_ids.get_id(&ident)) - { - Some(ident_id) => { - let symbol = Symbol::new(module_id, *ident_id); + match self.dep_idents.get(&module_id) { + Some(exposed_ids) => match exposed_ids.get_id(&ident) { + Some(ident_id) => { + let symbol = Symbol::new(module_id, *ident_id); - self.qualified_lookups.insert(symbol); + self.qualified_lookups.insert(symbol); - Ok(symbol) + Ok(symbol) + } + None => { + let exposed_values = exposed_ids + .idents() + .filter(|(_, ident)| { + ident + .as_ref() + .chars() + .next() + .filter(|c| c.is_lowercase()) + .is_some() + }) + .map(|(_, ident)| Lowercase::from(ident.as_ref())) + .collect(); + Err(RuntimeError::ValueNotExposed { + module_name, + ident, + region, + exposed_values, + }) + } + }, + None => { + panic!( + "Module {} exists, but is not recorded in dep_idents", + module_name + ) } - None => Err(RuntimeError::ValueNotExposed { - module_name, - ident, - region, - }), } } } diff --git a/compiler/problem/src/can.rs b/compiler/problem/src/can.rs index c5bfa42f53..d704d02dc1 100644 --- a/compiler/problem/src/can.rs +++ b/compiler/problem/src/can.rs @@ -139,6 +139,7 @@ pub enum RuntimeError { module_name: ModuleName, ident: Ident, region: Region, + exposed_values: Vec, }, ModuleNotImported { module_name: ModuleName, diff --git a/reporting/src/error/canonicalize.rs b/reporting/src/error/canonicalize.rs index 13d3406593..75c34b92a7 100644 --- a/reporting/src/error/canonicalize.rs +++ b/reporting/src/error/canonicalize.rs @@ -6,6 +6,7 @@ use roc_problem::can::{BadPattern, FloatErrorKind, IntErrorKind, Problem, Runtim use roc_region::all::{Located, Region}; use std::path::PathBuf; +use crate::error::r#type::suggest; use crate::report::{Annotation, Report, RocDocAllocator, RocDocBuilder, Severity}; use ven_pretty::DocAllocator; @@ -874,16 +875,36 @@ fn pretty_runtime_error<'b>( module_name, ident, region, + exposed_values, } => { + let mut suggestions = suggest::sort(ident.as_ref(), exposed_values); + suggestions.truncate(4); + + let did_you_mean = if suggestions.is_empty() { + alloc.concat(vec![ + alloc.reflow("In fact, it look like "), + alloc.module_name(module_name.clone()), + alloc.reflow(" doesn't expose any values!"), + ]) + } else { + let qualified_suggestions = suggestions + .into_iter() + .map(|v| alloc.string(module_name.to_string() + "." + v.as_str())); + alloc.stack(vec![ + alloc.reflow("Did you mean one of these?"), + alloc.vcat(qualified_suggestions).indent(4), + ]) + }; doc = alloc.stack(vec![ alloc.concat(vec![ alloc.reflow("The "), alloc.module_name(module_name), - alloc.reflow(" module does not expose a "), + alloc.reflow(" module does not expose `"), alloc.string(ident.to_string()), - alloc.reflow(" value:"), + alloc.reflow("`:"), ]), alloc.region(region), + did_you_mean, ]); title = VALUE_NOT_EXPOSED; @@ -1176,8 +1197,6 @@ fn not_found<'b>( thing: &'b str, options: MutSet>, ) -> RocDocBuilder<'b> { - use crate::error::r#type::suggest; - let mut suggestions = suggest::sort( name.as_inline_str().as_str(), options.iter().map(|v| v.as_ref()).collect(), diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 6e2ce062fa..f5bb1964df 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -298,17 +298,24 @@ mod test_reporting { report_problem_as( indoc!( r#" - List.foobar 1 2 + List.isempty 1 2 "# ), indoc!( r#" ── NOT EXPOSED ───────────────────────────────────────────────────────────────── - The List module does not expose a foobar value: + The List module does not expose `isempty`: - 1β”‚ List.foobar 1 2 - ^^^^^^^^^^^ + 1β”‚ List.isempty 1 2 + ^^^^^^^^^^^^ + + Did you mean one of these? + + List.isEmpty + List.set + List.get + List.keepIf "# ), ) @@ -5624,10 +5631,17 @@ mod test_reporting { r#" ── NOT EXPOSED ───────────────────────────────────────────────────────────────── - The Num module does not expose a if value: + The Num module does not expose `if`: 1β”‚ Num.if ^^^^^^ + + Did you mean one of these? + + Num.sin + Num.div + Num.abs + Num.neg "# ), ) From c5484a9ad3e8523e077c5d1b09542102f18bb712 Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Wed, 17 Nov 2021 22:47:49 -0500 Subject: [PATCH 156/223] fixing List.all on empty list to be true --- compiler/builtins/bitcode/src/list.zig | 2 +- compiler/test_gen/src/gen_list.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index e4a994e79b..69c91142fe 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -1136,7 +1136,7 @@ pub fn listAll( } return true; } - return false; + return true; } // SWAP ELEMENTS diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 5332a98c90..23e0f2ad95 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -2355,7 +2355,7 @@ fn list_any_empty_with_unknown_element_type() { #[test] #[cfg(any(feature = "gen-llvm"))] fn list_all() { - assert_evals_to!("List.all [] (\\e -> e > 3)", false, bool); + assert_evals_to!("List.all [] (\\e -> e > 3)", true, bool); assert_evals_to!("List.all [ 1, 2, 3 ] (\\e -> e > 3)", false, bool); assert_evals_to!("List.all [ 1, 2, 4 ] (\\e -> e > 3)", false, bool); assert_evals_to!("List.all [ 1, 2, 3 ] (\\e -> e >= 1)", true, bool); From 22be3493925b77b622b4b5b2b86d0f109e87badc Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 22:48:41 -0500 Subject: [PATCH 157/223] Remove redundant import --- reporting/src/error/canonicalize.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/reporting/src/error/canonicalize.rs b/reporting/src/error/canonicalize.rs index 75c34b92a7..922251ec77 100644 --- a/reporting/src/error/canonicalize.rs +++ b/reporting/src/error/canonicalize.rs @@ -1244,8 +1244,6 @@ fn module_not_found<'b>( name: &ModuleName, options: MutSet>, ) -> RocDocBuilder<'b> { - use crate::error::r#type::suggest; - let mut suggestions = suggest::sort(name.as_str(), options.iter().map(|v| v.as_ref()).collect()); suggestions.truncate(4); From 3d601ac02db7ecb84bfbba9fe3cd0f610424305d Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 22:58:16 -0500 Subject: [PATCH 158/223] Ensuer `RuntimeError::ValueNotExposed` is built properly in roc_ast --- ast/src/lang/env.rs | 49 +++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/ast/src/lang/env.rs b/ast/src/lang/env.rs index 03d93f561e..dc70adb13c 100644 --- a/ast/src/lang/env.rs +++ b/ast/src/lang/env.rs @@ -1,7 +1,7 @@ use crate::mem_pool::pool::{NodeId, Pool}; use bumpalo::{collections::Vec as BumpVec, Bump}; use roc_collections::all::{MutMap, MutSet}; -use roc_module::ident::{Ident, ModuleName}; +use roc_module::ident::{Ident, Lowercase, ModuleName}; use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol}; use roc_problem::can::{Problem, RuntimeError}; use roc_region::all::{Located, Region}; @@ -134,23 +134,42 @@ impl<'a> Env<'a> { )), } } else { - match self - .dep_idents - .get(&module_id) - .and_then(|exposed_ids| exposed_ids.get_id(&ident)) - { - Some(ident_id) => { - let symbol = Symbol::new(module_id, *ident_id); + match self.dep_idents.get(&module_id) { + Some(exposed_ids) => match exposed_ids.get_id(&ident) { + Some(ident_id) => { + let symbol = Symbol::new(module_id, *ident_id); - self.qualified_lookups.insert(symbol); + self.qualified_lookups.insert(symbol); - Ok(symbol) + Ok(symbol) + } + None => { + let exposed_values = exposed_ids + .idents() + .filter(|(_, ident)| { + ident + .as_ref() + .chars() + .next() + .filter(|c| c.is_lowercase()) + .is_some() + }) + .map(|(_, ident)| Lowercase::from(ident.as_ref())) + .collect(); + Err(RuntimeError::ValueNotExposed { + module_name, + ident, + region, + exposed_values, + }) + } + }, + None => { + panic!( + "Module {} exists, but is not recorded in dep_idents", + module_name + ) } - None => Err(RuntimeError::ValueNotExposed { - module_name, - ident, - region, - }), } } } From d165052e64e3259b0139a8f2aa4f012a886bfe10 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 00:12:17 -0500 Subject: [PATCH 159/223] Fix typo --- reporting/src/error/canonicalize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reporting/src/error/canonicalize.rs b/reporting/src/error/canonicalize.rs index 922251ec77..a3e5d7186a 100644 --- a/reporting/src/error/canonicalize.rs +++ b/reporting/src/error/canonicalize.rs @@ -882,7 +882,7 @@ fn pretty_runtime_error<'b>( let did_you_mean = if suggestions.is_empty() { alloc.concat(vec![ - alloc.reflow("In fact, it look like "), + alloc.reflow("In fact, it looks like "), alloc.module_name(module_name.clone()), alloc.reflow(" doesn't expose any values!"), ]) From 9b2f01042e98ba71499075f8ba3230a09ba4034f Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Thu, 18 Nov 2021 09:04:52 +0000 Subject: [PATCH 160/223] Enable all Str.concat tests --- compiler/test_gen/src/wasm_str.rs | 106 ++++++++++-------------------- 1 file changed, 36 insertions(+), 70 deletions(-) diff --git a/compiler/test_gen/src/wasm_str.rs b/compiler/test_gen/src/wasm_str.rs index 6682a58811..a937c5e8b8 100644 --- a/compiler/test_gen/src/wasm_str.rs +++ b/compiler/test_gen/src/wasm_str.rs @@ -305,80 +305,46 @@ fn small_str_concat_empty_first_arg() { ); } -// #[test] -// fn small_str_concat_empty_second_arg() { -// assert_llvm_evals_to!( -// r#"Str.concat "JJJJJJJJJJJJJJJ" """#, -// [ -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0b1000_1111 -// ], -// [u8; 16] -// ); -// } +#[test] +fn small_str_concat_empty_second_arg() { + assert_evals_to!( + r#"Str.concat "JJJJJJJ" """#, + [0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0b1000_0111], + [u8; 8] + ); +} -// #[test] -// fn small_str_concat_small_to_big() { -// assert_evals_to!( -// r#"Str.concat "abc" " this is longer than 15 chars""#, -// RocStr::from_slice(b"abc this is longer than 15 chars"), -// RocStr -// ); -// } +#[test] +fn small_str_concat_small_to_big() { + assert_evals_to!( + r#"Str.concat "abc" " this is longer than 7 chars""#, + RocStr::from_slice(b"abc this is longer than 7 chars"), + RocStr + ); +} -// #[test] -// fn small_str_concat_small_to_small_staying_small() { -// assert_llvm_evals_to!( -// r#"Str.concat "J" "JJJJJJJJJJJJJJ""#, -// [ -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0x4a, -// 0b1000_1111 -// ], -// [u8; 16] -// ); -// } +#[test] +fn small_str_concat_small_to_small_staying_small() { + assert_evals_to!( + r#"Str.concat "J" "JJJJJJ""#, + [0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0b1000_0111], + [u8; 8] + ); +} -// #[test] -// fn small_str_concat_small_to_small_overflow_to_big() { -// assert_evals_to!( -// r#"Str.concat "abcdefghijklm" "nopqrstuvwxyz""#, -// RocStr::from_slice(b"abcdefghijklmnopqrstuvwxyz"), -// RocStr -// ); -// } +#[test] +fn small_str_concat_small_to_small_overflow_to_big() { + assert_evals_to!( + r#"Str.concat "abcdefg" "hijklmn""#, + RocStr::from_slice(b"abcdefghijklmn"), + RocStr + ); +} -// #[test] -// fn str_concat_empty() { -// assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr); -// } +#[test] +fn str_concat_empty() { + assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr); +} // #[test] // fn small_str_is_empty() { From be555822901cfae2f561c402d3dfc44fa48ede9b Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Thu, 18 Nov 2021 09:59:52 +0000 Subject: [PATCH 161/223] Enable some more gen_wasm string builtins --- compiler/gen_wasm/src/low_level.rs | 29 +- compiler/test_gen/src/wasm_str.rs | 468 ++++++++++++++++++----------- 2 files changed, 318 insertions(+), 179 deletions(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 7698826b63..e3bbc2fe6e 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -28,11 +28,32 @@ pub fn decode_low_level<'a>( match lowlevel { StrConcat => return BuiltinCall(bitcode::STR_CONCAT), + StrJoinWith => return NotImplemented, // needs Array + StrIsEmpty => { + code_builder.i64_const(i64::MIN); + code_builder.i64_eq(); + } + StrStartsWith => return BuiltinCall(bitcode::STR_STARTS_WITH), + StrStartsWithCodePt => return BuiltinCall(bitcode::STR_STARTS_WITH_CODE_PT), + StrEndsWith => return BuiltinCall(bitcode::STR_ENDS_WITH), + StrSplit => return NotImplemented, // needs Array + StrCountGraphemes => return NotImplemented, // test needs Array + StrFromInt => return NotImplemented, // choose builtin based on storage size + StrFromUtf8 => return NotImplemented, // needs Array + StrTrimLeft => return BuiltinCall(bitcode::STR_TRIM_LEFT), + StrTrimRight => return BuiltinCall(bitcode::STR_TRIM_RIGHT), + StrFromUtf8Range => return NotImplemented, // needs Array + StrToUtf8 => return NotImplemented, // needs Array + StrRepeat => return BuiltinCall(bitcode::STR_REPEAT), + StrFromFloat => { + // linker errors for __ashlti3, __fixunsdfti, __multi3, __udivti3, __umodti3 + // https://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html + // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html + return NotImplemented; + } + StrTrim => return BuiltinCall(bitcode::STR_TRIM), - StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt | StrEndsWith | StrSplit - | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft | StrTrimRight - | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim | ListLen - | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat + ListLen | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListSublist diff --git a/compiler/test_gen/src/wasm_str.rs b/compiler/test_gen/src/wasm_str.rs index a937c5e8b8..7dafb39a5f 100644 --- a/compiler/test_gen/src/wasm_str.rs +++ b/compiler/test_gen/src/wasm_str.rs @@ -346,54 +346,54 @@ fn str_concat_empty() { assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr); } -// #[test] -// fn small_str_is_empty() { -// assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool); -// } +#[test] +fn small_str_is_empty() { + assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool); +} -// #[test] -// fn big_str_is_empty() { -// assert_evals_to!( -// r#"Str.isEmpty "this is more than 15 chars long""#, -// false, -// bool -// ); -// } +#[test] +fn big_str_is_empty() { + assert_evals_to!( + r#"Str.isEmpty "this is more than 15 chars long""#, + false, + bool + ); +} -// #[test] -// fn empty_str_is_empty() { -// assert_evals_to!(r#"Str.isEmpty """#, true, bool); -// } +#[test] +fn empty_str_is_empty() { + assert_evals_to!(r#"Str.isEmpty """#, true, bool); +} -// #[test] -// fn str_starts_with() { -// assert_evals_to!(r#"Str.startsWith "hello world" "hell""#, true, bool); -// assert_evals_to!(r#"Str.startsWith "hello world" """#, true, bool); -// assert_evals_to!(r#"Str.startsWith "nope" "hello world""#, false, bool); -// assert_evals_to!(r#"Str.startsWith "hell" "hello world""#, false, bool); -// assert_evals_to!(r#"Str.startsWith "" "hello world""#, false, bool); -// } +#[test] +fn str_starts_with() { + assert_evals_to!(r#"Str.startsWith "hello world" "hell""#, true, bool); + assert_evals_to!(r#"Str.startsWith "hello world" """#, true, bool); + assert_evals_to!(r#"Str.startsWith "nope" "hello world""#, false, bool); + assert_evals_to!(r#"Str.startsWith "hell" "hello world""#, false, bool); + assert_evals_to!(r#"Str.startsWith "" "hello world""#, false, bool); +} -// #[test] -// fn str_starts_with_code_point() { -// assert_evals_to!( -// &format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32), -// true, -// bool -// ); -// assert_evals_to!( -// &format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32), -// false, -// bool -// ); -// } +#[test] +fn str_starts_with_code_point() { + assert_evals_to!( + &format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32), + true, + bool + ); + assert_evals_to!( + &format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32), + false, + bool + ); +} -// #[test] -// fn str_ends_with() { -// assert_evals_to!(r#"Str.endsWith "hello world" "world""#, true, bool); -// assert_evals_to!(r#"Str.endsWith "nope" "hello world""#, false, bool); -// assert_evals_to!(r#"Str.endsWith "" "hello world""#, false, bool); -// } +#[test] +fn str_ends_with() { + assert_evals_to!(r#"Str.endsWith "hello world" "world""#, true, bool); + assert_evals_to!(r#"Str.endsWith "nope" "hello world""#, false, bool); + assert_evals_to!(r#"Str.endsWith "" "hello world""#, false, bool); +} // #[test] // fn str_count_graphemes_small_str() { @@ -414,37 +414,37 @@ fn str_concat_empty() { // ); // } -// #[test] -// fn str_starts_with_same_big_str() { -// assert_evals_to!( -// r#"Str.startsWith "123456789123456789" "123456789123456789""#, -// true, -// bool -// ); -// } +#[test] +fn str_starts_with_same_big_str() { + assert_evals_to!( + r#"Str.startsWith "123456789123456789" "123456789123456789""#, + true, + bool + ); +} -// #[test] -// fn str_starts_with_different_big_str() { -// assert_evals_to!( -// r#"Str.startsWith "12345678912345678910" "123456789123456789""#, -// true, -// bool -// ); -// } +#[test] +fn str_starts_with_different_big_str() { + assert_evals_to!( + r#"Str.startsWith "12345678912345678910" "123456789123456789""#, + true, + bool + ); +} -// #[test] -// fn str_starts_with_same_small_str() { -// assert_evals_to!(r#"Str.startsWith "1234" "1234""#, true, bool); -// } +#[test] +fn str_starts_with_same_small_str() { + assert_evals_to!(r#"Str.startsWith "1234" "1234""#, true, bool); +} -// #[test] -// fn str_starts_with_different_small_str() { -// assert_evals_to!(r#"Str.startsWith "1234" "12""#, true, bool); -// } -// #[test] -// fn str_starts_with_false_small_str() { -// assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool); -// } +#[test] +fn str_starts_with_different_small_str() { + assert_evals_to!(r#"Str.startsWith "1234" "12""#, true, bool); +} +#[test] +fn str_starts_with_false_small_str() { + assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool); +} // #[test] // fn str_from_int() { @@ -900,121 +900,239 @@ fn str_concat_empty() { // ); // } -// #[test] -// fn str_repeat_small() { -// assert_evals_to!( -// indoc!(r#"Str.repeat "Roc" 3"#), -// RocStr::from("RocRocRoc"), -// RocStr -// ); -// } +#[test] +fn str_repeat_small() { + assert_evals_to!( + indoc!(r#"Str.repeat "Roc" 3"#), + RocStr::from("RocRocRoc"), + RocStr + ); +} -// #[test] -// fn str_repeat_big() { -// assert_evals_to!( -// indoc!(r#"Str.repeat "more than 16 characters" 2"#), -// RocStr::from("more than 16 charactersmore than 16 characters"), -// RocStr -// ); -// } +#[test] +fn str_repeat_big() { + assert_evals_to!( + indoc!(r#"Str.repeat "more than 16 characters" 2"#), + RocStr::from("more than 16 charactersmore than 16 characters"), + RocStr + ); +} -// #[test] -// fn str_repeat_empty_string() { -// assert_evals_to!(indoc!(r#"Str.repeat "" 3"#), RocStr::from(""), RocStr); -// } +#[test] +fn str_repeat_empty_string() { + assert_evals_to!(indoc!(r#"Str.repeat "" 3"#), RocStr::from(""), RocStr); +} -// #[test] -// fn str_repeat_zero_times() { -// assert_evals_to!(indoc!(r#"Str.repeat "Roc" 0"#), RocStr::from(""), RocStr); -// } +#[test] +fn str_repeat_zero_times() { + assert_evals_to!(indoc!(r#"Str.repeat "Roc" 0"#), RocStr::from(""), RocStr); +} -// #[test] -// fn str_trim_empty_string() { -// assert_evals_to!(indoc!(r#"Str.trim """#), RocStr::from(""), RocStr); -// } +#[test] +fn str_trim_empty_string() { + assert_evals_to!(indoc!(r#"Str.trim """#), RocStr::from(""), RocStr); +} -// #[test] -// fn str_trim_small_blank_string() { -// assert_evals_to!(indoc!(r#"Str.trim " ""#), RocStr::from(""), RocStr); -// } +#[test] +fn str_trim_small_blank_string() { + assert_evals_to!(indoc!(r#"Str.trim " ""#), RocStr::from(""), RocStr); +} -// #[test] -// fn str_trim_small_to_small() { -// assert_evals_to!( -// indoc!(r#"Str.trim " hello world ""#), -// RocStr::from("hello world"), -// RocStr -// ); -// } +#[test] +fn str_trim_small_to_small() { + assert_evals_to!( + indoc!(r#"Str.trim " hello world ""#), + RocStr::from("hello world"), + RocStr + ); +} -// #[test] -// fn str_trim_large_to_large_unique() { -// assert_evals_to!( -// indoc!(r#"Str.trim (Str.concat " " "hello world from a large string ")"#), -// RocStr::from("hello world from a large string"), -// RocStr -// ); -// } +#[test] +fn str_trim_large_to_large_unique() { + assert_evals_to!( + indoc!(r#"Str.trim (Str.concat " " "hello world from a large string ")"#), + RocStr::from("hello world from a large string"), + RocStr + ); +} -// #[test] -// fn str_trim_large_to_small_unique() { -// assert_evals_to!( -// indoc!(r#"Str.trim (Str.concat " " "hello world ")"#), -// RocStr::from("hello world"), -// RocStr -// ); -// } +#[test] +fn str_trim_large_to_small_unique() { + assert_evals_to!( + indoc!(r#"Str.trim (Str.concat " " "hello world ")"#), + RocStr::from("hello world"), + RocStr + ); +} -// #[test] -// fn str_trim_large_to_large_shared() { -// assert_evals_to!( -// indoc!( -// r#" -// original : Str -// original = " hello world world " +#[test] +fn str_trim_large_to_large_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world world " -// { trimmed: Str.trim original, original: original } -// "# -// ), -// ( -// RocStr::from(" hello world world "), -// RocStr::from("hello world world"), -// ), -// (RocStr, RocStr) -// ); -// } + { trimmed: Str.trim original, original: original } + "# + ), + ( + RocStr::from(" hello world world "), + RocStr::from("hello world world"), + ), + (RocStr, RocStr) + ); +} -// #[test] -// fn str_trim_large_to_small_shared() { -// assert_evals_to!( -// indoc!( -// r#" -// original : Str -// original = " hello world " +#[test] +fn str_trim_large_to_small_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world " -// { trimmed: Str.trim original, original: original } -// "# -// ), -// ( -// RocStr::from(" hello world "), -// RocStr::from("hello world"), -// ), -// (RocStr, RocStr) -// ); -// } + { trimmed: Str.trim original, original: original } + "# + ), + ( + RocStr::from(" hello world "), + RocStr::from("hello world"), + ), + (RocStr, RocStr) + ); +} -// #[test] -// fn str_trim_small_to_small_shared() { -// assert_evals_to!( -// indoc!( -// r#" -// original : Str -// original = " hello world " +#[test] +fn str_trim_small_to_small_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world " -// { trimmed: Str.trim original, original: original } -// "# -// ), -// (RocStr::from(" hello world "), RocStr::from("hello world"),), -// (RocStr, RocStr) -// ); -// } + { trimmed: Str.trim original, original: original } + "# + ), + (RocStr::from(" hello world "), RocStr::from("hello world"),), + (RocStr, RocStr) + ); +} + +#[test] +fn str_trim_left_small_blank_string() { + assert_evals_to!(indoc!(r#"Str.trimLeft " ""#), RocStr::from(""), RocStr); +} + +#[test] +fn str_trim_left_small_to_small() { + assert_evals_to!( + indoc!(r#"Str.trimLeft " hello world ""#), + RocStr::from("hello world "), + RocStr + ); +} + +#[test] +fn str_trim_left_large_to_large_unique() { + assert_evals_to!( + indoc!(r#"Str.trimLeft (Str.concat " " "hello world from a large string ")"#), + RocStr::from("hello world from a large string "), + RocStr + ); +} + +#[test] +fn str_trim_left_large_to_small_unique() { + assert_evals_to!( + indoc!(r#"Str.trimLeft (Str.concat " " "hello world ")"#), + RocStr::from("hello world "), + RocStr + ); +} + +#[test] +fn str_trim_right_small_blank_string() { + assert_evals_to!(indoc!(r#"Str.trimRight " ""#), RocStr::from(""), RocStr); +} + +#[test] +fn str_trim_right_small_to_small() { + assert_evals_to!( + indoc!(r#"Str.trimRight " hello world ""#), + RocStr::from(" hello world"), + RocStr + ); +} + +#[test] +fn str_trim_right_large_to_large_unique() { + assert_evals_to!( + indoc!(r#"Str.trimRight (Str.concat " hello world from a large string" " ")"#), + RocStr::from(" hello world from a large string"), + RocStr + ); +} + +#[test] +fn str_trim_right_large_to_small_unique() { + assert_evals_to!( + indoc!(r#"Str.trimRight (Str.concat " hello world" " ")"#), + RocStr::from(" hello world"), + RocStr + ); +} + +#[test] +fn str_trim_right_large_to_large_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world world " + + { trimmed: Str.trimRight original, original: original } + "# + ), + ( + RocStr::from(" hello world world "), + RocStr::from(" hello world world"), + ), + (RocStr, RocStr) + ); +} + +#[test] +fn str_trim_right_large_to_small_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world " + + { trimmed: Str.trimRight original, original: original } + "# + ), + ( + RocStr::from(" hello world "), + RocStr::from(" hello world"), + ), + (RocStr, RocStr) + ); +} + +#[test] +fn str_trim_right_small_to_small_shared() { + assert_evals_to!( + indoc!( + r#" + original : Str + original = " hello world " + + { trimmed: Str.trimRight original, original: original } + "# + ), + (RocStr::from(" hello world "), RocStr::from(" hello world"),), + (RocStr, RocStr) + ); +} From 7ce9f1b3bd8ef03d495a67161dff5b254ca51d54 Mon Sep 17 00:00:00 2001 From: satotake Date: Thu, 18 Nov 2021 10:15:38 +0000 Subject: [PATCH 162/223] refactor after review --- compiler/can/src/builtins.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 2a247b9e61..2416ef3afc 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2166,7 +2166,7 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def { let int_var = var_store.fresh(); let zero = int(int_var, Variable::NATURAL, 0); - // \elem -> [sep, elem] + // \acc, elem -> acc |> List.append sep |> List.append elem let clos = Closure(ClosureData { function_type: clos_var, closure_type: var_store.fresh(), @@ -2180,19 +2180,21 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def { (sep_var, no_region(Pattern::Identifier(clos_elem_sym))), ], loc_body: { - let pair = List { - elem_var: sep_var, - loc_elems: vec![no_region(Var(sep_sym)), no_region(Var(clos_elem_sym))], + let append_sep = RunLowLevel { + op: LowLevel::ListAppend, + args: vec![(clos_acc_var, Var(clos_acc_sym)), (sep_var, Var(sep_sym))], + ret_var: clos_acc_var, }; + Box::new(no_region(RunLowLevel { - op: LowLevel::ListConcat, - args: vec![(clos_acc_var, Var(clos_acc_sym)), (clos_acc_var, pair)], + op: LowLevel::ListAppend, + args: vec![(clos_acc_var, append_sep), (sep_var, Var(clos_elem_sym))], ret_var: clos_acc_var, })) }, }); - // List.walk [] l (\acc, elem -> List.concat acc [sep, elem]) + // List.walk [] l (\acc, elem -> acc |> List.append sep |> List.append elem) let acc = RunLowLevel { op: LowLevel::ListWalk, args: vec![ From d04982cf98bedd414ebc257d7ca606c2c87fbda0 Mon Sep 17 00:00:00 2001 From: James Hegedus Date: Thu, 18 Nov 2021 21:38:33 +1100 Subject: [PATCH 163/223] docs: fix broken link to BUILDING_FROM_SOURCE --- editor/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/README.md b/editor/README.md index cbae3eb8ff..c5b3116e45 100644 --- a/editor/README.md +++ b/editor/README.md @@ -5,7 +5,7 @@ Unlike most editors, we use projectional or structural editing to edit the [Abst ## Getting started -- Install the compiler, see [here](../BUILDING_FROM_SOURCE). +- Install the compiler, see [here](../BUILDING_FROM_SOURCE.md). - Run the following from the roc folder: ``` From 9aabd0895309a58243dd76c684cf0e6988f15309 Mon Sep 17 00:00:00 2001 From: satotake Date: Thu, 18 Nov 2021 11:17:05 +0000 Subject: [PATCH 164/223] fmt --- compiler/can/src/builtins.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 4f4ef6643a..163a82fd92 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2227,7 +2227,6 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } - /// List.split : List elem, Nat -> { before: List elem, others: List elem } fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); From 2eae1a857be31021998ae97c3de10f3a9aaaac78 Mon Sep 17 00:00:00 2001 From: satotake Date: Thu, 18 Nov 2021 11:20:37 +0000 Subject: [PATCH 165/223] Fix comment wording --- compiler/test_gen/src/gen_num.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index ed3b1bbd7d..149473cef5 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -1216,9 +1216,9 @@ fn tail_call_elimination() { #[test] #[cfg(any(feature = "gen-dev"))] fn int_negate_dev() { - // Dev backend yet to have `Num.maxInt` or `Num.minInt`. - // TODO Remove this test and add "gen-dev" feature the below - // after implementing the both. + // TODO + // dev backend yet to have `Num.maxInt` or `Num.minInt`. + // add the "gen-dev" feature to the test below after implementing them both. assert_evals_to!("Num.neg 123", -123, i64); assert_evals_to!("Num.neg -123", 123, i64); assert_evals_to!("Num.neg 0", 0, i64); From f99542f066e9802985943c087f9af7d71460c885 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 18 Nov 2021 13:15:00 +0100 Subject: [PATCH 166/223] add special symbol for removed specializations --- compiler/module/src/symbol.rs | 3 +++ compiler/mono/src/ir.rs | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 65b8d366cf..ceb6748d80 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -877,6 +877,9 @@ define_builtins! { // used in wasm dev backend to mark temporary values in the VM stack 24 WASM_TMP: "#wasm_tmp" + + // the _ used in mono when a specialized symbol is deleted + 25 DELETED_SPECIALIZATION: "#deleted_specialization" } 1 NUM: "Num" => { 0 NUM_NUM: "Num" imported // the Num.Num type alias diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 268ba249f7..3f791837a9 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -544,8 +544,7 @@ impl<'a> Specialized<'a> { .zip(self.proc_layouts.into_iter()) .zip(self.procedures.into_iter()) .filter_map(|((s, l), in_progress)| { - // we use UNDERSCORE for removed symbols - if let Symbol::UNDERSCORE = s { + if let Symbol::REMOVED_SPECIALIZATION = s { None } else { match in_progress { @@ -596,8 +595,7 @@ impl<'a> Specialized<'a> { } if let Some(index) = index { - // we use UNDERSCORE for removed symbols - self.symbols[index] = Symbol::UNDERSCORE; + self.symbols[index] = Symbol::REMOVED_SPECIALIZATION; true } else { From 947051749dee54439504f5c91efdda1e8ea65824 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 18 Nov 2021 13:17:29 +0100 Subject: [PATCH 167/223] fix typo --- compiler/module/src/symbol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index ceb6748d80..77e790b68d 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -879,7 +879,7 @@ define_builtins! { 24 WASM_TMP: "#wasm_tmp" // the _ used in mono when a specialized symbol is deleted - 25 DELETED_SPECIALIZATION: "#deleted_specialization" + 25 REMOVED_SPECIALIZATION: "#removed_specialization" } 1 NUM: "Num" => { 0 NUM_NUM: "Num" imported // the Num.Num type alias From 6ec7b8eec0a8f25ecd3acba5d3b31c7307efefba Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Thu, 18 Nov 2021 09:12:51 -0500 Subject: [PATCH 168/223] Add James Hegedus to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 0ac6349b9b..5dc330e817 100644 --- a/AUTHORS +++ b/AUTHORS @@ -54,3 +54,4 @@ Takeshi Sato Joost Baas Callum Dunster Martin Stewart +James Hegedus From 12f7d4b4586f04c9a261f7ae8777c9d06e443b5c Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Thu, 18 Nov 2021 16:04:38 -0500 Subject: [PATCH 169/223] fixing format --- compiler/gen_wasm/src/low_level.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 69d86c1569..c2bb0dc622 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -36,9 +36,9 @@ pub fn decode_low_level<'a>( | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListSublist - | ListDropAt | ListSwap | ListAny | ListAll | ListFindUnsafe | DictSize | DictEmpty | DictInsert - | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues | DictUnion - | DictIntersection | DictDifference | DictWalk | SetFromList => { + | ListDropAt | ListSwap | ListAny | ListAll | ListFindUnsafe | DictSize | DictEmpty + | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues + | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { return NotImplemented; } From 9126169fcb25fb9ccb34c068b2874ef01f931c9e Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 18 Nov 2021 23:02:18 +0100 Subject: [PATCH 170/223] StorageSubs --- compiler/types/src/subs.rs | 179 ++++++++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 4d6765afbd..105c135b9f 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -677,7 +677,7 @@ impl Variable { Variable(v) } - pub fn index(&self) -> u32 { + pub const fn index(&self) -> u32 { self.0 } } @@ -2800,3 +2800,180 @@ fn restore_help(subs: &mut Subs, initial: Variable) { } } } + +#[derive(Clone)] +pub struct StorageSubs { + subs: Subs, +} + +struct StorageSubsOffsets { + utable: u32, + variables: u32, + tag_names: u32, + field_names: u32, + record_fields: u32, + variable_slices: u32, +} + +impl StorageSubs { + pub fn merge_into(self, target: &mut Subs) { + let offsets = StorageSubsOffsets { + utable: target.utable.len() as u32, + variables: target.variables.len() as u32, + tag_names: target.tag_names.len() as u32, + field_names: target.field_names.len() as u32, + record_fields: target.record_fields.len() as u32, + variable_slices: target.variable_slices.len() as u32, + }; + + let range = Variable::NUM_RESERVED_VARS..self.subs.utable.len(); + + target.utable.reserve(range.len()); + + for i in range { + let descriptor = self.subs.get_ref(Variable(i as u32)); + debug_assert!(descriptor.copy.is_none()); + + let new_content = Self::offset_content(&offsets, &descriptor.content); + + let new_variable = Variable(i as u32 + offsets.utable); + + let new_descriptor = Descriptor { + rank: descriptor.rank, + mark: descriptor.mark, + copy: OptVariable::NONE, + content: new_content, + }; + + target.set(new_variable, new_descriptor); + } + + target.variables.extend( + self.subs + .variables + .into_iter() + .map(|v| Self::offset_variable(&offsets, v)), + ); + + target.variable_slices.extend( + self.subs + .variable_slices + .into_iter() + .map(|v| Self::offset_variable_slice(&offsets, v)), + ); + + target.tag_names.extend(self.subs.tag_names); + target.field_names.extend(self.subs.field_names); + target.record_fields.extend(self.subs.record_fields); + } + fn offset_flat_type(offsets: &StorageSubsOffsets, flat_type: &FlatType) -> FlatType { + match flat_type { + FlatType::Apply(symbol, arguments) => { + FlatType::Apply(*symbol, Self::offset_variable_slice(offsets, *arguments)) + } + FlatType::Func(arguments, lambda_set, result) => FlatType::Func( + Self::offset_variable_slice(offsets, *arguments), + Self::offset_variable(offsets, *lambda_set), + Self::offset_variable(offsets, *result), + ), + FlatType::Record(record_fields, ext) => FlatType::Record( + Self::offset_record_fields(offsets, *record_fields), + Self::offset_variable(offsets, *ext), + ), + FlatType::TagUnion(union_tags, ext) => FlatType::TagUnion( + Self::offset_union_tags(offsets, *union_tags), + Self::offset_variable(offsets, *ext), + ), + FlatType::FunctionOrTagUnion(tag_name, symbol, ext) => FlatType::FunctionOrTagUnion( + Self::offset_tag_name_index(offsets, *tag_name), + *symbol, + Self::offset_variable(offsets, *ext), + ), + FlatType::RecursiveTagUnion(rec, union_tags, ext) => FlatType::RecursiveTagUnion( + Self::offset_variable(offsets, *rec), + Self::offset_union_tags(offsets, *union_tags), + Self::offset_variable(offsets, *ext), + ), + FlatType::Erroneous(problem) => FlatType::Erroneous(problem.clone()), + FlatType::EmptyRecord => FlatType::EmptyRecord, + FlatType::EmptyTagUnion => FlatType::EmptyTagUnion, + } + } + + fn offset_content(offsets: &StorageSubsOffsets, content: &Content) -> Content { + use Content::*; + + match content { + FlexVar(opt_name) => FlexVar(opt_name.clone()), + RigidVar(name) => RigidVar(name.clone()), + RecursionVar { + structure, + opt_name, + } => RecursionVar { + structure: Self::offset_variable(offsets, *structure), + opt_name: opt_name.clone(), + }, + Structure(flat_type) => Structure(Self::offset_flat_type(offsets, flat_type)), + Alias(symbol, alias_variables, actual) => Alias( + *symbol, + Self::offset_alias_variables(offsets, *alias_variables), + Self::offset_variable(offsets, *actual), + ), + Error => Content::Error, + } + } + + fn offset_alias_variables( + offsets: &StorageSubsOffsets, + mut alias_variables: AliasVariables, + ) -> AliasVariables { + alias_variables.lowercases_start += offsets.field_names; + alias_variables.variables_start += offsets.variables; + + alias_variables + } + + fn offset_union_tags(offsets: &StorageSubsOffsets, mut union_tags: UnionTags) -> UnionTags { + union_tags.tag_names_start += offsets.tag_names; + union_tags.variables_start += offsets.variables; + + union_tags + } + + fn offset_record_fields( + offsets: &StorageSubsOffsets, + mut record_fields: RecordFields, + ) -> RecordFields { + record_fields.field_names_start += offsets.field_names; + record_fields.variables_start += offsets.variables; + record_fields.field_types_start += offsets.record_fields; + + record_fields + } + + fn offset_tag_name_index( + offsets: &StorageSubsOffsets, + mut tag_name: SubsIndex, + ) -> SubsIndex { + tag_name.start += offsets.tag_names; + + tag_name + } + + fn offset_variable(offsets: &StorageSubsOffsets, variable: Variable) -> Variable { + if variable.index() < Variable::FIRST_USER_SPACE_VAR.index() { + variable + } else { + Variable(variable.0 + offsets.variables) + } + } + + fn offset_variable_slice( + offsets: &StorageSubsOffsets, + mut slice: VariableSubsSlice, + ) -> VariableSubsSlice { + slice.slice.start += offsets.variable_slices; + + slice + } +} From 30955a1eb8ae2d77912a64a85e383b834bbfe65c Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Wed, 17 Nov 2021 23:54:46 -0500 Subject: [PATCH 171/223] Take syntactic sugar into account when reporting errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, a program like ```roc word = "word" if True then 1 else "\(word) is a word" ``` would report an error like ``` ── TYPE MISMATCH ─────────────────────────────────────────────────────────────── This `if` has an `else` branch with a different type from its `then` branch: 3β”‚ if True then 1 else "\(word) is a word" ^^^^^^^^^^^^^^^^^^ This concat all produces: Str but the `then` branch has the type: Num a I need all branches in an `if` to have the same type! ``` but this is a little bit confusing, since the user shouldn't have to know (or care) that string interpolations are equivalent to concatenations under the current implementation. Indeed we should make this fully transparent. We now word the error message by taking into account the way calls are made. To support the case shown above, we introduce the `CalledVia::Sugar` variant to represent the fact that some calls may be the result of desugaring the surface syntax. This commit also demonstrates the usage of `CalledVia` to produce better error messages where we use binary comparison operators like `<`. There are more improvements we can make here for all `CalledVia` variants, but this is a good starting point to demonstrate the usage of the new procedure. Closes #1714 --- ast/src/constrain.rs | 4 +- compiler/can/src/expr.rs | 4 +- compiler/constrain/src/expr.rs | 4 +- compiler/module/src/operator.rs | 9 ++++ compiler/types/src/types.rs | 3 +- reporting/src/error/type.rs | 20 ++++++-- reporting/tests/test_reporting.rs | 76 +++++++++++++++++++++++++++++++ 7 files changed, 110 insertions(+), 10 deletions(-) diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index 80ff70491b..57d44ca2f0 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -277,7 +277,7 @@ pub fn constrain_expr<'a>( expr_id: expr_node_id, closure_var, fn_var, - .. + called_via, } => { // The expression that evaluates to the function being called, e.g. `foo` in // (foo) bar baz @@ -349,7 +349,7 @@ pub fn constrain_expr<'a>( region, ); - let category = Category::CallResult(opt_symbol); + let category = Category::CallResult(opt_symbol, *called_via); let mut and_constraints = BumpVec::with_capacity_in(4, arena); diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 098ad7926b..db2e005206 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -12,7 +12,7 @@ use crate::scope::Scope; use roc_collections::all::{ImSet, MutMap, MutSet, SendMap}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::operator::CalledVia; +use roc_module::operator::{CalledVia, Sugar}; use roc_module::symbol::Symbol; use roc_parse::ast::{self, EscapedChar, StrLiteral}; use roc_parse::pattern::PatternType::*; @@ -1711,7 +1711,7 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec) -> (var_store.fresh(), loc_new_expr), (var_store.fresh(), loc_expr), ], - CalledVia::Space, + CalledVia::Sugar(Sugar::StringInterpolation), ); loc_expr = Located::new(0, 0, 0, 0, expr); diff --git a/compiler/constrain/src/expr.rs b/compiler/constrain/src/expr.rs index 11d8c4cabe..eac7d8f1fc 100644 --- a/compiler/constrain/src/expr.rs +++ b/compiler/constrain/src/expr.rs @@ -254,7 +254,7 @@ pub fn constrain_expr( exists(vec![*elem_var], And(constraints)) } } - Call(boxed, loc_args, _application_style) => { + Call(boxed, loc_args, called_via) => { let (fn_var, loc_fn, closure_var, ret_var) = &**boxed; // The expression that evaluates to the function being called, e.g. `foo` in // (foo) bar baz @@ -317,7 +317,7 @@ pub fn constrain_expr( region, ); - let category = Category::CallResult(opt_symbol); + let category = Category::CallResult(opt_symbol, *called_via); exists( vars, diff --git a/compiler/module/src/operator.rs b/compiler/module/src/operator.rs index 14ba2de17b..99f638d428 100644 --- a/compiler/module/src/operator.rs +++ b/compiler/module/src/operator.rs @@ -12,6 +12,15 @@ pub enum CalledVia { /// Calling with a unary operator, e.g. (!foo bar baz) or (-foo bar baz) UnaryOp(UnaryOp), + + /// This call is the result of some desugaring, e.g. "\(first) \(last)" is + /// transformed into first ++ last. + Sugar(Sugar), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Sugar { + StringInterpolation, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index 3ccefd5fd3..1e3b7543cc 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -5,6 +5,7 @@ use crate::subs::{ use roc_collections::all::{ImMap, ImSet, Index, MutSet, SendMap}; use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName}; use roc_module::low_level::LowLevel; +use roc_module::operator::CalledVia; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_region::all::{Located, Region}; use std::fmt; @@ -1134,7 +1135,7 @@ pub enum Reason { #[derive(PartialEq, Debug, Clone)] pub enum Category { Lookup(Symbol), - CallResult(Option), + CallResult(Option, CalledVia), LowLevelOpResult(LowLevel), ForeignCall, TagApply { diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index 7b8049aa14..1b5c28d43d 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1,6 +1,7 @@ use roc_can::expected::{Expected, PExpected}; use roc_collections::all::{Index, MutSet, SendMap}; use roc_module::ident::{Ident, IdentStr, Lowercase, TagName}; +use roc_module::operator::{BinOp, CalledVia, Sugar}; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_solve::solve; @@ -1043,13 +1044,26 @@ fn add_category<'b>( alloc.record_field(field.to_owned()), alloc.text(" is a:"), ]), - - CallResult(Some(symbol)) => alloc.concat(vec![ + CallResult( + Some(symbol), + CalledVia::BinOp( + BinOp::Equals + | BinOp::NotEquals + | BinOp::LessThan + | BinOp::GreaterThan + | BinOp::LessThanOrEq + | BinOp::GreaterThanOrEq, + ), + ) => alloc.concat(vec![alloc.text("This comparison produces:")]), + CallResult(Some(symbol), CalledVia::Sugar(Sugar::StringInterpolation)) => { + alloc.concat(vec![alloc.text("This string interpolation produces:")]) + } + CallResult(Some(symbol), _) => alloc.concat(vec![ alloc.text("This "), alloc.symbol_foreign_qualified(*symbol), alloc.text(" call produces:"), ]), - CallResult(None) => alloc.concat(vec![this_is, alloc.text(":")]), + CallResult(None, _) => alloc.concat(vec![this_is, alloc.text(":")]), LowLevelOpResult(op) => { panic!( "Compiler bug: invalid return type from low-level op {:?}", diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 5210c72396..0b5a40bd25 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -5551,6 +5551,82 @@ mod test_reporting { ) } + #[test] + // https://github.com/rtfeldman/roc/issues/1714 + fn interpolate_concat_is_transparent_1714() { + report_problem_as( + indoc!( + r#" + greeting = "Privet" + + if True then 1 else "\(greeting), World!" + "#, + ), + indoc!( + r#" + ── TYPE MISMATCH ─────────────────────────────────────────────────────────────── + + This `if` has an `else` branch with a different type from its `then` branch: + + 3β”‚ if True then 1 else "\(greeting), World!" + ^^^^^^^^^^^^^^^^^^^^^ + + This string interpolation produces: + + Str + + but the `then` branch has the type: + + Num a + + I need all branches in an `if` to have the same type! + "# + ), + ) + } + + macro_rules! comparison_binop_transparency_tests { + ($($op:expr, $name:ident),* $(,)?) => { + $( + #[test] + fn $name() { + report_problem_as( + &format!(r#"if True then "abc" else 1 {} 2"#, $op), + &format!( +r#"── TYPE MISMATCH ─────────────────────────────────────────────────────────────── + +This `if` has an `else` branch with a different type from its `then` branch: + +1β”‚ if True then "abc" else 1 {} 2 + ^^{}^^ + +This comparison produces: + + Bool + +but the `then` branch has the type: + + Str + +I need all branches in an `if` to have the same type! +"#, + $op, "^".repeat($op.len()) + ), + ) + } + )* + } + } + + comparison_binop_transparency_tests! { + "<", lt_binop_is_transparent, + ">", gt_binop_is_transparent, + "==", eq_binop_is_transparent, + "!=", neq_binop_is_transparent, + "<=", leq_binop_is_transparent, + ">=", geq_binop_is_transparent, + } + #[test] fn keyword_record_field_access() { report_problem_as( From 8a60162a1e663b4886d00d845721caf36ace4ff8 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 00:09:53 -0500 Subject: [PATCH 172/223] Rename roc_module::operator -> roc_module::called_via A bit of a nit, but this file is now more general than just keeping track of operator methods. --- ast/src/lang/core/expr/expr2.rs | 2 +- cli/src/repl/eval.rs | 2 +- compiler/can/src/builtins.rs | 2 +- compiler/can/src/expr.rs | 2 +- compiler/can/src/operator.rs | 8 ++++---- compiler/fmt/src/expr.rs | 2 +- compiler/load/src/effect_module.rs | 2 +- compiler/module/src/{operator.rs => called_via.rs} | 0 compiler/module/src/lib.rs | 2 +- compiler/parse/src/ast.rs | 2 +- compiler/parse/src/expr.rs | 2 +- compiler/problem/src/can.rs | 2 +- compiler/types/src/types.rs | 2 +- reporting/src/error/type.rs | 2 +- reporting/src/report.rs | 2 +- 15 files changed, 17 insertions(+), 17 deletions(-) rename compiler/module/src/{operator.rs => called_via.rs} (100%) diff --git a/ast/src/lang/core/expr/expr2.rs b/ast/src/lang/core/expr/expr2.rs index 1f8983d8cc..dfea77f886 100644 --- a/ast/src/lang/core/expr/expr2.rs +++ b/ast/src/lang/core/expr/expr2.rs @@ -7,7 +7,7 @@ use crate::{ }; use roc_can::expr::Recursive; use roc_module::low_level::LowLevel; -use roc_module::operator::CalledVia; +use roc_module::called_via::CalledVia; use roc_module::symbol::Symbol; use super::record_field::RecordField; diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index 1abb0f2f07..148fab0f7b 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -3,7 +3,7 @@ use bumpalo::Bump; use libloading::Library; use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type}; use roc_module::ident::TagName; -use roc_module::operator::CalledVia; +use roc_module::called_via::CalledVia; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::ProcLayout; use roc_mono::layout::{union_sorted_tags_help, Builtin, Layout, UnionLayout, UnionVariant}; diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 163a82fd92..00582aaab4 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -5,7 +5,7 @@ use crate::pattern::Pattern; use roc_collections::all::SendMap; use roc_module::ident::{Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::operator::CalledVia; +use roc_module::called_via::CalledVia; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_types::subs::{VarStore, Variable}; diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index db2e005206..7d0d1db329 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -12,7 +12,7 @@ use crate::scope::Scope; use roc_collections::all::{ImSet, MutMap, MutSet, SendMap}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::operator::{CalledVia, Sugar}; +use roc_module::called_via::{CalledVia, Sugar}; use roc_module::symbol::Symbol; use roc_parse::ast::{self, EscapedChar, StrLiteral}; use roc_parse::pattern::PatternType::*; diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index c11242d71c..5dad8a74e6 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -3,8 +3,8 @@ use bumpalo::collections::Vec; use bumpalo::Bump; use roc_module::ident::ModuleName; -use roc_module::operator::BinOp::Pizza; -use roc_module::operator::{BinOp, CalledVia}; +use roc_module::called_via::BinOp::Pizza; +use roc_module::called_via::{BinOp, CalledVia}; use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::{AssignedField, Def, WhenBranch}; use roc_region::all::{Located, Region}; @@ -277,7 +277,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a }) } UnaryOp(loc_arg, loc_op) => { - use roc_module::operator::UnaryOp::*; + use roc_module::called_via::UnaryOp::*; let region = loc_op.region; let op = loc_op.value; @@ -475,7 +475,7 @@ fn binop_step<'a>( op_stack: &mut Vec>, next_op: Located, ) -> Step<'a> { - use roc_module::operator::Associativity::*; + use roc_module::called_via::Associativity::*; use std::cmp::Ordering; match op_stack.pop() { diff --git a/compiler/fmt/src/expr.rs b/compiler/fmt/src/expr.rs index f82fd61a1f..e28c1590ec 100644 --- a/compiler/fmt/src/expr.rs +++ b/compiler/fmt/src/expr.rs @@ -3,7 +3,7 @@ use crate::def::fmt_def; use crate::pattern::fmt_pattern; use crate::spaces::{add_spaces, fmt_comments_only, fmt_spaces, newline, NewlineAt, INDENT}; use bumpalo::collections::String; -use roc_module::operator::{self, BinOp}; +use roc_module::called_via::{self, BinOp}; use roc_parse::ast::StrSegment; use roc_parse::ast::{ AssignedField, Base, Collection, CommentOrNewline, Expr, Pattern, WhenBranch, diff --git a/compiler/load/src/effect_module.rs b/compiler/load/src/effect_module.rs index eeea64d7a1..22e07cb37e 100644 --- a/compiler/load/src/effect_module.rs +++ b/compiler/load/src/effect_module.rs @@ -6,7 +6,7 @@ use roc_can::pattern::Pattern; use roc_can::scope::Scope; use roc_collections::all::{MutSet, SendMap}; use roc_module::ident::TagName; -use roc_module::operator::CalledVia; +use roc_module::called_via::CalledVia; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_types::subs::{VarStore, Variable}; diff --git a/compiler/module/src/operator.rs b/compiler/module/src/called_via.rs similarity index 100% rename from compiler/module/src/operator.rs rename to compiler/module/src/called_via.rs diff --git a/compiler/module/src/lib.rs b/compiler/module/src/lib.rs index 3b0c3eea17..044f697a07 100644 --- a/compiler/module/src/lib.rs +++ b/compiler/module/src/lib.rs @@ -2,10 +2,10 @@ // See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check. #![allow(clippy::large_enum_variant, clippy::upper_case_acronyms)] +pub mod called_via; pub mod ident; pub mod low_level; pub mod module_err; -pub mod operator; pub mod symbol; #[macro_use] diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 0da46bb4a2..943c5d1058 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -4,7 +4,7 @@ use crate::header::{AppHeader, ImportsEntry, InterfaceHeader, PlatformHeader, Ty use crate::ident::Ident; use bumpalo::collections::{String, Vec}; use bumpalo::Bump; -use roc_module::operator::{BinOp, CalledVia, UnaryOp}; +use roc_module::called_via::{BinOp, CalledVia, UnaryOp}; use roc_region::all::{Loc, Position, Region}; #[derive(Clone, Debug, PartialEq)] diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index 90eaeb268f..77553c3ef2 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -13,7 +13,7 @@ use crate::pattern::loc_closure_param; use crate::type_annotation; use bumpalo::collections::Vec; use bumpalo::Bump; -use roc_module::operator::{BinOp, CalledVia, UnaryOp}; +use roc_module::called_via::{BinOp, CalledVia, UnaryOp}; use roc_region::all::{Located, Position, Region}; use crate::parser::Progress::{self, *}; diff --git a/compiler/problem/src/can.rs b/compiler/problem/src/can.rs index c5bfa42f53..f512e4b9de 100644 --- a/compiler/problem/src/can.rs +++ b/compiler/problem/src/can.rs @@ -1,6 +1,6 @@ use roc_collections::all::MutSet; use roc_module::ident::{Ident, Lowercase, ModuleName, TagName}; -use roc_module::operator::BinOp; +use roc_module::called_via::BinOp; use roc_module::symbol::{ModuleId, Symbol}; use roc_parse::ast::Base; use roc_parse::pattern::PatternType; diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index 1e3b7543cc..ed449d7996 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -5,7 +5,7 @@ use crate::subs::{ use roc_collections::all::{ImMap, ImSet, Index, MutSet, SendMap}; use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::operator::CalledVia; +use roc_module::called_via::CalledVia; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_region::all::{Located, Region}; use std::fmt; diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index 1b5c28d43d..de5f716aaf 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1,7 +1,7 @@ use roc_can::expected::{Expected, PExpected}; use roc_collections::all::{Index, MutSet, SendMap}; use roc_module::ident::{Ident, IdentStr, Lowercase, TagName}; -use roc_module::operator::{BinOp, CalledVia, Sugar}; +use roc_module::called_via::{BinOp, CalledVia, Sugar}; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_solve::solve; diff --git a/reporting/src/report.rs b/reporting/src/report.rs index cce7db7f3d..8832ac27aa 100644 --- a/reporting/src/report.rs +++ b/reporting/src/report.rs @@ -353,7 +353,7 @@ impl<'a> RocDocAllocator<'a> { pub fn binop( &'a self, - content: roc_module::operator::BinOp, + content: roc_module::called_via::BinOp, ) -> DocBuilder<'a, Self, Annotation> { self.text(content.to_string()).annotate(Annotation::BinOp) } From 8b7217847d8496b40b86fefaa3dae2b4fb2a7c36 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 00:17:52 -0500 Subject: [PATCH 173/223] Rename additional stale roc_module::operator refs and format --- ast/src/lang/core/expr/expr2.rs | 2 +- ast/src/lang/core/str.rs | 2 +- cli/src/repl/eval.rs | 2 +- compiler/can/src/builtins.rs | 2 +- compiler/can/src/expr.rs | 2 +- compiler/can/src/operator.rs | 2 +- compiler/fmt/src/expr.rs | 44 +++++++++++++++--------------- compiler/load/src/effect_module.rs | 2 +- compiler/problem/src/can.rs | 2 +- compiler/types/src/types.rs | 2 +- reporting/src/error/type.rs | 2 +- 11 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ast/src/lang/core/expr/expr2.rs b/ast/src/lang/core/expr/expr2.rs index dfea77f886..86d204447b 100644 --- a/ast/src/lang/core/expr/expr2.rs +++ b/ast/src/lang/core/expr/expr2.rs @@ -6,8 +6,8 @@ use crate::{ mem_pool::{pool::NodeId, pool_str::PoolStr, pool_vec::PoolVec}, }; use roc_can::expr::Recursive; -use roc_module::low_level::LowLevel; use roc_module::called_via::CalledVia; +use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; use super::record_field::RecordField; diff --git a/ast/src/lang/core/str.rs b/ast/src/lang/core/str.rs index 0463f77969..fb28813a02 100644 --- a/ast/src/lang/core/str.rs +++ b/ast/src/lang/core/str.rs @@ -1,4 +1,4 @@ -use roc_module::{operator::CalledVia, symbol::Symbol}; +use roc_module::{called_via::CalledVia, symbol::Symbol}; use roc_parse::ast::StrLiteral; use crate::{ diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index 148fab0f7b..271efc7c9b 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -2,8 +2,8 @@ use bumpalo::collections::Vec; use bumpalo::Bump; use libloading::Library; use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type}; -use roc_module::ident::TagName; use roc_module::called_via::CalledVia; +use roc_module::ident::TagName; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::ProcLayout; use roc_mono::layout::{union_sorted_tags_help, Builtin, Layout, UnionLayout, UnionVariant}; diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 00582aaab4..b8204d7dd9 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -3,9 +3,9 @@ use crate::expr::{ClosureData, Expr::*}; use crate::expr::{Expr, Field, Recursive, WhenBranch}; use crate::pattern::Pattern; use roc_collections::all::SendMap; +use roc_module::called_via::CalledVia; use roc_module::ident::{Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::called_via::CalledVia; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_types::subs::{VarStore, Variable}; diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 7d0d1db329..489fbfa4d7 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -10,9 +10,9 @@ use crate::pattern::{canonicalize_pattern, Pattern}; use crate::procedure::References; use crate::scope::Scope; use roc_collections::all::{ImSet, MutMap, MutSet, SendMap}; +use roc_module::called_via::{CalledVia, Sugar}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::called_via::{CalledVia, Sugar}; use roc_module::symbol::Symbol; use roc_parse::ast::{self, EscapedChar, StrLiteral}; use roc_parse::pattern::PatternType::*; diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index 5dad8a74e6..97dce75fb1 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -2,9 +2,9 @@ use bumpalo::collections::Vec; use bumpalo::Bump; -use roc_module::ident::ModuleName; use roc_module::called_via::BinOp::Pizza; use roc_module::called_via::{BinOp, CalledVia}; +use roc_module::ident::ModuleName; use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::{AssignedField, Def, WhenBranch}; use roc_region::all::{Located, Region}; diff --git a/compiler/fmt/src/expr.rs b/compiler/fmt/src/expr.rs index e28c1590ec..cb356ff53a 100644 --- a/compiler/fmt/src/expr.rs +++ b/compiler/fmt/src/expr.rs @@ -296,10 +296,10 @@ impl<'a> Formattable<'a> for Expr<'a> { BinOps(lefts, right) => fmt_bin_ops(buf, lefts, right, false, parens, indent), UnaryOp(sub_expr, unary_op) => { match &unary_op.value { - operator::UnaryOp::Negate => { + called_via::UnaryOp::Negate => { buf.push('-'); } - operator::UnaryOp::Not => { + called_via::UnaryOp::Not => { buf.push('!'); } } @@ -354,26 +354,26 @@ fn format_str_segment<'a>(seg: &StrSegment<'a>, buf: &mut String<'a>, indent: u1 fn push_op(buf: &mut String, op: BinOp) { match op { - operator::BinOp::Caret => buf.push('^'), - operator::BinOp::Star => buf.push('*'), - operator::BinOp::Slash => buf.push('/'), - operator::BinOp::DoubleSlash => buf.push_str("//"), - operator::BinOp::Percent => buf.push('%'), - operator::BinOp::DoublePercent => buf.push_str("%%"), - operator::BinOp::Plus => buf.push('+'), - operator::BinOp::Minus => buf.push('-'), - operator::BinOp::Equals => buf.push_str("=="), - operator::BinOp::NotEquals => buf.push_str("!="), - operator::BinOp::LessThan => buf.push('<'), - operator::BinOp::GreaterThan => buf.push('>'), - operator::BinOp::LessThanOrEq => buf.push_str("<="), - operator::BinOp::GreaterThanOrEq => buf.push_str(">="), - operator::BinOp::And => buf.push_str("&&"), - operator::BinOp::Or => buf.push_str("||"), - operator::BinOp::Pizza => buf.push_str("|>"), - operator::BinOp::Assignment => unreachable!(), - operator::BinOp::HasType => unreachable!(), - operator::BinOp::Backpassing => unreachable!(), + called_via::BinOp::Caret => buf.push('^'), + called_via::BinOp::Star => buf.push('*'), + called_via::BinOp::Slash => buf.push('/'), + called_via::BinOp::DoubleSlash => buf.push_str("//"), + called_via::BinOp::Percent => buf.push('%'), + called_via::BinOp::DoublePercent => buf.push_str("%%"), + called_via::BinOp::Plus => buf.push('+'), + called_via::BinOp::Minus => buf.push('-'), + called_via::BinOp::Equals => buf.push_str("=="), + called_via::BinOp::NotEquals => buf.push_str("!="), + called_via::BinOp::LessThan => buf.push('<'), + called_via::BinOp::GreaterThan => buf.push('>'), + called_via::BinOp::LessThanOrEq => buf.push_str("<="), + called_via::BinOp::GreaterThanOrEq => buf.push_str(">="), + called_via::BinOp::And => buf.push_str("&&"), + called_via::BinOp::Or => buf.push_str("||"), + called_via::BinOp::Pizza => buf.push_str("|>"), + called_via::BinOp::Assignment => unreachable!(), + called_via::BinOp::HasType => unreachable!(), + called_via::BinOp::Backpassing => unreachable!(), } } diff --git a/compiler/load/src/effect_module.rs b/compiler/load/src/effect_module.rs index 22e07cb37e..24f46cda44 100644 --- a/compiler/load/src/effect_module.rs +++ b/compiler/load/src/effect_module.rs @@ -5,8 +5,8 @@ use roc_can::expr::{ClosureData, Expr, Recursive}; use roc_can::pattern::Pattern; use roc_can::scope::Scope; use roc_collections::all::{MutSet, SendMap}; -use roc_module::ident::TagName; use roc_module::called_via::CalledVia; +use roc_module::ident::TagName; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_types::subs::{VarStore, Variable}; diff --git a/compiler/problem/src/can.rs b/compiler/problem/src/can.rs index f512e4b9de..38c80791c7 100644 --- a/compiler/problem/src/can.rs +++ b/compiler/problem/src/can.rs @@ -1,6 +1,6 @@ use roc_collections::all::MutSet; -use roc_module::ident::{Ident, Lowercase, ModuleName, TagName}; use roc_module::called_via::BinOp; +use roc_module::ident::{Ident, Lowercase, ModuleName, TagName}; use roc_module::symbol::{ModuleId, Symbol}; use roc_parse::ast::Base; use roc_parse::pattern::PatternType; diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index ed449d7996..edcf6dbaab 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -3,9 +3,9 @@ use crate::subs::{ GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice, }; use roc_collections::all::{ImMap, ImSet, Index, MutSet, SendMap}; +use roc_module::called_via::CalledVia; use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::called_via::CalledVia; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_region::all::{Located, Region}; use std::fmt; diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index de5f716aaf..38ddd951f8 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1,7 +1,7 @@ use roc_can::expected::{Expected, PExpected}; use roc_collections::all::{Index, MutSet, SendMap}; -use roc_module::ident::{Ident, IdentStr, Lowercase, TagName}; use roc_module::called_via::{BinOp, CalledVia, Sugar}; +use roc_module::ident::{Ident, IdentStr, Lowercase, TagName}; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_solve::solve; From 4ef40be0f02175d5736e98c83bcad3c59c11a98e Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 01:15:34 -0500 Subject: [PATCH 174/223] Remove unused variable refs --- reporting/src/error/type.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index 38ddd951f8..eac93684d8 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1045,7 +1045,7 @@ fn add_category<'b>( alloc.text(" is a:"), ]), CallResult( - Some(symbol), + Some(_), CalledVia::BinOp( BinOp::Equals | BinOp::NotEquals @@ -1055,7 +1055,7 @@ fn add_category<'b>( | BinOp::GreaterThanOrEq, ), ) => alloc.concat(vec![alloc.text("This comparison produces:")]), - CallResult(Some(symbol), CalledVia::Sugar(Sugar::StringInterpolation)) => { + CallResult(Some(_), CalledVia::Sugar(Sugar::StringInterpolation)) => { alloc.concat(vec![alloc.text("This string interpolation produces:")]) } CallResult(Some(symbol), _) => alloc.concat(vec![ From 5bfc52cd3b24e02b7ecda23805f7b63413b3551c Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 21:23:41 -0500 Subject: [PATCH 175/223] Remove `Sugar` enum and inline single variant into `CalledVia` --- compiler/can/src/expr.rs | 4 ++-- compiler/module/src/called_via.rs | 9 ++------- reporting/src/error/type.rs | 4 ++-- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 489fbfa4d7..faa5b7a283 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -10,7 +10,7 @@ use crate::pattern::{canonicalize_pattern, Pattern}; use crate::procedure::References; use crate::scope::Scope; use roc_collections::all::{ImSet, MutMap, MutSet, SendMap}; -use roc_module::called_via::{CalledVia, Sugar}; +use roc_module::called_via::CalledVia; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; @@ -1711,7 +1711,7 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec) -> (var_store.fresh(), loc_new_expr), (var_store.fresh(), loc_expr), ], - CalledVia::Sugar(Sugar::StringInterpolation), + CalledVia::StringInterpolation, ); loc_expr = Located::new(0, 0, 0, 0, expr); diff --git a/compiler/module/src/called_via.rs b/compiler/module/src/called_via.rs index 99f638d428..a53b20ab08 100644 --- a/compiler/module/src/called_via.rs +++ b/compiler/module/src/called_via.rs @@ -13,13 +13,8 @@ pub enum CalledVia { /// Calling with a unary operator, e.g. (!foo bar baz) or (-foo bar baz) UnaryOp(UnaryOp), - /// This call is the result of some desugaring, e.g. "\(first) \(last)" is - /// transformed into first ++ last. - Sugar(Sugar), -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Sugar { + /// This call is the result of desugaring string interpolation, + /// e.g. "\(first) \(last)" is transformed into Str.concat (Str.concat first " ") last. StringInterpolation, } diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index eac93684d8..1eba91322f 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1,6 +1,6 @@ use roc_can::expected::{Expected, PExpected}; use roc_collections::all::{Index, MutSet, SendMap}; -use roc_module::called_via::{BinOp, CalledVia, Sugar}; +use roc_module::called_via::{BinOp, CalledVia}; use roc_module::ident::{Ident, IdentStr, Lowercase, TagName}; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; @@ -1055,7 +1055,7 @@ fn add_category<'b>( | BinOp::GreaterThanOrEq, ), ) => alloc.concat(vec![alloc.text("This comparison produces:")]), - CallResult(Some(_), CalledVia::Sugar(Sugar::StringInterpolation)) => { + CallResult(Some(_), CalledVia::StringInterpolation) => { alloc.concat(vec![alloc.text("This string interpolation produces:")]) } CallResult(Some(symbol), _) => alloc.concat(vec![ From a985204d5c5613746623d91c191ce87e98ebb3d8 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 21:32:07 -0500 Subject: [PATCH 176/223] Simplify error message for string interpolation-related type mismatch --- reporting/src/error/type.rs | 2 +- reporting/tests/test_reporting.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index 1eba91322f..f80f3b63c9 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1056,7 +1056,7 @@ fn add_category<'b>( ), ) => alloc.concat(vec![alloc.text("This comparison produces:")]), CallResult(Some(_), CalledVia::StringInterpolation) => { - alloc.concat(vec![alloc.text("This string interpolation produces:")]) + alloc.concat(vec![this_is, alloc.text(" a string of type:")]) } CallResult(Some(symbol), _) => alloc.concat(vec![ alloc.text("This "), diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 0b5a40bd25..96342d19a5 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -5571,7 +5571,7 @@ mod test_reporting { 3β”‚ if True then 1 else "\(greeting), World!" ^^^^^^^^^^^^^^^^^^^^^ - This string interpolation produces: + The `else` branch is a string of type: Str From fe99d20be5034b7b1584320773588d0314dfb3a7 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 21:40:13 -0500 Subject: [PATCH 177/223] Apply review suggestions --- ast/src/lang/env.rs | 7 +------ compiler/can/src/env.rs | 7 +------ compiler/module/src/symbol.rs | 8 ++++++-- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/ast/src/lang/env.rs b/ast/src/lang/env.rs index dc70adb13c..04596cd84c 100644 --- a/ast/src/lang/env.rs +++ b/ast/src/lang/env.rs @@ -147,12 +147,7 @@ impl<'a> Env<'a> { let exposed_values = exposed_ids .idents() .filter(|(_, ident)| { - ident - .as_ref() - .chars() - .next() - .filter(|c| c.is_lowercase()) - .is_some() + ident.as_ref().starts_with(|c: char| c.is_lowercase()) }) .map(|(_, ident)| Lowercase::from(ident.as_ref())) .collect(); diff --git a/compiler/can/src/env.rs b/compiler/can/src/env.rs index 4ad1bbd058..c91fa67bae 100644 --- a/compiler/can/src/env.rs +++ b/compiler/can/src/env.rs @@ -112,12 +112,7 @@ impl<'a> Env<'a> { let exposed_values = exposed_ids .idents() .filter(|(_, ident)| { - ident - .as_ref() - .chars() - .next() - .filter(|c| c.is_lowercase()) - .is_some() + ident.as_ref().starts_with(|c: char| c.is_lowercase()) }) .map(|(_, ident)| Lowercase::from(ident.as_ref())) .collect(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 89666dfa12..251d72064b 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -990,7 +990,9 @@ define_builtins! { 2 BOOL: "Bool" => { 0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias 1 BOOL_FALSE: "False" imported // Bool.Bool = [ False, True ] + // NB: not strictly needed; used for finding global tag names in error suggestions 2 BOOL_TRUE: "True" imported // Bool.Bool = [ False, True ] + // NB: not strictly needed; used for finding global tag names in error suggestions 3 BOOL_AND: "and" 4 BOOL_OR: "or" 5 BOOL_NOT: "not" @@ -1079,8 +1081,10 @@ define_builtins! { } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias - 1 RESULT_OK: "Ok" imported // Result.Result = [ Ok a, Err e ] - 2 RESULT_ERR: "Err" imported // Result.Result = [ Ok a, Err e ] + 1 RESULT_OK: "Ok" imported // Result.Result a e = [ Ok a, Err e ] + // NB: not strictly needed; used for finding global tag names in error suggestions + 2 RESULT_ERR: "Err" imported // Result.Result a e = [ Ok a, Err e ] + // NB: not strictly needed; used for finding global tag names in error suggestions 3 RESULT_MAP: "map" 4 RESULT_MAP_ERR: "mapErr" 5 RESULT_WITH_DEFAULT: "withDefault" From 0c046476a94be5053fa6af56867688dbbc0bfe8c Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 22:06:33 -0500 Subject: [PATCH 178/223] Add test case for former issue Closes #1513 --- compiler/test_gen/src/gen_records.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/compiler/test_gen/src/gen_records.rs b/compiler/test_gen/src/gen_records.rs index 1c6274e20b..b59641aadd 100644 --- a/compiler/test_gen/src/gen_records.rs +++ b/compiler/test_gen/src/gen_records.rs @@ -968,3 +968,24 @@ fn update_the_only_field() { i64 ); } + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] +// https://github.com/rtfeldman/roc/issues/1513 +fn both_have_unique_fields() { + assert_evals_to!( + indoc!( + r#" + a = { x: 42, y: 43 } + b = { x: 42, z: 44 } + + f : { x : I64 }a, { x : I64 }b -> I64 + f = \{ x: x1}, { x: x2 } -> x1 + x2 + + f a b + "# + ), + 84, + i64 + ); +} From 0a495c6736d64f7f07e3a3fc74de8b54ab3066c3 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Thu, 18 Nov 2021 22:32:36 -0500 Subject: [PATCH 179/223] Add Cristiano Piemontese to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 5dc330e817..1825ce83ee 100644 --- a/AUTHORS +++ b/AUTHORS @@ -55,3 +55,4 @@ Joost Baas Callum Dunster Martin Stewart James Hegedus +Cristiano Piemontese From d29d536990c2ea922693b0abd1f4df41048fb8cd Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Thu, 18 Nov 2021 23:22:50 -0500 Subject: [PATCH 180/223] Don't test on gen-dev yet --- compiler/test_gen/src/gen_records.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/test_gen/src/gen_records.rs b/compiler/test_gen/src/gen_records.rs index b59641aadd..41babc0e07 100644 --- a/compiler/test_gen/src/gen_records.rs +++ b/compiler/test_gen/src/gen_records.rs @@ -970,7 +970,7 @@ fn update_the_only_field() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] // https://github.com/rtfeldman/roc/issues/1513 fn both_have_unique_fields() { assert_evals_to!( From 206c8889dff920f36e40bfec451d065012613447 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 19 Nov 2021 10:44:54 +0100 Subject: [PATCH 181/223] Use StorageSubs for pending specializations --- compiler/mono/src/ir.rs | 32 +-- compiler/solve/src/solve.rs | 340 -------------------------------- compiler/types/src/subs.rs | 381 ++++++++++++++++++++++++++++++++++-- compiler/unify/src/unify.rs | 6 +- 4 files changed, 385 insertions(+), 374 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 3f791837a9..d3ceaa9ef5 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -16,7 +16,7 @@ use roc_problem::can::RuntimeError; use roc_region::all::{Located, Region}; use roc_std::RocDec; use roc_types::solved_types::SolvedType; -use roc_types::subs::{Content, FlatType, Subs, Variable, VariableSubsSlice}; +use roc_types::subs::{Content, FlatType, StorageSubs, Subs, Variable, VariableSubsSlice}; use std::collections::HashMap; use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder}; @@ -437,7 +437,7 @@ impl<'a> ExternalSpecializations<'a> { fn insert_external(&mut self, symbol: Symbol, env_subs: &mut Subs, variable: Variable) { let variable = - roc_solve::solve::deep_copy_var_to(env_subs, &mut self.storage_subs, variable); + roc_types::subs::deep_copy_var_to(env_subs, &mut self.storage_subs, variable); match self.symbols.iter().position(|s| *s == symbol) { None => { @@ -468,7 +468,7 @@ impl<'a> ExternalSpecializations<'a> { #[derive(Clone, Debug)] pub struct Suspended<'a> { - pub store: Subs, + pub store: StorageSubs, pub symbols: Vec<'a, Symbol>, pub layouts: Vec<'a, ProcLayout<'a>>, pub variables: Vec<'a, Variable>, @@ -477,7 +477,7 @@ pub struct Suspended<'a> { impl<'a> Suspended<'a> { fn new_in(arena: &'a Bump) -> Self { Self { - store: Subs::new_from_varstore(Default::default()), + store: StorageSubs::new(Subs::new_from_varstore(Default::default())), symbols: Vec::new_in(arena), layouts: Vec::new_in(arena), variables: Vec::new_in(arena), @@ -505,7 +505,7 @@ impl<'a> Suspended<'a> { self.symbols.push(symbol); self.layouts.push(proc_layout); - let variable = roc_solve::solve::deep_copy_var_to(subs, &mut self.store, variable); + let variable = self.store.extend_with_variable(subs, variable); self.variables.push(variable); } @@ -1908,20 +1908,20 @@ pub fn specialize_all<'a>( match pending_specializations { PendingSpecializations::Making => {} - PendingSpecializations::Finding(mut suspended) => { - // TODO can we copy everything over in one pass (bumping variables by however many - // variables are in the env's subs? - for var in suspended.variables.iter_mut() { - debug_assert!((var.index() as usize) < suspended.store.len()); + PendingSpecializations::Finding(suspended) => { + let offset_variable = StorageSubs::merge_into(suspended.store, env.subs); - *var = roc_solve::solve::deep_copy_var_to(&mut suspended.store, env.subs, *var); - } - - for (i, symbol) in suspended.symbols.iter().enumerate() { + for (i, (symbol, var)) in suspended + .symbols + .iter() + .zip(suspended.variables.iter()) + .enumerate() + { let name = *symbol; - let var = suspended.variables[i]; let outside_layout = suspended.layouts[i]; + let var = offset_variable(*var); + // TODO define our own Entry for Specialized? let partial_proc = if procs.specialized.is_specialized(name, &outside_layout) { // already specialized, just continue @@ -2069,7 +2069,7 @@ fn specialize_externals_others_need<'a>( }; let variable = - roc_solve::solve::deep_copy_var_to(&mut store, env.subs, store_variable); + roc_types::subs::deep_copy_var_to(&mut store, env.subs, store_variable); // TODO I believe this is also duplicated match specialize_variable( diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index a72c36d4a7..8c92222966 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1383,346 +1383,6 @@ fn instantiate_rigids_help( var } -pub fn deep_copy_var_to( - source: &mut Subs, // mut to set the copy - target: &mut Subs, - var: Variable, -) -> Variable { - let mut pools = Pools::default(); - let rank = Rank::toplevel(); - - let mut mapping = Vec::with_capacity(100); - - let copy = deep_copy_var_to_help(source, target, rank, &mut pools, &mut mapping, var); - - source.restore(var); - - copy -} - -fn deep_copy_var_to_help( - // source: &mut Subs, // mut to set the copy - source: &mut Subs, - target: &mut Subs, - max_rank: Rank, - pools: &mut Pools, - mapping: &mut Vec, // maps copies in the source to copies in the target - var: Variable, -) -> Variable { - use roc_types::subs::Content::*; - use roc_types::subs::FlatType::*; - - let desc = source.get_without_compacting(var); - - if let Some(copy) = desc.copy.into_variable() { - debug_assert!(target.contains(copy)); - return copy; - } else if desc.rank != Rank::NONE { - // DO NOTHING - // - // The original deep_copy_var can do - // return var; - // - // but we cannot, because this `var` is in the source, not the target, and we - // should only return variables in the target - } - - let make_descriptor = |content| Descriptor { - content, - rank: max_rank, - mark: Mark::NONE, - copy: OptVariable::NONE, - }; - - let content = desc.content; - // let copy = target.fresh(make_descriptor(content.clone())); - let copy = target.fresh_unnamed_flex_var(); - - // pools.get_mut(max_rank).push(copy); - - // Link the original variable to the new variable. This lets us - // avoid making multiple copies of the variable we are instantiating. - // - // Need to do this before recursively copying to avoid looping. - - source.set( - var, - Descriptor { - content: content.clone(), - rank: desc.rank, - mark: Mark::NONE, - copy: copy.into(), - }, - ); - - // Now we recursively copy the content of the variable. - // We have already marked the variable as copied, so we - // will not repeat this work or crawl this variable again. - match content { - Structure(flat_type) => { - let new_flat_type = match flat_type { - Apply(symbol, args) => { - let mut new_arg_vars = Vec::with_capacity(args.len()); - - for index in args.into_iter() { - let var = source[index]; - let copy_var = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, var); - new_arg_vars.push(copy_var); - } - - let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars); - - Apply(symbol, arg_vars) - } - - Func(arg_vars, closure_var, ret_var) => { - let new_ret_var = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, ret_var); - - let new_closure_var = deep_copy_var_to_help( - source, - target, - max_rank, - pools, - mapping, - closure_var, - ); - - let mut new_arg_vars = Vec::with_capacity(arg_vars.len()); - - for index in arg_vars.into_iter() { - let var = source[index]; - let copy_var = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, var); - new_arg_vars.push(copy_var); - } - - let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars); - - Func(arg_vars, new_closure_var, new_ret_var) - } - - same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same, - - Record(fields, ext_var) => { - let record_fields = { - let mut new_vars = Vec::with_capacity(fields.len()); - - for index in fields.iter_variables() { - let var = source[index]; - let copy_var = deep_copy_var_to_help( - source, target, max_rank, pools, mapping, var, - ); - - new_vars.push(copy_var); - } - - let field_names_start = target.field_names.len() as u32; - let variables_start = target.variables.len() as u32; - let field_types_start = target.record_fields.len() as u32; - - let mut length = 0; - - for ((i1, _, i3), var) in fields.iter_all().zip(new_vars) { - let record_field = source[i3].map(|_| var); - - target.field_names.push(source[i1].clone()); - target.record_fields.push(record_field.map(|_| ())); - target.variables.push(*record_field.as_inner()); - - length += 1; - } - - RecordFields { - length, - field_names_start, - variables_start, - field_types_start, - } - }; - - Record( - record_fields, - deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var), - ) - } - - TagUnion(tags, ext_var) => { - let new_ext = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var); - - let mut new_variable_slices = Vec::with_capacity(tags.len()); - - let mut new_variables = Vec::new(); - for index in tags.variables() { - let slice = source[index]; - for var_index in slice { - let var = source[var_index]; - let new_var = deep_copy_var_to_help( - source, target, max_rank, pools, mapping, var, - ); - new_variables.push(new_var); - } - - let new_slice = - VariableSubsSlice::insert_into_subs(target, new_variables.drain(..)); - - new_variable_slices.push(new_slice); - } - - let new_variables = { - let start = target.variable_slices.len() as u32; - let length = new_variable_slices.len() as u16; - target.variable_slices.extend(new_variable_slices); - - SubsSlice::new(start, length) - }; - - let new_tag_names = { - let tag_names = tags.tag_names(); - let slice = &source.tag_names[tag_names.start as usize..] - [..tag_names.length as usize]; - - let start = target.tag_names.len() as u32; - let length = tag_names.len() as u16; - - target.tag_names.extend(slice.iter().cloned()); - - SubsSlice::new(start, length) - }; - - let union_tags = UnionTags::from_slices(new_tag_names, new_variables); - - TagUnion(union_tags, new_ext) - } - - FunctionOrTagUnion(tag_name, symbol, ext_var) => { - let new_tag_name = SubsIndex::new(target.tag_names.len() as u32); - - target.tag_names.push(source[tag_name].clone()); - - FunctionOrTagUnion( - new_tag_name, - symbol, - deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var), - ) - } - - RecursiveTagUnion(rec_var, tags, ext_var) => { - let mut new_variable_slices = Vec::with_capacity(tags.len()); - - let mut new_variables = Vec::new(); - for index in tags.variables() { - let slice = source[index]; - for var_index in slice { - let var = source[var_index]; - let new_var = deep_copy_var_to_help( - source, target, max_rank, pools, mapping, var, - ); - new_variables.push(new_var); - } - - let new_slice = - VariableSubsSlice::insert_into_subs(target, new_variables.drain(..)); - - new_variable_slices.push(new_slice); - } - - let new_variables = { - let start = target.variable_slices.len() as u32; - let length = new_variable_slices.len() as u16; - target.variable_slices.extend(new_variable_slices); - - SubsSlice::new(start, length) - }; - - let new_tag_names = { - let tag_names = tags.tag_names(); - let slice = &source.tag_names[tag_names.start as usize..] - [..tag_names.length as usize]; - - let start = target.tag_names.len() as u32; - let length = tag_names.len() as u16; - - target.tag_names.extend(slice.iter().cloned()); - - SubsSlice::new(start, length) - }; - - let union_tags = UnionTags::from_slices(new_tag_names, new_variables); - - let new_ext = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var); - let new_rec_var = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, rec_var); - - RecursiveTagUnion(new_rec_var, union_tags, new_ext) - } - }; - - target.set(copy, make_descriptor(Structure(new_flat_type))); - - copy - } - - FlexVar(_) | Error => copy, - - RecursionVar { - opt_name, - structure, - } => { - let new_structure = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, structure); - - debug_assert!((new_structure.index() as usize) < target.len()); - - target.set( - copy, - make_descriptor(RecursionVar { - opt_name, - structure: new_structure, - }), - ); - - copy - } - - RigidVar(name) => { - target.set(copy, make_descriptor(FlexVar(Some(name)))); - - copy - } - - Alias(symbol, mut args, real_type_var) => { - let mut new_vars = Vec::with_capacity(args.variables().len()); - - for var_index in args.variables() { - let var = source[var_index]; - let new_var = deep_copy_var_to_help(source, target, max_rank, pools, mapping, var); - - new_vars.push(new_var); - } - - args.replace_variables(target, new_vars); - - let lowercases = &source.field_names[args.lowercases_start as usize..] - [..args.lowercases_len as usize]; - - args.lowercases_start = target.field_names.len() as u32; - target.field_names.extend(lowercases.iter().cloned()); - - let new_real_type_var = - deep_copy_var_to_help(source, target, max_rank, pools, mapping, real_type_var); - let new_content = Alias(symbol, args, new_real_type_var); - - target.set(copy, make_descriptor(new_content)); - - copy - } - } -} - fn deep_copy_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, var: Variable) -> Variable { let copy = deep_copy_var_help(subs, rank, pools, var); diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 105c135b9f..4aaaf28abb 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -1051,6 +1051,7 @@ impl Subs { } pub fn extend_by(&mut self, entries: usize) { + self.utable.reserve(entries); for _ in 0..entries { self.utable.new_key(flex_var_descriptor()); } @@ -2801,11 +2802,12 @@ fn restore_help(subs: &mut Subs, initial: Variable) { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct StorageSubs { subs: Subs, } +#[derive(Copy, Clone, Debug)] struct StorageSubsOffsets { utable: u32, variables: u32, @@ -2816,7 +2818,24 @@ struct StorageSubsOffsets { } impl StorageSubs { - pub fn merge_into(self, target: &mut Subs) { + pub fn new(subs: Subs) -> Self { + Self { subs } + } + + pub fn extend_with_variable(&mut self, source: &mut Subs, variable: Variable) -> Variable { + deep_copy_var_to(source, &mut self.subs, variable) + } + + pub fn merge_into(self, target: &mut Subs) -> impl Fn(Variable) -> Variable { + let self_offsets = StorageSubsOffsets { + utable: self.subs.utable.len() as u32, + variables: self.subs.variables.len() as u32, + tag_names: self.subs.tag_names.len() as u32, + field_names: self.subs.field_names.len() as u32, + record_fields: self.subs.record_fields.len() as u32, + variable_slices: self.subs.variable_slices.len() as u32, + }; + let offsets = StorageSubsOffsets { utable: target.utable.len() as u32, variables: target.variables.len() as u32, @@ -2826,33 +2845,36 @@ impl StorageSubs { variable_slices: target.variable_slices.len() as u32, }; - let range = Variable::NUM_RESERVED_VARS..self.subs.utable.len(); + let range = 0..self.subs.utable.len(); - target.utable.reserve(range.len()); + // fill new slots with empty values + target.extend_by(range.len()); for i in range { - let descriptor = self.subs.get_ref(Variable(i as u32)); + let variable = Variable(i as u32); + let descriptor = self.subs.get_ref(variable); debug_assert!(descriptor.copy.is_none()); let new_content = Self::offset_content(&offsets, &descriptor.content); - let new_variable = Variable(i as u32 + offsets.utable); - let new_descriptor = Descriptor { rank: descriptor.rank, mark: descriptor.mark, + // rank: Rank::NONE, + // mark: Mark::NONE, copy: OptVariable::NONE, content: new_content, }; + let new_variable = Self::offset_variable(&offsets, variable); target.set(new_variable, new_descriptor); } target.variables.extend( self.subs .variables - .into_iter() - .map(|v| Self::offset_variable(&offsets, v)), + .iter() + .map(|v| Self::offset_variable(&offsets, *v)), ); target.variable_slices.extend( @@ -2865,6 +2887,21 @@ impl StorageSubs { target.tag_names.extend(self.subs.tag_names); target.field_names.extend(self.subs.field_names); target.record_fields.extend(self.subs.record_fields); + + debug_assert_eq!( + target.utable.len(), + (self_offsets.utable + offsets.utable) as usize + ); + + debug_assert_eq!( + target.tag_names.len(), + (self_offsets.tag_names + offsets.tag_names) as usize + ); + + move |v| { + let offsets = offsets; + Self::offset_variable(&offsets, v) + } } fn offset_flat_type(offsets: &StorageSubsOffsets, flat_type: &FlatType) -> FlatType { match flat_type { @@ -2935,7 +2972,7 @@ impl StorageSubs { fn offset_union_tags(offsets: &StorageSubsOffsets, mut union_tags: UnionTags) -> UnionTags { union_tags.tag_names_start += offsets.tag_names; - union_tags.variables_start += offsets.variables; + union_tags.variables_start += offsets.variable_slices; union_tags } @@ -2961,19 +2998,331 @@ impl StorageSubs { } fn offset_variable(offsets: &StorageSubsOffsets, variable: Variable) -> Variable { - if variable.index() < Variable::FIRST_USER_SPACE_VAR.index() { - variable - } else { - Variable(variable.0 + offsets.variables) - } + let new_index = variable.0 + offsets.utable; + Variable(new_index) } fn offset_variable_slice( offsets: &StorageSubsOffsets, mut slice: VariableSubsSlice, ) -> VariableSubsSlice { - slice.slice.start += offsets.variable_slices; + slice.slice.start += offsets.variables; slice } } + +pub fn deep_copy_var_to( + source: &mut Subs, // mut to set the copy + target: &mut Subs, + var: Variable, +) -> Variable { + let rank = Rank::toplevel(); + + let copy = deep_copy_var_to_help(source, target, rank, var); + + source.restore(var); + + copy +} + +fn deep_copy_var_to_help( + // source: &mut Subs, // mut to set the copy + source: &mut Subs, + target: &mut Subs, + max_rank: Rank, + var: Variable, +) -> Variable { + use Content::*; + use FlatType::*; + + let desc = source.get_without_compacting(var); + + if let Some(copy) = desc.copy.into_variable() { + debug_assert!(target.contains(copy)); + return copy; + } else if desc.rank != Rank::NONE { + // DO NOTHING + // + // The original deep_copy_var can do + // return var; + // + // but we cannot, because this `var` is in the source, not the target, and we + // should only return variables in the target + } + + let make_descriptor = |content| Descriptor { + content, + rank: max_rank, + mark: Mark::NONE, + copy: OptVariable::NONE, + }; + + let content = desc.content; + // let copy = target.fresh(make_descriptor(content.clone())); + let copy = target.fresh_unnamed_flex_var(); + + // pools.get_mut(max_rank).push(copy); + + // Link the original variable to the new variable. This lets us + // avoid making multiple copies of the variable we are instantiating. + // + // Need to do this before recursively copying to avoid looping. + + source.set( + var, + Descriptor { + content: content.clone(), + rank: desc.rank, + mark: Mark::NONE, + copy: copy.into(), + }, + ); + + // Now we recursively copy the content of the variable. + // We have already marked the variable as copied, so we + // will not repeat this work or crawl this variable again. + match content { + Structure(flat_type) => { + let new_flat_type = match flat_type { + Apply(symbol, args) => { + let mut new_arg_vars = Vec::with_capacity(args.len()); + + for index in args.into_iter() { + let var = source[index]; + let copy_var = deep_copy_var_to_help(source, target, max_rank, var); + new_arg_vars.push(copy_var); + } + + let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars); + + Apply(symbol, arg_vars) + } + + Func(arg_vars, closure_var, ret_var) => { + let new_ret_var = deep_copy_var_to_help(source, target, max_rank, ret_var); + + let new_closure_var = + deep_copy_var_to_help(source, target, max_rank, closure_var); + + let mut new_arg_vars = Vec::with_capacity(arg_vars.len()); + + for index in arg_vars.into_iter() { + let var = source[index]; + let copy_var = deep_copy_var_to_help(source, target, max_rank, var); + new_arg_vars.push(copy_var); + } + + let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars); + + Func(arg_vars, new_closure_var, new_ret_var) + } + + same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same, + + Record(fields, ext_var) => { + let record_fields = { + let mut new_vars = Vec::with_capacity(fields.len()); + + for index in fields.iter_variables() { + let var = source[index]; + let copy_var = deep_copy_var_to_help(source, target, max_rank, var); + + new_vars.push(copy_var); + } + + let field_names_start = target.field_names.len() as u32; + let variables_start = target.variables.len() as u32; + let field_types_start = target.record_fields.len() as u32; + + let mut length = 0; + + for ((i1, _, i3), var) in fields.iter_all().zip(new_vars) { + let record_field = source[i3].map(|_| var); + + target.field_names.push(source[i1].clone()); + target.record_fields.push(record_field.map(|_| ())); + target.variables.push(*record_field.as_inner()); + + length += 1; + } + + RecordFields { + length, + field_names_start, + variables_start, + field_types_start, + } + }; + + Record( + record_fields, + deep_copy_var_to_help(source, target, max_rank, ext_var), + ) + } + + TagUnion(tags, ext_var) => { + let new_ext = deep_copy_var_to_help(source, target, max_rank, ext_var); + + let mut new_variable_slices = Vec::with_capacity(tags.len()); + + let mut new_variables = Vec::new(); + for index in tags.variables() { + let slice = source[index]; + for var_index in slice { + let var = source[var_index]; + let new_var = deep_copy_var_to_help(source, target, max_rank, var); + new_variables.push(new_var); + } + + let new_slice = + VariableSubsSlice::insert_into_subs(target, new_variables.drain(..)); + + new_variable_slices.push(new_slice); + } + + let new_variables = { + let start = target.variable_slices.len() as u32; + let length = new_variable_slices.len() as u16; + target.variable_slices.extend(new_variable_slices); + + SubsSlice::new(start, length) + }; + + let new_tag_names = { + let tag_names = tags.tag_names(); + let slice = &source.tag_names[tag_names.start as usize..] + [..tag_names.length as usize]; + + let start = target.tag_names.len() as u32; + let length = tag_names.len() as u16; + + target.tag_names.extend(slice.iter().cloned()); + + SubsSlice::new(start, length) + }; + + let union_tags = UnionTags::from_slices(new_tag_names, new_variables); + + TagUnion(union_tags, new_ext) + } + + FunctionOrTagUnion(tag_name, symbol, ext_var) => { + let new_tag_name = SubsIndex::new(target.tag_names.len() as u32); + + target.tag_names.push(source[tag_name].clone()); + + FunctionOrTagUnion( + new_tag_name, + symbol, + deep_copy_var_to_help(source, target, max_rank, ext_var), + ) + } + + RecursiveTagUnion(rec_var, tags, ext_var) => { + let mut new_variable_slices = Vec::with_capacity(tags.len()); + + let mut new_variables = Vec::new(); + for index in tags.variables() { + let slice = source[index]; + for var_index in slice { + let var = source[var_index]; + let new_var = deep_copy_var_to_help(source, target, max_rank, var); + new_variables.push(new_var); + } + + let new_slice = + VariableSubsSlice::insert_into_subs(target, new_variables.drain(..)); + + new_variable_slices.push(new_slice); + } + + let new_variables = { + let start = target.variable_slices.len() as u32; + let length = new_variable_slices.len() as u16; + target.variable_slices.extend(new_variable_slices); + + SubsSlice::new(start, length) + }; + + let new_tag_names = { + let tag_names = tags.tag_names(); + let slice = &source.tag_names[tag_names.start as usize..] + [..tag_names.length as usize]; + + let start = target.tag_names.len() as u32; + let length = tag_names.len() as u16; + + target.tag_names.extend(slice.iter().cloned()); + + SubsSlice::new(start, length) + }; + + let union_tags = UnionTags::from_slices(new_tag_names, new_variables); + + let new_ext = deep_copy_var_to_help(source, target, max_rank, ext_var); + let new_rec_var = deep_copy_var_to_help(source, target, max_rank, rec_var); + + RecursiveTagUnion(new_rec_var, union_tags, new_ext) + } + }; + + target.set(copy, make_descriptor(Structure(new_flat_type))); + + copy + } + + FlexVar(_) | Error => copy, + + RecursionVar { + opt_name, + structure, + } => { + let new_structure = deep_copy_var_to_help(source, target, max_rank, structure); + + debug_assert!((new_structure.index() as usize) < target.len()); + + target.set( + copy, + make_descriptor(RecursionVar { + opt_name, + structure: new_structure, + }), + ); + + copy + } + + RigidVar(name) => { + target.set(copy, make_descriptor(FlexVar(Some(name)))); + + copy + } + + Alias(symbol, mut args, real_type_var) => { + let mut new_vars = Vec::with_capacity(args.variables().len()); + + for var_index in args.variables() { + let var = source[var_index]; + let new_var = deep_copy_var_to_help(source, target, max_rank, var); + + new_vars.push(new_var); + } + + args.replace_variables(target, new_vars); + + let lowercases = &source.field_names[args.lowercases_start as usize..] + [..args.lowercases_len as usize]; + + args.lowercases_start = target.field_names.len() as u32; + target.field_names.extend(lowercases.iter().cloned()); + + let new_real_type_var = deep_copy_var_to_help(source, target, max_rank, real_type_var); + let new_content = Alias(symbol, args, new_real_type_var); + + target.set(copy, make_descriptor(new_content)); + + copy + } + } +} diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index 51771efe07..f469b0be1c 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -133,12 +133,14 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome { // println!("\n --- \n"); // dbg!(ctx.second, type2); // println!("\n --------------- \n"); + let content_1 = subs.get(ctx.first).content; + let content_2 = subs.get(ctx.second).content; println!( "{:?} {:?} ~ {:?} {:?}", ctx.first, - subs.get(ctx.first).content, + roc_types::subs::SubsFmtContent(&content_1, subs), ctx.second, - subs.get(ctx.second).content + roc_types::subs::SubsFmtContent(&content_2, subs), ); } match &ctx.first_desc.content { From df91f63af8b057c534b5d5fb2bb361de3412885f Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Fri, 19 Nov 2021 07:24:07 -0500 Subject: [PATCH 182/223] changing const_zero to const_int --- compiler/gen_llvm/src/llvm/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index d1b61f06ce..178ca76b6e 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -5146,7 +5146,9 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( let (function, closure, closure_layout) = function_details!(); match list_layout { - Layout::Builtin(Builtin::EmptyList) => env.context.bool_type().const_zero().into(), + Layout::Builtin(Builtin::EmptyList) => { + env.context.bool_type().const_int(1, false).into() + } Layout::Builtin(Builtin::List(element_layout)) => { let argument_layouts = &[**element_layout]; From ef7052540feee26e952ecd3b679802b8a38de3ee Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 19 Nov 2021 08:52:34 -0500 Subject: [PATCH 183/223] Delete binary that was accidentally checked in --- examples/cli/hello-world | Bin 1935056 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 examples/cli/hello-world diff --git a/examples/cli/hello-world b/examples/cli/hello-world deleted file mode 100755 index c3248ebe2cb8a978fc62cfd9a1e8c405a8bfbd46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1935056 zcmeFa3wRXe^*_D~K>`U()F4q&qoRVgN)(kXAPHt+24)3?RH{V00AdxP$u5Qh64=CM z9H&iN_?CL9v|fr@HLZdX1vUh70l@%@5vqxzFzc#BPzV>Z|Iaz^%Pt`|C=(!Kds1b-QcHv zd$TXZVDS9*))X#8_et^MbW`lSoie4+AGotH_NaY(4QHovd!G=3@Xx*%cP>}5)!r%A z1JT};8Po2YJ*@!G+PC-Wd7`~XtO|5bc#r+-0N>qr-8E%e(OuJK`=|KtxU+qG*%yoU zlFt<_(0xLCv4+LPlqq-3y1y`v!1nEp&lT-8ZWpsk_X+sx&|cvF2kyCl>Xdu#pFRuk z+P62LZ*RumeHV#}bpPG(O`9=gdchqtr`hl((#x`8qP-c`e9*mh*$y&sOLS-AZ_1S1 zoQXM8t{->91VMeEFCJk?lylkiXWdhq^hdC!;cv>6yJy9*cH;J^EdN7$PPk~gpS51m zPse#kgfGp4udGZ|qI+k1j;8pM#yJ4Mig7yMN@ASZ_A^ObSoiigH0}t|GX> z<;oWAxQZ<~jC=amFiPALTu#_7aJh;HQ2~@258@d=N^&t6EtK<8)R$Pa=>-ZohXEV?du6h66+OAE1Y%ToXb7VdKaTE!L_{lR96}n?}65R#XG0EZnqar zJUjXCBnD1m;3Ni4V&EhOPGaCB22Nt&BnD1m;3Ni4V&EhOPGaCB22Nt&BnD1m;3Ni4 zV&EhOPGaCB22Nt&BnD1m;D^URo~(T;2R~1%^&Y3jD_rKo2sz5Z4Qct+<@m?%E5ClT z_VaU}JMdtBHQ#FoWWBqrKaebIwfW(JZ})Ibm(D9;;OzHWYrKAbcn-peD3a@P(fj=B z>6a&zNB_YQZhvoCADt}gH>Zj2#of3xS@X5ZnzuzZhF_kU>XMCK`_As|QjKmI{d(gr zuVw9J=-OQ0lH!`q@aBhy9l>?Hzwo0+6Yn2FHctHg1R!8i>7hWt{IW+Ew3xp_)|zCk z#+=m?w_1~Vb2J(S1g5Oz0Sfx{Hp)h~mNtIejLT;L5uUD)YrPc|X2owM;RB@`@w^WA z4HU|ijRh;r#)rGO*3q5$;H_QpX!v3z-N;6tL1<(xB?OqK>~9a>4Ad+)AKaJXl6CJg zIk=$Q?U!ZUx13wod<}SCXKqF0Th^-i`c6b!xfhH?)^?d=fCITSRP-Rf{iLVMl@$V_ zXWW`!E!S3Igi-0dY*+F8WH(?@+<|YJV5hK33l8O>|>mmTb7{2>l9`5USyq5D}_We1ffeRTXlr-~zsM!4H{B(k>pQjSN)^Z41F5T_FWF3X6*HWH>`B#Fw zG~~~awG368os6aiqp4eSZbMT&(Uha?P>g{X!}`bc9{fBL#0o<7wlZUkO9tLr7z@S% z)1*Gy(|fEO=$hzT2b~*Ne|RQiswHc?`P7=OsAP@T?ybB$tUuq?6=$FFaO7Xy>n|jh zzjb$Vd-&V)BjF1}3XbR+I0vY>G29EYmf!F?% zVe>aVx!>FIN<2n^9{g%Sc~73EaPIRxfG$BF3GJQTvArRNXfLf}doSV@H~h(?Jv(o2 z^ZJhPJtEo*;Z-~M^6mB}{?XCi%{f2K$;+8YSk7R|oCSh8Y!W;WF%2M`I$!A*{vWHx z)k#303f@tTX(1XP@EVe%)v6X%wY{o#z)V@(!=*&G1okqA`EUo^X55-HIVV5owwx)> zx$P7`$ErGvr>sE{p?iuSFl-<>AwQ!>G;0~F7Psy3}bTKp!x)4gC$Z=LFCkruyz2R?nlASD=0 zdZ4djc!%LtD7+QqS&mxLVp_t08+qU^#TeZ0`iFCe50!&Q(+aPYOSk*8v+5oEGbE|E zf4Cg2l0BOO2T35dy8UCrUNj)aBduyRXJCQj7gvUVgcn)ct#TKJ&%tda{xB_@sDxCS zLN#Nn+w^kTn0%I7(eg7@&oOE7ZM2Yh^6R9<6X^>4aRy`{@f9Z2Z22t3MWfbf)HVFD z;}|ZdF?h1-rSpnW!bR|3+YbJr;ZnSb!@pvy1^)$+SuxlHJiRlag~OoQZL>qx{ns82H9Pw415b?c16zeX@Sg~ z;sx25Kp*C8T5{k_#q(AmJqxuzZbzs&HQpR|yn)CEHoZbPft(PUG z3bZZO2T~ifD!D2=L|*ijC=fz{I+T-^gq$o8FJEPjh}Wm~H_26>q5gq*2is)NfjPZo ztp)8A^^m)E&#%rxYqFcyBB#F7DhC%PyNbHXy35&{MgRQr!GSFD$G2wHV+N(ARdQ_z zNQ=@yn7Gog0tHT^4k{_h3qPbt;D_jo7C!=v`3Z|5w4`J-Q`C)nbU>ciy^x3h+wzc~ zigrlW+Q5qFWjFP5O(aFGiU2ek>dFlEq?u z)*+A@sWcf%uqGLhST%1!&B&SFtV7_=sy##G9@R3dV1TVy&Vt0mLc2?loREth;2VOe zRse=^b?X_auGP?`z}L0rkvCZ^H$uoXDEe(6l}3=_h%)a!lzayzp^BEC#tS#JFyFq_ zlsjksehzAt?tbu6pMIU9k89031S-mwme$C%>uFq=_ni<*QUB?f$3UN~?U6H3ay3nT zBy}~-d8FHFRwXrG9ae=9Ix7^N4dKpwq1B|!5QLXdU)uW#46xfL$!+Llv#KqqfQnIx z`hVR+D|NRFQNLm}DJE2ZUx4b@n&XP_8{9Aib4e>loc{!|od>}#>!Uytp}ChhxY4uT zpUI5jU?5Sf=zUO*>{%aZHdlVZk|L2E1^@DTFcCBtB^}LIdg#F`e8zN4?LIN%1HJ~j zv}y$kLa?S4fI@bd_o6*jyGjmLCr7#}`gxcYhIB9}QNmZIxfADZsyl zvb(CNJE_IJ@~gSG{P6n+(Oncc2fwqtaIRNHa&77Ds0hpfWh-akQr6bY=AV^C^i%6C z7B2&3xGtxelq)aC|LG4jv}}5xX z&YM(TmAp_$S`{g`T9#gJR1SZvKqk9)`J|UWR^0Dw3)9QP`(*7sMSA(L?B@TpHlMah z)%GY_E&A)4qiuQMMK1Rds_jEHls%%jk5f~6J`G_-B#Ew6tOtibLN%1DQrr!y^zuhO z_XZLteQ9wyA|HNVJ+nEd__`mfQf@Q;ju3KGl54xnGrR&hfegqCmJA0#_eBn^N!Axs z(jtc`tfSGPoV?oQn)=sQRyFrh4R2jmy_wyT40c&i=L)>ZHr6)P-KL)UkyIW!)Q~H! zYRL)ibw~aj*9L5UGXF{z4(ttx5-59{u%sBnn@(k;=<(iA2-u$O@)2x6razXQ4|j*s z+iRFRa2nKx!qZY+5f}`8?xTzDxR`s*wn5-TSFTv^Y)T(F+<6T6gpw8@ zS_ja{4w|v&S9m^z&Bpd&r8@13g-c(aHO=y$RMrohw*L8#mS1k)xAU)5CT+f^p+(O8NIRtFLka zCK(SeSAt}E6^L1#hS}|eWE|^B+`fXRDnr$0q>+jBA~zd1u`Y#)^=F=QVPchcu&-VK zk;d(-FL1})^j-FqtR?!#ieQ1;^u+W)&a)x1o(*SLwwxbrj?;Xc-%0Jns%BjM^kvXR zh!<&vp7|=_EziU{(hN{r@c!~$yr{pCN{p4?3=O1Zb&`eV-uF}SCUeeg3+zPoFoC~- zAFIc_s~tTad&SYCarO0h2b{h56V`W{EhXuFpVngjc_wv2(|PrU)Pkj*Krx}WL3)c3 zL}oE4X%2nS=5Gu)IMn4I40?FKv7JxhX$FJo;mGN65%Mis1Gz-bMxEzSC&5oKo9i^0 zLw>@#*l>Oe%c;{^Wz{qB*j7ar2~YE+k^1MKWNlV=1MUE z?LlzJ_Zaqfz1PcSO<=9Lfa_cHt#`$=)0Eez(h#1A93&B zJIJ51c|!i&j#usE&$oER@@%jcmp?qd9n+I+{{zui%)gYu}dKVi4Ofk_3Yw4vetmE!^J_|vPWbh0fP+6NSluP=P+ARoR)QPb0-vx)>6qZx&Sy~2uPyH&(q<>; zhhGO86XYG?2e#EgC>+5d?!f7?E|cWTfK_6$E*gR7KmG^?GLgCF17R-+nLmdUn;b3+ zLf~$gLK3{`MxYs71uyCFpLcb!zdL09;|7-tmKm8ZP^hejPv9Z(Uwu^Nf0^Tz9c4aqnNRL#nR=AFV6gU`5(n!bNQV~Au?ank^<=z2zV6bzUlUh%M-xy9P6vK*|DoA^4j7Dd z8A4o>+4>>|AzqJwegteRu!2Xmt zKP~#aj2M@!$;0L%(FF67tY42VO4-iSQ)GPtq~lUy{264%srvN;WPM(StQTg2a+iVU zm!sju$&n1j z_JFybu&jH_xtmnfV;k68uIi;UP+w`tCwVt0dWHgCRrK*`(rb&(g0%tjzTmPLzstIt z8+a8xO0WGkg9=1JRaMi6mQ(4%4`HH7CCl+z*5BMlTZBP@a&)Uyl0#4htJ@UqD<$|* zcmEk#q3PwazAls72q~Vbz*q9X8aa5ZyR+U5r@|AtZw<+$p5{gf0x+$Vg#h0P8cub1$>J_5+63-eJ&<3T1aAi zQy3EiBr$66nz&4u8mZ=Vf9$pS=%U!Q?GGjVOaKDxdrj!en9L$@(Ch*E;cxDv)ipss z&1C;+ModLqwY8mySwuhx5p%ygE*N)Bi_7bWP$xlN`?wBbjdv3&JBS#|o^a|9n^$zy zPwvMEfrSuWwbM^}&9d~9SD{GQ_F-J!ApT>8z0w&FVVEfTxjy~=WYrV#Uxvkd5e8$2 zfXXqz5av8BzFzl)U{gFF1U_XNRfU-Ae7Uyq&GturxIElN$iJBW8$<5TwzNZTe~isS z?y0Ugau-aEBX=O`Bp|otuT-bWti%j-g522rvc7h3BOyrmw=MWw|Ln^5iTc$q--don ziy`S(`P@Z@DdR-fP= z>B%7QdOQoP<~p!{5ldfn>+2`a5Im0cb;2Dy&Q90Y zIDHv?mLmAi_#+jW5VVO~;*p(qc^rQiijkS~#8g>}zrdd*FD!U}wz!@C#Q41nu5_E8 ztn#Fvrsapv>@Yso9U{>b7dzbZ!@pWab5jfe1wAI#{~6BuNWhOhe{4TPRHs1`nS74J z3V7{lMpiSVX``6LtH4jS zC_+V_AcD5#mMvf6`p{MI<+1O;94tVH>qAdXIpKT>elz+!ahBy%>T6{dsDF@+4ynF-y%!?evP`I=LSqsolpNMq7d7ql8qR*qF<9Ez4kC`I;DrC5;%b| zaib7|A}yt>R6-|(WbIb9?JUoH`tO7yvSbteO0TV^n$l};Lkm(o?+2RXfgdWt)~*G2 zgM=V&6n(KM|A~pOc1I2B~%!5$0j3&^*1%;rfOmTFN@9wxAeTDTAsCy%3}Kv-&yw@}nf4rXed~ zW(dq&85g3^$ZX96&M9t1p^f6ExZ*nS)7YqIE-_#fVg+fF!>`Ul! zRjoj#_LWa-HP;e5>w#s!wLewWc}l|1+4`qT$Z=iSj5@&NnZ<2jICEL^dP+C1c= zttQOmhx`6MQQlJdtER=)U$I`^6}uPmg(9`uVRPt{9puXpFg=N@L3q_pzPxD5gNaaJ zWAcFIi`8D_PaWDzzDKmzj92a2TYy*WfAR-T(B5Mm+goPItMZQR^|Imn`b6-J?bzOo z8J7I(*xmw}f=xu~reGf>z&yDV^=V|$!BqO~k)b3w%_JiE#~B{fv$ zJ)T{>cSLsa)?$?VmM1N8JBr{OnZiq|%+%Co6wz8xxc`XM;xg~Ij^b@1q@7h|o|f8T z6-%{>IjXcdszinR(+C_lxA>8P$;qhB_4vOB{txE-cf&s%XXJIjKdqk=#@Bj30qM9b z3X(t>pX98?^56=SfgB^DeijLR;+Wu1bJh~$NA9#}Xn;jSpEwBOQ%Cu|IcqsD;!2B% zxST~qpE~O7b=29HBl4>B5em|S6n#pXJg^bzV+9v0$YO9eK~MjLtl|r|AdkR}yp$@H^GJqWv`lw9& znz+xvZ!>_CV|B#zXt#RHCiG?-6Zj4q%G)z>)UANk>*`keY5?#DUr z+Yi}4gB8PWGUb?PqoE^qyINerpWW>OaS8W#H%VM(;_^79vuLA%zHVW0nTE@q;xZYR z)qL4qt{t6Cc*qa0?}9NK!xtRn;Vg*_=ja;b!Ni;vF@FSnM3in1W;TP(b}Kju>VikAK{d;R=scQH)q&=EwuX5hsvdt2&fk# zx9*U?Cu?Hn`3=!%C*6OBqXDV=LmTY;Ah!1%_*nL5q?bAH0e>!e)G}ld2w(^Nqrmw( zR}ywW5Mi6oyv-R&QVBhm0gvA6mNc5dahUC1qs1j=yVqcGiP`RTzPQ9}_v$S!G26Y4 zNn8!H-OCi0nC)Kg@}*?YHYh`u26P+oaxa&3>ge&)Ye(PCAR_`5UJa-~2LWUjgRCEc zvrCZmfj6)ZBM$K^uM{8w@;|m(L#F4Tr3R#WHM;N` zzs-0=zb5^f$rC|eI!K5zF?FIJWMk^^73f4VflAz0;N5n8N;VzcN5UD z00AF?jy;HTts`*71U_9EXL=bFLiGF2`V_{Gd3c%IRpF)tFur##c*1|vy+w{D2YRrf z)pN5*Hx}}V-V1$?0v8mzSpt;6R#NqaX+BWx5T$BglHzWP^cMCv`KCR`{O8Jg*BXFf zku=6WR8aNUEr?US4;MEa5KQeEXce?ywKvJ%%kt|snHQlH3P6S)@OlZ3j3y-gbmvMQG6_nUkc!4AU{x9w1Ha@ z-33hKz#?~)l-&oC&G#@xBqDZ%oT8KK$LEvmT}&zMTLO5KRbyDTJ(Z`&JH;wAi00En znCe7G&EE{nQ{WTtc5w6)4MALD&*gdhg96W>{5Ej75s05 z`sfPGZvk&0;VwRz7XQceoAE3pk>g)G8rDAQ5r5ag)FO%~lnogs5aO+S$-lN;j8E1d zV{c=0JrXC$zt$iJk92qX*L2~H)V}x6AGu^Ogm|n?jpvX&o*sOIe4#GC&ztpyqBZ%9 zY3?w^zmbcZ!%^W#TDcP4iu7S$=_gW&1i)4OLgbIHEk->gA|Iy7{JfuN+A+nmr660?hmv6HlPkUU0>!UY<92tXr#0W+EXv%qJ3vnV zA^)4P4rWmYFETK{0^noy$M;i!8*L+&?k|8g2bUFgdmy-dW|r_5JMp=V@u>ul|6uq; zl6NE*<08~WhSGSmLO$(NMcaT81}+W%6WDZ;M>ZsTlVardcgIReC9k2-IKw{^EE8OZ;_AiG>VJ&{|Wtv^U(~(87{(aoXq>gL5|V8|H4ja z{i7HuezFlm-Of@Vo~qgj|MRw3TFY%20QQkerjiWMM-O7Ph-{u0fFVr9Lt?gSrQl9H zpe2In_n0r@*L}>dhrq9I0n^Uc z#IGM({A!hwO8$yM(hIWM)i$ev>FauRwnt_%kY%Sp2zH5Lheo z=N=$V3D$le{)~b@Uq$gBfInxV8H_VrhTs2)KXb7O>_q$-9MPo!Ccpy&2s;_J(hE1l z!c3;3{O~ELov@z+wygg$)^ZlY+`2w33QZRoYskl>Heg@O!{hOsbRDk8W`Bwau!_kq z3e(J~AzG&no6DgA$0^LpPiFloSUcW47bm(0-*moA1CNv zaeagBhD+>Keu#RHS%J2)c1O}}c@GVS9wDK{e@4!sl72#y3M8 z%>N^>kpB`W)KrBAdbY)7`w|6TcxTAc;o`CoTZa^*bUfx!_B8shRtA2cEZRu7KI7?r z)Sl3HNZ%enI}R6ZV7NpXp>NkJw6$+evUx3v!(VLPwbF^am_8`%r$l|*Z>ehPJ*~Df zQVc92zpR?>l|{A9i0JvpK+T&0pvuj7^8|oN7VJ{-m zhg#`uw84fNVUgu5RB>v%)_Q{itZ`YT6qHJ!4{9r>&)ZXJ>+@%eHf{Q_?HArZ|Nof& znzokKrok$zNV9|KHMISH1bY^;aE5|4-?!68i42K0=lLzfgbe|Hg^e zN6VgnV2}_T`aH-pa-UZ1?Ltp_u7*@|nIEr){L-(N$(GH;0+`Jf37ijIZRbNz7D(pn zT(IzVyR}K3wYEeQDxyMgn#`L`h0Z{ir@&i4#&H;c4tx-;_&2$ zwU-_B(cY|%?ZF?y@SMuSv>SWaYE0)5geyz#jyovk+ibR@KH$=ephO04I6nKiOBCr@I7^!4jl-heR zgNxXZhl^0uxjyBGHvzciqCfEbDOvOW=d@PuM}FU!TmH8^?k;Q1D_C`7$cmH;(fw^1}}uW0tk}CqI1P z1?T*-7mbb(k=tdzTIC)3-;^}i+8H3=06ewADLM-<#r&anLZxJ|gaS*NSNKdo6_XdX zKNj2JJN3tYzLI9AbAN0D-bL2NTaNiNb*KOT`G2(c|08EEBgy6B7(p*2*wIaXcrlkF z`eu2oFH8+WVeMw_d_Kjc&r1_G^?Z{~ebR&OaI~+&Bg8Zu{!`$O+ZOSMF|V}mU*NA8 z$5D-<4cl}m32{YxUP-lh#WY_fs#uu3mOgsb9-Eu-(t!eUvr}VWr903uRWpllK|HnO zIT1erGuR@TMH*RRLg?p*=c75N${WK6DnTfRXtCgl>g!}DYvmb1uvk84loPW?i%L@B zqSDufIlnr)BpPswtXpIF1z&PdX!*fjuC;IjyUgAT5)BZ0KMHU3mmEm`^zQ=6B7UZK z=TMDUMOdGQL4zrN@|DEF+4?-m7ucEP38a*2A?8Ju``T5p@ZpHR6#P%8@s~ecgYm_R!G&;uFlC)((;BHENilt>D;lu$q3??C{Ih~s?0PZ08)$eJ z0Q5{6UN)v4@E-DC>kRk2z!k&`1TjU?J{ToflJrU@jr?#46%%@%lR}uEc)sZT0is#Q zlIK(JZJkZdj(Cl7Ow?@BXD%1|j34@pzh4GH^(kp9z(5qS9vb+&EXm9ibR4O7ENo}f z!ghvyZ_8||B|@m=wfOjDn%Pmg7^Q{0+fiuA4h(`>;R&x0};ye6a z*S`19AGsvQcYOMs0puGz6S18uX~(+%Mn`Pt0f-QGs!;`U31R(=`Maf(D9~^DyqBRs z$M{amOF#|my-|5U>+#$Y0{$ik6xp(7i z5MlQjF8`$q572grh5%VJAIZg1Abso=YH$Q|$B}g%y3RIDG z{XdwWu<#cjqc+1OXf96PrwaQZM&Ge`jx|({O~m6l=`_?6#B*%@3GwDNILN8P`okyn z64yEGxws%*{Q?P6r~ShAWv{2$KBTF?g%@!o)nt&Fl8_zK#f4*Dp$=jpTF{(z$ovCp ztvd(zW;L$lfz{$>72OyW^a)a8p&dBy6~Z%N|Ii=);;=`BCgOy*TTJlx>;&HKax^=c z1`(6Lmc9V3O5`_WW2MZdl`?WhTsWXS>Z{7> z(L>8AJ^4?|_|Zcv@Iz~G?!P(Szda|$Yqz)DYVZ3E`+n4R3>#U9?SQ4Aud=9yfF%w4 zOKKeiap|9&_EcQo!QyG>8F`VM(hZAeU+45?)BI)9`gtMw0TQ%yv3`n0bLR?->K$G* zMbc3wEt+RDx;vVID^R)<-6W>}(ZRSq^o2?J;m@8(Nnkf&?}C4zYX63!BG?!Aq*Emq z`VF%2Fhx#%JnvbDKAs=`M+bcTQ1txPU;iz7UW#gtiH*+z(Q{|=h4_`^LVoxbR85pG z4*LI(`SbX*|JHamqS}ea^BwlhBdF*Uur@!7cm(u42pm>|v2s4hYNl=YWs`bl@%AXR zg7-s+=|@6I!@Cf&nH&xmtKd0YaLy#EdnRg(x5Y$~-PEyXsHss{qeK3=(Di1h_cV)0 z)dmi3iFjJ%T+7}@9Lw=oS#+H4{Cy7v$HTSNCD1GzZ_pESB0L_E?aDoKX4?Uoe&~LN z!`+8u}7W~lBVvDasQapUXZEH6Jh^JH28h&^9QJ$ zFa~(3qhn^~XZS9yOTh>FJoc2p zN%C6;H&=|Gnu70;B~B4u#JSHApVdbQkIT&{fIh^{7`{oSu5I_rwRpttmpFdOe+B9} zt8*v7qffQxU(pq`jRSltom}S`PkBO{6G?J;8iyIiSU|b3zC7-RKyU&^hal!OPAGsQGawpfvL^E{O6^|GkrS zWAxIQ{&XjNOG79PzoYydLjF$3luqLXZ$3fvCDNXezb#zQI0_vOrwu}PeiS7ll@1H& zB69C#!r=tEIvSyIxDXMOv4C-N5SB{`-?XE>Se zAa=Ic=Q$(ZW`#^I!|@MHtk^F#@L<9DaFo#zr7r(zWRkg&UAD{Yj#*H&+r){L*n<&X zhfR1mGDNE}uhSDJ$nv*CQlfiHt+3pfy@ivJKA0m5pxezS+14athZWDm0x|htFA#1t zlPF&!eQ}R&X{&@@m`2l+9`|kXzSi*O#}ekoA$acqhNwNW2p2?tOUiBe)gdxaidJIs z=HFZ&atM+WEpYu$2*TA)OoUr~ASs%%3JHmYNwf#C? z+ee}G__|Jm7|d`ni_+X-5<8hY$p%VnQD)s)WS~8>OyFV-erYR6ErHYW5h>YG^Q~XE z)2CzSk%{x}6r824ZKG2hV7?e@CPA2*PcQ1>3a%-_r90rq7bz-KozIJt^_92dp>-&n zs`Jt3NLfdg=H2km;%M&WV~pIPNUCd*f?o1g7&oJI-ZE9sFUCfwa^6>seN+SAmbEox zbl~A~+BK!(0Q8H+C*&U?ts3RVar0e*%_DNO-8sQM=M^7on&VMDHU8l^-1{0iT7&bwM^rVRlG~%D z_*hE;#B7a!7~bG%c#ccK9GcJQ z+h|J)(lPhw{ygq}J`IN2%K1sE8~ca4=7SP(W}W^FQ-%fQ;#-(Zuw_p3E)TZ=WE@cg zGE+x@%mCGgctXVC^BnbIuY)vtm(O?rL^o}jV%!qN>L&#i>Xi;R#J-ZqX{tLq#z?&u z`~9i#mZA(Tv;5{G(X9#%HGx*59Xx&fJfux9k z7b;-yXykd|2Ch1c6IF$NM{A`|F(#e^8bkws5q(X}z=?v_M^POvGQ@YfE@%k@)c>u7_Iy^Hs;eiujg~dcL0$DiC-$oXi z!6xSIif4!aR?tgdptf)r&23tlFC-gdaKa(_iq>J9NS(CG7s~mG+6VpTHTd5W*o)0b z!IR;$2p8`6WY1w)8VQ-yryD_%4M-~7d@|D!&@&#N!az6CF^Lxvm_QW{)hb#|L)mJM zFBR(->$|b@z_H8%DNp|lo6kF*zqs`8eC}EZhZ{j4;nN~}&F3?4>WeYYI)9NKq2rk- zXO{DudvX3E9oA^QnLuymh&oB)%tq^thu%yUb-E?gIgj3q6m?EXsM8H^6zyH}BD{p^ z-927S)jl&Nddg=!QWx~(+rE56jp^m`30uYE_C_K;f^A)-#gyK!Xy0H>Q;orM#$cn5 zd4oRnV9OZYf3V>Oeg45lM3Qm*y&{c%4@WQ5nR_+*oCl&ry~8^|(|9WdH{k+bV*+of z2XS~=Qnsx7tD!3Av_iM0UsKj^Y=O!RJ=;yOn6XCgOqc)X*hAZZeMjiII&!U3dcgiv zJpU}r#kL|SX|0Mj3a0WXQ_*i|QM4Oyn$juw1dK_WF|L3ufakZhpget9NE!`g7GRDL zV7^}TCU(_;@zDhWj*(vYA0GI~T}PYsy>)1dp;5J|I1N}MxD$8UJMvZH_*?XOB@maZ zd7lP#L%8IX0f`DJa&3JIlYQF$@K~Ik_IG#ADtAe}v^3-`IV3GzpSiv)4;w&mxX8?6 zRm)!%AM*6_;DV3gV9G@VJiCI(bY$K0q4h5Z5uu!0;V2o3@%2YLntH~Zv(hEFd7oX(y;aRKHa~f_k2>L~CE6{iA6AE8wWG z4>BlH3eQ73kzVl@C}9c78cRaqmkI6Vs%FaD%&~_0B3MP;3QQe{7p8cWUXV%rfL|D? zfja!A;Ws4fSIYV?L7Dh0i57r1mXoRK3T)V)fw8h=eJ);IDdUJSS-S;G#uzLfBQu$} zwO`P0ovi%=rRnIgU!X>y0_=g7s2aAJRyE4O^#f>MP3b&{Ughw6KKK3#cL@Rhux~~2 zSMKC0sbnN6Q26pB2s96uKF@wB_)mQ7XsnU6j#N8Y@1YD$t&tXw##<;5*pGYz2IIr| zZ#Q5tzB>G3FustY!y)ifbe#tfd;moTh%m}2mxzuan*`Rr4kj0V=A!{K+wNb0fa~$4lau=1(ri!VK7>zNf=i;hpvPphr9g zjg`>%aKiX93Gs(Mv)IW$KJ6gW*+Y0sbfy4JKp991V`hY6%uG@#3ZKeNgy5?HY7rOI zCst=5m7zLK(T5=tIk_6c8mefw;-?UFH34+R7{uy>;zU?P9iZ+p|rdIom zu>){up8$f7>K1SqGl*++0!5fB+Ag1dHjW;_99YL}KOr<)gMTz56BR)J%Rqty=rX$1 zKNwQe3%kKslZi>N)*IDxX5mE&1YWRe01S-4eno3>CJ@CdD4rG>XHr7qjWs5|=mLK) zlZ}b*LBg2v3CDcn8;T(?gYnBo)pM4t9WDIaiEn&o5AUVLH}eF}ES5dsXAj?$4gsK$ zfyIiEjwAX@Wr7>GKHRP=2K~dZ0617$VdA_&4=^~QH$~eP8Dot{)}J7w(i)`Cg98wg z9)ql?Ql;EFp-uWc&3K4jlGfv4gS=?XAk?^I0BoCwdhu$wQyqv?CR^m!x4b3(;Zsmx zX(}c!YNL`548?-k4b4lx3!%Mi>322R$u&69yEwb#5KeqqPd!T`TV?6`Mm!0m(t$bK zA~+%pIxxM{7Oap;-sUkdz-R;+NVtcvPzN5MbfSSUAJ)s#sP!b^ONhIm?w$c#0gH-% z8>kdo4K6^Y0r0(l8;BzS(KmP-=n|*1v+xU4pblQ_ln?L3^1cdp*U84Pb=Y8iG*i+1 zM>6RObm~8nL06z!|B6X&V1;P!;~Y~ofKwz#qa;e;<62qUxmdkaigR6E;X_Q3(8pARC52DJr?z18e@Rlq z7#-D)#M*cf<#9qi$rGRU9`ubAtOjv?BU%@yMyz)j@Eo@i#ncR2C9T>nAI7<%jKCu_ z{O#ajjGV5Bk&n>uw}YDp9|1Sh$R}^d{|0YIE922hNFWlT7fQzD1889~n!y!Xn2cs{ zg%&2G8NJ^Dh=>EItWq=mj_}$y3m5^}9k8g=LL(pbqQQ5p=Yc}ULpPNnojGNB&~otc!VjXxgYKNN1-P3uK-_l0 z<#>8Tw^)*sf;C-p$^ulPh#z%Zjwx1f^1^G>ku^mnlhB`Bg-JAqX<3I7@yosS!?#kY z!I}YW$U{3E2(#u3NY7fPWyAWbo?9A~;5#nk0f0N0ZY#ts zz`do69?`8F3?-??YVr;l4|G*MkJ6R>5?`bPV=10c;3bQK=rkk@0b9$D+rXy-_?)t& z{yxv-Yq>)J+}H+OzlX2I1wOSa5{BoX66=@5;=$K|6q0v>p1e`m3nZ8nVkHfB<5B4^pUMT{gxI*FEAAyW7cnK25r z{Pk&Ai0iTb=Aucgzlt`dRV*4~TJRgfJuDodjVKz`9n+|2Bx{Sk0fB<#SAJLr+y1FUTr%&EQY_f^y zdlSaF3GXpx(u-z8DVzkQkn|@YLz}pXF6!ul37Rfq6pgWN!hqB9P211_l6;G&0etzg zQj+EgQWuJ`Qner72VF{wg94LX7az&cMx*^wS{7wK1x$QVK|?Z@Udl_LgI;vImb=9b~39Y()eq*xCC)uCwNkI6RDab_|!;#}SPv|0ZZ zAtApUijz;<6S>4m0a#A>6ksZ^z0buTMRB3)u}%f`TMDkjvq)FyLeR2ct>;0+vR@yr zPoK6cq9V@}YCH@Km&xhEVX93I%T>bRuXt$qLkdC0eBtm9|PH$3cOx zD`8XiBg<&FGSt7ju@GNTPTCD|xf_!pn#VOJLNt%-WY}lBF(Ye)Qf+l5w+eM#ZV~Fb zYzlQB1nRmB{h16{Behy8xf*k>YHzDr19e;>1uw<}C%Up-uob?e+3{$W zs2v#(Q8(Pd2KtJ^^gJpLom~OdrXUoib3L-Q!`U3J$CXe7-0vpJ|Iz|^-SA2Hs zKK;I0lYnheJ#d2W0;=AzY_%f+1~zprEMe*_ABTUSP{CJp0t~!{9NNJLjxZD48-S)} zefoSFIRxBMM`M2zjit=(4G%p|4B8Osi!ucVaLx%(iuycwdWY!_0mNHrMrD04w(Lx< z0uq`?nSg^2z?oA-W2dP)e|&dtAGAl`x{c5tJL_RVM11|0(Ga4>6rA60op6s!LPaqs zXO5~56MYcrfNG{zC7^;Oz?XhT#p#4?A{aPUghdlMlQ8lbW8_;bazvgqi#RQW$HeYX zqRe5SOn(*d0*5V}Y=mTPd5LJ*ftNE-hVZf%D+hgaTFWnHv{(ez4lQ(6u|P}Ilr1RH zGYz<6?in^-@cH!*?WYBw3B=?9<9Tq*lS2sQ2~w=4&_0~R@uRmv8*k&IH0@~PgF;3~ z-??X5v{4bcAkIOEAMGjF8zU0{1486)VF@NVF`1N#cF&u8fjC%dqZJftw|)}od}xu5 zmXASj$TUN{fjcUY}{0-qgz z;ONr>D=hyUN-RK0+dpT*7|4K)5_p*alMnB}k=3?;j^(T6qPvfz6P?Laf(zAiPzsKR z;{-wlp6^@X1?i8k)`BhjCy&tw!?{1X#lcVJX$2OWpB^Uvp77s#nuI?O@Kla5k`7zC z7Y1bOUI3FmS0)2|{6{)zUs*%OfCeRvziCEqs6-x0iq+Y`hDytUfZRg}*n`rn(aF=L zh2G-niuB+{n3S0ogW}R;KGLU^!>{1O;bc*tr>5{;c+W$`wNQDO*NlEpW4slSi=7hy zQT;8xd0l~Z4>l%pmwbpzmwblFLy)}{JAptca1g-arKJJd>w*R|1uHT{GYHOGF&A@A z1!|-qw!4yXJr!fYNxs9XU;;73k24)*S=1ks~dp-7aA-L=Zl`Dy-5<@B<`j_vz9sZ}CBCA<|Po*H8<512^P8 z%&W4rcme{*04^JbWGxmqXbgR%;Llpo*1E$a&OS6BIVZ&xHE7Ka--_ofyAGLWTuA#i zrIJPD$lH#haeH59jR0u_lTasuPv=3(pksthWg^dNtn`p=6nkPx&x(CV;^JWg2|6R8 z9eoL<-6AkcX@}QK)n24Nk%AiBFW5OXb_;%X<(ku;k(;VI3FNYVEtgwS$wfaQ8p%HHPT+30iaMil41GNU~v?T z#3my2PxLnjQ3C4QqH7o~wDi6Uj5nB9iN3eYZHT~-#Y)RISp+*QD4rl%1_dwHPGJql zdJo%=?vdpm48e5bVhCT%gdUuZ#cgE<0D^utM>Ue_DvN3Gnzs^m3A+JzQeZaJ6IDwQ<;F^wZ^dWRZfqS4L<`LArm53SpJh1ZlX-JiFL&~DIzS!_B zJ#>U*pjP7>2we+4!WW(w|LAk^qR0c|;2cas!|WW~BK@u^xr$taC5U&CXAm92phTpL z4NE<*99}}YE-$GMq|-yYbejJldn-4S(Q~kEDAN+r$rR^W+F1xv!LAX z@o67;%Z36&Nb6JeyOJ@7RMFBgdAf7&V^Vub`eVoyYO9N^6#fPQA!HjQ8=1_AnCk*C zp+W(x_E=s_=COn^mP%;o31fLej0LqZ7R8v)%#5L&!t19{~o0>@{dCO432Ws9Ve3Cce_F8xr z=fKu&fbl#Zu0(xU0~GTHNZ-liN*spJDcrCn1IQhRSQ_nLMXj6RnM4$3@J-UHdg0Zf zPRSEFu?}sd!xK55s?V>(|I+KITh!PX@A*4>gii2Scop1XU@7!Rq!|1I3^hwWptb8E z#WrK8;Gb;xwGxI4KM&Lq9xguV*{bNXQKF~?KGjVCh@3#|7V@o7G}ztNDz0ebQ9?Eq z4U^kc@HiYp#Mp_froE$7eVzoz5J@b>{SL$liC|=mkzY`(UqayOEQzgE%vvZY>^g9d z^w29937kPBWZ(=6agaA@DlLteB}^F(dtv_%MnEejRstXt))JNpMeD0T4MDrChQQsy zz8zjBFf1yN3Xdex1wO(Oy;-i>58uua^s*Hc!lmUKMLl@CJf8H zhXoKolPYD;4U@{?I*>vgo(>Y;6ZS!`z+mc78nGlj0A;{0$cV%>dMfx6pD7xXw^+k1 znDNOe8{XIU6TJ9uFRl0w`x>O+Wf($u6Q0K_m<^YtxWZr4Go#Oa<>b<6Qnf?obGNbM z;!^R%d{o??ja%A=u8Z4=d|PWiK7|SozxelDr{*`dvm;#;3ve-HvwUfOjFRjuxkI!> zU0ruOJ4@Ipk_?(KU)(_uHksjRl;Q~bZ|@ITM$@Qy-z0J&rY1!rmYmTO!RyYFGb-SP zD92tdsF-DOS;p-L7rY5k_%141`5AN~J!yI0m7j4FrmY6d<*!Mj1cuAl;h;DZG%{^} zJK`n10dj1duphKyBIZ7d?rXc!2{z-l0 z>~{FWc%1nfaBlbyQJr=P8>&dyz>k%%fl<%^AVsYjUlpc{kx}b%j^%62bWy$rl*$hI8W2U4uVLqB)ZrF(?g{L> z2Ft!fi3KRx(Y|Y!dr@H-c7G#57+kOd#7Cb@huS9vXT!9EZUkW=r$K99s0>wW(xk=D z;k}hjHA98>24v7&cP2XhT4ILC8p;S_`u21D02nJ7DoDZQ9o{#^<;3E~vpz%N~(&&(G zf@XVDu9=k8&% zS)_NIDd0hZ4S`+f`Q=jZ@520AD03!(uYo=op-;dVDDX)0!Z``))s$CBb~kFhjq z7`RAS;MtQYVF9s=YD^9#l&IPhvoUCVlL1ZRg+Yrl=8=|S*ggECiRg~T3KZufAUHfA z%i*i#^~;k{cn;^ogfO2X9|r7mxsA^(g!XaT3KBQ9uOKzvMlJ%G3KMsr2`+9g_N3&{DZo+#h^9LKM;lo z4v42Gz+5p>;3D1_f5RqQZg~t4mt(G>BXnRtP(lG26(3nfg_V48L>LuMBa0kKz3RYf z^29lf3VG2nD#95DFe*gG!AHnAsLf7>+D91&(Rju|3*=cV9paQq+56k}s{=vuHK+!u zQ6ZH)!9a@?32ni0KqHmBk7rn6?5qReFP?SqV@x1a2+BGj!Po$fp{#?!_?y^(i6+7c zgizwtSdPIQ++9P8EY63fe1iEcRzAUe$|pd!5xBmE71>xmL737*fkLdWspHyqKzm5S=PTBEd{N51)q$acV)nkHO66)84|42dN|-uaSZu z)xL`56a0dkdxlt4Bup8`c78LZjr|fnk(8a3l2X zDiTbGA)AJg=pn=)=L&JuqmY?|7?rB@Yat&T<*Ojaf`kogU|>18fgM=@FmGa1hIbX= z-@+n5$ej`bV6YGZ87<%k?LCnXFe!~Q04T!F;eL@2@Bk$QWYZ%%ApoIutHdPnD0Dle z15{cFr``zJC9jbUf|LOG{S+q;J9{G)5ql*w+SV)JWW?8bYQytURear+asmkNv77+t zt0Er&83WFIfaZ8UK%E`(N9)K3_~mj=2DqideoW4L$^@tiylTxoX95uM_qAXKF%!&8 zZ&p6Q2<{NTnv@T)6FajAUQ2ER!T)sR0~F4KG%b$XKXyIVd zAecN#2e=6u3`PEb*`jDrwS_^(x^*np&(amKeUunuir9X^2mt_vcU$_s zGoG(l3O+q`QNa_GwB!^>A|_9! z7jtJUCXd)bxuWIvN5?|q>%0trwEKg!llp^p%GmBYCOzbV4+VDDB(S3ugeL_IRXO!8 zwLj32q)l_&5bn@jKEvM)@Y#rYUgv;MFQ@$qpoVh~L;I>(?Jkmct7pz~9 zy@TCHT9`|JaF9wP&}7Bd5o30tfe3Q=4~y7(5A+VzpH+0Yu@voSHF;oxsvg zRJU3ZG>lcz!1s5I)HaBmHY9Si0Z09ILbutOjPh-1!0662siXiCLdy_>53f|RD zp5izIEGX9l-PfB~>syc`ioTHE#qn^&!i}*e((KfscQwn}=7NSWWr2}}@l}|NY@x{z z#>|`g!bDrNfea{T(AVhmi^Z{c_)Fta#^`fJ{K@0u$vNVQX^7jO^6i)ApKj#xzriiV z!=t#3zzfsoL4HtU-gc7}3_k^1H}L$~MYetT^*B6WyN~Q`bLB=%2JF7CZgvL4Ax{(S zzu@PHcfZ9+@CU8Mupu%#P9fyKrT9P{7`B1zbSZcq#)~+|L2O6aV=-%GoLMW-$_gZ2 z1HVYRz7eP$ghe13c{O+fuO#ntAdNf^CF!+W(TT>9=7A_tgQM<@(+TAu$`bFrEHr9g}WF} zpkIo?42$}aFM^Qwesovp^LaKD-aO72JQZ9NQjPu#Z_w{Mn2e1bdjR`UAORU$+Gk_* zVFwWy+G8ejhf>LhB>bJ|Df@`HAh=;jB1t@3%*H~i z?G$OCw;@-bgSk3ve%8N-OCLL^B;-Fmh}^H>P`AG)zC~A^P2ZyH8mv#!#tuRpznM<7 zqKHS&{rEWb0B-|c=4yq5#I_LYNPK(0@8_8P5&tEhRQ@>~!exC@`M(kVU$(jbtKmO- z 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

    y-<17}8+BD`2*H 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

    E#m^J`nTt6JvfjR~}^uV~@M1 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 qDL&jYDZ?>w^3+}s=6300{q{LrE10 zoz>nwi?WApFF$N4xo~I+TFUzXudRjR@t@~697pzCC|tzmh2EsySmr+?Rm$GsfJ_TYQ=Te){D6D{TS(965!)aA)xC+|yJcQo!hWs|aZEk|Q9i(1-+GBI0O zV2ByrIlw_u#Egb!QEzwEVYpI}Q|w}+9HY;47d-ccKUBO`4djus(zJBHRp_MZWxGE4 zT-t?6t>?R{U9fmM624eu_DFPfX+7W0yB>kJJPaG14TvZ1-(vi=tUvBVw~ejb$4OPw znl0<0MZc0Rb7rM#m#l}3`6>K|*!XsHXX${k`N^0#-UbMJ|6mGq;{23|PY(Luk;TAA zox^Vmul|g=^AoG*v#_&oaf$?)NLtNU+{&0)7=#EtDQ zZzgtKDJd9-PFL7j_m>lHVYS1LR0y>iK&>WYDaO6m>PJa1*q`zas53sH^UDrj58r&_y3ZG zqF0f}6tn9;Wogo@CeMS?0e-W3-e&-@N&;PK0*&+$9o3Z|0tWniFrL^xwZ4Z znBnHv(1JBF z;u3>PeostUe@Ax4yN-*k-xJr%LOalGcq;~- zn4I3RUuY%srM`;`<2#7(Emj8PHfW`6msoLk)yifRGgT4dYDEaOA1BDS4+}X7@{}s+ zpT81XHH+H=f@~L%BjI5ReMsRc_JhJ`k?IdvxWHjJve^?bHEsM=R7O zL}HpGiuk5xwrpScUiNA=O$d62ImO1>sugue}F(WeVQJJp#s zg@;QGc+-G4)szmYDqW=GJ+;D_;$fDIpZliq1{5E8Rcpk!QK3NlzZ#?J%fv(S1O z3X#wH6vxjg@>ytooAFs6Yx()p2jl2G*#Oa(as+8mAO?*K1k?1x{~vpA0v%PAwGAhb zK!`vE5yb%sf&$_|ln4k&N~T*bN5qc*wfi(xHqzd zaxYw4d!%4t!jET zP1;_oV|QwMf@;)Vq$i=c*J)3byyrmPJZ9oW)T|Vdb^5tx8^8RV+eqwyT~UkDTQf`2 z8+lbJTYR@6f;mre8wnXiZ&*S~GpUW^namRUM3W5(xtYx3AKfHc{O5pd7)sd$Re`~y z#)Z`4z4q-;g$T*~uD_WAe$YAwk7bA|Xe`S*OX>cFXs#o>jk}pIrms0Pjb*oQE;~Na zeS2P^GBVIug-pf`EhPk~;lI{)70(vtGPpm4z>&F#qtzAp4G2(Jg13^L<8j zg!zuAgnx5#4F0J@p46(YXqDpMG|fN5Zj+eIoVisBIxfSUW3yDqS5G*~Ij$-B`~gcR zL^7bkejg}%S|FN@hp?o_5JOhe2m&_lA)!RDG4}p}wohoDME$&`)&e$~ z48D^8Sb%y~oraK%V%i~}G7l*@K|9zsual+4ez!3X%ehJVpzODgJAEIUyli6gIQvFGh&7d@ zY3!(+tras~5`N76ei3(ASTY4)_r9IX6o0yM+^KeU_iNY;L$^e~W z$8CSyj^*3*v(QaPv)|ZBeOow!NWNl=FD#n`=2v>hTZrk;G9hBhG59e@#rI%oGhCtS z?Q@yTjJ^NYWN;xo}J6)nKO3Sb&nDwidkU=IsJGuYG3KNaOY;PB_wRK zE7ZxFyPj;%*!gtcHx9+?bHBF@`RTloJ2M+;BxR%3a{-}MDU6Os$&`b7- zzq!QrnF^az_KBIMwofuuWuIiK%09_d#Xhsn$1U4qAPb)%3W({^Tq2MmwtNY0`^arC z-1d~)%W&IGZhPZ4Rc`y>w!Pe977|F2Tk-};a(e}C zP$BF-zMG=RhAvfsZ1{&74Kc>p#R4f;cCZoGx{_}Algmb z8>7Bn0?}^bdJQq`q>VtzRFhWW5BYMxjf(dBxntT*oDo$@gZ-gEw3|47k7AEgQG>li zAlglQ6$Pociv?1k+Oi=Ae+a1jBGG6Z(2pjh+8q;oaOaM<