From 56eae5df95a0a16e0e65745dd2126fd7be3a0f38 Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Mon, 8 Jul 2024 21:42:01 +0200 Subject: [PATCH 01/12] propagate type annotations to desugared ast --- crates/compiler/can/src/desugar.rs | 34 +++-- crates/compiler/can/src/suffixed.rs | 166 +++++++++++++++------ crates/compiler/can/tests/test_suffixed.rs | 12 ++ 3 files changed, 158 insertions(+), 54 deletions(-) diff --git a/crates/compiler/can/src/desugar.rs b/crates/compiler/can/src/desugar.rs index 051569943ec..9143064c4eb 100644 --- a/crates/compiler/can/src/desugar.rs +++ b/crates/compiler/can/src/desugar.rs @@ -10,7 +10,7 @@ use roc_module::ident::ModuleName; use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::{ AssignedField, Collection, ModuleImportParams, OldRecordBuilderField, Pattern, StrLiteral, - StrSegment, ValueDef, WhenBranch, + StrSegment, TypeAnnotation, ValueDef, WhenBranch, }; use roc_region::all::{LineInfo, Loc, Region}; @@ -154,15 +154,26 @@ fn desugar_value_def<'a>( IngestedFileImport(_) => *def, Stmt(stmt_expr) => { - // desugar into a Body({}, stmt_expr) - let loc_pattern = arena.alloc(Loc::at( - stmt_expr.region, - Pattern::RecordDestructure(Collection::empty()), - )); - Body( - loc_pattern, - desugar_expr(arena, stmt_expr, src, line_info, module_path), - ) + // desugar `stmt_expr!` to + // _ : {} + // _ = stmt_expr! + + let region = stmt_expr.region; + let new_pat = arena.alloc(Loc::at(region, Pattern::Underscore(""))); + + ValueDef::AnnotatedBody { + ann_pattern: new_pat, + ann_type: arena.alloc(Loc::at( + region, + TypeAnnotation::Record { + fields: Collection::empty(), + ext: None, + }, + )), + comment: None, + body_pattern: new_pat, + body_expr: desugar_expr(arena, stmt_expr, src, line_info, module_path), + } } } } @@ -211,7 +222,7 @@ pub fn desugar_value_def_suffixed<'a>(arena: &'a Bump, value_def: ValueDef<'a>) arena, Body( loc_pattern, - apply_task_await(arena, loc_expr.region, sub_arg, sub_pat, sub_new), + apply_task_await(arena, loc_expr.region, sub_arg, sub_pat, sub_new, None), ), ), Err(..) => Body( @@ -254,6 +265,7 @@ pub fn desugar_value_def_suffixed<'a>(arena: &'a Bump, value_def: ValueDef<'a>) sub_arg, sub_pat, sub_new, + Some(ann_type), ), }, ), diff --git a/crates/compiler/can/src/suffixed.rs b/crates/compiler/can/src/suffixed.rs index c3dc5d0e5fc..76a1ac8a3aa 100644 --- a/crates/compiler/can/src/suffixed.rs +++ b/crates/compiler/can/src/suffixed.rs @@ -6,7 +6,7 @@ use roc_error_macros::internal_error; use roc_module::called_via::CalledVia; use roc_module::ident::ModuleName; use roc_parse::ast::Expr::{self, *}; -use roc_parse::ast::{is_expr_suffixed, Pattern, ValueDef, WhenBranch}; +use roc_parse::ast::{is_expr_suffixed, Pattern, TypeAnnotation, ValueDef, WhenBranch}; use roc_region::all::{Loc, Region}; use std::cell::Cell; @@ -28,9 +28,18 @@ fn next_unique_suffixed_ident() -> String { } #[derive(Debug)] +/// pub enum EUnwrapped<'a> { + /// First suffixed expression in a definition. Emitted if an expression has def pattern + /// e.g. x = first! (second! 42) + /// The first unwrap will produce + /// `UnwrappedDefExpr` UnwrappedDefExpr(&'a Loc>), + /// Suffixed sub expression + /// e.g. x = first! (second! 42) + /// In this example, the second unwrap (after unwrapping the top level `first!`) will produce + /// `UnwrappedSubExpr<{ sub_arg: second 42, sub_pat: #!a0, sub_new: #!a0 }>` UnwrappedSubExpr { /// the unwrapped expression argument for Task.await sub_arg: &'a Loc>, @@ -42,6 +51,7 @@ pub enum EUnwrapped<'a> { sub_new: &'a Loc>, }, + /// Malformed use of the suffix Malformed, } @@ -240,7 +250,7 @@ pub fn unwrap_suffixed_expression_closure_help<'a>( Ok(new_closure) } Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - let new_closure_loc_ret = apply_task_await(arena, loc_expr.region, sub_arg, sub_pat, sub_new); + let new_closure_loc_ret = apply_task_await(arena, loc_expr.region, sub_arg, sub_pat, sub_new, None); let new_closure = arena.alloc(Loc::at(loc_expr.region, Expr::Closure(closure_args, new_closure_loc_ret))); Ok(new_closure) } @@ -361,8 +371,14 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>( sub_pat, sub_new, }) => { - let unwrapped_expression = - apply_task_await(arena, sub_arg.region, sub_arg, sub_pat, sub_new); + let unwrapped_expression = apply_task_await( + arena, + sub_arg.region, + sub_arg, + sub_pat, + sub_new, + None, + ); let mut new_if_thens = Vec::new_in(arena); @@ -437,6 +453,7 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>( sub_arg, sub_pat, new_if, + None, ); return unwrap_suffixed_expression( @@ -464,6 +481,7 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>( sub_arg, sub_pat, after_if, + None, ); let before_if_then = arena.alloc(Loc::at( @@ -500,7 +518,7 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>( sub_new, }) => { let unwrapped_final_else = - apply_task_await(arena, sub_arg.region, sub_arg, sub_pat, sub_new); + apply_task_await(arena, sub_arg.region, sub_arg, sub_pat, sub_new, None); let new_if = arena.alloc(Loc::at( loc_expr.region, @@ -535,7 +553,7 @@ pub fn unwrap_suffixed_expression_when_help<'a>( if is_expr_suffixed(&branch_loc_expr.value) { let unwrapped_branch_value = match unwrap_suffixed_expression(arena, branch_loc_expr, None) { Ok(unwrapped_branch_value) => unwrapped_branch_value, - Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => apply_task_await(arena, branch_loc_expr.region, sub_arg, sub_pat, sub_new), + Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => apply_task_await(arena, branch_loc_expr.region, sub_arg, sub_pat, sub_new, None), Err(..) => return Err(EUnwrapped::Malformed), }; @@ -564,7 +582,7 @@ pub fn unwrap_suffixed_expression_when_help<'a>( } Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { let new_when = arena.alloc(Loc::at(loc_expr.region, Expr::When(sub_new, branches))); - let applied_task_await = apply_task_await(arena,loc_expr.region,sub_arg,sub_pat,new_when); + let applied_task_await = apply_task_await(arena,loc_expr.region,sub_arg,sub_pat,new_when, None); Ok(applied_task_await) } Err(EUnwrapped::UnwrappedDefExpr(..)) @@ -601,15 +619,16 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( let maybe_suffixed_value_def = match current_value_def { Annotation(..) | Dbg{..} | Expect{..} | ExpectFx{..} | Stmt(..) | ModuleImport{..} | IngestedFileImport(_) => None, - AnnotatedBody { body_pattern, body_expr, .. } => Some((body_pattern, body_expr)), - Body (def_pattern, def_expr, .. ) => Some((def_pattern, def_expr)), + AnnotatedBody { body_pattern, body_expr, ann_type, ann_pattern, .. } if body_pattern.value == ann_pattern.value => Some((body_pattern, body_expr, Some(ann_type))), + AnnotatedBody { body_pattern, body_expr, .. } => Some((body_pattern, body_expr, None)), + Body (def_pattern, def_expr) => Some((def_pattern, def_expr, None)), }; match maybe_suffixed_value_def { None => { // We can't unwrap this def type, continue }, - Some((def_pattern, def_expr)) => { + Some((def_pattern, def_expr, ann_type)) => { match unwrap_suffixed_expression(arena, def_expr, Some(def_pattern)) { Ok(unwrapped_def) => { current_value_def.replace_expr(unwrapped_def); @@ -626,14 +645,14 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( Ok(next_expr) => next_expr, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { // We need to apply Task.ok here as the defs final expression was unwrapped - apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new) + apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new, ann_type) } Err(EUnwrapped::UnwrappedDefExpr(..)) | Err(EUnwrapped::Malformed) => { // TODO handle case when we have maybe_def_pat so can return an unwrapped up return Err(EUnwrapped::Malformed); }, }; - return unwrap_suffixed_expression(arena, apply_task_await(arena,def_expr.region,unwrapped_expr,def_pattern,next_expr), maybe_def_pat); + return unwrap_suffixed_expression(arena, apply_task_await(arena,def_expr.region,unwrapped_expr,def_pattern,next_expr, ann_type), maybe_def_pat); } else if before_empty { // NIL before, SOME after -> FIRST DEF let new_defs = arena.alloc(Loc::at(def_expr.region, Defs(arena.alloc(split_defs.after), loc_ret))); @@ -641,7 +660,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( let next_expr = match unwrap_suffixed_expression(arena,new_defs,maybe_def_pat){ Ok(next_expr) => next_expr, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new) + apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new, ann_type) } Err(EUnwrapped::UnwrappedDefExpr(..)) | Err(EUnwrapped::Malformed) => { // TODO handle case when we have maybe_def_pat so can return an unwrapped up @@ -649,19 +668,19 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( }, }; - return unwrap_suffixed_expression(arena, apply_task_await(arena,def_expr.region,unwrapped_expr,def_pattern,next_expr), maybe_def_pat); + return unwrap_suffixed_expression(arena, apply_task_await(arena,def_expr.region,unwrapped_expr,def_pattern,next_expr, ann_type), maybe_def_pat); } else if after_empty { // SOME before, NIL after -> LAST DEF // We pass None as a def pattern here because it's desugaring of the ret expression match unwrap_suffixed_expression(arena,loc_ret,None){ Ok(new_loc_ret) => { - let applied_task_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret); + let applied_task_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret, ann_type); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(split_defs.before), applied_task_await))); return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); }, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - let new_loc_ret = apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new); - let applied_task_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret); + let new_loc_ret = apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new, ann_type); + let applied_task_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret, ann_type); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(split_defs.before), applied_task_await))); return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); } @@ -679,13 +698,13 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( match unwrap_suffixed_expression(arena,after_defs,maybe_def_pat){ Ok(new_loc_ret) => { - let applied_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret); + let applied_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret, ann_type); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(split_defs.before), applied_await))); return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); }, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - let new_loc_ret = apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new); - let applied_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret); + let new_loc_ret = apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new, ann_type); + let applied_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret, ann_type); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(split_defs.before), applied_await))); return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); } @@ -700,7 +719,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( let new_body_def = ValueDef::Body(def_pattern, sub_new); local_defs.replace_with_value_def(tag_index,new_body_def, sub_new.region); let new_defs_expr = arena.alloc(Loc::at(def_expr.region,Defs(arena.alloc(local_defs), loc_ret))); - let replaced_def = apply_task_await(arena,def_expr.region,sub_arg,sub_pat,new_defs_expr); + let replaced_def = apply_task_await(arena,def_expr.region,sub_arg,sub_pat,new_defs_expr, ann_type); return unwrap_suffixed_expression(arena,replaced_def,maybe_def_pat); } Err(err) => return Err(err) @@ -712,10 +731,10 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( // try to unwrap the loc_ret match unwrap_suffixed_expression(arena,loc_ret,maybe_def_pat){ Ok(new_loc_ret) => { - Ok(arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(local_defs), new_loc_ret)))) + Ok(arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(local_defs), new_loc_ret)))) }, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - let new_loc_ret = apply_task_await(arena, loc_expr.region,sub_arg,sub_pat,sub_new); + let new_loc_ret = apply_task_await(arena, loc_expr.region,sub_arg,sub_pat,sub_new, None); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(local_defs), new_loc_ret))); unwrap_suffixed_expression(arena, new_defs, maybe_def_pat) } @@ -761,7 +780,14 @@ fn unwrap_low_level_dbg<'a>( unwrap_suffixed_expression( arena, - apply_task_await(arena, new_dbg.region, sub_arg, sub_pat, new_dbg), + apply_task_await( + arena, + new_dbg.region, + sub_arg, + sub_pat, + new_dbg, + None, + ), maybe_def_pat, ) } @@ -813,33 +839,87 @@ fn unwrap_low_level_dbg<'a>( } } -/// Helper for `Task.await (loc_arg) \loc_pat -> loc_new` +/// Helper for `Task.await loc_expr \loc_pat -> loc_cont` pub fn apply_task_await<'a>( arena: &'a Bump, region: Region, - loc_arg: &'a Loc>, + loc_expr: &'a Loc>, loc_pat: &'a Loc>, - loc_new: &'a Loc>, + loc_cont: &'a Loc>, + maybe_loc_type: Option<&'a Loc>>, ) -> &'a Loc> { - // If the pattern and the new are matching answers then we don't need to unwrap anything - // e.g. `Task.await foo \#!a1 -> Task.ok #!a1` is the same as `foo` - if is_matching_intermediate_answer(loc_pat, loc_new) { - return loc_arg; - } + let task_await_first_arg = match maybe_loc_type { + Some(loc_type) => { + // loc_pat : loc_type + // loc_pat = loc_expr! + // loc_cont + + // desugar to + // Task.await + // ( + // #!a0 : Task loc_type _ + // #!a0 = loc_expr + // #!a0 + // ) + // \loc_pat -> loc_cont + use roc_parse::ast::*; + + // #!a0 + let new_ident = arena.alloc(next_unique_suffixed_ident()); + // #!a0 (pattern) + let new_pat = arena.alloc(Loc::at(region, Pattern::Identifier { ident: new_ident })); + + // #!a0 : Task loc_type _ + // #!a0 = loc_expr + let value_def = ValueDef::AnnotatedBody { + ann_pattern: new_pat, + ann_type: arena.alloc(Loc::at( + region, + TypeAnnotation::Apply( + arena.alloc(""), + arena.alloc("Task"), + arena.alloc([*loc_type, Loc::at(region, TypeAnnotation::Inferred)]), + ), + )), + comment: None, + body_pattern: new_pat, + body_expr: loc_expr, + }; + + // #!a0 (variable) + let new_var = arena.alloc(Loc::at( + region, + Expr::Var { + module_name: "", + ident: new_ident, + }, + )); - let mut task_await_apply_args: Vec<&'a Loc>> = Vec::new_in(arena); + let mut defs = roc_parse::ast::Defs::default(); + defs.push_value_def(value_def, region, &[], &[]); - // apply the unwrapped suffixed expression - task_await_apply_args.push(loc_arg); + arena.alloc(Loc::at(region, Defs(arena.alloc(defs), new_var))) + } + _ => { + // If the pattern and the new are matching answers then we don't need to unwrap anything + // e.g. `Task.await foo \#!a1 -> Task.ok #!a1` is the same as `foo` + if is_matching_intermediate_answer(loc_pat, loc_cont) { + return loc_expr; + } - // apply the closure - let mut closure_pattern = Vec::new_in(arena); - closure_pattern.push(*loc_pat); - task_await_apply_args.push(arena.alloc(Loc::at( - region, - Closure(arena.alloc_slice_copy(closure_pattern.as_slice()), loc_new), - ))); + // loc_pat = loc_expr! + // loc_cont + + // desugar to + // Task.await loc_expr \loc_pat -> loc_cont + loc_expr + } + }; + + // \loc_pat -> loc_cont + let closure = arena.alloc(Loc::at(region, Closure(arena.alloc([*loc_pat]), loc_cont))); + // Task.await task_first_arg closure arena.alloc(Loc::at( region, Apply( @@ -850,7 +930,7 @@ pub fn apply_task_await<'a>( ident: "await", }, }), - arena.alloc(task_await_apply_args), + arena.alloc([task_await_first_arg, closure]), CalledVia::BangSuffix, ), )) diff --git a/crates/compiler/can/tests/test_suffixed.rs b/crates/compiler/can/tests/test_suffixed.rs index 329db343550..9ef2be2965b 100644 --- a/crates/compiler/can/tests/test_suffixed.rs +++ b/crates/compiler/can/tests/test_suffixed.rs @@ -546,6 +546,18 @@ mod suffixed_tests { "## ); } + + #[test] + fn type_annotation() { + run_test!( + r##" + f = \x -> + r : A + r = x! + Task.ok r + "## + ); + } } #[cfg(test)] From 3e17168098833085a8515fdb1aae55a0116b1069 Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Thu, 11 Jul 2024 12:51:22 +0200 Subject: [PATCH 02/12] print formatted desugared code instead of ast --- Cargo.lock | 1 + crates/compiler/can/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index e44c1472b98..47570a85248 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2347,6 +2347,7 @@ dependencies = [ "roc_collections", "roc_error_macros", "roc_exhaustive", + "roc_fmt", "roc_module", "roc_parse", "roc_problem", diff --git a/crates/compiler/can/Cargo.toml b/crates/compiler/can/Cargo.toml index 76b115bd5af..9ef92392782 100644 --- a/crates/compiler/can/Cargo.toml +++ b/crates/compiler/can/Cargo.toml @@ -13,6 +13,7 @@ roc_error_macros = { path = "../../error_macros" } roc_exhaustive = { path = "../exhaustive" } roc_module = { path = "../module" } roc_parse = { path = "../parse" } +roc_fmt = { path = "../fmt" } roc_problem = { path = "../problem" } roc_region = { path = "../region" } roc_serialize = { path = "../serialize" } From a7ca02dd61c04f10c5dfb59f57f66e6a2f042dab Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Fri, 12 Jul 2024 10:46:06 +0200 Subject: [PATCH 03/12] unwrap identity call --- crates/compiler/can/src/suffixed.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/compiler/can/src/suffixed.rs b/crates/compiler/can/src/suffixed.rs index 76a1ac8a3aa..091e18d286c 100644 --- a/crates/compiler/can/src/suffixed.rs +++ b/crates/compiler/can/src/suffixed.rs @@ -901,12 +901,6 @@ pub fn apply_task_await<'a>( arena.alloc(Loc::at(region, Defs(arena.alloc(defs), new_var))) } _ => { - // If the pattern and the new are matching answers then we don't need to unwrap anything - // e.g. `Task.await foo \#!a1 -> Task.ok #!a1` is the same as `foo` - if is_matching_intermediate_answer(loc_pat, loc_cont) { - return loc_expr; - } - // loc_pat = loc_expr! // loc_cont @@ -916,6 +910,12 @@ pub fn apply_task_await<'a>( } }; + // If the pattern and the new are matching answers then we don't need to unwrap anything + // e.g. `Task.await foo \#!a1 -> Task.ok #!a1` is the same as `foo` + if is_matching_intermediate_answer(loc_pat, loc_cont) { + return task_await_first_arg; + } + // \loc_pat -> loc_cont let closure = arena.alloc(Loc::at(region, Closure(arena.alloc([*loc_pat]), loc_cont))); From 4d5586b68ab9a2648f743d56e4d8cfd729a90c25 Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Fri, 12 Jul 2024 12:46:35 +0200 Subject: [PATCH 04/12] simplify identity unwrap --- crates/compiler/can/src/suffixed.rs | 34 +++++++---------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/crates/compiler/can/src/suffixed.rs b/crates/compiler/can/src/suffixed.rs index 091e18d286c..ae07d7a1ee1 100644 --- a/crates/compiler/can/src/suffixed.rs +++ b/crates/compiler/can/src/suffixed.rs @@ -936,18 +936,6 @@ pub fn apply_task_await<'a>( )) } -fn extract_wrapped_task_ok_value<'a>(loc_expr: &'a Loc>) -> Option<&'a Loc>> { - match loc_expr.value { - Expr::Apply(function, arguments, _) => match function.value { - Var { - module_name, ident, .. - } if module_name == ModuleName::TASK && ident == "ok" => arguments.first().copied(), - _ => None, - }, - _ => None, - } -} - pub fn is_matching_intermediate_answer<'a>( loc_pat: &'a Loc>, loc_new: &'a Loc>, @@ -956,24 +944,18 @@ pub fn is_matching_intermediate_answer<'a>( Pattern::Identifier { ident, .. } => Some(ident), _ => None, }; + let exp_ident = match loc_new.value { Expr::Var { - module_name, ident, .. - } if module_name.is_empty() && ident.starts_with('#') => Some(ident), + module_name: "", + ident, + .. + } => Some(ident), _ => None, }; - let exp_ident_in_task = match extract_wrapped_task_ok_value(loc_new) { - Some(task_expr) => match task_expr.value { - Expr::Var { - module_name, ident, .. - } if module_name.is_empty() && ident.starts_with('#') => Some(ident), - _ => None, - }, - None => None, - }; - match (pat_ident, exp_ident, exp_ident_in_task) { - (Some(a), Some(b), None) => a == b, - (Some(a), None, Some(b)) => a == b, + + match (pat_ident, exp_ident) { + (Some(a), Some(b)) => a == b, _ => false, } } From 9a37aeb82f692baab63ed8c2b1b90335434a1e90 Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Fri, 12 Jul 2024 13:14:27 +0200 Subject: [PATCH 05/12] fix types propagation --- crates/compiler/can/src/suffixed.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/compiler/can/src/suffixed.rs b/crates/compiler/can/src/suffixed.rs index ae07d7a1ee1..9986e034729 100644 --- a/crates/compiler/can/src/suffixed.rs +++ b/crates/compiler/can/src/suffixed.rs @@ -645,7 +645,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( Ok(next_expr) => next_expr, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { // We need to apply Task.ok here as the defs final expression was unwrapped - apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new, ann_type) + apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new, None) } Err(EUnwrapped::UnwrappedDefExpr(..)) | Err(EUnwrapped::Malformed) => { // TODO handle case when we have maybe_def_pat so can return an unwrapped up @@ -660,7 +660,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( let next_expr = match unwrap_suffixed_expression(arena,new_defs,maybe_def_pat){ Ok(next_expr) => next_expr, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new, ann_type) + apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new, None) } Err(EUnwrapped::UnwrappedDefExpr(..)) | Err(EUnwrapped::Malformed) => { // TODO handle case when we have maybe_def_pat so can return an unwrapped up @@ -668,7 +668,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( }, }; - return unwrap_suffixed_expression(arena, apply_task_await(arena,def_expr.region,unwrapped_expr,def_pattern,next_expr, ann_type), maybe_def_pat); + return unwrap_suffixed_expression(arena, apply_task_await(arena,def_expr.region,unwrapped_expr,def_pattern,next_expr,ann_type), maybe_def_pat); } else if after_empty { // SOME before, NIL after -> LAST DEF // We pass None as a def pattern here because it's desugaring of the ret expression @@ -679,7 +679,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); }, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - let new_loc_ret = apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new, ann_type); + let new_loc_ret = apply_task_await(arena,def_expr.region,sub_arg,sub_pat,sub_new, None); let applied_task_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret, ann_type); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(split_defs.before), applied_task_await))); return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); @@ -703,7 +703,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); }, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { - let new_loc_ret = apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new, ann_type); + let new_loc_ret = apply_task_await(arena, def_expr.region, sub_arg, sub_pat, sub_new, None); let applied_await = apply_task_await(arena, loc_expr.region, unwrapped_expr, def_pattern, new_loc_ret, ann_type); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(split_defs.before), applied_await))); return unwrap_suffixed_expression(arena, new_defs, maybe_def_pat); @@ -729,14 +729,14 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( } // try to unwrap the loc_ret - match unwrap_suffixed_expression(arena,loc_ret,maybe_def_pat){ + match unwrap_suffixed_expression(arena,loc_ret,None){ Ok(new_loc_ret) => { Ok(arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(local_defs), new_loc_ret)))) }, Err(EUnwrapped::UnwrappedSubExpr { sub_arg, sub_pat, sub_new }) => { let new_loc_ret = apply_task_await(arena, loc_expr.region,sub_arg,sub_pat,sub_new, None); let new_defs = arena.alloc(Loc::at(loc_expr.region,Defs(arena.alloc(local_defs), new_loc_ret))); - unwrap_suffixed_expression(arena, new_defs, maybe_def_pat) + unwrap_suffixed_expression(arena, new_defs, None) } Err(EUnwrapped::UnwrappedDefExpr(..)) => { // TODO confirm this is correct with test case From 10bdabf52e74a841f991bdceb26a24ee767e7160 Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Fri, 12 Jul 2024 13:22:14 +0200 Subject: [PATCH 06/12] better desugared idents --- crates/compiler/can/src/desugar.rs | 4 +- crates/compiler/can/src/suffixed.rs | 82 ++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 28 deletions(-) diff --git a/crates/compiler/can/src/desugar.rs b/crates/compiler/can/src/desugar.rs index 9143064c4eb..a036b1b7669 100644 --- a/crates/compiler/can/src/desugar.rs +++ b/crates/compiler/can/src/desugar.rs @@ -159,7 +159,7 @@ fn desugar_value_def<'a>( // _ = stmt_expr! let region = stmt_expr.region; - let new_pat = arena.alloc(Loc::at(region, Pattern::Underscore(""))); + let new_pat = arena.alloc(Loc::at(region, Pattern::Underscore("#!stmt"))); ValueDef::AnnotatedBody { ann_pattern: new_pat, @@ -265,7 +265,7 @@ pub fn desugar_value_def_suffixed<'a>(arena: &'a Bump, value_def: ValueDef<'a>) sub_arg, sub_pat, sub_new, - Some(ann_type), + Some((ann_pattern, ann_type)), ), }, ), diff --git a/crates/compiler/can/src/suffixed.rs b/crates/compiler/can/src/suffixed.rs index 9986e034729..4656a0a650c 100644 --- a/crates/compiler/can/src/suffixed.rs +++ b/crates/compiler/can/src/suffixed.rs @@ -23,7 +23,7 @@ fn next_unique_suffixed_ident() -> String { // # is used as prefix because it's impossible for code authors to define names like this. // This makes it easy to see this identifier was created by the compiler. - format!("#!a{}", count) + format!("#!{}", count) }) } @@ -70,19 +70,17 @@ fn init_unwrapped_err<'a>( // Provide an intermediate answer expression and pattern when unwrapping a // (sub) expression. // e.g. `x = foo (bar!)` unwraps to `x = Task.await (bar) \#!a0 -> foo #!a0` - let answer_ident = arena.alloc(next_unique_suffixed_ident()); + let ident = arena.alloc(format!("{}_arg", next_unique_suffixed_ident())); let sub_new = arena.alloc(Loc::at( unwrapped_expr.region, Expr::Var { module_name: "", - ident: answer_ident, + ident, }, )); let sub_pat = arena.alloc(Loc::at( unwrapped_expr.region, - Pattern::Identifier { - ident: answer_ident, - }, + Pattern::Identifier { ident }, )); Err(EUnwrapped::UnwrappedSubExpr { @@ -619,8 +617,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>( let maybe_suffixed_value_def = match current_value_def { Annotation(..) | Dbg{..} | Expect{..} | ExpectFx{..} | Stmt(..) | ModuleImport{..} | IngestedFileImport(_) => None, - AnnotatedBody { body_pattern, body_expr, ann_type, ann_pattern, .. } if body_pattern.value == ann_pattern.value => Some((body_pattern, body_expr, Some(ann_type))), - AnnotatedBody { body_pattern, body_expr, .. } => Some((body_pattern, body_expr, None)), + AnnotatedBody { body_pattern, body_expr, ann_type, ann_pattern, .. } => Some((body_pattern, body_expr, Some((ann_pattern, ann_type)))), Body (def_pattern, def_expr) => Some((def_pattern, def_expr, None)), }; @@ -846,47 +843,72 @@ pub fn apply_task_await<'a>( loc_expr: &'a Loc>, loc_pat: &'a Loc>, loc_cont: &'a Loc>, - maybe_loc_type: Option<&'a Loc>>, + maybe_loc_ann: Option<(&'a Loc, &'a Loc>)>, ) -> &'a Loc> { - let task_await_first_arg = match maybe_loc_type { - Some(loc_type) => { - // loc_pat : loc_type + let task_await_first_arg = match maybe_loc_ann { + Some((loc_ann_pat, loc_type)) => { + // loc_ann_pat : loc_type // loc_pat = loc_expr! // loc_cont // desugar to // Task.await // ( - // #!a0 : Task loc_type _ - // #!a0 = loc_expr - // #!a0 + // #!0_expr : Task loc_type _ + // #!0_expr = loc_expr + // #!0_expr // ) // \loc_pat -> loc_cont use roc_parse::ast::*; // #!a0 - let new_ident = arena.alloc(next_unique_suffixed_ident()); - // #!a0 (pattern) - let new_pat = arena.alloc(Loc::at(region, Pattern::Identifier { ident: new_ident })); + let new_ident = next_unique_suffixed_ident(); + let new_ident = match loc_pat.value { + Pattern::Underscore("#!stmt") => format!("{}_stmt", new_ident), + Pattern::Identifier { ident } + if ident.starts_with('#') && ident.ends_with("_stmt") => + { + format!("{}_stmt", new_ident) + } + _ => format!("{}_expr", new_ident), + }; + let new_ident = arena.alloc(new_ident); - // #!a0 : Task loc_type _ - // #!a0 = loc_expr + // #!0_expr (pattern) + // #!0_expr : Task loc_type _ + // #!0_expr = loc_expr let value_def = ValueDef::AnnotatedBody { - ann_pattern: new_pat, + ann_pattern: arena.alloc(Loc::at( + loc_ann_pat.region, + Pattern::Identifier { + ident: if loc_ann_pat.value.equivalent(&loc_pat.value) { + new_ident + } else { + // create another pattern to preserve inconsistency + arena.alloc(next_unique_suffixed_ident()) + }, + }, + )), ann_type: arena.alloc(Loc::at( - region, + loc_type.region, TypeAnnotation::Apply( arena.alloc(""), arena.alloc("Task"), - arena.alloc([*loc_type, Loc::at(region, TypeAnnotation::Inferred)]), + arena.alloc([ + *loc_type, + Loc::at(loc_type.region, TypeAnnotation::Inferred), + ]), ), )), comment: None, - body_pattern: new_pat, + body_pattern: arena.alloc(Loc::at( + loc_pat.region, + Pattern::Identifier { ident: new_ident }, + )), body_expr: loc_expr, }; - // #!a0 (variable) + // #!0_expr (variable) let new_var = arena.alloc(Loc::at( region, Expr::Var { @@ -895,10 +917,18 @@ pub fn apply_task_await<'a>( }, )); + // ( + // #!0_expr : Task loc_type _ + // #!0_expr = loc_expr + // #!0_expr + // ) let mut defs = roc_parse::ast::Defs::default(); defs.push_value_def(value_def, region, &[], &[]); - arena.alloc(Loc::at(region, Defs(arena.alloc(defs), new_var))) + arena.alloc(Loc::at( + Region::span_across(&loc_ann_pat.region, &loc_expr.region), + Defs(arena.alloc(defs), new_var), + )) } _ => { // loc_pat = loc_expr! From 7a8a5bc9e7076999a9b04aca04dd4fc4243f6dee Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Fri, 12 Jul 2024 16:52:01 +0200 Subject: [PATCH 07/12] update type annotation errors --- crates/reporting/src/error/type.rs | 37 ++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/crates/reporting/src/error/type.rs b/crates/reporting/src/error/type.rs index b13c24781cc..65278dd7973 100644 --- a/crates/reporting/src/error/type.rs +++ b/crates/reporting/src/error/type.rs @@ -675,9 +675,24 @@ fn to_expr_report<'b>( } } Expected::FromAnnotation(name, _arity, annotation_source, expected_type) => { + use roc_can::pattern::Pattern; use roc_types::types::AnnotationSource::*; + let is_suffixed = match &name.value { + Pattern::Identifier(symbol) => symbol.as_str(alloc.interns).starts_with("#!"), + _ => false, + }; + + let is_suffixed_stmt = match &name.value { + Pattern::Identifier(symbol) => { + let ident = symbol.as_str(alloc.interns); + ident.starts_with("#!") && ident.ends_with("_stmt") + } + _ => false, + }; + let (the_name_text, on_name_text) = match pattern_to_doc(alloc, &name.value) { + _ if is_suffixed => (alloc.text("this suffixed"), alloc.nil()), Some(doc) => ( alloc.concat([alloc.reflow("the "), doc.clone()]), alloc.concat([alloc.reflow(" on "), doc]), @@ -714,6 +729,11 @@ fn to_expr_report<'b>( alloc.keyword("when"), alloc.text(" expression:"), ]), + TypedBody { .. } if is_suffixed_stmt => alloc.concat([ + alloc.text("body of "), + the_name_text, + alloc.text(" statement:"), + ]), TypedBody { .. } => alloc.concat([ alloc.text("body of "), the_name_text, @@ -769,11 +789,18 @@ fn to_expr_report<'b>( expected_type, expectation_context, add_category(alloc, alloc.text(it_is), &category), - alloc.concat([ - alloc.text("But the type annotation"), - on_name_text, - alloc.text(" says it should be:"), - ]), + if is_suffixed_stmt { + // TODO: add a tip for using underscore + alloc.text( + "But a suffixed statement is expected to resolve to an empty record:", + ) + } else { + alloc.concat([ + alloc.text("But the type annotation"), + on_name_text, + alloc.text(" says it should be:"), + ]) + }, None, ) }; From 1f65d95e09f45d5662f582d18c9b76215b7f6be0 Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Tue, 16 Jul 2024 08:58:07 +0200 Subject: [PATCH 08/12] update suffixed tests snapshots --- ...ffixed_tests__apply_argument_multiple.snap | 8 +- ...suffixed_tests__apply_argument_single.snap | 4 +- ...ffixed_tests__apply_argument_suffixed.snap | 4 +- ...ffixed_tests__apply_function_suffixed.snap | 4 +- ...ed__suffixed_tests__bang_in_pipe_root.snap | 4 +- .../test_suffixed__suffixed_tests__basic.snap | 56 ++++++- ...ed__suffixed_tests__body_parens_apply.snap | 4 +- ...fixed__suffixed_tests__closure_simple.snap | 70 +++++++-- ...fixed_tests__closure_with_annotations.snap | 89 +++++++---- ...ed__suffixed_tests__closure_with_defs.snap | 132 +++++++++++++--- ...uffixed__suffixed_tests__dbg_stmt_arg.snap | 4 +- ..._suffixed_tests__defs_suffixed_middle.snap | 70 +++++++-- ..._suffixed__suffixed_tests__if_complex.snap | 144 ++++++++++++++---- ...t_suffixed__suffixed_tests__if_simple.snap | 8 +- ...sts__last_stmt_not_top_level_suffixed.snap | 4 +- ...uffixed_tests__last_suffixed_multiple.snap | 112 ++++++++++++-- ...xed__suffixed_tests__multi_defs_stmts.snap | 68 +++++++-- ...ixed__suffixed_tests__multiple_suffix.snap | 97 ++++++++---- ...fixed__suffixed_tests__nested_complex.snap | 4 +- ...ffixed__suffixed_tests__nested_simple.snap | 4 +- ...uffixed__suffixed_tests__simple_pizza.snap | 104 +++++++++---- ...ixed__suffixed_tests__trailing_binops.snap | 68 +++++++-- ...ixed__suffixed_tests__type_annotation.snap | 112 ++++++++++++++ ...uffixed__suffixed_tests__var_suffixes.snap | 4 +- ...ffixed__suffixed_tests__when_branches.snap | 72 +++++++-- ...suffixed__suffixed_tests__when_simple.snap | 4 +- 26 files changed, 1000 insertions(+), 254 deletions(-) create mode 100644 crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__type_annotation.snap diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_multiple.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_multiple.snap index bcf77038305..d5f94a4db28 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_multiple.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_multiple.snap @@ -35,7 +35,7 @@ Defs { @15-22 Closure( [ @17-18 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @15-22 Apply( @@ -51,7 +51,7 @@ Defs { @15-22 Closure( [ @20-21 Identifier { - ident: "#!a1", + ident: "#!1_arg", }, ], @15-22 Defs( @@ -83,11 +83,11 @@ Defs { [ @17-18 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, @20-21 Var { module_name: "", - ident: "#!a1", + ident: "#!1_arg", }, ], Space, diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_single.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_single.snap index d9655bb25e7..c121a190255 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_single.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_single.snap @@ -35,7 +35,7 @@ Defs { @15-19 Closure( [ @17-18 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @15-19 Defs( @@ -67,7 +67,7 @@ Defs { [ @17-18 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ], Space, diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_suffixed.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_suffixed.snap index 682e7623aab..2828856b170 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_suffixed.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_argument_suffixed.snap @@ -45,7 +45,7 @@ Defs { @15-33 Closure( [ Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @15-33 Defs( @@ -78,7 +78,7 @@ Defs { @20-32 ParensAround( Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ), ], diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_function_suffixed.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_function_suffixed.snap index ec3072d8f54..d72b00aad3f 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_function_suffixed.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__apply_function_suffixed.snap @@ -45,7 +45,7 @@ Defs { @15-35 Closure( [ Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @15-35 Defs( @@ -73,7 +73,7 @@ Defs { @16-26 ParensAround( Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ), [ diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__bang_in_pipe_root.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__bang_in_pipe_root.snap index 8a9bb0e1912..62aaa64c9f0 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__bang_in_pipe_root.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__bang_in_pipe_root.snap @@ -35,7 +35,7 @@ Defs { @15-22 Closure( [ @15-16 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @15-22 Defs( @@ -67,7 +67,7 @@ Defs { [ @15-16 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ], BinOp( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__basic.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__basic.snap index 9907b760c3d..c78f101cc81 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__basic.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__basic.snap @@ -28,14 +28,58 @@ Defs { ident: "await", }, [ - @11-15 Var { - module_name: "", - ident: "foo", - }, + @11-15 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @11-15, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @11-15 Identifier { + ident: "#!0_stmt", + }, + ann_type: @11-15 Apply( + "", + "Task", + [ + @11-15 Record { + fields: [], + ext: None, + }, + @11-15 Inferred, + ], + ), + comment: None, + body_pattern: @11-15 Identifier { + ident: "#!0_stmt", + }, + body_expr: @11-15 Var { + module_name: "", + ident: "foo", + }, + }, + ], + }, + @11-15 Var { + module_name: "", + ident: "#!0_stmt", + }, + ), @11-15 Closure( [ - @11-15 RecordDestructure( - [], + @11-15 Underscore( + "#!stmt", ), ], @21-26 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__body_parens_apply.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__body_parens_apply.snap index 603e9ebafce..247b3cb142f 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__body_parens_apply.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__body_parens_apply.snap @@ -35,7 +35,7 @@ Defs { @16-35 Closure( [ Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @16-35 Defs( @@ -63,7 +63,7 @@ Defs { @17-29 ParensAround( Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ), [ diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_simple.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_simple.snap index e07bf01969e..4ed25bf707f 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_simple.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_simple.snap @@ -55,25 +55,69 @@ Defs { ident: "await", }, [ - @31-42 Apply( + @31-42 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @31-42, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @31-42 Identifier { + ident: "#!0_stmt", + }, + ann_type: @31-42 Apply( + "", + "Task", + [ + @31-42 Record { + fields: [], + ext: None, + }, + @31-42 Inferred, + ], + ), + comment: None, + body_pattern: @31-42 Identifier { + ident: "#!0_stmt", + }, + body_expr: @31-42 Apply( + @31-42 Var { + module_name: "", + ident: "line", + }, + [ + @31-34 Var { + module_name: "", + ident: "msg", + }, + ], + BinOp( + Pizza, + ), + ), + }, + ], + }, @31-42 Var { module_name: "", - ident: "line", + ident: "#!0_stmt", }, - [ - @31-34 Var { - module_name: "", - ident: "msg", - }, - ], - BinOp( - Pizza, - ), ), @31-42 Closure( [ - @31-42 RecordDestructure( - [], + @31-42 Underscore( + "#!stmt", ), ], @52-57 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_annotations.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_annotations.snap index ef9f601967b..c88b75ab111 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_annotations.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_annotations.snap @@ -70,38 +70,69 @@ Defs { ident: "msg", }, ], - @78-91 Apply( - @78-91 Var { - module_name: "Task", - ident: "await", - }, - [ - @78-91 Apply( - @78-91 Var { - module_name: "", - ident: "line", - }, - [ - @88-91 Var { - module_name: "", - ident: "msg", + @56-91 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @78-91, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @56-57 Identifier { + ident: "#!0_expr", }, - ], - Space, - ), - @78-91 Closure( - [ - @78-79 Identifier { - ident: "y", + ann_type: @60-69 Apply( + "", + "Task", + [ + @60-69 Apply( + "", + "Task", + [ + @65-67 Record { + fields: [], + ext: None, + }, + @68-69 Inferred, + ], + ), + @60-69 Inferred, + ], + ), + comment: None, + body_pattern: @78-79 Identifier { + ident: "#!0_expr", }, - ], - @100-101 Var { - module_name: "", - ident: "y", + body_expr: @78-91 Apply( + @78-91 Var { + module_name: "", + ident: "line", + }, + [ + @88-91 Var { + module_name: "", + ident: "msg", + }, + ], + Space, + ), }, - ), - ], - BangSuffix, + ], + }, + @78-91 Var { + module_name: "", + ident: "#!0_expr", + }, ), ), }, diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_defs.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_defs.snap index 12aee871b82..490fddac5a7 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_defs.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__closure_with_defs.snap @@ -98,23 +98,67 @@ Defs { ident: "await", }, [ - @76-83 Apply( + @76-83 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @76-83, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @76-83 Identifier { + ident: "#!1_stmt", + }, + ann_type: @76-83 Apply( + "", + "Task", + [ + @76-83 Record { + fields: [], + ext: None, + }, + @76-83 Inferred, + ], + ), + comment: None, + body_pattern: @76-83 Identifier { + ident: "#!1_stmt", + }, + body_expr: @76-83 Apply( + @76-83 Var { + module_name: "", + ident: "line", + }, + [ + @82-83 Var { + module_name: "", + ident: "a", + }, + ], + Space, + ), + }, + ], + }, @76-83 Var { module_name: "", - ident: "line", + ident: "#!1_stmt", }, - [ - @82-83 Var { - module_name: "", - ident: "a", - }, - ], - Space, ), @76-83 Closure( [ - @76-83 RecordDestructure( - [], + @76-83 Underscore( + "#!stmt", ), ], @92-99 Apply( @@ -123,23 +167,67 @@ Defs { ident: "await", }, [ - @92-99 Apply( + @92-99 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @92-99, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @92-99 Identifier { + ident: "#!0_stmt", + }, + ann_type: @92-99 Apply( + "", + "Task", + [ + @92-99 Record { + fields: [], + ext: None, + }, + @92-99 Inferred, + ], + ), + comment: None, + body_pattern: @92-99 Identifier { + ident: "#!0_stmt", + }, + body_expr: @92-99 Apply( + @92-99 Var { + module_name: "", + ident: "line", + }, + [ + @98-99 Var { + module_name: "", + ident: "b", + }, + ], + Space, + ), + }, + ], + }, @92-99 Var { module_name: "", - ident: "line", + ident: "#!0_stmt", }, - [ - @98-99 Var { - module_name: "", - ident: "b", - }, - ], - Space, ), @92-99 Closure( [ - @92-99 RecordDestructure( - [], + @92-99 Underscore( + "#!stmt", ), ], @109-119 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__dbg_stmt_arg.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__dbg_stmt_arg.snap index e3a74788fe7..d3918ce09bb 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__dbg_stmt_arg.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__dbg_stmt_arg.snap @@ -35,7 +35,7 @@ Defs { @11-24 Closure( [ @15-17 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @11-24 LowLevelDbg( @@ -51,7 +51,7 @@ Defs { [ @15-17 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ], Space, diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__defs_suffixed_middle.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__defs_suffixed_middle.snap index 996bf5b081d..a07119b6c8a 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__defs_suffixed_middle.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__defs_suffixed_middle.snap @@ -64,23 +64,67 @@ Defs { ident: "await", }, [ - @25-39 Apply( - @25-39 Var { - module_name: "Stdout", - ident: "line", + @25-39 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @25-39, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @25-39 Identifier { + ident: "#!1_stmt", + }, + ann_type: @25-39 Apply( + "", + "Task", + [ + @25-39 Record { + fields: [], + ext: None, + }, + @25-39 Inferred, + ], + ), + comment: None, + body_pattern: @25-39 Identifier { + ident: "#!1_stmt", + }, + body_expr: @25-39 Apply( + @25-39 Var { + module_name: "Stdout", + ident: "line", + }, + [ + @38-39 Var { + module_name: "", + ident: "a", + }, + ], + Space, + ), + }, + ], + }, + @11-54 Var { + module_name: "", + ident: "#!1_stmt", }, - [ - @38-39 Var { - module_name: "", - ident: "a", - }, - ], - Space, ), @11-54 Closure( [ - @25-39 RecordDestructure( - [], + @25-39 Underscore( + "#!stmt", ), ], @45-54 Var { diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_complex.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_complex.snap index c517084dd8b..9e62fed3526 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_complex.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_complex.snap @@ -129,7 +129,7 @@ Defs { Closure( [ Identifier { - ident: "#!a0", + ident: "#!1_arg", }, ], @109-298 If( @@ -144,7 +144,7 @@ Defs { @114-121 ParensAround( Var { module_name: "", - ident: "#!a0", + ident: "#!1_arg", }, ), ], @@ -158,24 +158,68 @@ Defs { ident: "await", }, [ - @140-152 Apply( + @140-152 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @140-152, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @140-152 Identifier { + ident: "#!0_stmt", + }, + ann_type: @140-152 Apply( + "", + "Task", + [ + @140-152 Record { + fields: [], + ext: None, + }, + @140-152 Inferred, + ], + ), + comment: None, + body_pattern: @140-152 Identifier { + ident: "#!0_stmt", + }, + body_expr: @140-152 Apply( + @140-152 Var { + module_name: "", + ident: "line", + }, + [ + @146-152 Str( + PlainLine( + "fail", + ), + ), + ], + Space, + ), + }, + ], + }, @140-152 Var { module_name: "", - ident: "line", + ident: "#!0_stmt", }, - [ - @146-152 Str( - PlainLine( - "fail", - ), - ), - ], - Space, ), @140-152 Closure( [ - @140-152 RecordDestructure( - [], + @140-152 Underscore( + "#!stmt", ), ], @165-170 Apply( @@ -218,7 +262,7 @@ Defs { Closure( [ Identifier { - ident: "#!a1", + ident: "#!3_arg", }, ], @109-298 If( @@ -227,7 +271,7 @@ Defs { @187-209 ParensAround( Var { module_name: "", - ident: "#!a1", + ident: "#!3_arg", }, ), @227-239 Apply( @@ -236,24 +280,68 @@ Defs { ident: "await", }, [ - @227-239 Apply( + @227-239 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @227-239, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @227-239 Identifier { + ident: "#!2_stmt", + }, + ann_type: @227-239 Apply( + "", + "Task", + [ + @227-239 Record { + fields: [], + ext: None, + }, + @227-239 Inferred, + ], + ), + comment: None, + body_pattern: @227-239 Identifier { + ident: "#!2_stmt", + }, + body_expr: @227-239 Apply( + @227-239 Var { + module_name: "", + ident: "line", + }, + [ + @233-239 Str( + PlainLine( + "nope", + ), + ), + ], + Space, + ), + }, + ], + }, @227-239 Var { module_name: "", - ident: "line", + ident: "#!2_stmt", }, - [ - @233-239 Str( - PlainLine( - "nope", - ), - ), - ], - Space, ), @227-239 Closure( [ - @227-239 RecordDestructure( - [], + @227-239 Underscore( + "#!stmt", ), ], @252-257 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_simple.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_simple.snap index 2bdacac9efc..02592ffa7b8 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_simple.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__if_simple.snap @@ -96,7 +96,7 @@ Defs { @79-87 Closure( [ @79-87 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @76-189 If( @@ -104,7 +104,7 @@ Defs { ( @79-87 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, @101-112 Apply( @101-105 Var { @@ -135,7 +135,7 @@ Defs { @125-132 Closure( [ @125-132 Identifier { - ident: "#!a1", + ident: "#!1_arg", }, ], @76-189 If( @@ -143,7 +143,7 @@ Defs { ( @125-132 Var { module_name: "", - ident: "#!a1", + ident: "#!1_arg", }, @146-160 Apply( @146-150 Var { diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_stmt_not_top_level_suffixed.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_stmt_not_top_level_suffixed.snap index c3d1d5865cd..8af15de1a89 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_stmt_not_top_level_suffixed.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_stmt_not_top_level_suffixed.snap @@ -62,7 +62,7 @@ Defs { @11-26 Closure( [ @24-25 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @22-26 Apply( @@ -73,7 +73,7 @@ Defs { [ @24-25 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ], Space, diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_suffixed_multiple.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_suffixed_multiple.snap index d4f68f6bea9..8a090182841 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_suffixed_multiple.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__last_suffixed_multiple.snap @@ -28,14 +28,58 @@ Defs { ident: "await", }, [ - @11-15 Var { - module_name: "", - ident: "foo", - }, + @11-15 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @11-15, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @11-15 Identifier { + ident: "#!2_stmt", + }, + ann_type: @11-15 Apply( + "", + "Task", + [ + @11-15 Record { + fields: [], + ext: None, + }, + @11-15 Inferred, + ], + ), + comment: None, + body_pattern: @11-15 Identifier { + ident: "#!2_stmt", + }, + body_expr: @11-15 Var { + module_name: "", + ident: "foo", + }, + }, + ], + }, + @11-15 Var { + module_name: "", + ident: "#!2_stmt", + }, + ), @11-15 Closure( [ - @11-15 RecordDestructure( - [], + @11-15 Underscore( + "#!stmt", ), ], @20-24 Apply( @@ -44,14 +88,58 @@ Defs { ident: "await", }, [ - @20-24 Var { - module_name: "", - ident: "bar", - }, + @20-24 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @20-24, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @20-24 Identifier { + ident: "#!1_stmt", + }, + ann_type: @20-24 Apply( + "", + "Task", + [ + @20-24 Record { + fields: [], + ext: None, + }, + @20-24 Inferred, + ], + ), + comment: None, + body_pattern: @20-24 Identifier { + ident: "#!1_stmt", + }, + body_expr: @20-24 Var { + module_name: "", + ident: "bar", + }, + }, + ], + }, + @20-24 Var { + module_name: "", + ident: "#!1_stmt", + }, + ), @20-24 Closure( [ - @20-24 RecordDestructure( - [], + @20-24 Underscore( + "#!stmt", ), ], @29-33 Var { diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multi_defs_stmts.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multi_defs_stmts.snap index c5ced02d17b..3f9caf99ca0 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multi_defs_stmts.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multi_defs_stmts.snap @@ -28,24 +28,68 @@ Defs { ident: "await", }, [ - @11-23 Apply( + @11-23 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @11-23, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @11-23 Identifier { + ident: "#!0_stmt", + }, + ann_type: @11-23 Apply( + "", + "Task", + [ + @11-23 Record { + fields: [], + ext: None, + }, + @11-23 Inferred, + ], + ), + comment: None, + body_pattern: @11-23 Identifier { + ident: "#!0_stmt", + }, + body_expr: @11-23 Apply( + @11-23 Var { + module_name: "", + ident: "line", + }, + [ + @17-23 Str( + PlainLine( + "Ahoy", + ), + ), + ], + Space, + ), + }, + ], + }, @11-23 Var { module_name: "", - ident: "line", + ident: "#!0_stmt", }, - [ - @17-23 Str( - PlainLine( - "Ahoy", - ), - ), - ], - Space, ), @11-23 Closure( [ - @11-23 RecordDestructure( - [], + @11-23 Underscore( + "#!stmt", ), ], @33-55 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multiple_suffix.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multiple_suffix.snap index 945758bd5e7..4e2c7cb925d 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multiple_suffix.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__multiple_suffix.snap @@ -22,46 +22,77 @@ Defs { @0-4 Identifier { ident: "main", }, - @11-24 Apply( - @11-24 Var { + @11-16 Apply( + @11-16 Var { module_name: "Task", ident: "await", }, [ - @11-16 Var { - module_name: "", - ident: "foo", - }, - @11-24 Closure( - [ - @11-16 Identifier { - ident: "#!a0", - }, - ], - @11-16 Apply( - @11-16 Var { - module_name: "Task", - ident: "await", - }, - [ - @11-16 Var { - module_name: "", - ident: "#!a0", - }, - @11-16 Closure( - [ - @11-16 RecordDestructure( - [], - ), - ], - @21-24 Var { + @11-16 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @11-16, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @11-16 Identifier { + ident: "#!1_stmt", + }, + ann_type: @11-16 Apply( + "", + "Task", + [ + @11-16 Apply( + "", + "Task", + [ + @11-16 Record { + fields: [], + ext: None, + }, + @11-16 Inferred, + ], + ), + @11-16 Inferred, + ], + ), + comment: None, + body_pattern: @11-16 Identifier { + ident: "#!1_stmt", + }, + body_expr: @11-16 Var { module_name: "", - ident: "bar", + ident: "foo", }, - ), + }, ], - BangSuffix, - ), + }, + @11-16 Var { + module_name: "", + ident: "#!1_stmt", + }, + ), + @11-16 Closure( + [ + @11-16 Underscore( + "#!stmt", + ), + ], + @21-24 Var { + module_name: "", + ident: "bar", + }, ), ], BangSuffix, diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_complex.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_complex.snap index 0e75e9dfe9b..f9a595f7f96 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_complex.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_complex.snap @@ -44,7 +44,7 @@ Defs { @15-43 Closure( [ Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @15-43 Apply( @@ -62,7 +62,7 @@ Defs { @21-29 ParensAround( Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ), @32-42 ParensAround( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_simple.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_simple.snap index 8e0d3d20231..b670cca0e45 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_simple.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__nested_simple.snap @@ -35,7 +35,7 @@ Defs { @0-22 Closure( [ Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @0-22 Apply( @@ -47,7 +47,7 @@ Defs { @13-21 ParensAround( Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, ), ], diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__simple_pizza.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__simple_pizza.snap index 2f8ede049bd..5bf0ebd4e0c 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__simple_pizza.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__simple_pizza.snap @@ -28,42 +28,86 @@ Defs { ident: "await", }, [ - @11-56 Apply( - @11-56 Var { - module_name: "", - ident: "line", - }, - [ - @11-44 Apply( - @26-36 Var { - module_name: "Str", - ident: "concat", - }, - [ - @11-18 Str( - PlainLine( - "hello", - ), + @26-56 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @11-56, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @26-56 Identifier { + ident: "#!0_stmt", + }, + ann_type: @26-56 Apply( + "", + "Task", + [ + @26-56 Record { + fields: [], + ext: None, + }, + @26-56 Inferred, + ], ), - @37-44 Str( - PlainLine( - "world", + comment: None, + body_pattern: @26-56 Identifier { + ident: "#!0_stmt", + }, + body_expr: @11-56 Apply( + @11-56 Var { + module_name: "", + ident: "line", + }, + [ + @11-44 Apply( + @26-36 Var { + module_name: "Str", + ident: "concat", + }, + [ + @11-18 Str( + PlainLine( + "hello", + ), + ), + @37-44 Str( + PlainLine( + "world", + ), + ), + ], + BinOp( + Pizza, + ), + ), + ], + BinOp( + Pizza, ), ), - ], - BinOp( - Pizza, - ), - ), - ], - BinOp( - Pizza, - ), + }, + ], + }, + @11-56 Var { + module_name: "", + ident: "#!0_stmt", + }, ), @11-56 Closure( [ - @26-56 RecordDestructure( - [], + @26-56 Underscore( + "#!stmt", ), ], @63-73 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_binops.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_binops.snap index d616d3f91fd..52dbd271583 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_binops.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_binops.snap @@ -37,24 +37,68 @@ Defs { ident: "await", }, [ - @19-30 Apply( + @19-30 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @19-30, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @19-30 Identifier { + ident: "#!1_stmt", + }, + ann_type: @19-30 Apply( + "", + "Task", + [ + @19-30 Record { + fields: [], + ext: None, + }, + @19-30 Inferred, + ], + ), + comment: None, + body_pattern: @19-30 Identifier { + ident: "#!1_stmt", + }, + body_expr: @19-30 Apply( + @19-30 Var { + module_name: "", + ident: "line", + }, + [ + @25-30 Str( + PlainLine( + "FOO", + ), + ), + ], + Space, + ), + }, + ], + }, @19-30 Var { module_name: "", - ident: "line", + ident: "#!1_stmt", }, - [ - @25-30 Str( - PlainLine( - "FOO", - ), - ), - ], - Space, ), @19-30 Closure( [ - @19-30 RecordDestructure( - [], + @19-30 Underscore( + "#!stmt", ), ], @36-67 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__type_annotation.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__type_annotation.snap new file mode 100644 index 00000000000..e53888deea0 --- /dev/null +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__type_annotation.snap @@ -0,0 +1,112 @@ +--- +source: crates/compiler/can/tests/test_suffixed.rs +expression: snapshot +--- +Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @0-44, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-1 Identifier { + ident: "f", + }, + @4-44 Closure( + [ + @5-6 Identifier { + ident: "x", + }, + ], + @24-30 Apply( + @24-30 Var { + module_name: "Task", + ident: "await", + }, + [ + @14-30 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @24-30, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @14-15 Identifier { + ident: "#!0_expr", + }, + ann_type: @18-19 Apply( + "", + "Task", + [ + @18-19 Apply( + "", + "A", + [], + ), + @18-19 Inferred, + ], + ), + comment: None, + body_pattern: @24-25 Identifier { + ident: "#!0_expr", + }, + body_expr: @24-30 Var { + module_name: "", + ident: "x", + }, + }, + ], + }, + @24-30 Var { + module_name: "", + ident: "#!0_expr", + }, + ), + @24-30 Closure( + [ + @24-25 Identifier { + ident: "r", + }, + ], + @35-44 Apply( + @35-42 Var { + module_name: "Task", + ident: "ok", + }, + [ + @43-44 Var { + module_name: "", + ident: "r", + }, + ], + Space, + ), + ), + ], + BangSuffix, + ), + ), + ), + ], +} diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__var_suffixes.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__var_suffixes.snap index 7bd511af7ae..89099ba13b3 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__var_suffixes.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__var_suffixes.snap @@ -51,7 +51,7 @@ Defs { @15-19 Closure( [ @24-33 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @24-33 Apply( @@ -62,7 +62,7 @@ Defs { [ @24-33 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, @24-33 Closure( [ diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_branches.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_branches.snap index be4fbe082a7..c8ef89774fa 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_branches.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_branches.snap @@ -35,13 +35,13 @@ Defs { @11-120 Closure( [ @16-24 Identifier { - ident: "#!a1", + ident: "#!2_arg", }, ], @11-120 When( @16-24 Var { module_name: "", - ident: "#!a1", + ident: "#!2_arg", }, [ WhenBranch { @@ -56,24 +56,68 @@ Defs { ident: "await", }, [ - @54-65 Apply( + @54-65 Defs( + Defs { + tags: [ + Index(2147483648), + ], + regions: [ + @54-65, + ], + space_before: [ + Slice(start = 0, length = 0), + ], + space_after: [ + Slice(start = 0, length = 0), + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @54-65 Identifier { + ident: "#!1_stmt", + }, + ann_type: @54-65 Apply( + "", + "Task", + [ + @54-65 Record { + fields: [], + ext: None, + }, + @54-65 Inferred, + ], + ), + comment: None, + body_pattern: @54-65 Identifier { + ident: "#!1_stmt", + }, + body_expr: @54-65 Apply( + @54-65 Var { + module_name: "", + ident: "line", + }, + [ + @60-65 Str( + PlainLine( + "foo", + ), + ), + ], + Space, + ), + }, + ], + }, @54-65 Var { module_name: "", - ident: "line", + ident: "#!1_stmt", }, - [ - @60-65 Str( - PlainLine( - "foo", - ), - ), - ], - Space, ), @54-65 Closure( [ - @54-65 RecordDestructure( - [], + @54-65 Underscore( + "#!stmt", ), ], @78-89 Apply( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_simple.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_simple.snap index 1aaeca4b284..443dc9d0651 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_simple.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__when_simple.snap @@ -35,13 +35,13 @@ Defs { @11-74 Closure( [ @16-24 Identifier { - ident: "#!a0", + ident: "#!0_arg", }, ], @11-74 When( @16-24 Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }, [ WhenBranch { From 863fb3b29fe180e6db857c64daed10b7228d3e3f Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Tue, 16 Jul 2024 11:33:47 +0200 Subject: [PATCH 09/12] remove obsolete test --- crates/compiler/can/tests/test_suffixed.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/crates/compiler/can/tests/test_suffixed.rs b/crates/compiler/can/tests/test_suffixed.rs index 9ef2be2965b..0b9e618ec49 100644 --- a/crates/compiler/can/tests/test_suffixed.rs +++ b/crates/compiler/can/tests/test_suffixed.rs @@ -564,8 +564,6 @@ mod suffixed_tests { mod test_suffixed_helpers { use roc_can::suffixed::is_matching_intermediate_answer; - use roc_module::called_via::CalledVia; - use roc_module::ident::ModuleName; use roc_parse::ast::Expr; use roc_parse::ast::Pattern; use roc_region::all::Loc; @@ -580,21 +578,4 @@ mod test_suffixed_helpers { std::assert!(is_matching_intermediate_answer(&loc_pat, &loc_new)); } - - #[test] - fn test_matching_answer_task_ok() { - let loc_pat = Loc::at_zero(Pattern::Identifier { ident: "#!a0" }); - let intermetiate = &[&Loc::at_zero(Expr::Var { - module_name: "", - ident: "#!a0", - })]; - let task_ok = Loc::at_zero(Expr::Var { - module_name: ModuleName::TASK, - ident: "ok", - }); - - let loc_new = Loc::at_zero(Expr::Apply(&task_ok, intermetiate, CalledVia::BangSuffix)); - - std::assert!(is_matching_intermediate_answer(&loc_pat, &loc_new)); - } } From 692f8e8090056056f72253ec140cf98a158b012c Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Tue, 16 Jul 2024 11:50:28 +0200 Subject: [PATCH 10/12] remove redundant dependency --- Cargo.lock | 1 - crates/compiler/can/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47570a85248..e44c1472b98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2347,7 +2347,6 @@ dependencies = [ "roc_collections", "roc_error_macros", "roc_exhaustive", - "roc_fmt", "roc_module", "roc_parse", "roc_problem", diff --git a/crates/compiler/can/Cargo.toml b/crates/compiler/can/Cargo.toml index 9ef92392782..76b115bd5af 100644 --- a/crates/compiler/can/Cargo.toml +++ b/crates/compiler/can/Cargo.toml @@ -13,7 +13,6 @@ roc_error_macros = { path = "../../error_macros" } roc_exhaustive = { path = "../exhaustive" } roc_module = { path = "../module" } roc_parse = { path = "../parse" } -roc_fmt = { path = "../fmt" } roc_problem = { path = "../problem" } roc_region = { path = "../region" } roc_serialize = { path = "../serialize" } From 0086a531a20b6769598f90a9ae9f2739fcdcc14f Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Tue, 16 Jul 2024 11:56:42 +0200 Subject: [PATCH 11/12] add todo tests --- crates/compiler/load/tests/test_reporting.rs | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/crates/compiler/load/tests/test_reporting.rs b/crates/compiler/load/tests/test_reporting.rs index 71418e4288c..4eb61cef502 100644 --- a/crates/compiler/load/tests/test_reporting.rs +++ b/crates/compiler/load/tests/test_reporting.rs @@ -14503,4 +14503,38 @@ In roc, functions are always written as a lambda, like{} make partial application explicit. " ); + + // TODO: add the following tests after built-in Tasks are added + // https://github.com/roc-lang/roc/pull/6836 + + // test_report!( + // suffixed_stmt_invalid_type, + // indoc!( + // r###" + // app "test" provides [main] to "./platform" + + // main : Task U64 _ -> _ + // main = \task -> + // task! + // 42 + // "### + // ), + // @r"" + // ); + + // test_report!( + // suffixed_expr_invalid_type, + // indoc!( + // r###" + // app "test" provides [main] to "./platform" + + // main : Task U64 _ -> _ + // main = \task -> + // result : U32 + // result = task! + // result + // "### + // ), + // @r"" + // ); } From 7aa31a16390d0ff82b5ae662f53af2e7ba1ebe57 Mon Sep 17 00:00:00 2001 From: Kiryl Dziamura Date: Mon, 22 Jul 2024 20:04:43 +0200 Subject: [PATCH 12/12] code cleanup --- crates/compiler/can/src/suffixed.rs | 14 ++++++++------ crates/compiler/can/tests/test_suffixed.rs | 8 ++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/compiler/can/src/suffixed.rs b/crates/compiler/can/src/suffixed.rs index 4656a0a650c..b9299566d25 100644 --- a/crates/compiler/can/src/suffixed.rs +++ b/crates/compiler/can/src/suffixed.rs @@ -39,7 +39,7 @@ pub enum EUnwrapped<'a> { /// Suffixed sub expression /// e.g. x = first! (second! 42) /// In this example, the second unwrap (after unwrapping the top level `first!`) will produce - /// `UnwrappedSubExpr<{ sub_arg: second 42, sub_pat: #!a0, sub_new: #!a0 }>` + /// `UnwrappedSubExpr<{ sub_arg: second 42, sub_pat: #!0_arg, sub_new: #!0_arg }>` UnwrappedSubExpr { /// the unwrapped expression argument for Task.await sub_arg: &'a Loc>, @@ -69,7 +69,7 @@ fn init_unwrapped_err<'a>( None => { // Provide an intermediate answer expression and pattern when unwrapping a // (sub) expression. - // e.g. `x = foo (bar!)` unwraps to `x = Task.await (bar) \#!a0 -> foo #!a0` + // e.g. `x = foo (bar!)` unwraps to `x = Task.await (bar) \#!0_arg -> foo #!0_arg` let ident = arena.alloc(format!("{}_arg", next_unique_suffixed_ident())); let sub_new = arena.alloc(Loc::at( unwrapped_expr.region, @@ -861,7 +861,7 @@ pub fn apply_task_await<'a>( // \loc_pat -> loc_cont use roc_parse::ast::*; - // #!a0 + // #!0_expr or #!0_stmt let new_ident = next_unique_suffixed_ident(); let new_ident = match loc_pat.value { Pattern::Underscore("#!stmt") => format!("{}_stmt", new_ident), @@ -930,7 +930,7 @@ pub fn apply_task_await<'a>( Defs(arena.alloc(defs), new_var), )) } - _ => { + None => { // loc_pat = loc_expr! // loc_cont @@ -940,8 +940,10 @@ pub fn apply_task_await<'a>( } }; - // If the pattern and the new are matching answers then we don't need to unwrap anything - // e.g. `Task.await foo \#!a1 -> Task.ok #!a1` is the same as `foo` + // If the last expression is suffixed - don't await + // e.g. + // \x -> x! + // \x -> x if is_matching_intermediate_answer(loc_pat, loc_cont) { return task_await_first_arg; } diff --git a/crates/compiler/can/tests/test_suffixed.rs b/crates/compiler/can/tests/test_suffixed.rs index 0b9e618ec49..48ac9fb91ca 100644 --- a/crates/compiler/can/tests/test_suffixed.rs +++ b/crates/compiler/can/tests/test_suffixed.rs @@ -128,7 +128,7 @@ mod suffixed_tests { * Example with a parens suffixed sub-expression * in the function part of an Apply. * - * Note how the parens unwraps into an intermediate answer #!a0 instead of + * Note how the parens unwraps into an intermediate answer #!0_arg instead of * unwrapping the def `do`. * */ @@ -162,7 +162,7 @@ mod suffixed_tests { /** * Example with a multiple suffixed Var * - * Note it unwraps into an intermediate answer `#!a0` + * Note it unwraps into an intermediate answer `#!0_arg` * */ #[test] @@ -570,10 +570,10 @@ mod test_suffixed_helpers { #[test] fn test_matching_answer() { - let loc_pat = Loc::at_zero(Pattern::Identifier { ident: "#!a0" }); + let loc_pat = Loc::at_zero(Pattern::Identifier { ident: "#!0_arg" }); let loc_new = Loc::at_zero(Expr::Var { module_name: "", - ident: "#!a0", + ident: "#!0_arg", }); std::assert!(is_matching_intermediate_answer(&loc_pat, &loc_new));