From 20ddbeb528297992fc6fab44d83ac3a15caed163 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 13 Aug 2020 00:09:57 +0200 Subject: [PATCH 1/8] implement optional fields in function pattern matches --- compiler/gen/tests/gen_records.rs | 32 ++++++ compiler/mono/src/decision_tree.rs | 6 +- compiler/mono/src/ir.rs | 172 ++++++++++++++++++++++------- compiler/mono/src/layout.rs | 29 ++++- compiler/mono/tests/test_mono.rs | 77 ++++++++++++- 5 files changed, 264 insertions(+), 52 deletions(-) diff --git a/compiler/gen/tests/gen_records.rs b/compiler/gen/tests/gen_records.rs index 577538db01..ad3339d026 100644 --- a/compiler/gen/tests/gen_records.rs +++ b/compiler/gen/tests/gen_records.rs @@ -399,4 +399,36 @@ mod gen_records { (i64, i64) ); } + + #[test] + fn optional_field_use_default() { + assert_evals_to!( + indoc!( + r#" + f = \{ x ? 10, y } -> x + y + + + f { y: 9 } + "# + ), + 19, + i64 + ); + } + + #[test] + fn optional_field_no_use_default() { + assert_evals_to!( + indoc!( + r#" + f = \{ x ? 10, y } -> x + y + + + f { x: 4, y: 9 } + "# + ), + 13, + i64 + ); + } } diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 536fc8f937..d2099e515a 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -409,7 +409,8 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V arguments.push((Pattern::Underscore, destruct.layout.clone())); } DestructType::Optional(_expr) => { - todo!("test_at_type for optional destruct"); + // todo!("test_at_type for optional destruct"); + arguments.push((Pattern::Underscore, destruct.layout.clone())); } } } @@ -542,7 +543,8 @@ fn to_relevant_branch_help<'a>( DestructType::Guard(guard) => guard.clone(), DestructType::Required => Pattern::Underscore, DestructType::Optional(_expr) => { - todo!("TODO decision tree for optional field branch"); + // todo!("TODO decision tree for optional field branch"); + Pattern::Underscore } }; diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index c3a52c3349..30a2e7088e 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1399,13 +1399,20 @@ pub fn with_hole<'a>( for (label, layout) in sorted_fields.into_iter() { field_layouts.push(layout); - let field = fields.remove(&label).unwrap(); - if let roc_can::expr::Expr::Var(symbol) = field.loc_expr.value { - field_symbols.push(symbol); - can_fields.push(None); - } else { - field_symbols.push(env.unique_symbol()); - can_fields.push(Some(field)); + match fields.remove(&label) { + Some(field) => { + if let roc_can::expr::Expr::Var(symbol) = field.loc_expr.value { + field_symbols.push(symbol); + can_fields.push(None); + } else { + field_symbols.push(env.unique_symbol()); + can_fields.push(Some(field)); + } + } + None => { + // this field was optional, but not given + continue; + } } } @@ -1643,11 +1650,22 @@ pub fn with_hole<'a>( let mut index = None; let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena); - for (current, (label, field_layout)) in sorted_fields.into_iter().enumerate() { - field_layouts.push(field_layout); + let mut current = 0; + for (label, opt_field_layout) in sorted_fields.into_iter() { + match opt_field_layout { + Err(_) => { + // this was an optional field, and now does not exist! + // do not increment `current`! + } + Ok(field_layout) => { + field_layouts.push(field_layout); - if label == field { - index = Some(current); + if label == field { + index = Some(current); + } + + current += 1; + } } } @@ -2670,8 +2688,15 @@ fn store_record_destruct<'a>( env.arena.alloc(stmt), ); } - DestructType::Optional(_expr) => { - todo!("TODO monomorphize optional field destructure's default expr"); + DestructType::Optional(expr) => { + stmt = with_hole( + env, + expr.clone(), + procs, + layout_cache, + destruct.symbol, + env.arena.alloc(stmt), + ); } DestructType::Guard(guard_pattern) => match &guard_pattern { Identifier(symbol) => { @@ -3173,6 +3198,7 @@ pub fn from_can_pattern<'a>( destructs, .. } => { + // sorted fields based on the destruct let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena); let mut destructs = destructs.clone(); destructs.sort_by(|a, b| a.value.label.cmp(&b.value.label)); @@ -3180,40 +3206,100 @@ pub fn from_can_pattern<'a>( let mut it = destructs.iter(); let mut opt_destruct = it.next(); + // sorted fields based on the type let sorted_fields = crate::layout::sort_record_fields(env.arena, *whole_var, env.subs); let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena); - for (label, field_layout) in sorted_fields.into_iter() { - if let Some(destruct) = opt_destruct { - if destruct.value.label == label { - opt_destruct = it.next(); + // next we step through both sequences of fields. The outer loop is the sequence based + // on the type, since not all fields need to actually be destructured in the source + // language. + // + // However in mono patterns, we do destruct all patterns (but use Underscore) when + // in the source the field is not matche in the source language. + // + // Optional fields somewhat complicate the matter here + for (label, opt_field_layout) in sorted_fields.into_iter() { + match opt_field_layout { + Ok(field_layout) => { + match opt_destruct { + Some(destruct) => { + if destruct.value.label == label { + opt_destruct = it.next(); - mono_destructs.push(from_can_record_destruct( - env, - layout_cache, - &destruct.value, - field_layout.clone(), - )); - } else { - // insert underscore pattern - mono_destructs.push(RecordDestruct { - label: label.clone(), - symbol: env.unique_symbol(), - layout: field_layout.clone(), - typ: DestructType::Guard(Pattern::Underscore), - }); + mono_destructs.push(from_can_record_destruct( + env, + layout_cache, + &destruct.value, + field_layout.clone(), + )); + } else { + // insert underscore pattern + mono_destructs.push(RecordDestruct { + label: label.clone(), + symbol: env.unique_symbol(), + layout: field_layout.clone(), + typ: DestructType::Guard(Pattern::Underscore), + }); + } + } + None => { + // the remainder of the fields (from the type) is not matched on in + // this pattern; to fill it out, we put underscores + mono_destructs.push(RecordDestruct { + label: label.clone(), + symbol: env.unique_symbol(), + layout: field_layout.clone(), + typ: DestructType::Guard(Pattern::Underscore), + }); + } + } + + field_layouts.push(field_layout); + } + Err(field_layout) => { + // this field was optional, and now does not exist + // if it was actually matched on, we need to evaluate the default + match opt_destruct { + Some(destruct) => { + if destruct.value.label == label { + opt_destruct = it.next(); + + mono_destructs.push(RecordDestruct { + label: destruct.value.label.clone(), + symbol: destruct.value.symbol, + layout: field_layout, + typ: match &destruct.value.typ { + roc_can::pattern::DestructType::Optional( + _, + loc_expr, + ) => { + // if we reach this stage, the optional field is not present + // so use the default + DestructType::Optional(loc_expr.value.clone()) + } + _ => unreachable!( + "only optional destructs can be optional fields" + ), + }, + }); + } else { + // insert underscore pattern + mono_destructs.push(RecordDestruct { + label: label.clone(), + symbol: env.unique_symbol(), + layout: field_layout.clone(), + typ: DestructType::Guard(Pattern::Underscore), + }); + } + } + None => { + // this field does not exist, and was not request in the pattern match + continue; + } + } } - } else { - // insert underscore pattern - mono_destructs.push(RecordDestruct { - label: label.clone(), - symbol: env.unique_symbol(), - layout: field_layout.clone(), - typ: DestructType::Guard(Pattern::Underscore), - }); } - field_layouts.push(field_layout); } Pattern::RecordDestructure( @@ -3236,8 +3322,10 @@ fn from_can_record_destruct<'a>( layout: field_layout, typ: match &can_rd.typ { roc_can::pattern::DestructType::Required => DestructType::Required, - roc_can::pattern::DestructType::Optional(_, loc_expr) => { - DestructType::Optional(loc_expr.value.clone()) + roc_can::pattern::DestructType::Optional(_, _) => { + // if we reach this stage, the optional field is present + // DestructType::Optional(loc_expr.value.clone()) + DestructType::Required } roc_can::pattern::DestructType::Guard(_, loc_pattern) => { DestructType::Guard(from_can_pattern(env, layout_cache, &loc_pattern.value)) diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 8ca6734b8f..64f21c3616 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -366,7 +366,17 @@ fn layout_from_flat_type<'a>( for (_, field) in sorted_fields { use LayoutProblem::*; - let field_var = field.into_inner(); + let field_var = { + use roc_types::types::RecordField::*; + match field { + Optional(_) => { + // optional values are not available at this point + continue; + } + Required(var) => var, + Demanded(var) => var, + } + }; let field_content = subs.get_without_compacting(field_var).content; match Layout::new(arena, field_content, subs) { @@ -414,7 +424,7 @@ pub fn sort_record_fields<'a>( arena: &'a Bump, var: Variable, subs: &Subs, -) -> Vec<'a, (Lowercase, Layout<'a>)> { +) -> Vec<'a, (Lowercase, Result, Layout<'a>>)> { let mut fields_map = MutMap::default(); match roc_types::pretty_print::chase_ext_record(subs, var, &mut fields_map) { @@ -422,13 +432,24 @@ pub fn sort_record_fields<'a>( // Sort the fields by label let mut sorted_fields = Vec::with_capacity_in(fields_map.len(), arena); + use roc_types::types::RecordField; for (label, field) in fields_map { - let var = field.into_inner(); + let var = match field { + RecordField::Demanded(v) => v, + RecordField::Required(v) => v, + RecordField::Optional(v) => { + let layout = + Layout::from_var(arena, v, subs).expect("invalid layout from var"); + sorted_fields.push((label, Err(layout))); + continue; + } + }; + let layout = Layout::from_var(arena, var, subs).expect("invalid layout from var"); // Drop any zero-sized fields like {} if !layout.is_zero_sized() { - sorted_fields.push((label, layout)); + sorted_fields.push((label, Ok(layout))); } } diff --git a/compiler/mono/tests/test_mono.rs b/compiler/mono/tests/test_mono.rs index eba781c146..92e0c9a479 100644 --- a/compiler/mono/tests/test_mono.rs +++ b/compiler/mono/tests/test_mono.rs @@ -710,7 +710,7 @@ mod test_mono { x : [ Red, White, Blue ] x = Blue - y = + y = when x is Red -> 1 White -> 2 @@ -747,7 +747,7 @@ mod test_mono { r#" if True then 1 - else + else 2 "#, indoc!( @@ -774,7 +774,7 @@ mod test_mono { 1 else if False then 2 - else + else 3 "#, indoc!( @@ -807,7 +807,7 @@ mod test_mono { x : Result Int Int x = Ok 2 - y = + y = when x is Ok 3 -> 1 Ok _ -> 2 @@ -1037,4 +1037,73 @@ mod test_mono { ), ) } + + #[test] + fn record_optional_field_no_use_default() { + compiles_to_ir( + indoc!( + r#" + f = \{ x ? 10, y } -> x + y + + + f { x: 4, y: 9 } + "# + ), + indoc!( + r#" + procedure Test.0 (Test.4): + let Test.2 = Index 0 Test.4; + let Test.3 = Index 1 Test.4; + let Test.11 = CallByName Num.14 Test.2 Test.3; + jump Test.10 Test.11; + joinpoint Test.10 Test.9: + ret Test.9; + + procedure Num.14 (#Attr.2, #Attr.3): + let Test.12 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.12; + + let Test.7 = 4i64; + let Test.8 = 9i64; + let Test.6 = Struct {Test.7, Test.8}; + let Test.5 = CallByName Test.0 Test.6; + ret Test.5; + "# + ), + ) + } + + #[test] + fn record_optional_field_use_default() { + compiles_to_ir( + indoc!( + r#" + f = \{ x ? 10, y } -> x + y + + + f { y: 9 } + "# + ), + indoc!( + r#" + procedure Test.0 (Test.4): + let Test.2 = 10i64; + let Test.3 = Index 1 Test.4; + let Test.10 = CallByName Num.14 Test.2 Test.3; + jump Test.9 Test.10; + joinpoint Test.9 Test.8: + ret Test.8; + + procedure Num.14 (#Attr.2, #Attr.3): + let Test.11 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.11; + + let Test.7 = 9i64; + let Test.6 = Struct {Test.7}; + let Test.5 = CallByName Test.0 Test.6; + ret Test.5; + "# + ), + ) + } } From b05e126d7891963096dcadee73ebd93e8a43a32f Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 13 Aug 2020 00:19:01 +0200 Subject: [PATCH 2/8] add more tests --- compiler/mono/tests/test_mono.rs | 77 +++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/compiler/mono/tests/test_mono.rs b/compiler/mono/tests/test_mono.rs index 92e0c9a479..29ae1b8129 100644 --- a/compiler/mono/tests/test_mono.rs +++ b/compiler/mono/tests/test_mono.rs @@ -1039,7 +1039,80 @@ mod test_mono { } #[test] - fn record_optional_field_no_use_default() { + fn record_optional_field_let_no_use_default() { + compiles_to_ir( + indoc!( + r#" + f = \r -> + { x ? 10, y } = r + x + y + + + f { x: 4, y: 9 } + "# + ), + indoc!( + r#" + procedure Test.0 (Test.4): + let Test.2 = Index 0 Test.4; + let Test.3 = Index 1 Test.4; + let Test.11 = CallByName Num.14 Test.2 Test.3; + jump Test.10 Test.11; + joinpoint Test.10 Test.9: + ret Test.9; + + procedure Num.14 (#Attr.2, #Attr.3): + let Test.12 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.12; + + let Test.7 = 4i64; + let Test.8 = 9i64; + let Test.6 = Struct {Test.7, Test.8}; + let Test.5 = CallByName Test.0 Test.6; + ret Test.5; + "# + ), + ) + } + + #[test] + fn record_optional_field_let_use_default() { + compiles_to_ir( + indoc!( + r#" + f = \r -> + { x ? 10, y } = r + x + y + + + f { y: 9 } + "# + ), + indoc!( + r#" + procedure Test.0 (Test.4): + let Test.2 = 10i64; + let Test.3 = Index 1 Test.4; + let Test.10 = CallByName Num.14 Test.2 Test.3; + jump Test.9 Test.10; + joinpoint Test.9 Test.8: + ret Test.8; + + procedure Num.14 (#Attr.2, #Attr.3): + let Test.11 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.11; + + let Test.7 = 9i64; + let Test.6 = Struct {Test.7}; + let Test.5 = CallByName Test.0 Test.6; + ret Test.5; + "# + ), + ) + } + + #[test] + fn record_optional_field_function_no_use_default() { compiles_to_ir( indoc!( r#" @@ -1074,7 +1147,7 @@ mod test_mono { } #[test] - fn record_optional_field_use_default() { + fn record_optional_field_function_use_default() { compiles_to_ir( indoc!( r#" From 5ca843822fcb80d502b3d6fe9fc236abdaf8b8ee Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 13 Aug 2020 01:39:59 +0200 Subject: [PATCH 3/8] implement optional fields in let bindings and when --- compiler/gen/src/llvm/build.rs | 5 +- compiler/gen/tests/gen_records.rs | 78 ++++++++++++++++++++++++++++- compiler/mono/src/ir.rs | 81 ++++++++++++++++++++----------- compiler/mono/tests/test_mono.rs | 32 ++++++------ 4 files changed, 144 insertions(+), 52 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 3f83cf61cb..f9a22e518a 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -274,7 +274,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( FunctionCall { call_type: ByName(name), - layout, + full_layout, args, .. } => { @@ -287,7 +287,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( call_with_args( env, layout_ids, - layout, + &full_layout, *name, parent, arg_tuples.into_bump_slice(), @@ -296,7 +296,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( FunctionCall { call_type: ByPointer(name), - layout: _, args, .. } => { diff --git a/compiler/gen/tests/gen_records.rs b/compiler/gen/tests/gen_records.rs index ad3339d026..08f509d7e7 100644 --- a/compiler/gen/tests/gen_records.rs +++ b/compiler/gen/tests/gen_records.rs @@ -401,7 +401,81 @@ mod gen_records { } #[test] - fn optional_field_use_default() { + fn optional_field_when_use_default() { + assert_evals_to!( + indoc!( + r#" + f = \r -> + when r is + { x: Blue, y ? 3 } -> y + { x: Red, y ? 5 } -> y + + a = f { x: Blue, y: 7 } + b = f { x: Blue } + c = f { x: Red, y: 11 } + d = f { x: Red } + + a * b * c * d + "# + ), + 3 * 5 * 7 * 11, + i64 + ); + } + + #[test] + fn optional_field_when_no_use_default() { + assert_evals_to!( + indoc!( + r#" + f = \r -> + { x ? 10, y } = r + x + y + + f { x: 4, y: 9 } + "# + ), + 13, + i64 + ); + } + + #[test] + fn optional_field_let_use_default() { + assert_evals_to!( + indoc!( + r#" + f = \r -> + { x ? 10, y } = r + x + y + + f { y: 9 } + "# + ), + 19, + i64 + ); + } + + #[test] + fn optional_field_let_no_use_default() { + assert_evals_to!( + indoc!( + r#" + f = \r -> + { x ? 10, y } = r + x + y + + f { x: 4, y: 9 } + "# + ), + 13, + i64 + ); + } + + #[test] + fn optional_field_function_use_default() { assert_evals_to!( indoc!( r#" @@ -417,7 +491,7 @@ mod gen_records { } #[test] - fn optional_field_no_use_default() { + fn optional_field_function_no_use_default() { assert_evals_to!( indoc!( r#" diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index fa4ebc7c79..a0c7ebaf17 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -467,7 +467,8 @@ pub enum Expr<'a> { FunctionPointer(Symbol, Layout<'a>), FunctionCall { call_type: CallType, - layout: Layout<'a>, + full_layout: Layout<'a>, + ret_layout: Layout<'a>, arg_layouts: &'a [Layout<'a>], args: &'a [Symbol], }, @@ -1849,13 +1850,13 @@ pub fn with_hole<'a>( arg_symbols.push(env.unique_symbol()); } - let layout = layout_cache + let full_layout = layout_cache .from_var(env.arena, fn_var, env.subs) .unwrap_or_else(|err| { panic!("TODO turn fn_var into a RuntimeError {:?}", err) }); - let arg_layouts = match layout { + let arg_layouts = match full_layout { Layout::FunctionPointer(args, _) => args, _ => unreachable!("function has layout that is not function pointer"), }; @@ -1872,7 +1873,8 @@ pub fn with_hole<'a>( assigned, Expr::FunctionCall { call_type: CallType::ByPointer(function_symbol), - layout, + full_layout: full_layout, + ret_layout: ret_layout.clone(), args: arg_symbols, arg_layouts, }, @@ -2154,19 +2156,25 @@ pub fn from_can<'a>( // convert the continuation let mut stmt = from_can(env, cont.value, procs, layout_cache); - let outer_symbol = env.unique_symbol(); - stmt = store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt) - .unwrap(); + if let roc_can::expr::Expr::Var(outer_symbol) = def.loc_expr.value { + store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt) + .unwrap() + } else { + let outer_symbol = env.unique_symbol(); + stmt = + store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt) + .unwrap(); - // convert the def body, store in outer_symbol - with_hole( - env, - def.loc_expr.value, - procs, - layout_cache, - outer_symbol, - env.arena.alloc(stmt), - ) + // convert the def body, store in outer_symbol + with_hole( + env, + def.loc_expr.value, + procs, + layout_cache, + outer_symbol, + env.arena.alloc(stmt), + ) + } } } @@ -2552,7 +2560,8 @@ fn substitute_in_expr<'a>( call_type, args, arg_layouts, - layout, + ret_layout, + full_layout, } => { let opt_call_type = match call_type { CallType::ByName(s) => substitute(subs, *s).map(CallType::ByName), @@ -2580,7 +2589,8 @@ fn substitute_in_expr<'a>( call_type, args, arg_layouts: *arg_layouts, - layout: layout.clone(), + ret_layout: ret_layout.clone(), + full_layout: full_layout.clone(), }) } else { None @@ -2934,24 +2944,30 @@ fn call_by_name<'a>( } } + let full_layout = layout.clone(); + // TODO does this work? let empty = &[] as &[_]; - let (arg_layouts, layout) = if let Layout::FunctionPointer(args, rlayout) = layout { + let (arg_layouts, ret_layout) = if let Layout::FunctionPointer(args, rlayout) = layout { (args, rlayout) } else { (empty, &layout) }; // If we've already specialized this one, no further work is needed. - if procs.specialized.contains_key(&(proc_name, layout.clone())) { + if procs + .specialized + .contains_key(&(proc_name, full_layout.clone())) + { let call = Expr::FunctionCall { call_type: CallType::ByName(proc_name), - layout: layout.clone(), + ret_layout: ret_layout.clone(), + full_layout: full_layout.clone(), arg_layouts, args: field_symbols, }; - let mut result = Stmt::Let(assigned, call, layout.clone(), hole); + let mut result = Stmt::Let(assigned, call, ret_layout.clone(), hole); for ((_, loc_arg), symbol) in loc_args.into_iter().rev().zip(field_symbols.iter().rev()) @@ -2992,16 +3008,22 @@ fn call_by_name<'a>( match &mut procs.pending_specializations { Some(pending_specializations) => { // register the pending specialization, so this gets code genned later - add_pending(pending_specializations, proc_name, layout.clone(), pending); + add_pending( + pending_specializations, + proc_name, + full_layout.clone(), + pending, + ); let call = Expr::FunctionCall { call_type: CallType::ByName(proc_name), - layout: layout.clone(), + ret_layout: ret_layout.clone(), + full_layout: full_layout.clone(), arg_layouts, args: field_symbols, }; - let mut result = Stmt::Let(assigned, call, layout.clone(), hole); + let mut result = Stmt::Let(assigned, call, ret_layout.clone(), hole); for ((_, loc_arg), symbol) in loc_args.into_iter().rev().zip(field_symbols.iter().rev()) @@ -3035,7 +3057,7 @@ fn call_by_name<'a>( // (We had a bug around this before this system existed!) procs .specialized - .insert((proc_name, layout.clone()), InProgress); + .insert((proc_name, full_layout.clone()), InProgress); match specialize( env, @@ -3048,17 +3070,18 @@ fn call_by_name<'a>( Ok(proc) => { procs .specialized - .insert((proc_name, layout.clone()), Done(proc)); + .insert((proc_name, full_layout.clone()), Done(proc)); let call = Expr::FunctionCall { call_type: CallType::ByName(proc_name), - layout: layout.clone(), + ret_layout: ret_layout.clone(), + full_layout: full_layout.clone(), arg_layouts, args: field_symbols, }; let mut result = - Stmt::Let(assigned, call, layout.clone(), hole); + Stmt::Let(assigned, call, ret_layout.clone(), hole); for ((_, loc_arg), symbol) in loc_args .into_iter() diff --git a/compiler/mono/tests/test_mono.rs b/compiler/mono/tests/test_mono.rs index c32898d839..928ad65f97 100644 --- a/compiler/mono/tests/test_mono.rs +++ b/compiler/mono/tests/test_mono.rs @@ -943,17 +943,15 @@ mod test_mono { ), indoc!( r#" - procedure Test.0 (Test.4): - let Test.2 = Index 0 Test.4; - let Test.3 = Index 1 Test.4; - let Test.11 = CallByName Num.14 Test.2 Test.3; - jump Test.10 Test.11; - joinpoint Test.10 Test.9: - ret Test.9; + procedure Test.0 (Test.2): + let Test.3 = Index 0 Test.2; + let Test.4 = Index 1 Test.2; + let Test.9 = CallByName Num.14 Test.3 Test.4; + ret Test.9; procedure Num.14 (#Attr.2, #Attr.3): - let Test.12 = lowlevel NumAdd #Attr.2 #Attr.3; - ret Test.12; + let Test.10 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.10; let Test.7 = 4i64; let Test.8 = 9i64; @@ -980,17 +978,15 @@ mod test_mono { ), indoc!( r#" - procedure Test.0 (Test.4): - let Test.2 = 10i64; - let Test.3 = Index 1 Test.4; - let Test.10 = CallByName Num.14 Test.2 Test.3; - jump Test.9 Test.10; - joinpoint Test.9 Test.8: - ret Test.8; + procedure Test.0 (Test.2): + let Test.3 = 10i64; + let Test.4 = Index 1 Test.2; + let Test.8 = CallByName Num.14 Test.3 Test.4; + ret Test.8; procedure Num.14 (#Attr.2, #Attr.3): - let Test.11 = lowlevel NumAdd #Attr.2 #Attr.3; - ret Test.11; + let Test.9 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.9; let Test.7 = 9i64; let Test.6 = Struct {Test.7}; From c52f866d8acd8adb820f2d6ec900ca5b0d78fc79 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 13 Aug 2020 01:40:03 +0200 Subject: [PATCH 4/8] fix tests --- compiler/mono/tests/test_mono.rs | 80 ++++++++++++++++---------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/compiler/mono/tests/test_mono.rs b/compiler/mono/tests/test_mono.rs index 928ad65f97..08e35aa084 100644 --- a/compiler/mono/tests/test_mono.rs +++ b/compiler/mono/tests/test_mono.rs @@ -526,15 +526,15 @@ mod test_mono { "#, indoc!( r#" - procedure List.5 (#Attr.2, #Attr.3): - let Test.9 = lowlevel ListAppend #Attr.2 #Attr.3; - ret Test.9; - procedure Test.0 (Test.2): let Test.8 = 42i64; let Test.7 = CallByName List.5 Test.2 Test.8; ret Test.7; + procedure List.5 (#Attr.2, #Attr.3): + let Test.9 = lowlevel ListAppend #Attr.2 #Attr.3; + ret Test.9; + let Test.5 = 1i64; let Test.6 = 2i64; let Test.4 = Array [Test.5, Test.6]; @@ -580,12 +580,16 @@ mod test_mono { "#, indoc!( r#" + procedure Num.14 (#Attr.2, #Attr.3): + let Test.13 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.13; + procedure List.7 (#Attr.2): let Test.9 = lowlevel ListLen #Attr.2; ret Test.9; - procedure Num.14 (#Attr.2, #Attr.3): - let Test.11 = lowlevel NumAdd #Attr.2 #Attr.3; + procedure List.7 (#Attr.2): + let Test.11 = lowlevel ListLen #Attr.2; ret Test.11; let Test.8 = 1f64; @@ -901,6 +905,12 @@ mod test_mono { ), indoc!( r#" + procedure Test.1 (Test.3): + let Test.9 = 0i64; + let Test.10 = 0i64; + let Test.8 = CallByName List.4 Test.3 Test.9 Test.10; + ret Test.8; + procedure List.4 (#Attr.2, #Attr.3, #Attr.4): let Test.14 = lowlevel ListLen #Attr.2; let Test.12 = lowlevel NumLt #Attr.3 Test.14; @@ -910,12 +920,6 @@ mod test_mono { else ret #Attr.2; - procedure Test.1 (Test.3): - let Test.9 = 0i64; - let Test.10 = 0i64; - let Test.8 = CallByName List.4 Test.3 Test.9 Test.10; - ret Test.8; - let Test.5 = 1i64; let Test.6 = 2i64; let Test.7 = 3i64; @@ -943,16 +947,16 @@ mod test_mono { ), indoc!( r#" + procedure Num.14 (#Attr.2, #Attr.3): + let Test.10 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.10; + procedure Test.0 (Test.2): let Test.3 = Index 0 Test.2; let Test.4 = Index 1 Test.2; let Test.9 = CallByName Num.14 Test.3 Test.4; ret Test.9; - procedure Num.14 (#Attr.2, #Attr.3): - let Test.10 = lowlevel NumAdd #Attr.2 #Attr.3; - ret Test.10; - let Test.7 = 4i64; let Test.8 = 9i64; let Test.6 = Struct {Test.7, Test.8}; @@ -978,16 +982,16 @@ mod test_mono { ), indoc!( r#" + procedure Num.14 (#Attr.2, #Attr.3): + let Test.9 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.9; + procedure Test.0 (Test.2): let Test.3 = 10i64; let Test.4 = Index 1 Test.2; let Test.8 = CallByName Num.14 Test.3 Test.4; ret Test.8; - procedure Num.14 (#Attr.2, #Attr.3): - let Test.9 = lowlevel NumAdd #Attr.2 #Attr.3; - ret Test.9; - let Test.7 = 9i64; let Test.6 = Struct {Test.7}; let Test.5 = CallByName Test.0 Test.6; @@ -1010,17 +1014,15 @@ mod test_mono { ), indoc!( r#" + procedure Num.14 (#Attr.2, #Attr.3): + let Test.10 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.10; + procedure Test.0 (Test.4): let Test.2 = Index 0 Test.4; let Test.3 = Index 1 Test.4; - let Test.11 = CallByName Num.14 Test.2 Test.3; - jump Test.10 Test.11; - joinpoint Test.10 Test.9: - ret Test.9; - - procedure Num.14 (#Attr.2, #Attr.3): - let Test.12 = lowlevel NumAdd #Attr.2 #Attr.3; - ret Test.12; + let Test.9 = CallByName Num.14 Test.2 Test.3; + ret Test.9; let Test.7 = 4i64; let Test.8 = 9i64; @@ -1045,17 +1047,15 @@ mod test_mono { ), indoc!( r#" + procedure Num.14 (#Attr.2, #Attr.3): + let Test.9 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Test.9; + procedure Test.0 (Test.4): let Test.2 = 10i64; let Test.3 = Index 1 Test.4; - let Test.10 = CallByName Num.14 Test.2 Test.3; - jump Test.9 Test.10; - joinpoint Test.9 Test.8: - ret Test.8; - - procedure Num.14 (#Attr.2, #Attr.3): - let Test.11 = lowlevel NumAdd #Attr.2 #Attr.3; - ret Test.11; + let Test.8 = CallByName Num.14 Test.2 Test.3; + ret Test.8; let Test.7 = 9i64; let Test.6 = Struct {Test.7}; @@ -1232,14 +1232,14 @@ mod test_mono { let Test.10 = CallByName Num.16 Test.2 Test.3; jump Test.20 Test.9 Test.10; - procedure Num.15 (#Attr.2, #Attr.3): - let Test.14 = lowlevel NumSub #Attr.2 #Attr.3; - ret Test.14; - procedure Num.16 (#Attr.2, #Attr.3): let Test.11 = lowlevel NumMul #Attr.2 #Attr.3; ret Test.11; + procedure Num.15 (#Attr.2, #Attr.3): + let Test.14 = lowlevel NumSub #Attr.2 #Attr.3; + ret Test.14; + let Test.5 = 10i64; let Test.6 = 1i64; let Test.4 = CallByName Test.0 Test.5 Test.6; From fe0da7a8d7695e35ff575e84ad48545e3be8cb30 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 12 Aug 2020 22:33:10 -0400 Subject: [PATCH 5/8] Appease 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 a0c7ebaf17..5db5cd815f 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1873,7 +1873,7 @@ pub fn with_hole<'a>( assigned, Expr::FunctionCall { call_type: CallType::ByPointer(function_symbol), - full_layout: full_layout, + full_layout, ret_layout: ret_layout.clone(), args: arg_symbols, arg_layouts, From 84789d3077870c821d2d18a8788be4982c1bfbde Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 12 Aug 2020 22:48:28 -0400 Subject: [PATCH 6/8] Drop commented-out code --- compiler/mono/src/decision_tree.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index d2099e515a..d883f3e7f9 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -543,7 +543,6 @@ fn to_relevant_branch_help<'a>( DestructType::Guard(guard) => guard.clone(), DestructType::Required => Pattern::Underscore, DestructType::Optional(_expr) => { - // todo!("TODO decision tree for optional field branch"); Pattern::Underscore } }; From 2173bc6f6f91d5483ceb2404d2eec043beacd47d Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 12 Aug 2020 22:48:36 -0400 Subject: [PATCH 7/8] Drop commented-out code --- compiler/mono/src/decision_tree.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index d883f3e7f9..42a11c0da3 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -409,7 +409,6 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V arguments.push((Pattern::Underscore, destruct.layout.clone())); } DestructType::Optional(_expr) => { - // todo!("test_at_type for optional destruct"); arguments.push((Pattern::Underscore, destruct.layout.clone())); } } From 31811410ee82150f39a19e16809a5b9432b6a42c Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 12 Aug 2020 23:03:09 -0400 Subject: [PATCH 8/8] cargo fmt --- compiler/mono/src/decision_tree.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 42a11c0da3..a3f637efb7 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -541,9 +541,7 @@ fn to_relevant_branch_help<'a>( let pattern = match destruct.typ { DestructType::Guard(guard) => guard.clone(), DestructType::Required => Pattern::Underscore, - DestructType::Optional(_expr) => { - Pattern::Underscore - } + DestructType::Optional(_expr) => Pattern::Underscore, }; (