diff --git a/crates/compiler/can/src/desugar.rs b/crates/compiler/can/src/desugar.rs index 051569943ec..a036b1b7669 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("#!stmt"))); + + 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_pattern, ann_type)), ), }, ), diff --git a/crates/compiler/can/src/suffixed.rs b/crates/compiler/can/src/suffixed.rs index c3dc5d0e5fc..b9299566d25 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; @@ -23,14 +23,23 @@ 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) }) } #[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: #!0_arg, sub_new: #!0_arg }>` 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, } @@ -59,20 +69,18 @@ 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` - let answer_ident = arena.alloc(next_unique_suffixed_ident()); + // 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, 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 { @@ -240,7 +248,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 +369,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 +451,7 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>( sub_arg, sub_pat, new_if, + None, ); return unwrap_suffixed_expression( @@ -464,6 +479,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 +516,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 +551,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 +580,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 +617,15 @@ 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, .. } => Some((body_pattern, body_expr, Some((ann_pattern, ann_type)))), + 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 +642,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, None) } 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 +657,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, None) } Err(EUnwrapped::UnwrappedDefExpr(..)) | Err(EUnwrapped::Malformed) => { // TODO handle case when we have maybe_def_pat so can return an unwrapped up @@ -649,19 +665,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, 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); } @@ -679,13 +695,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, 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); } @@ -700,7 +716,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) @@ -710,14 +726,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)))) + 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) + unwrap_suffixed_expression(arena, new_defs, None) } Err(EUnwrapped::UnwrappedDefExpr(..)) => { // TODO confirm this is correct with test case @@ -761,7 +777,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 +836,122 @@ 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_ann: Option<(&'a Loc, &'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_ann { + Some((loc_ann_pat, loc_type)) => { + // loc_ann_pat : loc_type + // loc_pat = loc_expr! + // loc_cont + + // desugar to + // Task.await + // ( + // #!0_expr : Task loc_type _ + // #!0_expr = loc_expr + // #!0_expr + // ) + // \loc_pat -> loc_cont + use roc_parse::ast::*; + + // #!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), + 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); + + // #!0_expr (pattern) + // #!0_expr : Task loc_type _ + // #!0_expr = loc_expr + let value_def = ValueDef::AnnotatedBody { + 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( + loc_type.region, + TypeAnnotation::Apply( + arena.alloc(""), + arena.alloc("Task"), + arena.alloc([ + *loc_type, + Loc::at(loc_type.region, TypeAnnotation::Inferred), + ]), + ), + )), + comment: None, + body_pattern: arena.alloc(Loc::at( + loc_pat.region, + Pattern::Identifier { ident: new_ident }, + )), + body_expr: loc_expr, + }; + + // #!0_expr (variable) + let new_var = arena.alloc(Loc::at( + region, + Expr::Var { + module_name: "", + ident: new_ident, + }, + )); + + // ( + // #!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::span_across(&loc_ann_pat.region, &loc_expr.region), + Defs(arena.alloc(defs), new_var), + )) + } + None => { + // loc_pat = loc_expr! + // loc_cont - let mut task_await_apply_args: Vec<&'a Loc>> = Vec::new_in(arena); + // desugar to + // Task.await loc_expr \loc_pat -> loc_cont + loc_expr + } + }; - // apply the unwrapped suffixed expression - task_await_apply_args.push(loc_arg); + // 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; + } - // 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_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,24 +962,12 @@ pub fn apply_task_await<'a>( ident: "await", }, }), - arena.alloc(task_await_apply_args), + arena.alloc([task_await_first_arg, closure]), CalledVia::BangSuffix, ), )) } -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>, @@ -876,24 +976,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, } } 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 { diff --git a/crates/compiler/can/tests/test_suffixed.rs b/crates/compiler/can/tests/test_suffixed.rs index 329db343550..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] @@ -546,43 +546,36 @@ mod suffixed_tests { "## ); } + + #[test] + fn type_annotation() { + run_test!( + r##" + f = \x -> + r : A + r = x! + Task.ok r + "## + ); + } } #[cfg(test)] 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; #[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)); } - - #[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)); - } } 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"" + // ); } 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, ) };