@@ -4894,13 +4894,128 @@ pub fn canonicalizeExpr(
48944894 .free_vars = null ,
48954895 };
48964896 },
4897- .local_dispatch = > | _ | {
4898- const feature = try self .env .insertString ("canonicalize local_dispatch expression" );
4899- const expr_idx = try self .env .pushMalformed (Expr .Idx , Diagnostic { .not_implemented = .{
4900- .feature = feature ,
4901- .region = Region .zero (),
4902- } });
4903- return CanonicalizedExpr { .idx = expr_idx , .free_vars = null };
4897+ .local_dispatch = > | local_dispatch | {
4898+ // Desugar `arg1->fn(arg2, arg3)` to `fn(arg1, arg2, arg3)`
4899+ // and `arg1->fn` to `fn(arg1)`
4900+ const region = self .parse_ir .tokenizedRegionToRegion (local_dispatch .region );
4901+ const free_vars_start = self .scratch_free_vars .top ();
4902+
4903+ // Canonicalize the left expression (first argument)
4904+ const can_first_arg = try self .canonicalizeExpr (local_dispatch .left ) orelse return null ;
4905+
4906+ // Get the right expression to determine the function and additional args
4907+ const right_expr = self .parse_ir .store .getExpr (local_dispatch .right );
4908+
4909+ switch (right_expr ) {
4910+ .apply = > | apply | {
4911+ // Case: `arg1->fn(arg2, arg3)` - function call with additional args
4912+ // Check if this is a tag application
4913+ const ast_fn = self .parse_ir .store .getExpr (apply .@"fn" );
4914+ if (ast_fn == .tag ) {
4915+ // Tag application: `arg1->Tag(arg2)` becomes `Tag(arg1, arg2)`
4916+ const tag_expr = ast_fn .tag ;
4917+ const tag_name = self .parse_ir .tokens .resolveIdentifier (tag_expr .token ) orelse @panic ("tag token is not an ident" );
4918+
4919+ // Build args: first_arg followed by apply.args
4920+ const scratch_top = self .env .store .scratchExprTop ();
4921+ try self .env .store .addScratchExpr (can_first_arg .idx );
4922+
4923+ const additional_args = self .parse_ir .store .exprSlice (apply .args );
4924+ for (additional_args ) | arg | {
4925+ if (try self .canonicalizeExpr (arg )) | can_arg | {
4926+ try self .env .store .addScratchExpr (can_arg .idx );
4927+ }
4928+ }
4929+
4930+ const args_span = try self .env .store .exprSpanFrom (scratch_top );
4931+
4932+ const expr_idx = try self .env .addExpr (CIR.Expr {
4933+ .e_tag = .{
4934+ .name = tag_name ,
4935+ .args = args_span ,
4936+ },
4937+ }, region );
4938+
4939+ const free_vars_span = self .scratch_free_vars .spanFrom (free_vars_start );
4940+ return CanonicalizedExpr { .idx = expr_idx , .free_vars = if (free_vars_span .len > 0 ) free_vars_span else null };
4941+ }
4942+
4943+ // Normal function call
4944+ const can_fn_expr = try self .canonicalizeExpr (apply .@"fn" ) orelse return null ;
4945+
4946+ // Build args: first_arg followed by apply.args
4947+ const scratch_top = self .env .store .scratchExprTop ();
4948+ try self .env .store .addScratchExpr (can_first_arg .idx );
4949+
4950+ const additional_args = self .parse_ir .store .exprSlice (apply .args );
4951+ for (additional_args ) | arg | {
4952+ if (try self .canonicalizeExpr (arg )) | can_arg | {
4953+ try self .env .store .addScratchExpr (can_arg .idx );
4954+ }
4955+ }
4956+
4957+ const args_span = try self .env .store .exprSpanFrom (scratch_top );
4958+
4959+ const expr_idx = try self .env .addExpr (CIR.Expr {
4960+ .e_call = .{
4961+ .func = can_fn_expr .idx ,
4962+ .args = args_span ,
4963+ .called_via = CalledVia .apply ,
4964+ },
4965+ }, region );
4966+
4967+ const free_vars_span = self .scratch_free_vars .spanFrom (free_vars_start );
4968+ return CanonicalizedExpr { .idx = expr_idx , .free_vars = if (free_vars_span .len > 0 ) free_vars_span else null };
4969+ },
4970+ .ident , .tag = > {
4971+ // Case: `arg1->fn` or `arg1->Tag` - simple function/tag call with single arg
4972+ if (right_expr == .tag ) {
4973+ const tag_expr = right_expr .tag ;
4974+ const tag_name = self .parse_ir .tokens .resolveIdentifier (tag_expr .token ) orelse @panic ("tag token is not an ident" );
4975+
4976+ const scratch_top = self .env .store .scratchExprTop ();
4977+ try self .env .store .addScratchExpr (can_first_arg .idx );
4978+ const args_span = try self .env .store .exprSpanFrom (scratch_top );
4979+
4980+ const expr_idx = try self .env .addExpr (CIR.Expr {
4981+ .e_tag = .{
4982+ .name = tag_name ,
4983+ .args = args_span ,
4984+ },
4985+ }, region );
4986+
4987+ const free_vars_span = self .scratch_free_vars .spanFrom (free_vars_start );
4988+ return CanonicalizedExpr { .idx = expr_idx , .free_vars = if (free_vars_span .len > 0 ) free_vars_span else null };
4989+ }
4990+
4991+ // It's an ident
4992+ const can_fn_expr = try self .canonicalizeExpr (local_dispatch .right ) orelse return null ;
4993+
4994+ const scratch_top = self .env .store .scratchExprTop ();
4995+ try self .env .store .addScratchExpr (can_first_arg .idx );
4996+ const args_span = try self .env .store .exprSpanFrom (scratch_top );
4997+
4998+ const expr_idx = try self .env .addExpr (CIR.Expr {
4999+ .e_call = .{
5000+ .func = can_fn_expr .idx ,
5001+ .args = args_span ,
5002+ .called_via = CalledVia .apply ,
5003+ },
5004+ }, region );
5005+
5006+ const free_vars_span = self .scratch_free_vars .spanFrom (free_vars_start );
5007+ return CanonicalizedExpr { .idx = expr_idx , .free_vars = if (free_vars_span .len > 0 ) free_vars_span else null };
5008+ },
5009+ else = > {
5010+ // Unexpected expression type on right side of arrow
5011+ const feature = try self .env .insertString ("arrow with complex expression" );
5012+ const expr_idx = try self .env .pushMalformed (Expr .Idx , Diagnostic { .not_implemented = .{
5013+ .feature = feature ,
5014+ .region = region ,
5015+ } });
5016+ return CanonicalizedExpr { .idx = expr_idx , .free_vars = null };
5017+ },
5018+ }
49045019 },
49055020 .bin_op = > | e | {
49065021 const region = self .parse_ir .tokenizedRegionToRegion (e .region );
0 commit comments