Repository: Kakadu/comp24
Pull request #58: BasedML (Middleend): Match and pattern elimination
Author: login: Salvatore112
Created: 2025-02-28T22:15:33Z | Merged: 2025-03-03T14:25:20Z



Diff:
diff --git a/BasedML/lib/middleend/alpha_conversion.ml b/BasedML/lib/middleend/alpha_conversion.ml
index ecc846247..7ba4edb53 100644
--- a/BasedML/lib/middleend/alpha_conversion.ml
+++ b/BasedML/lib/middleend/alpha_conversion.ml
@@ -349,7 +349,9 @@ let rec alpha_convert_decl_list ctx acc = function
              :: acc)
             tail
         | DLet (let_pat, let_body) :: tl ->
-          let* renamed_body, ctx_after_body = alpha_convert_expr ctx let_body in
+          let* renamed_body, ctx_after_body =
+            alpha_convert_expr { ctx with name_mapping = full_ctx.name_mapping } let_body
+          in
           let* renamed_let_pat, ctx_after_let_name =
             alpha_convert_pattern
               { ctx with reserved_names = ctx_after_body.reserved_names }
diff --git a/BasedML/lib/middleend/anf.ml b/BasedML/lib/middleend/anf.ml
index c34a95a52..b9c29e8bb 100644
--- a/BasedML/lib/middleend/anf.ml
+++ b/BasedML/lib/middleend/anf.ml
@@ -31,14 +31,12 @@ type prefix =
   | Tuple
   | Application
   | Constraint
-  | Matching
 
 let prefix_to_string = function
   | IfThenElse -> "anf_ifthenelse_"
   | Tuple -> "anf_tuple_"
   | Application -> "anf_app_"
   | Constraint -> "anf_constraint_"
-  | Matching -> "anf_matching_"
 ;;
 
 let get_new_num =
@@ -82,7 +80,7 @@ let rec anf ctx llexpr expr_with_hole =
       let* fresh_name = new_name Constraint ctx in
       let imm_id = ImmIdentifier fresh_name in
       let* aexp = expr_with_hole imm_id in
-      return (ALetIn (PIdentifier fresh_name, CImmExpr (ImmConstraint (imm, typ)), aexp)))
+      return (ALetIn (fresh_name, CImmExpr (ImmConstraint (imm, typ)), aexp)))
   | LLIfThenElse (guard, then_branch, else_branch) ->
     anf ctx guard (fun imm_guard ->
       let* then_aexpr =
@@ -94,15 +92,13 @@ let rec anf ctx llexpr expr_with_hole =
       let* fresh_name = new_name IfThenElse ctx in
       let imm_id = ImmIdentifier fresh_name in
       let* aexp = expr_with_hole imm_id in
-      return
-        (ALetIn
-           (PIdentifier fresh_name, CIfThenElse (imm_guard, then_aexpr, else_aexpr), aexp)))
+      return (ALetIn (fresh_name, CIfThenElse (imm_guard, then_aexpr, else_aexpr), aexp)))
   | LLTuple elems ->
     anf_list ctx elems (fun list ->
       let* fresh_name = new_name Tuple ctx in
       let imm_id = ImmIdentifier fresh_name in
       let* aexp = expr_with_hole imm_id in
-      return (ALetIn (PIdentifier fresh_name, CImmExpr (ImmTuple list), aexp)))
+      return (ALetIn (fresh_name, CImmExpr (ImmTuple list), aexp)))
   | LLApplication (left, right) ->
     let rec sep_llapp exp cont =
       match exp with
@@ -112,7 +108,7 @@ let rec anf ctx llexpr expr_with_hole =
     in
     let rest, llexp = sep_llapp (LLApplication (left, right)) Fun.id in
     anf ctx llexp (fun imm_exp ->
-      anf_list ctx (List.rev rest) (fun imm_rest ->
+      anf_list ctx rest (fun imm_rest ->
         let* fresh_name = new_name Application ctx in
         let imm_id = ImmIdentifier fresh_name in
         let* aexp = expr_with_hole imm_id in
@@ -123,27 +119,14 @@ let rec anf ctx llexpr expr_with_hole =
             return (CApplication (CImmExpr h, rest))
           | [] -> fail "Error while building application"
         in
-        let* built_app = build_app (imm_exp :: imm_rest) in
-        return (ALetIn (PIdentifier fresh_name, built_app, aexp))))
-  | LLMatch (exp, cases) ->
-    let rec convert_cases cases acc =
-      match cases with
-      | (pat, exp) :: tl ->
-        let* aexpr = anf ctx exp (fun timm -> return (ACExpr (CImmExpr timm))) in
-        convert_cases tl ((pat, aexpr) :: acc)
-      | [] -> return (List.rev acc)
-    in
-    let* cases = convert_cases cases [] in
-    anf ctx exp (fun imm_exp ->
-      let* fresh_name = new_name Matching ctx in
-      let imm_id = ImmIdentifier fresh_name in
-      let* aexp = expr_with_hole imm_id in
-      return (ALetIn (PIdentifier fresh_name, CMatch (imm_exp, cases), aexp)))
-  | LLLetIn (_, pat, outer, inner) ->
-    let new_env = Lambda_lifting.collect_bindings_from_pat pat in
+        let* built_app = build_app (imm_exp :: List.rev imm_rest) in
+        return (ALetIn (fresh_name, built_app, aexp))))
+  | LLLetIn (_, PIdentifier id, outer, inner) ->
+    let new_env = Lambda_lifting.collect_bindings_from_pat (PIdentifier id) in
     anf new_env outer (fun imm_outer ->
       let* aexp = anf new_env inner expr_with_hole in
-      return (ALetIn (pat, CImmExpr imm_outer, aexp)))
+      return (ALetIn (id, CImmExpr imm_outer, aexp)))
+  | _ -> "Error: unexpected expression" |> fail
 ;;
 
 let rec map1 f = function
@@ -156,20 +139,28 @@ let anf_decl env =
     Base.Set.union acc (Lambda_lifting.collect_bindings_from_pat pat)
   in
   let process_lllet = function
-    | LLLet (pat, args, e) ->
+    | LLLet (PIdentifier id, args, e) ->
+      let* new_args =
+        map1
+          (function
+            | PIdentifier x -> x |> return
+            | _ -> fail "Error: unexpected arguments")
+          args
+      in
       let* aexp =
         anf (List.fold_left collect_bindings env args) e (fun ie ->
           return (ACExpr (CImmExpr ie)))
       in
-      return (ALet (pat, args, aexp))
+      return (ALet (id, new_args, aexp))
+    | _ -> fail "Error: unexpected lllet"
   in
   function
   | LLDSingleLet (rec_flag, LLLet (pat, args, e)) ->
     let* anf_let = process_lllet (LLLet (pat, args, e)) in
     return (ADSingleLet (rec_flag, anf_let))
-  | LLDMutualRecDecl (rec_flag, decls) ->
+  | LLDMutualRecDecl (_, decls) ->
     let* anf_decls = map1 process_lllet decls in
-    return (ADMutualRecDecl (rec_flag, anf_decls))
+    return (ADMutualRecDecl anf_decls)
 ;;
 
 let transform decls =
diff --git a/BasedML/lib/middleend/anf_ast.ml b/BasedML/lib/middleend/anf_ast.ml
index d4da236d0..04ceccf66 100644
--- a/BasedML/lib/middleend/anf_ast.ml
+++ b/BasedML/lib/middleend/anf_ast.ml
@@ -16,17 +16,16 @@ type immexpr =
 type cexpr =
   | CApplication of cexpr * cexpr
   | CIfThenElse of immexpr * aexpr * aexpr
-  | CMatch of immexpr * (pattern * aexpr) list
   | CImmExpr of immexpr
 
 and aexpr =
-  | ALetIn of pattern * cexpr * aexpr
+  | ALetIn of string * cexpr * aexpr
   | ACExpr of cexpr
 
-type single_anf_binding = ALet of pattern * pattern list * aexpr
+type single_anf_binding = ALet of string * string list * aexpr
 
 type anf_decl =
   | ADSingleLet of rec_flag * single_anf_binding
-  | ADMutualRecDecl of rec_flag * single_anf_binding list (**List.length >= 2 *)
+  | ADMutualRecDecl of single_anf_binding list (**List.length >= 2 *)
 
 type anf_prog = anf_decl list
diff --git a/BasedML/lib/middleend/anf_to_str.ml b/BasedML/lib/middleend/anf_to_str.ml
index 2425d8a06..44774393c 100644
--- a/BasedML/lib/middleend/anf_to_str.ml
+++ b/BasedML/lib/middleend/anf_to_str.ml
@@ -26,14 +26,6 @@ let rec type_name_to_string tp =
   | TList tp -> Printf.sprintf "(%s list)" (type_name_to_string tp)
 ;;
 
-let constant_to_string = function
-  | CInt i -> string_of_int i
-  | CBool false -> "false"
-  | CBool true -> "true"
-  | CNil -> "[]"
-  | CUnit -> "()"
-;;
-
 let list_to_string pp sep lst =
   let rec aux = function
     | [] -> ""
@@ -55,25 +47,6 @@ let rec imm_to_string = function
     Printf.sprintf "(%s : %s)" (imm_to_string imm) (type_name_to_string typ)
 ;;
 
-let rec pattern_to_string pat =
-  let rec_call = pattern_to_string in
-  match pat with
-  | PWildCard -> "_"
-  | PCons (h_pat, t_pat) -> Printf.sprintf "(%s :: %s)" (rec_call h_pat) (rec_call t_pat)
-  | PIdentifier x -> x
-  | PTuple lst ->
-    let tuple_str =
-      lst
-      |> List.mapi (fun i pat ->
-        if i <> 0 then Printf.sprintf ", %s" (rec_call pat) else rec_call pat)
-      |> String.concat ""
-    in
-    Printf.sprintf "(%s)" tuple_str
-  | PConstant c -> constant_to_string c
-  | PConstraint (pat, tp) ->
-    Printf.sprintf "(%s : %s)" (rec_call pat) (type_name_to_string tp)
-;;
-
 let rec cexpr_to_string = function
   | CImmExpr imm -> imm_to_string imm
   | CIfThenElse (cond, then_branch, else_branch) ->
@@ -82,14 +55,6 @@ let rec cexpr_to_string = function
       (imm_to_string cond)
       (aexpr_to_string then_branch)
       (aexpr_to_string else_branch)
-  | CMatch (exp_head, pat_exp_lst) ->
-    let match_cases =
-      pat_exp_lst
-      |> List.map (fun (pat, ae) ->
-        Printf.sprintf "| %s -> %s" (pattern_to_string pat) (aexpr_to_string ae))
-      |> String.concat "\n"
-    in
-    Printf.sprintf "match %s with\n%s" (imm_to_string exp_head) match_cases
   | CApplication (left, right) ->
     Printf.sprintf "%s %s" (cexpr_to_string left) (cexpr_to_string right)
 
@@ -98,7 +63,7 @@ and aexpr_to_string = function
   | ALetIn (pat, outer, inner) ->
     Printf.sprintf
       "let %s = %s in\n%s"
-      (pattern_to_string pat)
+      pat
       (cexpr_to_string outer)
       (aexpr_to_string inner)
 ;;
@@ -113,10 +78,10 @@ let anf_decl_to_string = function
     Printf.sprintf
       "let %s %s %s = %s;;"
       (rec_flag_to_string rec_flag)
-      (pattern_to_string pat)
-      (patterns |> List.map pattern_to_string |> String.concat " ")
+      pat
+      (patterns |> String.concat " ")
       (aexpr_to_string body)
-  | ADMutualRecDecl (rec_flag, bindings) ->
+  | ADMutualRecDecl bindings ->
     let bindings_str =
       bindings
       |> List.mapi (fun i binding ->
@@ -125,14 +90,14 @@ let anf_decl_to_string = function
           | ALet (pat, patterns, exp) ->
             Printf.sprintf
               "%s %s = %s"
-              (pattern_to_string pat)
-              (patterns |> List.map pattern_to_string |> String.concat " ")
+              pat
+              (patterns |> String.concat " ")
               (aexpr_to_string exp)
         in
         if i <> 0 then Printf.sprintf " and %s" binding_str else binding_str)
       |> String.concat ""
     in
-    Printf.sprintf "let %s %s" (rec_flag_to_string rec_flag) bindings_str
+    Printf.sprintf "let %s %s" "rec" bindings_str
 ;;
 
 let program_to_string declarations =
diff --git a/BasedML/lib/middleend/match_elimination.ml b/BasedML/lib/middleend/match_elimination.ml
new file mode 100644
index 000000000..84aa056ab
--- /dev/null
+++ b/BasedML/lib/middleend/match_elimination.ml
@@ -0,0 +1,374 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+open Common.StateMonad
+open Llast
+open Ast
+
+type bound_expr = BoundExpression of pattern * llexpr
+
+let rec map1 f = function
+  | [] -> return []
+  | h :: tl -> f h >>= fun c -> map1 f tl >>= fun lst -> return (c :: lst)
+;;
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+let empty_context = { reserved_names = (module Base.String) |> Base.Set.empty }
+
+let rec collect_bindings_from_pat = function
+  | PWildCard -> (module Base.String) |> Base.Set.empty
+  | PConstant _ -> (module Base.String) |> Base.Set.empty
+  | PIdentifier id -> Base.Set.add ((module Base.String) |> Base.Set.empty) id
+  | PCons (left, right) ->
+    let collected_in_left = collect_bindings_from_pat left in
+    let collected_in_right = collect_bindings_from_pat right in
+    Base.Set.union collected_in_left collected_in_right
+  | PConstraint (pat, _) -> collect_bindings_from_pat pat
+  | PTuple pats ->
+    Base.List.fold_left
+      pats
+      ~init:((module Base.String) |> Base.Set.empty)
+      ~f:(fun acc h -> Base.Set.union acc (collect_bindings_from_pat h))
+;;
+
+let show_idname old_name counter =
+  if counter >= 0 then Printf.sprintf "%s_%d" old_name counter else old_name
+;;
+
+let rec generate_bindings =
+  let optimized_conj operand1 operand2 =
+    match operand1, operand2 with
+    | _, LLConstant (CBool true) | LLConstant (CBool false), _ -> operand1
+    | LLConstant (CBool true), _ | _, LLConstant (CBool false) -> operand2
+    | _ -> LLApplication (LLApplication (LLIdentifier "( && )", operand1), operand2)
+  in
+  function
+  | BoundExpression (PConstant constant, expression) ->
+    ( LLApplication (LLApplication (LLIdentifier "( = )", expression), LLConstant constant)
+    , [] )
+    |> return
+  | BoundExpression (PTuple pattern_list, expression) ->
+    let tuple_helper pattern_list expression_list =
+      let rec step
+        collected_conditions
+        collected_bindings
+        new_pattern_list
+        new_expression_list
+        =
+        match new_pattern_list, new_expression_list with
+        | [], [] -> return (collected_conditions, collected_bindings)
+        | pattern :: rest_patterns, expression :: rest_expressions ->
+          let bound_expr = BoundExpression (pattern, expression) in
+          let* head_condition, bindings = generate_bindings bound_expr in
+          step
+            (optimized_conj collected_conditions head_condition)
+            (List.append collected_bindings bindings)
+            rest_patterns
+            rest_expressions
+        | _ -> fail "Length mismatch"
+      in
+      step (LLConstant (CBool true)) [] pattern_list expression_list
+    in
+    (match expression with
+     | LLTuple elements_list -> tuple_helper pattern_list elements_list
+     | other ->
+       let accessed_fields =
+         List.init (List.length pattern_list) (fun num ->
+           LLApplication
+             (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt num)))
+       in
+       tuple_helper pattern_list accessed_fields)
+  | BoundExpression (PWildCard, _) -> (LLConstant (CBool true), []) |> return
+  | BoundExpression (PCons (left, right), expression) ->
+    (match expression with
+     | LLApplication (LLApplication (LLIdentifier "( :: )", head), tail) ->
+       let bound_left = BoundExpression (left, head) in
+       let bound_right = BoundExpression (right, tail) in
+       let* head_condition, head_bindings = generate_bindings bound_left in
+       let* tail_condition, tail_bindings = generate_bindings bound_right in
+       ( optimized_conj head_condition tail_condition
+       , List.append head_bindings tail_bindings )
+       |> return
+     | other ->
+       let tag_checking =
+         LLApplication
+           (LLApplication (LLIdentifier "check_tag", other), LLConstant (CInt 0))
+       in
+       let* head_condition, head_bindings =
+         let bound_left =
+           BoundExpression
+             ( left
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 0)) )
+         in
+         generate_bindings bound_left
+       in
+       let* tail_condition, tail_bindings =
+         let bound_right =
+           BoundExpression
+             ( right
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 1)) )
+         in
+         generate_bindings bound_right
+       in
+       ( optimized_conj tag_checking (optimized_conj head_condition tail_condition)
+       , List.append head_bindings tail_bindings )
+       |> return)
+  | BoundExpression (PConstraint (pat, _), llexpr) ->
+    let bound_expr = BoundExpression (pat, llexpr) in
+    generate_bindings bound_expr
+  | BoundExpression (PIdentifier name, llexpr) ->
+    (LLConstant (CBool true), [ name, llexpr ]) |> return
+;;
+
+let rec generate_unique_name old_name counter =
+  let* ctx = read in
+  let new_name = old_name, counter in
+  if Base.Set.mem
+       (Base.Set.union
+          ctx.reserved_names
+          (Base.Set.singleton (module Base.String) old_name))
+       (show_idname old_name counter)
+  then generate_unique_name old_name (counter + 1)
+  else
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.add ctx.reserved_names (Printf.sprintf "%s_%d" old_name counter)
+        }
+    in
+    new_name |> return
+;;
+
+let rec match_of_pat_let = function
+  | LLConstant c -> LLConstant c |> return
+  | LLIdentifier id ->
+    let* old_ctx = read in
+    let* _ = write { reserved_names = Base.Set.add old_ctx.reserved_names id } in
+    LLIdentifier id |> return
+  | LLIfThenElse (guard, then_branch, else_branch) ->
+    let* turned_guard = match_of_pat_let guard in
+    let* turned_then_branch = match_of_pat_let then_branch in
+    let* turned_else_branch = match_of_pat_let else_branch in
+    LLIfThenElse (turned_guard, turned_then_branch, turned_else_branch) |> return
+  | LLConstraint (llex, typ) ->
+    let* turned_llexp = match_of_pat_let llex in
+    LLConstraint (turned_llexp, typ) |> return
+  | LLApplication (left, right) ->
+    let* turned_left = match_of_pat_let left in
+    let* turned_right = match_of_pat_let right in
+    LLApplication (turned_left, turned_right) |> return
+  | LLTuple elems ->
+    let* new_elems = map1 match_of_pat_let elems in
+    LLTuple new_elems |> return
+  | LLLetIn (_, pat, outer, inner) ->
+    let* old_ctx = read in
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+        }
+    in
+    let* converted_outer = match_of_pat_let outer in
+    let* converted_inner = match_of_pat_let inner in
+    LLMatch (converted_outer, [ pat, converted_inner ]) |> return
+  | LLMatch (main_exp, cases) ->
+    let* new_main_exp = match_of_pat_let main_exp in
+    let rec case_helper acc = function
+      | [] -> List.rev acc |> return
+      | (pat, expr) :: tl ->
+        let* old_ctx = read in
+        let* _ =
+          write
+            { reserved_names =
+                Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+            }
+        in
+        let* new_expr = match_of_pat_let expr in
+        case_helper ((pat, new_expr) :: acc) tl
+    in
+    let* new_cases = case_helper [] cases in
+    LLMatch (new_main_exp, new_cases) |> return
+;;
+
+let rec eliminate_lexpr =
+  let optimized_if_then_else guard then_branch else_branch =
+    match guard with
+    | LLConstant (CBool true) -> then_branch
+    | LLConstant (CBool false) -> else_branch
+    | _ -> LLIfThenElse (guard, then_branch, else_branch)
+  in
+  function
+  | LLTuple elements ->
+    let* new_elements = map1 eliminate_lexpr elements in
+    LLTuple new_elements |> return
+  | LLIfThenElse (guard_branch, then_branch, else_branch) ->
+    let* new_guard_branch = eliminate_lexpr guard_branch in
+    let* new_then_branch = eliminate_lexpr then_branch in
+    let* new_else_branch = eliminate_lexpr else_branch in
+    LLIfThenElse (new_guard_branch, new_then_branch, new_else_branch) |> return
+  | LLApplication (left, right) ->
+    let* new_left = eliminate_lexpr left in
+    let* new_right = eliminate_lexpr right in
+    LLApplication (new_left, new_right) |> return
+  | LLConstraint (llexpr, typ) ->
+    let* new_llexpr = eliminate_lexpr llexpr in
+    LLConstraint (new_llexpr, typ) |> return
+  | LLMatch (main_expression, match_cases) ->
+    let* match_free_main_expression = eliminate_lexpr main_expression in
+    let* conditions =
+      map1
+        (fun (pat, _) ->
+          let bound_expr = BoundExpression (pat, match_free_main_expression) in
+          generate_bindings bound_expr)
+        match_cases
+    in
+    List.fold_right2
+      (fun (head_condition, binds) (_, expr) acc ->
+        let* match_free_lexpr = eliminate_lexpr expr in
+        let* acc' = acc in
+        return
+          (optimized_if_then_else
+             head_condition
+             (List.fold_right
+                (fun (name, llexpr) acc ->
+                  LLLetIn (NotRec, PIdentifier name, llexpr, acc))
+                binds
+                match_free_lexpr)
+             acc'))
+      conditions
+      match_cases
+      (LLApplication (LLIdentifier "match_error", LLConstant CUnit) |> return)
+  | LLConstant constant -> LLConstant constant |> return
+  | LLIdentifier name -> LLIdentifier name |> return
+  | _ -> fail "Error: Unexpected expression"
+;;
+
+let rec rename_pat = function
+  | PWildCard -> PWildCard |> return
+  | PConstant c -> PConstant c |> return
+  | PConstraint (pat, typ) ->
+    let* new_pat = rename_pat pat in
+    PConstraint (new_pat, typ) |> return
+  | PCons (left, right) ->
+    let* new_left = rename_pat left in
+    let* new_right = rename_pat right in
+    PCons (new_left, new_right) |> return
+  | PTuple pats ->
+    let* new_pats = map1 rename_pat pats in
+    PTuple new_pats |> return
+  | PIdentifier id ->
+    let* old_name, counter = generate_unique_name id 0 in
+    PIdentifier (Printf.sprintf "%s_%d" old_name counter) |> return
+;;
+
+let rec get_all_id acc = function
+  | PWildCard | PConstant _ -> acc
+  | PConstraint (pat, _tp) -> get_all_id acc pat
+  | PCons (pat1, pat2) -> get_all_id (get_all_id acc pat2) pat1
+  | PTuple plst -> List.fold_left get_all_id acc plst
+  | PIdentifier x -> x :: acc
+;;
+
+let rec get_new_args acc = function
+  | [] -> List.rev acc |> return
+  | PIdentifier id :: tl -> get_new_args (id :: acc) tl
+  | _ :: tl ->
+    let* name, counter = generate_unique_name "arg" 0 in
+    let new_name = Printf.sprintf "%s_%d" name counter in
+    get_new_args (new_name :: acc) tl
+;;
+
+let rec bind_names_to_patterns base_exp names patterns =
+  match names, patterns with
+  | [], [] -> return base_exp
+  | _ :: names_tail, PIdentifier _ :: patterns_tail ->
+    bind_names_to_patterns base_exp names_tail patterns_tail
+  | name :: names_tail, pattern :: patterns_tail ->
+    let* ctx = read in
+    let* _ = write { reserved_names = Base.Set.add ctx.reserved_names name } in
+    let* inner_exp = bind_names_to_patterns base_exp names_tail patterns_tail in
+    return (LLLetIn (NotRec, pattern, LLIdentifier name, inner_exp))
+  | _ -> fail "Error: Mismatch in the lengths of names and patterns lists"
+;;
+
+let rec eliminate_match_in_declarations acc = function
+  | LLDSingleLet (flag, LLLet (PIdentifier id, args, llexpr)) :: tl ->
+    let* new_let =
+      let* let_env = read in
+      write { reserved_names = Base.Set.add let_env.reserved_names id }
+      *>
+      let* fresh_names = get_new_args [] args in
+      let* new_llexpr = bind_names_to_patterns llexpr fresh_names args in
+      let* let_in_free_exp = match_of_pat_let new_llexpr in
+      let* match_free_exp = eliminate_lexpr let_in_free_exp in
+      let fresh_ids = List.map (fun x -> PIdentifier x) fresh_names in
+      LLLet (PIdentifier id, fresh_ids, match_free_exp) |> return
+    in
+    eliminate_match_in_declarations (LLDSingleLet (flag, new_let) :: acc) tl
+  | LLDSingleLet (flag, LLLet (arbitrary_pattern, [], llexpr)) :: tl ->
+    let rec after_let_helper acc counter = function
+      | [] -> List.rev acc
+      | h :: tl ->
+        let new_elem =
+          LLDSingleLet
+            ( NotRec
+            , LLLet
+                ( PIdentifier h
+                , []
+                , LLApplication
+                    ( LLApplication (LLIdentifier "get_field", LLIdentifier "res")
+                    , LLConstant (CInt counter) ) ) )
+        in
+        after_let_helper (new_elem :: acc) (counter + 1) tl
+    in
+    let old_names = get_all_id [] arbitrary_pattern in
+    let* pat_with_new_names = rename_pat arbitrary_pattern in
+    let new_names = get_all_id [] pat_with_new_names in
+    let additional_lets = List.rev (after_let_helper [] 0 (List.rev old_names)) in
+    let* eliminated_llexpr = eliminate_lexpr llexpr in
+    let* new_body =
+      eliminate_lexpr
+        (LLMatch
+           ( eliminated_llexpr
+           , [ ( pat_with_new_names
+               , LLTuple (List.map (fun x -> LLIdentifier x) (List.rev new_names)) )
+             ] ))
+    in
+    eliminate_match_in_declarations
+      (List.append
+         (List.append
+            additional_lets
+            [ LLDSingleLet (flag, LLLet (PIdentifier "res", [], new_body)) ])
+         acc)
+      tl
+  | LLDMutualRecDecl (Rec, lets) :: tl ->
+    let* new_lets =
+      map1
+        (fun decl ->
+          match decl with
+          | LLLet (PIdentifier id, args, llexpr) ->
+            let* ctx = read in
+            let* _ = write { reserved_names = Base.Set.add ctx.reserved_names id } in
+            let* new_names = get_new_args [] args in
+            let* new_llexpr = bind_names_to_patterns llexpr new_names args in
+            let* llexpr_with_no_lets = match_of_pat_let new_llexpr in
+            let* llexpr_with_no_matches = eliminate_lexpr llexpr_with_no_lets in
+            LLLet
+              ( PIdentifier id
+              , List.map (fun x -> PIdentifier x) new_names
+              , llexpr_with_no_matches )
+            |> return
+          | _ -> fail "Error: unexpected declaration")
+        lets
+    in
+    let new_mut_let = LLDMutualRecDecl (Rec, new_lets) in
+    eliminate_match_in_declarations (new_mut_let :: acc) tl
+  | [] -> List.rev acc |> return
+  | _ -> fail "Error: unexpected declaration"
+;;
+
+let transform ast = run (eliminate_match_in_declarations [] ast) empty_context
diff --git a/BasedML/lib/middleend/match_elimination.mli b/BasedML/lib/middleend/match_elimination.mli
new file mode 100644
index 000000000..8cac5c8b5
--- /dev/null
+++ b/BasedML/lib/middleend/match_elimination.mli
@@ -0,0 +1,16 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+val empty_context : context
+
+val eliminate_match_in_declarations
+  :  Llast.lllet_declaration list
+  -> Llast.lllet_declaration list
+  -> (context, Llast.lllet_declaration list) Common.StateMonad.t
+
+val transform
+  :  Llast.lllet_declaration list
+  -> context * (Llast.lllet_declaration list, string) result
diff --git a/BasedML/lib/middleend/restore_anf_ast.ml b/BasedML/lib/middleend/restore_anf_ast.ml
index 9fa026446..0b337bdcf 100644
--- a/BasedML/lib/middleend/restore_anf_ast.ml
+++ b/BasedML/lib/middleend/restore_anf_ast.ml
@@ -103,33 +103,13 @@ let rec restore_cexpr ppf = function
       then_branch
       pp_aexpr
       else_branch
-  | CMatch (pat_head, pat_exp_lst) ->
-    fprintf
-      ppf
-      "match %a with\n%a"
-      frestore_imm
-      pat_head
-      (fun ppf ->
-        pp_list
-          ppf
-          (fun ppf (pat, ae) -> fprintf ppf "| %a -> %a" frestore_pattern pat pp_aexpr ae)
-          "\n")
-      pat_exp_lst
   | CApplication (left, rigth) ->
     fprintf ppf "%a %a" restore_cexpr left restore_cexpr rigth
 
 and pp_aexpr ppf = function
   | ACExpr cexp -> fprintf ppf "%a" restore_cexpr cexp
   | ALetIn (pat, outer, inner) ->
-    fprintf
-      ppf
-      "let %a = %a in\n %a"
-      frestore_pattern
-      pat
-      restore_cexpr
-      outer
-      pp_aexpr
-      inner
+    fprintf ppf "let %s = %a in\n %a" pat restore_cexpr outer pp_aexpr inner
 ;;
 
 let frestore_rec_flag ppf = function
@@ -141,30 +121,24 @@ let restore_anf_decl fmt = function
   | ADSingleLet (rec_flag, ALet (pat, patterns, body)) ->
     Format.fprintf
       fmt
-      "let %a %a %a = %a;;"
+      "let %a %s %a = %a;;"
       frestore_rec_flag
       rec_flag
-      frestore_pattern
       pat
-      (fun fmt -> List.iter (fun pat -> Format.fprintf fmt "%a " frestore_pattern pat))
+      (fun fmt -> List.iter (fun pat -> Format.fprintf fmt "%s " pat))
       patterns
       pp_aexpr
       body
-  | ADMutualRecDecl (rec_flag, bindings) ->
-    Format.fprintf fmt "let ";
-    frestore_rec_flag fmt rec_flag;
+  | ADMutualRecDecl bindings ->
+    Format.fprintf fmt "let %s" "rec";
     Format.fprintf fmt " ";
     List.iteri
       (fun i binding ->
         if i != 0 then Format.fprintf fmt " and ";
         match binding with
         | ALet (pat, patterns, exp) ->
-          Format.fprintf fmt " ";
-          frestore_pattern fmt pat;
-          (fun fmt ->
-            List.iter (fun pat -> Format.fprintf fmt " %a " frestore_pattern pat))
-            fmt
-            patterns;
+          Format.fprintf fmt " %s" pat;
+          (fun fmt -> List.iter (fun pat -> Format.fprintf fmt " %s " pat)) fmt patterns;
           Format.fprintf fmt " = %a " pp_aexpr exp)
       bindings
 ;;
diff --git a/BasedML/lib/parser/parser.ml b/BasedML/lib/parser/parser.ml
index bf0d059b9..209ef0571 100644
--- a/BasedML/lib/parser/parser.ml
+++ b/BasedML/lib/parser/parser.ml
@@ -52,12 +52,13 @@ let is_identifier_char = function
 ;;
 
 let is_op_symb = function
-  | "-" | "+" | "/" | "*" | "<" | "<=" | ">=" | "<>" | ">" | "::" | "=" | "==" -> true
+  | "-" | "+" | "/" | "*" | "<" | "<=" | ">=" | "<>" | ">" | "::" | "=" | "==" | "&&" ->
+    true
   | _ -> false
 ;;
 
 let is_inf_op_symb = function
-  | '-' | '+' | '/' | '*' | '<' | '>' | ':' | '=' -> true
+  | '-' | '+' | '/' | '*' | '<' | '>' | ':' | '=' | '&' -> true
   | _ -> false
 ;;
 
diff --git a/BasedML/lib/typeinference/typeinference.ml b/BasedML/lib/typeinference/typeinference.ml
index 921cb56cc..b5bd5a144 100644
--- a/BasedML/lib/typeinference/typeinference.ml
+++ b/BasedML/lib/typeinference/typeinference.ml
@@ -250,52 +250,49 @@ let test_infer_prog string_exp =
 
 module StringMap = Map.Make (String)
 
-(* Helper function to compare two types with alpha equivalence *)
-let rec alpha_equivalent
-  (mapping_t1_to_t2 : string StringMap.t)
-  (mapping_t2_to_t1 : string StringMap.t)
+let rec is_first_more_general
+  (mapping_t2_to_t1 : type_name StringMap.t)
   (t1 : type_name)
   (t2 : type_name)
-  : bool * string StringMap.t * string StringMap.t
+  : bool * type_name StringMap.t
   =
   match t1, t2 with
-  | TUnit, TUnit | TInt, TInt | TBool, TBool -> true, mapping_t1_to_t2, mapping_t2_to_t1
-  | TPoly var1, TPoly var2 ->
-    let mapped_var2 = StringMap.find_opt var1 mapping_t1_to_t2 in
+  | TUnit, TUnit | TInt, TInt | TBool, TBool -> true, mapping_t2_to_t1
+  | var1, TPoly var2 ->
     let mapped_var1 = StringMap.find_opt var2 mapping_t2_to_t1 in
-    (match mapped_var2, mapped_var1 with
-     | Some mapped_var2', Some mapped_var1' ->
-       if mapped_var2' = var2 && mapped_var1' = var1
-       then true, mapping_t1_to_t2, mapping_t2_to_t1
-       else false, mapping_t1_to_t2, mapping_t2_to_t1
-     | None, None ->
-       let updated_mapping_t1_to_t2 = StringMap.add var1 var2 mapping_t1_to_t2 in
+    (match mapped_var1 with
+     | Some mapped_var1' ->
+       if mapped_var1' = var1 then true, mapping_t2_to_t1 else false, mapping_t2_to_t1
+     | None ->
        let updated_mapping_t2_to_t1 = StringMap.add var2 var1 mapping_t2_to_t1 in
-       true, updated_mapping_t1_to_t2, updated_mapping_t2_to_t1
-     | _ -> false, mapping_t1_to_t2, mapping_t2_to_t1)
+       true, updated_mapping_t2_to_t1)
   | TTuple ts1, TTuple ts2 ->
     if List.compare_lengths ts1 ts2 = 0
     then
       List.fold_right2
-        (fun tp1 tp2 (res, map1, map2) ->
-          if res then alpha_equivalent map1 map2 tp1 tp2 else false, map1, map2)
+        (fun tp1 tp2 (res, map2) ->
+          if res then is_first_more_general map2 tp1 tp2 else false, map2)
         ts1
         ts2
-        (true, mapping_t1_to_t2, mapping_t2_to_t1)
-    else false, mapping_t1_to_t2, mapping_t2_to_t1
+        (true, mapping_t2_to_t1)
+    else false, mapping_t2_to_t1
   | TFunction (dom1, codom1), TFunction (dom2, codom2) ->
-    let dom_equal, updated_mapping_t1_to_t2, updated_mapping_t2_to_t1 =
-      alpha_equivalent mapping_t1_to_t2 mapping_t2_to_t1 dom1 dom2
+    let dom_equal, updated_mapping_t2_to_t1 =
+      is_first_more_general mapping_t2_to_t1 dom1 dom2
     in
     if not dom_equal
-    then false, updated_mapping_t1_to_t2, updated_mapping_t2_to_t1
-    else alpha_equivalent updated_mapping_t1_to_t2 updated_mapping_t2_to_t1 codom1 codom2
-  | TList t1, TList t2 -> alpha_equivalent mapping_t1_to_t2 mapping_t2_to_t1 t1 t2
-  | _ -> false, mapping_t1_to_t2, mapping_t2_to_t1
+    then false, updated_mapping_t2_to_t1
+    else is_first_more_general updated_mapping_t2_to_t1 codom1 codom2
+  | TList t1, TList t2 -> is_first_more_general mapping_t2_to_t1 t1 t2
+  | _ -> false, mapping_t2_to_t1
 ;;
 
 (* Public function to compare two types *)
-let types_equal t1 t2 =
-  let result, _, _ = alpha_equivalent StringMap.empty StringMap.empty t1 t2 in
+let type_more_general t1 t2 =
+  let result, _ = is_first_more_general StringMap.empty t1 t2 in
   result
 ;;
+
+let infer_with_system_fun ast =
+  infer_prog_with_custom_state start_state_with_system_fun ast
+;;
diff --git a/BasedML/lib/typeinference/typeinference.mli b/BasedML/lib/typeinference/typeinference.mli
index f71e2bb47..46f30ca6e 100644
--- a/BasedML/lib/typeinference/typeinference.mli
+++ b/BasedML/lib/typeinference/typeinference.mli
@@ -16,7 +16,7 @@ val infer_prog : Ast.declarations -> (res_map, string) result
 val test_infer_exp : string -> unit
 val test_infer_prog_with_state : StatementInfer.state -> string -> unit
 val test_infer_prog : string -> unit
-val types_equal : Ast.type_name -> Ast.type_name -> bool
+val type_more_general : Ast.type_name -> Ast.type_name -> bool
 
 module StringMap : sig
   type key = string
@@ -63,3 +63,5 @@ module StringMap : sig
   val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t
   val of_seq : (key * 'a) Seq.t -> 'a t
 end
+
+val infer_with_system_fun : Ast.declarations -> (res_map, string) result
diff --git a/BasedML/test/anf_demo.ml b/BasedML/test/anf_demo.ml
index 0a43c417f..4cc0484d3 100644
--- a/BasedML/test/anf_demo.ml
+++ b/BasedML/test/anf_demo.ml
@@ -24,11 +24,14 @@ let () =
          0
      with
      | _, Ok lst ->
-       lst
-       |> Middleend.Closure_conversion.convert_ast
-       |> Middleend.Lambda_lifting.lift_ast
-       |> Middleend.Anf.transform
-       |> print_anf
+       let lifted =
+         lst
+         |> Middleend.Closure_conversion.convert_ast
+         |> Middleend.Lambda_lifting.lift_ast
+       in
+       (match Middleend.Match_elimination.transform lifted with
+        | _, Ok new_ast -> new_ast |> Middleend.Anf.transform |> print_anf
+        | _, Error message -> Format.printf "Error: %s\n" message)
      | _, Error err -> Format.printf "%s" err)
   | Error message -> Format.printf "Error: %s\n" message
 ;;
diff --git a/BasedML/test/anf_tests.t b/BasedML/test/anf_tests.t
index 547f89e0e..d1e496af6 100644
--- a/BasedML/test/anf_tests.t
+++ b/BasedML/test/anf_tests.t
@@ -1,16 +1,23 @@
   $ dune exec ./anf_demo.exe << EOF
-  > let nested1 = let nested2 = 5 in 
-  > let nested3 = 6 in
-  > let nested4 x = x + (fun i -> nested2 + nested3) 8 in nested4 55
+  > let test = let nested_pat x = match x with | 5 -> a 5 | 6 -> 6 in nested_pat 7 
   > EOF
-  let  ll_1 nested2_0 nested3_0 i_0  = let anf_app_0 = ( + ) nested2_0 nested3_0 in
+  let  ll_0 unbound_a_0 x_0  = let anf_app_0 = ( = ) x_0 5 in
+   let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = unbound_a_0 5 in
+   anf_app_1 else let anf_app_2 = ( = ) x_0 6 in
+   let anf_ifthenelse_4 = if anf_app_2 then 6 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4 in
+   anf_ifthenelse_5;;
+  let  test_0  = let anf_app_0 = ll_0 unbound_a_0 7 in
    anf_app_0;;
-  let  ll_0 nested2_0 nested3_0 x_0  = let anf_app_0 = ll_1 nested2_0 nested3_0 8 in
-   let anf_app_1 = ( + ) x_0 anf_app_0 in
-   anf_app_1;;
-  let  nested1_0  = let nested2_0 = 5 in
-   let nested3_0 = 6 in
-   let anf_app_0 = ll_0 nested2_0 nested3_0 55 in
+
+  $ dune exec ./anf_demo.exe << EOF
+  > let test = let nested_pat x = if x 5 then 5 else 6 in nested_pat 7 
+  > EOF
+  let  ll_0 x_0  = let anf_app_0 = x_0 5 in
+   let anf_ifthenelse_1 = if anf_app_0 then 5 else 6 in
+   anf_ifthenelse_1;;
+  let  test_0  = let anf_app_0 = ll_0 7 in
    anf_app_0;;
 
   $ dune exec ./anf_demo.exe << EOF
@@ -25,9 +32,9 @@
    anf_app_1;;
   let rec fact_cps_0 n_0 cont_0  = let anf_app_0 = ( = ) n_0 0 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = cont_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 cont_0 n_0 in
-   let anf_app_4 = fact_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 cont_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fact_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
 
@@ -45,17 +52,17 @@
   let  ll_1 a_0 cont_0 b_0  = let anf_app_0 = ( + ) a_0 b_0 in
    let anf_app_1 = cont_0 anf_app_0 in
    anf_app_1;;
-  let  ll_0 cont_0 fib_cps_0 n_0 a_0  = let anf_app_0 = ( - ) n_0 2 in
-   let anf_app_1 = ll_1 a_0 cont_0 in
-   let anf_app_2 = fib_cps_0 anf_app_0 anf_app_1 in
+  let  ll_0 cont_0 fib_cps_0 n_0 a_0  = let anf_app_0 = ll_1 a_0 cont_0 in
+   let anf_app_1 = ( - ) n_0 2 in
+   let anf_app_2 = fib_cps_0 anf_app_1 anf_app_0 in
    anf_app_2;;
   let rec fib_cps_0 n_0 cont_0  = let anf_app_0 = ( = ) n_0 0 in
    let anf_ifthenelse_8 = if anf_app_0 then let anf_app_1 = cont_0 0 in
    anf_app_1 else let anf_app_2 = ( = ) n_0 1 in
    let anf_ifthenelse_7 = if anf_app_2 then let anf_app_3 = cont_0 1 in
-   anf_app_3 else let anf_app_4 = ( - ) n_0 1 in
-   let anf_app_5 = ll_0 cont_0 fib_cps_0 n_0 in
-   let anf_app_6 = fib_cps_0 anf_app_4 anf_app_5 in
+   anf_app_3 else let anf_app_4 = ll_0 cont_0 fib_cps_0 n_0 in
+   let anf_app_5 = ( - ) n_0 1 in
+   let anf_app_6 = fib_cps_0 anf_app_5 anf_app_4 in
    anf_app_6 in
    anf_ifthenelse_7 in
    anf_ifthenelse_8;;
@@ -80,8 +87,10 @@
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
   let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
@@ -89,16 +98,18 @@
    anf_app_1;;
   let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
   let  ll_1 print_int_0  = print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
   let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
@@ -110,20 +121,24 @@
    anf_app_3 in
    anf_ifthenelse_4;;
   let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
   let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
@@ -149,10 +164,12 @@
   let  main_0  = let anf_app_0 = wrap_0 test10_0 1 10 100 1000 10000 100000 1000000 10000000 100000000 1000000000 in
    let rez_0 = anf_app_0 in
    let anf_app_1 = print_int rez_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = wrap_0 test3_0 1 10 100 in
-   let temp2_0 = anf_app_2 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_5 = if anf_app_2 then let anf_app_3 = wrap_0 test3_0 1 10 100 in
+   let temp2_0 = anf_app_3 in
+   0 else let anf_app_4 = match_error () in
+   anf_app_4 in
+   anf_ifthenelse_5;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/005fix.ml
   let rec fix_0 f_0 x_0  = let anf_app_0 = fix_0 f_0 in
@@ -166,8 +183,10 @@
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fix_0 fac_0 6 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/006partial.ml
   let  ll_0 foo_1  = let anf_app_0 = ( + ) foo_1 2 in
@@ -183,19 +202,27 @@
    anf_app_3;;
   let  main_0  = let anf_app_0 = foo_3 11 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/006partial2.ml
   let  foo_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
-   let () = anf_app_0 in
-   let anf_app_1 = print_int b_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = print_int c_0 in
-   let () = anf_app_2 in
-   let anf_app_3 = ( * ) b_0 c_0 in
-   let anf_app_4 = ( + ) a_0 anf_app_3 in
-   anf_app_4;;
+   let anf_app_1 = ( = ) anf_app_0 () in
+   let anf_ifthenelse_13 = if anf_app_1 then let anf_app_2 = print_int b_0 in
+   let anf_app_3 = ( = ) anf_app_2 () in
+   let anf_ifthenelse_11 = if anf_app_3 then let anf_app_4 = print_int c_0 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_9 = if anf_app_5 then let anf_app_6 = ( * ) b_0 c_0 in
+   let anf_app_7 = ( + ) a_0 anf_app_6 in
+   anf_app_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9 else let anf_app_10 = match_error () in
+   anf_app_10 in
+   anf_ifthenelse_11 else let anf_app_12 = match_error () in
+   anf_app_12 in
+   anf_ifthenelse_13;;
   let  main_0  = let anf_app_0 = foo_0 1 in
    let foo_1 = anf_app_0 in
    let anf_app_1 = foo_1 2 in
@@ -203,37 +230,61 @@
    let anf_app_2 = foo_2 3 in
    let foo_3 = anf_app_2 in
    let anf_app_3 = print_int foo_3 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_4 = ( = ) anf_app_3 () in
+   let anf_ifthenelse_6 = if anf_app_4 then 0 else let anf_app_5 = match_error () in
+   anf_app_5 in
+   anf_ifthenelse_6;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/006partial3.ml
   let  ll_1 c_0  = let anf_app_0 = print_int c_0 in
    anf_app_0;;
   let  ll_0 b_0  = let anf_app_0 = print_int b_0 in
-   let () = anf_app_0 in
-   ll_1;;
+   let anf_app_1 = ( = ) anf_app_0 () in
+   let anf_ifthenelse_3 = if anf_app_1 then ll_1 else let anf_app_2 = match_error () in
+   anf_app_2 in
+   anf_ifthenelse_3;;
   let  foo_0 a_0  = let anf_app_0 = print_int a_0 in
-   let () = anf_app_0 in
-   ll_0;;
+   let anf_app_1 = ( = ) anf_app_0 () in
+   let anf_ifthenelse_3 = if anf_app_1 then ll_0 else let anf_app_2 = match_error () in
+   anf_app_2 in
+   anf_ifthenelse_3;;
   let  main_0  = let anf_app_0 = foo_0 4 8 9 in
-   let () = anf_app_0 in
-   0;;
+   let anf_app_1 = ( = ) anf_app_0 () in
+   let anf_ifthenelse_3 = if anf_app_1 then 0 else let anf_app_2 = match_error () in
+   anf_app_2 in
+   anf_ifthenelse_3;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/007order.ml
-  let  _start_0 () () a_0 () b_0 _c_0 () d_0 ___0  = let anf_app_0 = ( + ) a_0 b_0 in
-   let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = print_int ___0 in
-   let () = anf_app_2 in
-   let anf_app_3 = ( * ) a_0 b_0 in
-   let anf_app_4 = ( / ) anf_app_3 _c_0 in
-   let anf_app_5 = ( + ) anf_app_4 d_0 in
-   anf_app_5;;
-  let  main_0  = let anf_app_0 = print_int 1 in
-   let anf_app_1 = print_int 2 in
-   let anf_app_2 = print_int 4 in
-   let anf_app_3 = print_int -1 in
-   let anf_app_4 = _start_0 anf_app_0 anf_app_1 3 anf_app_2 100 1000 anf_app_3 10000 -555555 in
+  let  _start_0 arg_0 arg_1 a_0 arg_2 b_0 _c_0 arg_3 d_0 ___0  = let anf_app_0 = ( = ) arg_0 () in
+   let anf_ifthenelse_23 = if anf_app_0 then let anf_app_1 = ( = ) arg_1 () in
+   let anf_ifthenelse_21 = if anf_app_1 then let anf_app_2 = ( = ) arg_2 () in
+   let anf_ifthenelse_19 = if anf_app_2 then let anf_app_3 = ( = ) arg_3 () in
+   let anf_ifthenelse_17 = if anf_app_3 then let anf_app_4 = ( + ) a_0 b_0 in
+   let anf_app_5 = print_int anf_app_4 in
+   let anf_app_6 = ( = ) anf_app_5 () in
+   let anf_ifthenelse_15 = if anf_app_6 then let anf_app_7 = print_int ___0 in
+   let anf_app_8 = ( = ) anf_app_7 () in
+   let anf_ifthenelse_13 = if anf_app_8 then let anf_app_9 = ( * ) a_0 b_0 in
+   let anf_app_10 = ( / ) anf_app_9 _c_0 in
+   let anf_app_11 = ( + ) anf_app_10 d_0 in
+   anf_app_11 else let anf_app_12 = match_error () in
+   anf_app_12 in
+   anf_ifthenelse_13 else let anf_app_14 = match_error () in
+   anf_app_14 in
+   anf_ifthenelse_15 else let anf_app_16 = match_error () in
+   anf_app_16 in
+   anf_ifthenelse_17 else let anf_app_18 = match_error () in
+   anf_app_18 in
+   anf_ifthenelse_19 else let anf_app_20 = match_error () in
+   anf_app_20 in
+   anf_ifthenelse_21 else let anf_app_22 = match_error () in
+   anf_app_22 in
+   anf_ifthenelse_23;;
+  let  main_0  = let anf_app_0 = print_int -1 in
+   let anf_app_1 = print_int 4 in
+   let anf_app_2 = print_int 2 in
+   let anf_app_3 = print_int 1 in
+   let anf_app_4 = _start_0 anf_app_3 anf_app_2 3 anf_app_1 100 1000 anf_app_0 10000 -555555 in
    let anf_app_5 = print_int anf_app_4 in
    anf_app_5;;
 
@@ -252,8 +303,10 @@
    anf_app_1;;
   let  main_0  = let anf_app_0 = addi_0 ll_0 ll_1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/009let_poly.ml
   let  ll_0 x_0  = x_0;;
@@ -266,11 +319,14 @@
   let rec fix_0 f_0 x_0  = let anf_app_0 = fix_0 f_0 in
    let anf_app_1 = f_0 anf_app_0 x_0 in
    anf_app_1;;
-  let  map_0 f_0 p_0  = let (a_0, b_0) = p_0 in
-   let anf_app_0 = f_0 a_0 in
-   let anf_app_1 = f_0 b_0 in
-   let anf_tuple_2 = (anf_app_0, anf_app_1) in
-   anf_tuple_2;;
+  let  map_0 f_0 p_0  = let anf_app_0 = get_field p_0 0 in
+   let a_0 = anf_app_0 in
+   let anf_app_1 = get_field p_0 1 in
+   let b_0 = anf_app_1 in
+   let anf_app_2 = f_0 a_0 in
+   let anf_app_3 = f_0 b_0 in
+   let anf_tuple_4 = (anf_app_2, anf_app_3) in
+   anf_tuple_4;;
   let  ll_1 l_1 self_0 li_0 x_0  = let anf_app_0 = self_0 l_1 in
    let anf_app_1 = li_0 anf_app_0 x_0 in
    anf_app_1;;
@@ -279,18 +335,24 @@
    anf_app_1;;
   let  fixpoly_0 l_0  = let anf_app_0 = fix_0 ll_0 l_0 in
    anf_app_0;;
-  let  feven_0 p_1 n_0  = let (e_0, o_0) = p_1 in
-   let anf_app_0 = ( == ) n_0 0 in
-   let anf_ifthenelse_3 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
-   let anf_app_2 = o_0 anf_app_1 in
-   anf_app_2 in
-   anf_ifthenelse_3;;
-  let  fodd_0 p_2 n_1  = let (e_1, o_1) = p_2 in
-   let anf_app_0 = ( == ) n_1 0 in
-   let anf_ifthenelse_3 = if anf_app_0 then 0 else let anf_app_1 = ( - ) n_1 1 in
-   let anf_app_2 = e_1 anf_app_1 in
-   anf_app_2 in
-   anf_ifthenelse_3;;
+  let  feven_0 p_1 n_0  = let anf_app_0 = get_field p_1 0 in
+   let e_0 = anf_app_0 in
+   let anf_app_1 = get_field p_1 1 in
+   let o_0 = anf_app_1 in
+   let anf_app_2 = ( == ) n_0 0 in
+   let anf_ifthenelse_5 = if anf_app_2 then 1 else let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = o_0 anf_app_3 in
+   anf_app_4 in
+   anf_ifthenelse_5;;
+  let  fodd_0 p_2 n_1  = let anf_app_0 = get_field p_2 0 in
+   let e_1 = anf_app_0 in
+   let anf_app_1 = get_field p_2 1 in
+   let o_1 = anf_app_1 in
+   let anf_app_2 = ( == ) n_1 0 in
+   let anf_ifthenelse_5 = if anf_app_2 then 0 else let anf_app_3 = ( - ) n_1 1 in
+   let anf_app_4 = e_1 anf_app_3 in
+   anf_app_4 in
+   anf_ifthenelse_5;;
   let  tie_0  = let anf_tuple_0 = (feven_0, fodd_0) in
    let anf_app_1 = fixpoly_0 anf_tuple_0 in
    anf_app_1;;
@@ -305,108 +367,235 @@
    anf_ifthenelse_7 
   let  main_0  = let anf_app_0 = modd_0 1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = meven_0 2 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   let (even_0, odd_0) = tie_0 in
-   let anf_app_4 = odd_0 3 in
-   let anf_app_5 = print_int anf_app_4 in
-   let () = anf_app_5 in
-   let anf_app_6 = even_0 4 in
-   let anf_app_7 = print_int anf_app_6 in
-   let () = anf_app_7 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_21 = if anf_app_2 then let anf_app_3 = meven_0 2 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_19 = if anf_app_5 then let anf_app_6 = get_field tie_0 0 in
+   let even_0 = anf_app_6 in
+   let anf_app_7 = get_field tie_0 1 in
+   let odd_0 = anf_app_7 in
+   let anf_app_8 = odd_0 3 in
+   let anf_app_9 = print_int anf_app_8 in
+   let anf_app_10 = ( = ) anf_app_9 () in
+   let anf_ifthenelse_17 = if anf_app_10 then let anf_app_11 = even_0 4 in
+   let anf_app_12 = print_int anf_app_11 in
+   let anf_app_13 = ( = ) anf_app_12 () in
+   let anf_ifthenelse_15 = if anf_app_13 then 0 else let anf_app_14 = match_error () in
+   anf_app_14 in
+   anf_ifthenelse_15 else let anf_app_16 = match_error () in
+   anf_app_16 in
+   anf_ifthenelse_17 else let anf_app_18 = match_error () in
+   anf_app_18 in
+   anf_ifthenelse_19 else let anf_app_20 = match_error () in
+   anf_app_20 in
+   anf_ifthenelse_21;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/016lists.ml
-  let rec length_0 xs_0  = let anf_matching_2 = match xs_0 with
-  | [] -> 0
-  | (h_0 :: tl_0) -> let anf_app_0 = length_0 tl_0 in
-   let anf_app_1 = ( + ) 1 anf_app_0 in
-   anf_app_1 in
-   anf_matching_2;;
-  let rec ll_0 acc_0 xs_0  = let anf_matching_2 = match xs_0 with
-  | [] -> acc_0
-  | (h_0 :: tl_0) -> let anf_app_0 = ( + ) acc_0 1 in
-   let anf_app_1 = ll_0 anf_app_0 tl_0 in
-   anf_app_1 in
-   anf_matching_2;;
+  let rec length_0 xs_0  = let anf_app_0 = ( = ) xs_0 [] in
+   let anf_ifthenelse_8 = if anf_app_0 then 0 else let anf_app_1 = check_tag xs_0 0 in
+   let anf_ifthenelse_7 = if anf_app_1 then let anf_app_2 = get_field xs_0 0 in
+   let h_0 = anf_app_2 in
+   let anf_app_3 = get_field xs_0 1 in
+   let tl_0 = anf_app_3 in
+   let anf_app_4 = length_0 tl_0 in
+   let anf_app_5 = ( + ) 1 anf_app_4 in
+   anf_app_5 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 in
+   anf_ifthenelse_8;;
+  let rec ll_0 acc_0 xs_0  = let anf_app_0 = ( = ) xs_0 [] in
+   let anf_ifthenelse_8 = if anf_app_0 then acc_0 else let anf_app_1 = check_tag xs_0 0 in
+   let anf_ifthenelse_7 = if anf_app_1 then let anf_app_2 = get_field xs_0 0 in
+   let h_0 = anf_app_2 in
+   let anf_app_3 = get_field xs_0 1 in
+   let tl_0 = anf_app_3 in
+   let anf_app_4 = ( + ) acc_0 1 in
+   let anf_app_5 = ll_0 anf_app_4 tl_0 in
+   anf_app_5 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 in
+   anf_ifthenelse_8;;
   let  length_tail_0  = let anf_app_0 = ll_0 0 in
    anf_app_0;;
-  let rec map_0 f_0 xs_0  = let anf_matching_21 = match xs_0 with
-  | [] -> []
-  | (a_0 :: []) -> let anf_app_0 = f_0 a_0 in
-   let anf_app_1 = ( :: ) anf_app_0 [] in
-   anf_app_1
-  | (a_1 :: (b_0 :: [])) -> let anf_app_2 = f_0 a_1 in
-   let anf_app_3 = f_0 b_0 in
-   let anf_app_4 = ( :: ) anf_app_3 [] in
-   let anf_app_5 = ( :: ) anf_app_2 anf_app_4 in
-   anf_app_5
-  | (a_2 :: (b_1 :: (c_0 :: []))) -> let anf_app_6 = f_0 a_2 in
-   let anf_app_7 = f_0 b_1 in
-   let anf_app_8 = f_0 c_0 in
-   let anf_app_9 = ( :: ) anf_app_8 [] in
-   let anf_app_10 = ( :: ) anf_app_7 anf_app_9 in
-   let anf_app_11 = ( :: ) anf_app_6 anf_app_10 in
-   anf_app_11
-  | (a_3 :: (b_2 :: (c_1 :: (d_0 :: tl_0)))) -> let anf_app_12 = f_0 a_3 in
-   let anf_app_13 = f_0 b_2 in
-   let anf_app_14 = f_0 c_1 in
-   let anf_app_15 = f_0 d_0 in
-   let anf_app_16 = map_0 f_0 tl_0 in
-   let anf_app_17 = ( :: ) anf_app_15 anf_app_16 in
-   let anf_app_18 = ( :: ) anf_app_14 anf_app_17 in
-   let anf_app_19 = ( :: ) anf_app_13 anf_app_18 in
-   let anf_app_20 = ( :: ) anf_app_12 anf_app_19 in
-   anf_app_20 in
-   anf_matching_21;;
-  let rec append_0 xs_0 ys_0  = let anf_matching_2 = match xs_0 with
-  | [] -> ys_0
-  | (x_0 :: xs_1) -> let anf_app_0 = append_0 xs_1 ys_0 in
-   let anf_app_1 = ( :: ) x_0 anf_app_0 in
-   anf_app_1 in
-   anf_matching_2;;
-  let rec ll_1 xs_0  = let anf_matching_2 = match xs_0 with
-  | [] -> []
-  | (h_0 :: tl_0) -> let anf_app_0 = ll_1 tl_0 in
-   let anf_app_1 = append_0 h_0 anf_app_0 in
-   anf_app_1 in
-   anf_matching_2;;
+  let rec map_0 f_0 xs_0  = let anf_app_0 = ( = ) xs_0 [] in
+   let anf_ifthenelse_89 = if anf_app_0 then [] else let anf_app_1 = get_field xs_0 1 in
+   let anf_app_2 = ( = ) anf_app_1 [] in
+   let anf_app_3 = check_tag xs_0 0 in
+   let anf_app_4 = ( && ) anf_app_3 anf_app_2 in
+   let anf_ifthenelse_88 = if anf_app_4 then let anf_app_5 = get_field xs_0 0 in
+   let a_0 = anf_app_5 in
+   let anf_app_6 = f_0 a_0 in
+   let anf_app_7 = ( :: ) anf_app_6 [] in
+   anf_app_7 else let anf_app_8 = get_field xs_0 1 in
+   let anf_app_9 = get_field anf_app_8 1 in
+   let anf_app_10 = ( = ) anf_app_9 [] in
+   let anf_app_11 = get_field xs_0 1 in
+   let anf_app_12 = check_tag anf_app_11 0 in
+   let anf_app_13 = ( && ) anf_app_12 anf_app_10 in
+   let anf_app_14 = check_tag xs_0 0 in
+   let anf_app_15 = ( && ) anf_app_14 anf_app_13 in
+   let anf_ifthenelse_87 = if anf_app_15 then let anf_app_16 = get_field xs_0 0 in
+   let a_1 = anf_app_16 in
+   let anf_app_17 = get_field xs_0 1 in
+   let anf_app_18 = get_field anf_app_17 0 in
+   let b_0 = anf_app_18 in
+   let anf_app_19 = f_0 b_0 in
+   let anf_app_20 = ( :: ) anf_app_19 [] in
+   let anf_app_21 = f_0 a_1 in
+   let anf_app_22 = ( :: ) anf_app_21 anf_app_20 in
+   anf_app_22 else let anf_app_23 = get_field xs_0 1 in
+   let anf_app_24 = get_field anf_app_23 1 in
+   let anf_app_25 = get_field anf_app_24 1 in
+   let anf_app_26 = ( = ) anf_app_25 [] in
+   let anf_app_27 = get_field xs_0 1 in
+   let anf_app_28 = get_field anf_app_27 1 in
+   let anf_app_29 = check_tag anf_app_28 0 in
+   let anf_app_30 = ( && ) anf_app_29 anf_app_26 in
+   let anf_app_31 = get_field xs_0 1 in
+   let anf_app_32 = check_tag anf_app_31 0 in
+   let anf_app_33 = ( && ) anf_app_32 anf_app_30 in
+   let anf_app_34 = check_tag xs_0 0 in
+   let anf_app_35 = ( && ) anf_app_34 anf_app_33 in
+   let anf_ifthenelse_86 = if anf_app_35 then let anf_app_36 = get_field xs_0 0 in
+   let a_2 = anf_app_36 in
+   let anf_app_37 = get_field xs_0 1 in
+   let anf_app_38 = get_field anf_app_37 0 in
+   let b_1 = anf_app_38 in
+   let anf_app_39 = get_field xs_0 1 in
+   let anf_app_40 = get_field anf_app_39 1 in
+   let anf_app_41 = get_field anf_app_40 0 in
+   let c_0 = anf_app_41 in
+   let anf_app_42 = f_0 c_0 in
+   let anf_app_43 = ( :: ) anf_app_42 [] in
+   let anf_app_44 = f_0 b_1 in
+   let anf_app_45 = ( :: ) anf_app_44 anf_app_43 in
+   let anf_app_46 = f_0 a_2 in
+   let anf_app_47 = ( :: ) anf_app_46 anf_app_45 in
+   anf_app_47 else let anf_app_48 = get_field xs_0 1 in
+   let anf_app_49 = get_field anf_app_48 1 in
+   let anf_app_50 = get_field anf_app_49 1 in
+   let anf_app_51 = check_tag anf_app_50 0 in
+   let anf_app_52 = get_field xs_0 1 in
+   let anf_app_53 = get_field anf_app_52 1 in
+   let anf_app_54 = check_tag anf_app_53 0 in
+   let anf_app_55 = ( && ) anf_app_54 anf_app_51 in
+   let anf_app_56 = get_field xs_0 1 in
+   let anf_app_57 = check_tag anf_app_56 0 in
+   let anf_app_58 = ( && ) anf_app_57 anf_app_55 in
+   let anf_app_59 = check_tag xs_0 0 in
+   let anf_app_60 = ( && ) anf_app_59 anf_app_58 in
+   let anf_ifthenelse_85 = if anf_app_60 then let anf_app_61 = get_field xs_0 0 in
+   let a_3 = anf_app_61 in
+   let anf_app_62 = get_field xs_0 1 in
+   let anf_app_63 = get_field anf_app_62 0 in
+   let b_2 = anf_app_63 in
+   let anf_app_64 = get_field xs_0 1 in
+   let anf_app_65 = get_field anf_app_64 1 in
+   let anf_app_66 = get_field anf_app_65 0 in
+   let c_1 = anf_app_66 in
+   let anf_app_67 = get_field xs_0 1 in
+   let anf_app_68 = get_field anf_app_67 1 in
+   let anf_app_69 = get_field anf_app_68 1 in
+   let anf_app_70 = get_field anf_app_69 0 in
+   let d_0 = anf_app_70 in
+   let anf_app_71 = get_field xs_0 1 in
+   let anf_app_72 = get_field anf_app_71 1 in
+   let anf_app_73 = get_field anf_app_72 1 in
+   let anf_app_74 = get_field anf_app_73 1 in
+   let tl_0 = anf_app_74 in
+   let anf_app_75 = map_0 f_0 tl_0 in
+   let anf_app_76 = f_0 d_0 in
+   let anf_app_77 = ( :: ) anf_app_76 anf_app_75 in
+   let anf_app_78 = f_0 c_1 in
+   let anf_app_79 = ( :: ) anf_app_78 anf_app_77 in
+   let anf_app_80 = f_0 b_2 in
+   let anf_app_81 = ( :: ) anf_app_80 anf_app_79 in
+   let anf_app_82 = f_0 a_3 in
+   let anf_app_83 = ( :: ) anf_app_82 anf_app_81 in
+   anf_app_83 else let anf_app_84 = match_error () in
+   anf_app_84 in
+   anf_ifthenelse_85 in
+   anf_ifthenelse_86 in
+   anf_ifthenelse_87 in
+   anf_ifthenelse_88 in
+   anf_ifthenelse_89;;
+  let rec append_0 xs_0 ys_0  = let anf_app_0 = ( = ) xs_0 [] in
+   let anf_ifthenelse_8 = if anf_app_0 then ys_0 else let anf_app_1 = check_tag xs_0 0 in
+   let anf_ifthenelse_7 = if anf_app_1 then let anf_app_2 = get_field xs_0 0 in
+   let x_0 = anf_app_2 in
+   let anf_app_3 = get_field xs_0 1 in
+   let xs_1 = anf_app_3 in
+   let anf_app_4 = append_0 xs_1 ys_0 in
+   let anf_app_5 = ( :: ) x_0 anf_app_4 in
+   anf_app_5 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 in
+   anf_ifthenelse_8;;
+  let rec ll_1 xs_0  = let anf_app_0 = ( = ) xs_0 [] in
+   let anf_ifthenelse_8 = if anf_app_0 then [] else let anf_app_1 = check_tag xs_0 0 in
+   let anf_ifthenelse_7 = if anf_app_1 then let anf_app_2 = get_field xs_0 0 in
+   let h_0 = anf_app_2 in
+   let anf_app_3 = get_field xs_0 1 in
+   let tl_0 = anf_app_3 in
+   let anf_app_4 = ll_1 tl_0 in
+   let anf_app_5 = append_0 h_0 anf_app_4 in
+   anf_app_5 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 in
+   anf_ifthenelse_8;;
   let  concat_0  = ll_1;;
-  let rec iter_0 f_0 xs_0  = let anf_matching_2 = match xs_0 with
-  | [] -> ()
-  | (h_0 :: tl_0) -> let anf_app_0 = f_0 h_0 in
-   let () = anf_app_0 in
-   let anf_app_1 = iter_0 f_0 tl_0 in
-   anf_app_1 in
-   anf_matching_2;;
+  let rec iter_0 f_0 xs_0  = let anf_app_0 = ( = ) xs_0 [] in
+   let anf_ifthenelse_11 = if anf_app_0 then () else let anf_app_1 = check_tag xs_0 0 in
+   let anf_ifthenelse_10 = if anf_app_1 then let anf_app_2 = get_field xs_0 0 in
+   let h_0 = anf_app_2 in
+   let anf_app_3 = get_field xs_0 1 in
+   let tl_0 = anf_app_3 in
+   let anf_app_4 = f_0 h_0 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_8 = if anf_app_5 then let anf_app_6 = iter_0 f_0 tl_0 in
+   anf_app_6 else let anf_app_7 = match_error () in
+   anf_app_7 in
+   anf_ifthenelse_8 else let anf_app_9 = match_error () in
+   anf_app_9 in
+   anf_ifthenelse_10 in
+   anf_ifthenelse_11;;
   let  ll_2 h_0 a_0  = let anf_tuple_0 = (h_0, a_0) in
    anf_tuple_0;;
-  let rec cartesian_0 xs_0 ys_0  = let anf_matching_4 = match xs_0 with
-  | [] -> []
-  | (h_0 :: tl_0) -> let anf_app_0 = ll_2 h_0 in
-   let anf_app_1 = map_0 anf_app_0 ys_0 in
-   let anf_app_2 = cartesian_0 tl_0 ys_0 in
-   let anf_app_3 = append_0 anf_app_1 anf_app_2 in
-   anf_app_3 in
-   anf_matching_4;;
+  let rec cartesian_0 xs_0 ys_0  = let anf_app_0 = ( = ) xs_0 [] in
+   let anf_ifthenelse_10 = if anf_app_0 then [] else let anf_app_1 = check_tag xs_0 0 in
+   let anf_ifthenelse_9 = if anf_app_1 then let anf_app_2 = get_field xs_0 0 in
+   let h_0 = anf_app_2 in
+   let anf_app_3 = get_field xs_0 1 in
+   let tl_0 = anf_app_3 in
+   let anf_app_4 = cartesian_0 tl_0 ys_0 in
+   let anf_app_5 = ll_2 h_0 in
+   let anf_app_6 = map_0 anf_app_5 ys_0 in
+   let anf_app_7 = append_0 anf_app_6 anf_app_4 in
+   anf_app_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9 in
+   anf_ifthenelse_10;;
   let  main_0  = let anf_app_0 = ( :: ) 3 [] in
    let anf_app_1 = ( :: ) 2 anf_app_0 in
    let anf_app_2 = ( :: ) 1 anf_app_1 in
    let anf_app_3 = iter_0 print_int anf_app_2 in
-   let () = anf_app_3 in
-   let anf_app_4 = ( :: ) 2 [] in
-   let anf_app_5 = ( :: ) 1 anf_app_4 in
-   let anf_app_6 = ( :: ) 4 [] in
-   let anf_app_7 = ( :: ) 3 anf_app_6 in
-   let anf_app_8 = ( :: ) 2 anf_app_7 in
-   let anf_app_9 = ( :: ) 1 anf_app_8 in
-   let anf_app_10 = cartesian_0 anf_app_5 anf_app_9 in
-   let anf_app_11 = length_0 anf_app_10 in
-   let anf_app_12 = print_int anf_app_11 in
-   let () = anf_app_12 in
-   0;;
+   let anf_app_4 = ( = ) anf_app_3 () in
+   let anf_ifthenelse_18 = if anf_app_4 then let anf_app_5 = ( :: ) 4 [] in
+   let anf_app_6 = ( :: ) 3 anf_app_5 in
+   let anf_app_7 = ( :: ) 2 anf_app_6 in
+   let anf_app_8 = ( :: ) 1 anf_app_7 in
+   let anf_app_9 = ( :: ) 2 [] in
+   let anf_app_10 = ( :: ) 1 anf_app_9 in
+   let anf_app_11 = cartesian_0 anf_app_10 anf_app_8 in
+   let anf_app_12 = length_0 anf_app_11 in
+   let anf_app_13 = print_int anf_app_12 in
+   let anf_app_14 = ( = ) anf_app_13 () in
+   let anf_ifthenelse_16 = if anf_app_14 then 0 else let anf_app_15 = match_error () in
+   anf_app_15 in
+   anf_ifthenelse_16 else let anf_app_17 = match_error () in
+   anf_app_17 in
+   anf_ifthenelse_18;;
 
   $ dune exec ./anf_demo.exe << EOF
   > let test a1 a2 a3 = a1 + a2 + a3
@@ -415,10 +604,10 @@
   let  test_0 a1_0 a2_0 a3_0  = let anf_app_0 = ( + ) a1_0 a2_0 in
    let anf_app_1 = ( + ) anf_app_0 a3_0 in
    anf_app_1;;
-  let  test_var_0  = let anf_app_0 = ( + ) 5 5 in
+  let  test_var_0  = let anf_app_0 = ( + ) 7 7 in
    let anf_app_1 = ( + ) 6 6 in
-   let anf_app_2 = ( + ) 7 7 in
-   let anf_app_3 = test_0 anf_app_0 anf_app_1 anf_app_2 in
+   let anf_app_2 = ( + ) 5 5 in
+   let anf_app_3 = test_0 anf_app_2 anf_app_1 anf_app_0 in
    anf_app_3;;
 
   $ dune exec ./anf_demo.exe << EOF
@@ -433,9 +622,13 @@
    anf_app_0;;
   let  funct_1 a_2  = let anf_app_0 = ( + ) a_2 500 in
    anf_app_0;;
-  let  ()  = let anf_app_0 = g_0 5 in
+  let  res  = let anf_app_0 = g_0 5 in
    let anf_app_1 = print_int anf_app_0 in
-   anf_app_1;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_5 = if anf_app_2 then let anf_tuple_3 = () in
+   anf_tuple_3 else let anf_app_4 = match_error () in
+   anf_app_4 in
+   anf_ifthenelse_5;;
 
   $ dune exec ./anf_demo.exe << EOF
   > let rec even n =
@@ -447,29 +640,62 @@
   >   | 0 -> false
   >   | x -> even (x - 1)
   > EOF
-  let rec  even_0 n_0  = let anf_matching_2 = match n_0 with
-  | 0 -> true
-  | x_0 -> let anf_app_0 = ( - ) x_0 1 in
-   let anf_app_1 = odd_0 anf_app_0 in
-   anf_app_1 in
-   anf_matching_2  and  odd_0 n_1  = let anf_matching_5 = match n_1 with
-  | 0 -> false
-  | x_1 -> let anf_app_3 = ( - ) x_1 1 in
-   let anf_app_4 = even_0 anf_app_3 in
-   anf_app_4 in
-   anf_matching_5 
+  let rec  even_0 n_0  = let anf_app_0 = ( = ) n_0 0 in
+   let anf_ifthenelse_3 = if anf_app_0 then true else let x_0 = n_0 in
+   let anf_app_1 = ( - ) x_0 1 in
+   let anf_app_2 = odd_0 anf_app_1 in
+   anf_app_2 in
+   anf_ifthenelse_3  and  odd_0 n_1  = let anf_app_4 = ( = ) n_1 0 in
+   let anf_ifthenelse_7 = if anf_app_4 then false else let x_1 = n_1 in
+   let anf_app_5 = ( - ) x_1 1 in
+   let anf_app_6 = even_0 anf_app_5 in
+   anf_app_6 in
+   anf_ifthenelse_7 
 
   $ dune exec ./anf_demo.exe << EOF
   > let _ = a + b
   > let ( + ) a b = a - b
   > let test_var = test (5 + 5) (6 + 6) (7 + 7)
   > EOF
-  let  _  = let anf_app_0 = ( + ) unbound_a_0 unbound_b_0 in
-   anf_app_0;;
+  let  res  = let anf_tuple_0 = () in
+   anf_tuple_0;;
   let  ( + )_0 a_0 b_0  = let anf_app_0 = ( - ) a_0 b_0 in
    anf_app_0;;
-  let  test_var_0  = let anf_app_0 = ( + )_0 5 5 in
+  let  test_var_0  = let anf_app_0 = ( + )_0 7 7 in
    let anf_app_1 = ( + )_0 6 6 in
-   let anf_app_2 = ( + )_0 7 7 in
-   let anf_app_3 = unbound_test_0 anf_app_0 anf_app_1 anf_app_2 in
+   let anf_app_2 = ( + )_0 5 5 in
+   let anf_app_3 = unbound_test_0 anf_app_2 anf_app_1 anf_app_0 in
    anf_app_3;;
+
+  $ dune exec ./anf_demo.exe << EOF
+  > let test a = 5 
+  > EOF
+  let  test_0 a_0  = 5;;
+
+  $ dune exec ./anf_demo.exe << EOF
+  > let rec map_cps f l k =
+  > match l with
+  > | [] -> k []
+  > | x :: xs -> map_cps f xs (fun t -> k (f x :: t))
+  > let map f l = map_cps f l (fun x -> x)
+  > EOF
+  let  ll_0 f_0 k_0 x_0 t_0  = let anf_app_0 = f_0 x_0 in
+   let anf_app_1 = ( :: ) anf_app_0 t_0 in
+   let anf_app_2 = k_0 anf_app_1 in
+   anf_app_2;;
+  let rec map_cps_0 f_0 l_0 k_0  = let anf_app_0 = ( = ) l_0 [] in
+   let anf_ifthenelse_9 = if anf_app_0 then let anf_app_1 = k_0 [] in
+   anf_app_1 else let anf_app_2 = check_tag l_0 0 in
+   let anf_ifthenelse_8 = if anf_app_2 then let anf_app_3 = get_field l_0 0 in
+   let x_0 = anf_app_3 in
+   let anf_app_4 = get_field l_0 1 in
+   let xs_0 = anf_app_4 in
+   let anf_app_5 = ll_0 f_0 k_0 x_0 in
+   let anf_app_6 = map_cps_0 f_0 xs_0 anf_app_5 in
+   anf_app_6 else let anf_app_7 = match_error () in
+   anf_app_7 in
+   anf_ifthenelse_8 in
+   anf_ifthenelse_9;;
+  let  ll_1 x_0  = x_0;;
+  let  map_0 f_0 l_0  = let anf_app_0 = map_cps_0 f_0 l_0 ll_1 in
+   anf_app_0;;
diff --git a/BasedML/test/anf_types_demo.ml b/BasedML/test/anf_types_demo.ml
index eb3c69d73..216b642ba 100644
--- a/BasedML/test/anf_types_demo.ml
+++ b/BasedML/test/anf_types_demo.ml
@@ -9,46 +9,53 @@ let () =
   let s = Stdio.In_channel.input_all Stdlib.stdin in
   match Parser.parse_program s with
   | Ok ast_before ->
-    let final =
+    let lifted =
       ast_before
       |> Middleend.Closure_conversion.convert_ast
       |> Middleend.Lambda_lifting.lift_ast
-      |> Middleend.Anf.transform
     in
-    let rec anf_helper acc = function
-      | Ok h :: tl -> anf_helper (Middleend.Anf_to_str.anf_decl_to_string h ^ acc) tl
-      | [] -> acc
-      | _ -> "Error "
-    in
-    (match Parser.parse_program (anf_helper "" (List.rev final)) with
-     | Ok ast_after ->
-       (match Typeinference.infer_prog ast_before, Typeinference.infer_prog ast_after with
-        | Ok map1, Ok map2 ->
-          let all_types_match =
-            Typeinference.StringMap.for_all
-              (fun key typ1 ->
-                if is_stdlib key
-                then true
-                else (
-                  match Typeinference.StringMap.find_opt key map2 with
-                  | Some typ2 ->
-                    Format.printf "Name: %s\n" key;
-                    Format.printf "Original program: %a\n" Ast.pp_type_name typ1;
-                    Format.printf "ANF: %a\n\n" Ast.pp_type_name typ2;
-                    if not (Typeinference.types_equal typ1 typ2)
-                    then (
-                      Format.printf "There's been a discrepancy for name %s\n" key;
-                      false)
-                    else true
-                  | None ->
-                    Format.printf "Name %s found in map1 but not in map2\n" key;
-                    false))
-              map1
-          in
-          if all_types_match
-          then Format.printf "All types are correct\n"
-          else Format.printf "There's been a type mismatch\n"
-        | _ -> Format.printf "Error while typechecking\n")
-     | _ -> Format.printf "Error while parsing ANF program\n")
+    let match_free = Middleend.Match_elimination.transform lifted in
+    (match match_free with
+     | _, Ok new_ast ->
+       let final = Middleend.Anf.transform new_ast in
+       let rec anf_helper acc = function
+         | Ok h :: tl -> anf_helper (Middleend.Anf_to_str.anf_decl_to_string h ^ acc) tl
+         | [] -> acc
+         | _ -> "Error "
+       in
+       (match Parser.parse_program (anf_helper "" (List.rev final)) with
+        | Ok ast_after ->
+          (match
+             ( Typeinference.infer_with_system_fun ast_before
+             , Typeinference.infer_with_system_fun ast_after )
+           with
+           | Ok map1, Ok map2 ->
+             let all_types_match =
+               Typeinference.StringMap.for_all
+                 (fun key typ1 ->
+                   if is_stdlib key
+                   then true
+                   else (
+                     match Typeinference.StringMap.find_opt key map2 with
+                     | Some typ2 ->
+                       Format.printf "Name: %s\n" key;
+                       Format.printf "Original program: %a\n" Ast.pp_type_name typ1;
+                       Format.printf "ANF: %a\n\n" Ast.pp_type_name typ2;
+                       if not (Typeinference.type_more_general typ1 typ2)
+                       then (
+                         Format.printf "There's been a discrepancy for name %s\n" key;
+                         false)
+                       else true
+                     | None ->
+                       Format.printf "Name %s found in map1 but not in map2\n" key;
+                       false))
+                 map1
+             in
+             if all_types_match
+             then Format.printf "All types are correct\n"
+             else Format.printf "There's been a type mismatch\n"
+           | _ -> Format.printf "Error while typechecking\n")
+        | _ -> Format.printf "Error while parsing ANF program\n")
+     | _, Error message -> Format.printf "Error: %s\n" message)
   | _ -> Format.printf "Error while parsing original program\n"
 ;;
diff --git a/BasedML/test/anf_types_tests.t b/BasedML/test/anf_types_tests.t
index b06000986..eac921ece 100644
--- a/BasedML/test/anf_types_tests.t
+++ b/BasedML/test/anf_types_tests.t
@@ -5,8 +5,8 @@
   >   else
   >    fact_cps (n - 1) (fun acc -> cont (n * acc))
   Name: fact_cps
-  Original program: (int -> ((int -> 'p19) -> 'p19))
-  ANF: (int -> ((int -> 'p27) -> 'p27))
+  Original program: (int -> ((int -> 'p1f) -> 'p1f))
+  ANF: (int -> ((int -> 'p2d) -> 'p2d))
   
   All types are correct
 
@@ -34,8 +34,8 @@
 
   $ dune exec ./anf_types_demo.exe < ./manytests/typed/002fac.ml
   Name: fac_cps
-  Original program: (int -> ((int -> 'p20) -> 'p20))
-  ANF: (int -> ((int -> 'p32) -> 'p32))
+  Original program: (int -> ((int -> 'p26) -> 'p26))
+  ANF: (int -> ((int -> 'p41) -> 'p41))
   
   Name: main
   Original program: int
@@ -55,8 +55,8 @@
   >   cont (a + b)))
   > EOF
   Name: fib_cps
-  Original program: (int -> ((int -> 'p23) -> 'p23))
-  ANF: (int -> ((int -> 'p40) -> 'p40))
+  Original program: (int -> ((int -> 'p29) -> 'p29))
+  ANF: (int -> ((int -> 'p46) -> 'p46))
   
   All types are correct
 
@@ -98,8 +98,8 @@
   ANF: (int -> (int -> (int -> int)))
   
   Name: wrap
-  Original program: ('p4c -> 'p4c)
-  ANF: ('p5d -> 'p5d)
+  Original program: ('p55 -> 'p55)
+  ANF: ('p6f -> 'p6f)
   
   All types are correct
 
@@ -109,8 +109,8 @@
   ANF: ((int -> int) -> (int -> int))
   
   Name: fix
-  Original program: ((('p22 -> 'p23) -> ('p22 -> 'p23)) -> ('p22 -> 'p23))
-  ANF: ((('p2b -> 'p2c) -> ('p2b -> 'p2c)) -> ('p2b -> 'p2c))
+  Original program: ((('p28 -> 'p29) -> ('p28 -> 'p29)) -> ('p28 -> 'p29))
+  ANF: ((('p3a -> 'p3b) -> ('p3a -> 'p3b)) -> ('p3a -> 'p3b))
   
   Name: main
   Original program: int
@@ -159,36 +159,36 @@
   All types are correct
 
   $ dune exec ./anf_types_demo.exe < ./manytests/typed/016lists.ml
-  Name: append
-  Original program: (('pdc list) -> (('pdc list) -> ('pdc list)))
-  ANF: (('p11c list) -> (('p11c list) -> ('p11c list)))
+  Name: iter
+  Original program: (('pe8 -> unit) -> (('pe8 list) -> unit))
+  ANF: (('p337 -> unit) -> (('p336 list) -> unit))
   
-  Name: length
-  Original program: (('pe1 list) -> int)
-  ANF: (('p121 list) -> int)
+  Name: cartesian
+  Original program: (('pe2 list) -> (('pe3 list) -> (('pe2 * 'pe3) list)))
+  ANF: (('p32e list) -> (('p32f list) -> ('p330 list)))
+  
+  Name: append
+  Original program: (('pe1 list) -> (('pe1 list) -> ('pe1 list)))
+  ANF: (('p32c list) -> (('p32d list) -> ('p32d list)))
   
   Name: concat
-  Original program: ((('pdf list) list) -> ('pdf list))
-  ANF: ((('p11f list) list) -> ('p11f list))
+  Original program: ((('pe5 list) list) -> ('pe5 list))
+  ANF: (('p332 list) -> ('p333 list))
   
-  Name: cartesian
-  Original program: (('pdd list) -> (('pde list) -> (('pdd * 'pde) list)))
-  ANF: (('p11d list) -> (('p11e list) -> (('p11d * 'p11e) list)))
+  Name: length_tail
+  Original program: (('pea list) -> int)
+  ANF: (('p339 list) -> int)
   
-  Name: iter
-  Original program: (('pe0 -> unit) -> (('pe0 list) -> unit))
-  ANF: (('p120 -> unit) -> (('p120 list) -> unit))
+  Name: length
+  Original program: (('pe9 list) -> int)
+  ANF: (('p338 list) -> int)
+  
+  Name: map
+  Original program: (('peb -> 'pec) -> (('peb list) -> ('pec list)))
+  ANF: (('p33f -> 'p340) -> (('p341 list) -> ('p340 list)))
   
   Name: main
   Original program: int
   ANF: int
   
-  Name: length_tail
-  Original program: (('pe2 list) -> int)
-  ANF: (('p122 list) -> int)
-  
-  Name: map
-  Original program: (('pe3 -> 'pe4) -> (('pe3 list) -> ('pe4 list)))
-  ANF: (('p127 -> 'p128) -> (('p127 list) -> ('p128 list)))
-  
   All types are correct
diff --git a/BasedML/test/dune b/BasedML/test/dune
index c30909a6a..360516b96 100644
--- a/BasedML/test/dune
+++ b/BasedML/test/dune
@@ -34,6 +34,16 @@
  (public_name egraphs_demo)
  (libraries middleend stdio ast))
 
+(executable
+ (name match_elimination_demo)
+ (modules match_elimination_demo)
+ (public_name match_elimination_demo)
+ (libraries middleend stdio ast))
+
+(cram
+ (applies_to match_elimination_tests)
+ (deps ./match_elimination_demo.exe))
+
 (cram
  (applies_to typeinference_tests)
  (deps
diff --git a/BasedML/test/match_elimination_demo.ml b/BasedML/test/match_elimination_demo.ml
new file mode 100644
index 000000000..0e0b3c7e0
--- /dev/null
+++ b/BasedML/test/match_elimination_demo.ml
@@ -0,0 +1,23 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+let () =
+  let s = Stdio.In_channel.input_all Stdlib.stdin in
+  match Parser.parse_program s with
+  | Ok ast ->
+    let lifted =
+      ast |> Middleend.Closure_conversion.convert_ast |> Middleend.Lambda_lifting.lift_ast
+    in
+    (match Middleend.Match_elimination.transform lifted with
+     | _, Ok new_ast ->
+       List.iter
+         (fun binding ->
+           Stdlib.Format.printf
+             "%a\n"
+             Middleend.Restore_llast.pp_lllet_declaration
+             binding)
+         new_ast
+     | _, Error message -> Format.printf "Error: %s\n" message)
+  | Error message -> Format.printf "Error: %s\n" message
+;;
diff --git a/BasedML/test/match_elimination_tests.t b/BasedML/test/match_elimination_tests.t
new file mode 100644
index 000000000..431cdd1df
--- /dev/null
+++ b/BasedML/test/match_elimination_tests.t
@@ -0,0 +1,10 @@
+  $ dune exec ./match_elimination_demo.exe << EOF
+  > let prog = let (difficult_pattern, nasty_pattern) = (5, 6) in a
+  > EOF
+  let  prog  = (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))
+
+  $ dune exec ./match_elimination_demo.exe << EOF
+  > let prog = let (difficult_pattern, nasty_pattern) = let (difficult_pattern, nasty_pattern) = (5, 6) in a in a
+  > EOF
+  let  prog  = (let  difficult_pattern = ((get_field (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))) 0) in (let  nasty_pattern = ((get_field (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))) 1) in a))
+


Reviews:
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-02-28T22:20:22Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T15:34:32Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T15:59:36Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-01T18:22:40Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-01T19:13:43Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-01T20:04:56Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-01T20:23:19Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-01T20:51:06Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T21:47:49Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T21:49:05Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T21:50:53Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T21:51:03Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T21:54:01Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T21:54:18Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-01T21:54:48Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T22:12:07Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T22:14:41Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T22:17:56Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T22:18:46Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-01T22:59:20Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-02T07:43:24Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-02T07:44:04Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T11:41:14Z
user: login: Kakadu
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-02T18:19:47Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T19:21:49Z
user: login: Salvatore112
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T00:29:35Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-03T00:37:12Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-03T12:42:02Z
user: login: github-actions[bot]
body: Zanuda-linter report
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-03T13:15:13Z

Review comments:
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Kakadu
body: А как при избвалении от мэтчинга появилась эта пачка переименований?
created_at: 2025-03-01T15:34:32Z
author_association: OWNER
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Salvatore112
body: Появляются в результате избавления от паттернов-аргументов, которые далее элиминируются в теле.
created_at: 2025-03-01T15:59:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Kakadu
body: А чьём теле?
created_at: 2025-03-01T21:47:49Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,355 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+open Common.StateMonad
+open Llast
+open Ast
+
+type bound_expr = BoundExpression of pattern * llexpr
+
+let rec map1 f = function
+  | [] -> return []
+  | h :: tl -> f h >>= fun c -> map1 f tl >>= fun lst -> return (c :: lst)
+;;
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+let empty_context = { reserved_names = (module Base.String) |> Base.Set.empty }
+
+let rec collect_bindings_from_pat = function
+  | PWildCard -> (module Base.String) |> Base.Set.empty
+  | PConstant _ -> (module Base.String) |> Base.Set.empty
+  | PIdentifier id -> Base.Set.add ((module Base.String) |> Base.Set.empty) id
+  | PCons (left, right) ->
+    let collected_in_left = collect_bindings_from_pat left in
+    let collected_in_right = collect_bindings_from_pat right in
+    Base.Set.union collected_in_left collected_in_right
+  | PConstraint (pat, _) -> collect_bindings_from_pat pat
+  | PTuple pats ->
+    Base.List.fold_left
+      pats
+      ~init:((module Base.String) |> Base.Set.empty)
+      ~f:(fun acc h -> Base.Set.union acc (collect_bindings_from_pat h))
+;;
+
+let show_idname old_name counter =
+  if counter >= 0 then Printf.sprintf "%s_%d" old_name counter else old_name
+;;
+
+let rec get_all_id acc = function
+  | PWildCard | PConstant _ -> acc
+  | PConstraint (pat, _tp) -> get_all_id acc pat
+  | PCons (pat1, pat2) -> get_all_id (get_all_id acc pat2) pat1
+  | PTuple plst -> List.fold_left get_all_id acc plst
+  | PIdentifier x -> x :: acc
+;;
+
+let rec generate_bindings =
+  let optimized_conj operand1 operand2 =
+    match operand1, operand2 with
+    | _, LLConstant (CBool true) | LLConstant (CBool false), _ -> operand1
+    | LLConstant (CBool true), _ | _, LLConstant (CBool false) -> operand2
+    | _ -> LLApplication (LLApplication (LLIdentifier "( && )", operand1), operand2)
+  in
+  function
+  | BoundExpression (PConstant constant, expression) ->
+    ( LLApplication (LLApplication (LLIdentifier "( = )", expression), LLConstant constant)
+    , [] )
+    |> return
+  | BoundExpression (PTuple pattern_list, expression) ->
+    let tuple_helper pattern_list expression_list =
+      let rec step
+        collected_conditions
+        collected_bindings
+        new_pattern_list
+        new_expression_list
+        =
+        match new_pattern_list, new_expression_list with
+        | [], [] -> return (collected_conditions, collected_bindings)
+        | pattern :: rest_patterns, expression :: rest_expressions ->
+          let bound_expr = BoundExpression (pattern, expression) in
+          let* head_condition, bindings = generate_bindings bound_expr in
+          step
+            (optimized_conj collected_conditions head_condition)
+            (List.append collected_bindings bindings)
+            rest_patterns
+            rest_expressions
+        | _ -> fail "Length mismatch"
+      in
+      step (LLConstant (CBool true)) [] pattern_list expression_list
+    in
+    (match expression with
+     | LLTuple elements_list -> tuple_helper pattern_list elements_list
+     | other ->
+       let accessed_fields =
+         List.init (List.length pattern_list) (fun num ->
+           LLApplication
+             (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt num)))
+       in
+       tuple_helper pattern_list accessed_fields)
+  | BoundExpression (PWildCard, _) -> (LLConstant (CBool true), []) |> return
+  | BoundExpression (PCons (left, right), expression) ->
+    (match expression with
+     | LLApplication (LLApplication (LLIdentifier "( :: )", head), tail) ->
+       let bound_left = BoundExpression (left, head) in
+       let bound_right = BoundExpression (right, tail) in
+       let* head_condition, head_bindings = generate_bindings bound_left in
+       let* tail_condition, tail_bindings = generate_bindings bound_right in
+       ( optimized_conj head_condition tail_condition
+       , List.append head_bindings tail_bindings )
+       |> return
+     | other ->
+       let tag_checking =
+         LLApplication
+           (LLApplication (LLIdentifier "check_tag", other), LLConstant (CInt 0))
+       in
+       let* head_condition, head_bindings =
+         let bound_left =
+           BoundExpression
+             ( left
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 0)) )
+         in
+         generate_bindings bound_left
+       in
+       let* tail_condition, tail_bindings =
+         let bound_right =
+           BoundExpression
+             ( right
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 1)) )
+         in
+         generate_bindings bound_right
+       in
+       ( optimized_conj tag_checking (optimized_conj head_condition tail_condition)
+       , List.append head_bindings tail_bindings )
+       |> return)
+  | BoundExpression (PConstraint (pat, _), llexpr) ->
+    let bound_expr = BoundExpression (pat, llexpr) in
+    generate_bindings bound_expr
+  | BoundExpression (PIdentifier name, llexpr) ->
+    (LLConstant (CBool true), [ name, llexpr ]) |> return
+;;
+
+let rec generate_unique_name old_name counter =
+  let* ctx = read in
+  let new_name = old_name, counter in
+  if Base.Set.mem
+       (Base.Set.union
+          ctx.reserved_names
+          (Base.Set.singleton (module Base.String) old_name))
+       (show_idname old_name counter)
+  then generate_unique_name old_name (counter + 1)
+  else
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.add ctx.reserved_names (Printf.sprintf "%s_%d" old_name counter)
+        }
+    in
+    new_name |> return
+;;
+
+let rec match_of_pat_let = function
+  | LLConstant c -> LLConstant c |> return
+  | LLIdentifier id ->
+    let* old_ctx = read in
+    let* _ = write { reserved_names = Base.Set.add old_ctx.reserved_names id } in
+    LLIdentifier id |> return
+  | LLIfThenElse (guard, then_branch, else_branch) ->
+    let* turned_guard = match_of_pat_let guard in
+    let* turned_then_branch = match_of_pat_let then_branch in
+    let* turned_else_branch = match_of_pat_let else_branch in
+    LLIfThenElse (turned_guard, turned_then_branch, turned_else_branch) |> return
+  | LLConstraint (llex, typ) ->
+    let* turned_llexp = match_of_pat_let llex in
+    LLConstraint (turned_llexp, typ) |> return
+  | LLApplication (left, right) ->
+    let* turned_left = match_of_pat_let left in
+    let* turned_right = match_of_pat_let right in
+    LLApplication (turned_left, turned_right) |> return
+  | LLTuple elems ->
+    let* new_elems = map1 match_of_pat_let elems in
+    LLTuple new_elems |> return
+  | LLLetIn (_, pat, outer, inner) ->
+    let* old_ctx = read in
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+        }
+    in
+    let* converted_outer = match_of_pat_let outer in
+    let* converted_inner = match_of_pat_let inner in
+    LLMatch (converted_outer, [ pat, converted_inner ]) |> return
+  | LLMatch (main_exp, cases) ->
+    let* new_main_exp = match_of_pat_let main_exp in
+    let rec case_helper acc = function
+      | [] -> List.rev acc |> return
+      | (pat, expr) :: tl ->
+        let* old_ctx = read in
+        let* _ =
+          write
+            { reserved_names =
+                Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+            }
+        in
+        let* new_expr = match_of_pat_let expr in
+        case_helper ((pat, new_expr) :: acc) tl
+    in
+    let* new_cases = case_helper [] cases in
+    LLMatch (new_main_exp, new_cases) |> return
+;;
+
+let rec eliminate_lexpr =
+  let optimized_if_then_else guard then_branch else_branch =
+    match guard with
+    | LLConstant (CBool true) -> then_branch
+    | LLConstant (CBool false) -> else_branch
+    | _ -> LLIfThenElse (guard, then_branch, else_branch)
+  in
+  function
+  | LLTuple elements ->
+    let* new_elements = map1 eliminate_lexpr elements in
+    LLTuple new_elements |> return
+  | LLIfThenElse (guard_branch, then_branch, else_branch) ->
+    let* new_guard_branch = eliminate_lexpr guard_branch in
+    let* new_then_branch = eliminate_lexpr then_branch in
+    let* new_else_branch = eliminate_lexpr else_branch in
+    LLIfThenElse (new_guard_branch, new_then_branch, new_else_branch) |> return
+  | LLApplication (left, right) ->
+    let* new_left = eliminate_lexpr left in
+    let* new_right = eliminate_lexpr right in
+    LLApplication (new_left, new_right) |> return
+  | LLConstraint (llexpr, typ) ->
+    let* new_llexpr = eliminate_lexpr llexpr in
+    LLConstraint (new_llexpr, typ) |> return
+  | LLMatch (main_expression, match_cases) ->
+    let* match_free_main_expression = eliminate_lexpr main_expression in
+    let* conditions =
+      map1
+        (fun (pat, _) ->
+          let bound_expr = BoundExpression (pat, match_free_main_expression) in
+          generate_bindings bound_expr)
+        match_cases
+    in
+    List.fold_right2
+      (fun (head_condition, binds) (_, expr) acc ->
+        let* match_free_lexpr = eliminate_lexpr expr in
+        let* acc' = acc in
+        return
+          (optimized_if_then_else
+             head_condition
+             (List.fold_right
+                (fun (name, llexpr) acc ->
+                  LLLetIn (NotRec, PIdentifier name, llexpr, acc))
+                binds
+                match_free_lexpr)
+             acc'))
+      conditions
+      match_cases
+      (LLApplication (LLIdentifier "match_error", LLConstant CUnit) |> return)
+  | LLConstant constant -> LLConstant constant |> return
+  | LLIdentifier name -> LLIdentifier name |> return
+  | _ -> fail "Error: Unexpected expression"
path: BasedML/lib/middleend/match_elimination.ml
user: login: Kakadu
body: Недоделка?
created_at: 2025-03-01T21:49:05Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,355 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+open Common.StateMonad
+open Llast
+open Ast
+
+type bound_expr = BoundExpression of pattern * llexpr
+
+let rec map1 f = function
+  | [] -> return []
+  | h :: tl -> f h >>= fun c -> map1 f tl >>= fun lst -> return (c :: lst)
+;;
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+let empty_context = { reserved_names = (module Base.String) |> Base.Set.empty }
+
+let rec collect_bindings_from_pat = function
+  | PWildCard -> (module Base.String) |> Base.Set.empty
+  | PConstant _ -> (module Base.String) |> Base.Set.empty
+  | PIdentifier id -> Base.Set.add ((module Base.String) |> Base.Set.empty) id
+  | PCons (left, right) ->
+    let collected_in_left = collect_bindings_from_pat left in
+    let collected_in_right = collect_bindings_from_pat right in
+    Base.Set.union collected_in_left collected_in_right
+  | PConstraint (pat, _) -> collect_bindings_from_pat pat
+  | PTuple pats ->
+    Base.List.fold_left
+      pats
+      ~init:((module Base.String) |> Base.Set.empty)
+      ~f:(fun acc h -> Base.Set.union acc (collect_bindings_from_pat h))
+;;
+
+let show_idname old_name counter =
+  if counter >= 0 then Printf.sprintf "%s_%d" old_name counter else old_name
+;;
+
+let rec get_all_id acc = function
+  | PWildCard | PConstant _ -> acc
+  | PConstraint (pat, _tp) -> get_all_id acc pat
+  | PCons (pat1, pat2) -> get_all_id (get_all_id acc pat2) pat1
+  | PTuple plst -> List.fold_left get_all_id acc plst
+  | PIdentifier x -> x :: acc
+;;
+
+let rec generate_bindings =
+  let optimized_conj operand1 operand2 =
+    match operand1, operand2 with
+    | _, LLConstant (CBool true) | LLConstant (CBool false), _ -> operand1
+    | LLConstant (CBool true), _ | _, LLConstant (CBool false) -> operand2
+    | _ -> LLApplication (LLApplication (LLIdentifier "( && )", operand1), operand2)
+  in
+  function
+  | BoundExpression (PConstant constant, expression) ->
+    ( LLApplication (LLApplication (LLIdentifier "( = )", expression), LLConstant constant)
+    , [] )
+    |> return
+  | BoundExpression (PTuple pattern_list, expression) ->
+    let tuple_helper pattern_list expression_list =
+      let rec step
+        collected_conditions
+        collected_bindings
+        new_pattern_list
+        new_expression_list
+        =
+        match new_pattern_list, new_expression_list with
+        | [], [] -> return (collected_conditions, collected_bindings)
+        | pattern :: rest_patterns, expression :: rest_expressions ->
+          let bound_expr = BoundExpression (pattern, expression) in
+          let* head_condition, bindings = generate_bindings bound_expr in
+          step
+            (optimized_conj collected_conditions head_condition)
+            (List.append collected_bindings bindings)
+            rest_patterns
+            rest_expressions
+        | _ -> fail "Length mismatch"
+      in
+      step (LLConstant (CBool true)) [] pattern_list expression_list
+    in
+    (match expression with
+     | LLTuple elements_list -> tuple_helper pattern_list elements_list
+     | other ->
+       let accessed_fields =
+         List.init (List.length pattern_list) (fun num ->
+           LLApplication
+             (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt num)))
+       in
+       tuple_helper pattern_list accessed_fields)
+  | BoundExpression (PWildCard, _) -> (LLConstant (CBool true), []) |> return
+  | BoundExpression (PCons (left, right), expression) ->
+    (match expression with
+     | LLApplication (LLApplication (LLIdentifier "( :: )", head), tail) ->
+       let bound_left = BoundExpression (left, head) in
+       let bound_right = BoundExpression (right, tail) in
+       let* head_condition, head_bindings = generate_bindings bound_left in
+       let* tail_condition, tail_bindings = generate_bindings bound_right in
+       ( optimized_conj head_condition tail_condition
+       , List.append head_bindings tail_bindings )
+       |> return
+     | other ->
+       let tag_checking =
+         LLApplication
+           (LLApplication (LLIdentifier "check_tag", other), LLConstant (CInt 0))
+       in
+       let* head_condition, head_bindings =
+         let bound_left =
+           BoundExpression
+             ( left
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 0)) )
+         in
+         generate_bindings bound_left
+       in
+       let* tail_condition, tail_bindings =
+         let bound_right =
+           BoundExpression
+             ( right
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 1)) )
+         in
+         generate_bindings bound_right
+       in
+       ( optimized_conj tag_checking (optimized_conj head_condition tail_condition)
+       , List.append head_bindings tail_bindings )
+       |> return)
+  | BoundExpression (PConstraint (pat, _), llexpr) ->
+    let bound_expr = BoundExpression (pat, llexpr) in
+    generate_bindings bound_expr
+  | BoundExpression (PIdentifier name, llexpr) ->
+    (LLConstant (CBool true), [ name, llexpr ]) |> return
+;;
+
+let rec generate_unique_name old_name counter =
+  let* ctx = read in
+  let new_name = old_name, counter in
+  if Base.Set.mem
+       (Base.Set.union
+          ctx.reserved_names
+          (Base.Set.singleton (module Base.String) old_name))
+       (show_idname old_name counter)
+  then generate_unique_name old_name (counter + 1)
+  else
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.add ctx.reserved_names (Printf.sprintf "%s_%d" old_name counter)
+        }
+    in
+    new_name |> return
+;;
+
+let rec match_of_pat_let = function
+  | LLConstant c -> LLConstant c |> return
+  | LLIdentifier id ->
+    let* old_ctx = read in
+    let* _ = write { reserved_names = Base.Set.add old_ctx.reserved_names id } in
+    LLIdentifier id |> return
+  | LLIfThenElse (guard, then_branch, else_branch) ->
+    let* turned_guard = match_of_pat_let guard in
+    let* turned_then_branch = match_of_pat_let then_branch in
+    let* turned_else_branch = match_of_pat_let else_branch in
+    LLIfThenElse (turned_guard, turned_then_branch, turned_else_branch) |> return
+  | LLConstraint (llex, typ) ->
+    let* turned_llexp = match_of_pat_let llex in
+    LLConstraint (turned_llexp, typ) |> return
+  | LLApplication (left, right) ->
+    let* turned_left = match_of_pat_let left in
+    let* turned_right = match_of_pat_let right in
+    LLApplication (turned_left, turned_right) |> return
+  | LLTuple elems ->
+    let* new_elems = map1 match_of_pat_let elems in
+    LLTuple new_elems |> return
+  | LLLetIn (_, pat, outer, inner) ->
+    let* old_ctx = read in
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+        }
+    in
+    let* converted_outer = match_of_pat_let outer in
+    let* converted_inner = match_of_pat_let inner in
+    LLMatch (converted_outer, [ pat, converted_inner ]) |> return
+  | LLMatch (main_exp, cases) ->
+    let* new_main_exp = match_of_pat_let main_exp in
+    let rec case_helper acc = function
+      | [] -> List.rev acc |> return
+      | (pat, expr) :: tl ->
+        let* old_ctx = read in
+        let* _ =
+          write
+            { reserved_names =
+                Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+            }
+        in
+        let* new_expr = match_of_pat_let expr in
+        case_helper ((pat, new_expr) :: acc) tl
+    in
+    let* new_cases = case_helper [] cases in
+    LLMatch (new_main_exp, new_cases) |> return
+;;
+
+let rec eliminate_lexpr =
+  let optimized_if_then_else guard then_branch else_branch =
+    match guard with
+    | LLConstant (CBool true) -> then_branch
+    | LLConstant (CBool false) -> else_branch
+    | _ -> LLIfThenElse (guard, then_branch, else_branch)
+  in
+  function
+  | LLTuple elements ->
+    let* new_elements = map1 eliminate_lexpr elements in
+    LLTuple new_elements |> return
+  | LLIfThenElse (guard_branch, then_branch, else_branch) ->
+    let* new_guard_branch = eliminate_lexpr guard_branch in
+    let* new_then_branch = eliminate_lexpr then_branch in
+    let* new_else_branch = eliminate_lexpr else_branch in
+    LLIfThenElse (new_guard_branch, new_then_branch, new_else_branch) |> return
+  | LLApplication (left, right) ->
+    let* new_left = eliminate_lexpr left in
+    let* new_right = eliminate_lexpr right in
+    LLApplication (new_left, new_right) |> return
+  | LLConstraint (llexpr, typ) ->
+    let* new_llexpr = eliminate_lexpr llexpr in
+    LLConstraint (new_llexpr, typ) |> return
+  | LLMatch (main_expression, match_cases) ->
+    let* match_free_main_expression = eliminate_lexpr main_expression in
+    let* conditions =
+      map1
+        (fun (pat, _) ->
+          let bound_expr = BoundExpression (pat, match_free_main_expression) in
+          generate_bindings bound_expr)
+        match_cases
+    in
+    List.fold_right2
+      (fun (head_condition, binds) (_, expr) acc ->
+        let* match_free_lexpr = eliminate_lexpr expr in
+        let* acc' = acc in
+        return
+          (optimized_if_then_else
+             head_condition
+             (List.fold_right
+                (fun (name, llexpr) acc ->
+                  LLLetIn (NotRec, PIdentifier name, llexpr, acc))
+                binds
+                match_free_lexpr)
+             acc'))
+      conditions
+      match_cases
+      (LLApplication (LLIdentifier "match_error", LLConstant CUnit) |> return)
+  | LLConstant constant -> LLConstant constant |> return
+  | LLIdentifier name -> LLIdentifier name |> return
+  | _ -> fail "Error: Unexpected expression"
+;;
+
+let rec rename_pat = function
+  | PWildCard -> PWildCard |> return
+  | PConstant c -> PConstant c |> return
+  | PConstraint (pat, typ) ->
+    let* new_pat = rename_pat pat in
+    PConstraint (new_pat, typ) |> return
+  | PCons (left, right) ->
+    let* new_left = rename_pat left in
+    let* new_right = rename_pat right in
+    PCons (new_left, new_right) |> return
+  | PTuple pats ->
+    let* new_pats = map1 rename_pat pats in
+    PTuple new_pats |> return
+  | PIdentifier id ->
+    let* old_name, counter = generate_unique_name id 0 in
+    PIdentifier (Printf.sprintf "%s_%d" old_name counter) |> return
+;;
+
+let process_simple_let = function
+  | LLLet (PIdentifier id, args, llexpr) ->
+    let rec get_new_args acc = function
+      | [] -> List.rev acc |> return
+      | _ :: tl ->
+        let* name, counter = generate_unique_name "arg" 0 in
+        let new_name = Printf.sprintf "%s_%d" name counter in
+        get_new_args (new_name :: acc) tl
+    in
+    let rec bind_names_to_patterns base_exp names patterns =
+      match names, patterns with
+      | [], [] -> return base_exp
+      | name :: names_tail, pattern :: patterns_tail ->
+        let* ctx = read in
+        let* _ = write { reserved_names = Base.Set.add ctx.reserved_names name } in
+        let* inner_exp = bind_names_to_patterns base_exp names_tail patterns_tail in
+        return (LLLetIn (NotRec, pattern, LLIdentifier name, inner_exp))
+      | _ -> fail "Error: Mismatch in the lengths of names and patterns lists"
+    in
+    let* ctx = read in
+    let* _ = write { reserved_names = Base.Set.add ctx.reserved_names id } in
+    let* new_names = get_new_args [] args in
+    let* new_llexpr = bind_names_to_patterns llexpr new_names args in
+    let* llexpr_with_no_lets = match_of_pat_let new_llexpr in
+    let* llexpr_with_no_matches = eliminate_lexpr llexpr_with_no_lets in
+    LLLet
+      (PIdentifier id, List.map (fun x -> PIdentifier x) new_names, llexpr_with_no_matches)
+    |> return
+  | _ -> fail "Error: unexpected lllet"
+;;
+
+let rec eliminate_match_in_declarations acc = function
+  | LLDSingleLet (flag, LLLet (PIdentifier id, args, llexpr)) :: tl ->
+    let* new_let = process_simple_let (LLLet (PIdentifier id, args, llexpr)) in
path: BasedML/lib/middleend/match_elimination.ml
user: login: Kakadu
body: копипаста?
created_at: 2025-03-01T21:50:53Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,355 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+open Common.StateMonad
+open Llast
+open Ast
+
+type bound_expr = BoundExpression of pattern * llexpr
+
+let rec map1 f = function
+  | [] -> return []
+  | h :: tl -> f h >>= fun c -> map1 f tl >>= fun lst -> return (c :: lst)
+;;
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+let empty_context = { reserved_names = (module Base.String) |> Base.Set.empty }
+
+let rec collect_bindings_from_pat = function
+  | PWildCard -> (module Base.String) |> Base.Set.empty
+  | PConstant _ -> (module Base.String) |> Base.Set.empty
+  | PIdentifier id -> Base.Set.add ((module Base.String) |> Base.Set.empty) id
+  | PCons (left, right) ->
+    let collected_in_left = collect_bindings_from_pat left in
+    let collected_in_right = collect_bindings_from_pat right in
+    Base.Set.union collected_in_left collected_in_right
+  | PConstraint (pat, _) -> collect_bindings_from_pat pat
+  | PTuple pats ->
+    Base.List.fold_left
+      pats
+      ~init:((module Base.String) |> Base.Set.empty)
+      ~f:(fun acc h -> Base.Set.union acc (collect_bindings_from_pat h))
+;;
+
+let show_idname old_name counter =
+  if counter >= 0 then Printf.sprintf "%s_%d" old_name counter else old_name
+;;
+
+let rec get_all_id acc = function
+  | PWildCard | PConstant _ -> acc
+  | PConstraint (pat, _tp) -> get_all_id acc pat
+  | PCons (pat1, pat2) -> get_all_id (get_all_id acc pat2) pat1
+  | PTuple plst -> List.fold_left get_all_id acc plst
+  | PIdentifier x -> x :: acc
+;;
+
+let rec generate_bindings =
+  let optimized_conj operand1 operand2 =
+    match operand1, operand2 with
+    | _, LLConstant (CBool true) | LLConstant (CBool false), _ -> operand1
+    | LLConstant (CBool true), _ | _, LLConstant (CBool false) -> operand2
+    | _ -> LLApplication (LLApplication (LLIdentifier "( && )", operand1), operand2)
+  in
+  function
+  | BoundExpression (PConstant constant, expression) ->
+    ( LLApplication (LLApplication (LLIdentifier "( = )", expression), LLConstant constant)
+    , [] )
+    |> return
+  | BoundExpression (PTuple pattern_list, expression) ->
+    let tuple_helper pattern_list expression_list =
+      let rec step
+        collected_conditions
+        collected_bindings
+        new_pattern_list
+        new_expression_list
+        =
+        match new_pattern_list, new_expression_list with
+        | [], [] -> return (collected_conditions, collected_bindings)
+        | pattern :: rest_patterns, expression :: rest_expressions ->
+          let bound_expr = BoundExpression (pattern, expression) in
+          let* head_condition, bindings = generate_bindings bound_expr in
+          step
+            (optimized_conj collected_conditions head_condition)
+            (List.append collected_bindings bindings)
+            rest_patterns
+            rest_expressions
+        | _ -> fail "Length mismatch"
+      in
+      step (LLConstant (CBool true)) [] pattern_list expression_list
+    in
+    (match expression with
+     | LLTuple elements_list -> tuple_helper pattern_list elements_list
+     | other ->
+       let accessed_fields =
+         List.init (List.length pattern_list) (fun num ->
+           LLApplication
+             (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt num)))
+       in
+       tuple_helper pattern_list accessed_fields)
+  | BoundExpression (PWildCard, _) -> (LLConstant (CBool true), []) |> return
+  | BoundExpression (PCons (left, right), expression) ->
+    (match expression with
+     | LLApplication (LLApplication (LLIdentifier "( :: )", head), tail) ->
+       let bound_left = BoundExpression (left, head) in
+       let bound_right = BoundExpression (right, tail) in
+       let* head_condition, head_bindings = generate_bindings bound_left in
+       let* tail_condition, tail_bindings = generate_bindings bound_right in
+       ( optimized_conj head_condition tail_condition
+       , List.append head_bindings tail_bindings )
+       |> return
+     | other ->
+       let tag_checking =
+         LLApplication
+           (LLApplication (LLIdentifier "check_tag", other), LLConstant (CInt 0))
+       in
+       let* head_condition, head_bindings =
+         let bound_left =
+           BoundExpression
+             ( left
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 0)) )
+         in
+         generate_bindings bound_left
+       in
+       let* tail_condition, tail_bindings =
+         let bound_right =
+           BoundExpression
+             ( right
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 1)) )
+         in
+         generate_bindings bound_right
+       in
+       ( optimized_conj tag_checking (optimized_conj head_condition tail_condition)
+       , List.append head_bindings tail_bindings )
+       |> return)
+  | BoundExpression (PConstraint (pat, _), llexpr) ->
+    let bound_expr = BoundExpression (pat, llexpr) in
+    generate_bindings bound_expr
+  | BoundExpression (PIdentifier name, llexpr) ->
+    (LLConstant (CBool true), [ name, llexpr ]) |> return
+;;
+
+let rec generate_unique_name old_name counter =
+  let* ctx = read in
+  let new_name = old_name, counter in
+  if Base.Set.mem
+       (Base.Set.union
+          ctx.reserved_names
+          (Base.Set.singleton (module Base.String) old_name))
+       (show_idname old_name counter)
+  then generate_unique_name old_name (counter + 1)
+  else
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.add ctx.reserved_names (Printf.sprintf "%s_%d" old_name counter)
+        }
+    in
+    new_name |> return
+;;
+
+let rec match_of_pat_let = function
+  | LLConstant c -> LLConstant c |> return
+  | LLIdentifier id ->
+    let* old_ctx = read in
+    let* _ = write { reserved_names = Base.Set.add old_ctx.reserved_names id } in
+    LLIdentifier id |> return
+  | LLIfThenElse (guard, then_branch, else_branch) ->
+    let* turned_guard = match_of_pat_let guard in
+    let* turned_then_branch = match_of_pat_let then_branch in
+    let* turned_else_branch = match_of_pat_let else_branch in
+    LLIfThenElse (turned_guard, turned_then_branch, turned_else_branch) |> return
+  | LLConstraint (llex, typ) ->
+    let* turned_llexp = match_of_pat_let llex in
+    LLConstraint (turned_llexp, typ) |> return
+  | LLApplication (left, right) ->
+    let* turned_left = match_of_pat_let left in
+    let* turned_right = match_of_pat_let right in
+    LLApplication (turned_left, turned_right) |> return
+  | LLTuple elems ->
+    let* new_elems = map1 match_of_pat_let elems in
+    LLTuple new_elems |> return
+  | LLLetIn (_, pat, outer, inner) ->
+    let* old_ctx = read in
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+        }
+    in
+    let* converted_outer = match_of_pat_let outer in
+    let* converted_inner = match_of_pat_let inner in
+    LLMatch (converted_outer, [ pat, converted_inner ]) |> return
+  | LLMatch (main_exp, cases) ->
+    let* new_main_exp = match_of_pat_let main_exp in
+    let rec case_helper acc = function
+      | [] -> List.rev acc |> return
+      | (pat, expr) :: tl ->
+        let* old_ctx = read in
+        let* _ =
+          write
+            { reserved_names =
+                Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+            }
+        in
+        let* new_expr = match_of_pat_let expr in
+        case_helper ((pat, new_expr) :: acc) tl
+    in
+    let* new_cases = case_helper [] cases in
+    LLMatch (new_main_exp, new_cases) |> return
+;;
+
+let rec eliminate_lexpr =
+  let optimized_if_then_else guard then_branch else_branch =
+    match guard with
+    | LLConstant (CBool true) -> then_branch
+    | LLConstant (CBool false) -> else_branch
+    | _ -> LLIfThenElse (guard, then_branch, else_branch)
+  in
+  function
+  | LLTuple elements ->
+    let* new_elements = map1 eliminate_lexpr elements in
+    LLTuple new_elements |> return
+  | LLIfThenElse (guard_branch, then_branch, else_branch) ->
+    let* new_guard_branch = eliminate_lexpr guard_branch in
+    let* new_then_branch = eliminate_lexpr then_branch in
+    let* new_else_branch = eliminate_lexpr else_branch in
+    LLIfThenElse (new_guard_branch, new_then_branch, new_else_branch) |> return
+  | LLApplication (left, right) ->
+    let* new_left = eliminate_lexpr left in
+    let* new_right = eliminate_lexpr right in
+    LLApplication (new_left, new_right) |> return
+  | LLConstraint (llexpr, typ) ->
+    let* new_llexpr = eliminate_lexpr llexpr in
+    LLConstraint (new_llexpr, typ) |> return
+  | LLMatch (main_expression, match_cases) ->
+    let* match_free_main_expression = eliminate_lexpr main_expression in
+    let* conditions =
+      map1
+        (fun (pat, _) ->
+          let bound_expr = BoundExpression (pat, match_free_main_expression) in
+          generate_bindings bound_expr)
+        match_cases
+    in
+    List.fold_right2
+      (fun (head_condition, binds) (_, expr) acc ->
+        let* match_free_lexpr = eliminate_lexpr expr in
+        let* acc' = acc in
+        return
+          (optimized_if_then_else
+             head_condition
+             (List.fold_right
+                (fun (name, llexpr) acc ->
+                  LLLetIn (NotRec, PIdentifier name, llexpr, acc))
+                binds
+                match_free_lexpr)
+             acc'))
+      conditions
+      match_cases
+      (LLApplication (LLIdentifier "match_error", LLConstant CUnit) |> return)
+  | LLConstant constant -> LLConstant constant |> return
+  | LLIdentifier name -> LLIdentifier name |> return
+  | _ -> fail "Error: Unexpected expression"
+;;
+
+let rec rename_pat = function
+  | PWildCard -> PWildCard |> return
+  | PConstant c -> PConstant c |> return
+  | PConstraint (pat, typ) ->
+    let* new_pat = rename_pat pat in
+    PConstraint (new_pat, typ) |> return
+  | PCons (left, right) ->
+    let* new_left = rename_pat left in
+    let* new_right = rename_pat right in
+    PCons (new_left, new_right) |> return
+  | PTuple pats ->
+    let* new_pats = map1 rename_pat pats in
+    PTuple new_pats |> return
+  | PIdentifier id ->
+    let* old_name, counter = generate_unique_name id 0 in
+    PIdentifier (Printf.sprintf "%s_%d" old_name counter) |> return
+;;
+
+let process_simple_let = function
+  | LLLet (PIdentifier id, args, llexpr) ->
+    let rec get_new_args acc = function
+      | [] -> List.rev acc |> return
+      | _ :: tl ->
+        let* name, counter = generate_unique_name "arg" 0 in
+        let new_name = Printf.sprintf "%s_%d" name counter in
+        get_new_args (new_name :: acc) tl
+    in
+    let rec bind_names_to_patterns base_exp names patterns =
+      match names, patterns with
+      | [], [] -> return base_exp
+      | name :: names_tail, pattern :: patterns_tail ->
+        let* ctx = read in
+        let* _ = write { reserved_names = Base.Set.add ctx.reserved_names name } in
+        let* inner_exp = bind_names_to_patterns base_exp names_tail patterns_tail in
+        return (LLLetIn (NotRec, pattern, LLIdentifier name, inner_exp))
+      | _ -> fail "Error: Mismatch in the lengths of names and patterns lists"
+    in
+    let* ctx = read in
+    let* _ = write { reserved_names = Base.Set.add ctx.reserved_names id } in
+    let* new_names = get_new_args [] args in
+    let* new_llexpr = bind_names_to_patterns llexpr new_names args in
+    let* llexpr_with_no_lets = match_of_pat_let new_llexpr in
+    let* llexpr_with_no_matches = eliminate_lexpr llexpr_with_no_lets in
+    LLLet
+      (PIdentifier id, List.map (fun x -> PIdentifier x) new_names, llexpr_with_no_matches)
+    |> return
+  | _ -> fail "Error: unexpected lllet"
path: BasedML/lib/middleend/match_elimination.ml
user: login: Kakadu
body: говнокод?
created_at: 2025-03-01T21:51:03Z
author_association: OWNER
diff_hunk: @@ -9,46 +9,57 @@ let () =
   let s = Stdio.In_channel.input_all Stdlib.stdin in
   match Parser.parse_program s with
   | Ok ast_before ->
-    let final =
+    let lifted =
       ast_before
       |> Middleend.Closure_conversion.convert_ast
       |> Middleend.Lambda_lifting.lift_ast
-      |> Middleend.Anf.transform
     in
-    let rec anf_helper acc = function
-      | Ok h :: tl -> anf_helper (Middleend.Anf_to_str.anf_decl_to_string h ^ acc) tl
-      | [] -> acc
-      | _ -> "Error "
-    in
-    (match Parser.parse_program (anf_helper "" (List.rev final)) with
-     | Ok ast_after ->
-       (match Typeinference.infer_prog ast_before, Typeinference.infer_prog ast_after with
-        | Ok map1, Ok map2 ->
-          let all_types_match =
-            Typeinference.StringMap.for_all
-              (fun key typ1 ->
-                if is_stdlib key
-                then true
-                else (
-                  match Typeinference.StringMap.find_opt key map2 with
-                  | Some typ2 ->
-                    Format.printf "Name: %s\n" key;
-                    Format.printf "Original program: %a\n" Ast.pp_type_name typ1;
-                    Format.printf "ANF: %a\n\n" Ast.pp_type_name typ2;
-                    if not (Typeinference.types_equal typ1 typ2)
-                    then (
-                      Format.printf "There's been a discrepancy for name %s\n" key;
-                      false)
-                    else true
-                  | None ->
-                    Format.printf "Name %s found in map1 but not in map2\n" key;
-                    false))
-              map1
-          in
-          if all_types_match
-          then Format.printf "All types are correct\n"
-          else Format.printf "There's been a type mismatch\n"
-        | _ -> Format.printf "Error while typechecking\n")
-     | _ -> Format.printf "Error while parsing ANF program\n")
+    let match_free = Middleend.Match_elimination.transform lifted in
+    (match match_free with
+     | _, Ok new_ast ->
+       let final = Middleend.Anf.transform new_ast in
+       let rec anf_helper acc = function
+         | Ok h :: tl -> anf_helper (Middleend.Anf_to_str.anf_decl_to_string h ^ acc) tl
+         | [] -> acc
+         | _ -> "Error "
+       in
+       (match Parser.parse_program (anf_helper "" (List.rev final)) with
+        | Ok ast_after ->
+          (match
+             ( Typeinference.infer_prog_with_custom_state
+                 Typeinference__StartState.start_state_with_system_fun
+                 ast_before
+             , Typeinference.infer_prog_with_custom_state
+                 Typeinference__StartState.start_state_with_system_fun
+                 ast_after )
+           with
+           | Ok map1, Ok map2 ->
path: BasedML/test/anf_types_demo.ml
user: login: Kakadu
body: Copy-paste driven development
created_at: 2025-03-01T21:54:00Z
author_association: OWNER
diff_hunk: @@ -24,11 +24,18 @@ let () =
          0
      with
      | _, Ok lst ->
-       lst
-       |> Middleend.Closure_conversion.convert_ast
-       |> Middleend.Lambda_lifting.lift_ast
-       |> Middleend.Anf.transform
-       |> print_anf
+       let lifted =
+         lst
+         |> Middleend.Closure_conversion.convert_ast
+         |> Middleend.Lambda_lifting.lift_ast
+       in
+       (match
+          Common.StateMonad.run
+            (Middleend.Match_elimination.eliminate_match_in_declarations [] lifted)
+            Middleend.Match_elimination.empty_context
path: BasedML/test/anf_demo.ml
user: login: Kakadu
body: Где-то эту копипасту я уже видел....
created_at: 2025-03-01T21:54:17Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,10 @@
+  $ dune exec ./match_elimination_demo.exe << EOF
+  > let prog = let (difficult_pattern, nasty_pattern) = (5, 6) in a
+  > EOF
+  let  prog  = (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))
+
+  $ dune exec ./match_elimination_demo.exe << EOF
+  > let prog = let (difficult_pattern, nasty_pattern) = let (difficult_pattern, nasty_pattern) = (5, 6) in a in a
+  > EOF
+  let  prog  = (let  difficult_pattern = ((get_field (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))) 0) in (let  nasty_pattern = ((get_field (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))) 1) in a))
+
path: BasedML/test/match_elimination_tests.t
user: login: Kakadu
body: Неинтересные примеры, даже списков нет.
created_at: 2025-03-01T21:54:48Z
author_association: OWNER
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Salvatore112
body: > А чьём теле?

Например у нас `let f (a, b) = body`, `(a, b)` переименовывается в `arg1`, а дальше в body избавляемся от паттерна `(a, b)`
created_at: 2025-03-01T22:12:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,355 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+open Common.StateMonad
+open Llast
+open Ast
+
+type bound_expr = BoundExpression of pattern * llexpr
+
+let rec map1 f = function
+  | [] -> return []
+  | h :: tl -> f h >>= fun c -> map1 f tl >>= fun lst -> return (c :: lst)
+;;
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+let empty_context = { reserved_names = (module Base.String) |> Base.Set.empty }
+
+let rec collect_bindings_from_pat = function
+  | PWildCard -> (module Base.String) |> Base.Set.empty
+  | PConstant _ -> (module Base.String) |> Base.Set.empty
+  | PIdentifier id -> Base.Set.add ((module Base.String) |> Base.Set.empty) id
+  | PCons (left, right) ->
+    let collected_in_left = collect_bindings_from_pat left in
+    let collected_in_right = collect_bindings_from_pat right in
+    Base.Set.union collected_in_left collected_in_right
+  | PConstraint (pat, _) -> collect_bindings_from_pat pat
+  | PTuple pats ->
+    Base.List.fold_left
+      pats
+      ~init:((module Base.String) |> Base.Set.empty)
+      ~f:(fun acc h -> Base.Set.union acc (collect_bindings_from_pat h))
+;;
+
+let show_idname old_name counter =
+  if counter >= 0 then Printf.sprintf "%s_%d" old_name counter else old_name
+;;
+
+let rec get_all_id acc = function
+  | PWildCard | PConstant _ -> acc
+  | PConstraint (pat, _tp) -> get_all_id acc pat
+  | PCons (pat1, pat2) -> get_all_id (get_all_id acc pat2) pat1
+  | PTuple plst -> List.fold_left get_all_id acc plst
+  | PIdentifier x -> x :: acc
+;;
+
+let rec generate_bindings =
+  let optimized_conj operand1 operand2 =
+    match operand1, operand2 with
+    | _, LLConstant (CBool true) | LLConstant (CBool false), _ -> operand1
+    | LLConstant (CBool true), _ | _, LLConstant (CBool false) -> operand2
+    | _ -> LLApplication (LLApplication (LLIdentifier "( && )", operand1), operand2)
+  in
+  function
+  | BoundExpression (PConstant constant, expression) ->
+    ( LLApplication (LLApplication (LLIdentifier "( = )", expression), LLConstant constant)
+    , [] )
+    |> return
+  | BoundExpression (PTuple pattern_list, expression) ->
+    let tuple_helper pattern_list expression_list =
+      let rec step
+        collected_conditions
+        collected_bindings
+        new_pattern_list
+        new_expression_list
+        =
+        match new_pattern_list, new_expression_list with
+        | [], [] -> return (collected_conditions, collected_bindings)
+        | pattern :: rest_patterns, expression :: rest_expressions ->
+          let bound_expr = BoundExpression (pattern, expression) in
+          let* head_condition, bindings = generate_bindings bound_expr in
+          step
+            (optimized_conj collected_conditions head_condition)
+            (List.append collected_bindings bindings)
+            rest_patterns
+            rest_expressions
+        | _ -> fail "Length mismatch"
+      in
+      step (LLConstant (CBool true)) [] pattern_list expression_list
+    in
+    (match expression with
+     | LLTuple elements_list -> tuple_helper pattern_list elements_list
+     | other ->
+       let accessed_fields =
+         List.init (List.length pattern_list) (fun num ->
+           LLApplication
+             (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt num)))
+       in
+       tuple_helper pattern_list accessed_fields)
+  | BoundExpression (PWildCard, _) -> (LLConstant (CBool true), []) |> return
+  | BoundExpression (PCons (left, right), expression) ->
+    (match expression with
+     | LLApplication (LLApplication (LLIdentifier "( :: )", head), tail) ->
+       let bound_left = BoundExpression (left, head) in
+       let bound_right = BoundExpression (right, tail) in
+       let* head_condition, head_bindings = generate_bindings bound_left in
+       let* tail_condition, tail_bindings = generate_bindings bound_right in
+       ( optimized_conj head_condition tail_condition
+       , List.append head_bindings tail_bindings )
+       |> return
+     | other ->
+       let tag_checking =
+         LLApplication
+           (LLApplication (LLIdentifier "check_tag", other), LLConstant (CInt 0))
+       in
+       let* head_condition, head_bindings =
+         let bound_left =
+           BoundExpression
+             ( left
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 0)) )
+         in
+         generate_bindings bound_left
+       in
+       let* tail_condition, tail_bindings =
+         let bound_right =
+           BoundExpression
+             ( right
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 1)) )
+         in
+         generate_bindings bound_right
+       in
+       ( optimized_conj tag_checking (optimized_conj head_condition tail_condition)
+       , List.append head_bindings tail_bindings )
+       |> return)
+  | BoundExpression (PConstraint (pat, _), llexpr) ->
+    let bound_expr = BoundExpression (pat, llexpr) in
+    generate_bindings bound_expr
+  | BoundExpression (PIdentifier name, llexpr) ->
+    (LLConstant (CBool true), [ name, llexpr ]) |> return
+;;
+
+let rec generate_unique_name old_name counter =
+  let* ctx = read in
+  let new_name = old_name, counter in
+  if Base.Set.mem
+       (Base.Set.union
+          ctx.reserved_names
+          (Base.Set.singleton (module Base.String) old_name))
+       (show_idname old_name counter)
+  then generate_unique_name old_name (counter + 1)
+  else
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.add ctx.reserved_names (Printf.sprintf "%s_%d" old_name counter)
+        }
+    in
+    new_name |> return
+;;
+
+let rec match_of_pat_let = function
+  | LLConstant c -> LLConstant c |> return
+  | LLIdentifier id ->
+    let* old_ctx = read in
+    let* _ = write { reserved_names = Base.Set.add old_ctx.reserved_names id } in
+    LLIdentifier id |> return
+  | LLIfThenElse (guard, then_branch, else_branch) ->
+    let* turned_guard = match_of_pat_let guard in
+    let* turned_then_branch = match_of_pat_let then_branch in
+    let* turned_else_branch = match_of_pat_let else_branch in
+    LLIfThenElse (turned_guard, turned_then_branch, turned_else_branch) |> return
+  | LLConstraint (llex, typ) ->
+    let* turned_llexp = match_of_pat_let llex in
+    LLConstraint (turned_llexp, typ) |> return
+  | LLApplication (left, right) ->
+    let* turned_left = match_of_pat_let left in
+    let* turned_right = match_of_pat_let right in
+    LLApplication (turned_left, turned_right) |> return
+  | LLTuple elems ->
+    let* new_elems = map1 match_of_pat_let elems in
+    LLTuple new_elems |> return
+  | LLLetIn (_, pat, outer, inner) ->
+    let* old_ctx = read in
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+        }
+    in
+    let* converted_outer = match_of_pat_let outer in
+    let* converted_inner = match_of_pat_let inner in
+    LLMatch (converted_outer, [ pat, converted_inner ]) |> return
+  | LLMatch (main_exp, cases) ->
+    let* new_main_exp = match_of_pat_let main_exp in
+    let rec case_helper acc = function
+      | [] -> List.rev acc |> return
+      | (pat, expr) :: tl ->
+        let* old_ctx = read in
+        let* _ =
+          write
+            { reserved_names =
+                Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+            }
+        in
+        let* new_expr = match_of_pat_let expr in
+        case_helper ((pat, new_expr) :: acc) tl
+    in
+    let* new_cases = case_helper [] cases in
+    LLMatch (new_main_exp, new_cases) |> return
+;;
+
+let rec eliminate_lexpr =
+  let optimized_if_then_else guard then_branch else_branch =
+    match guard with
+    | LLConstant (CBool true) -> then_branch
+    | LLConstant (CBool false) -> else_branch
+    | _ -> LLIfThenElse (guard, then_branch, else_branch)
+  in
+  function
+  | LLTuple elements ->
+    let* new_elements = map1 eliminate_lexpr elements in
+    LLTuple new_elements |> return
+  | LLIfThenElse (guard_branch, then_branch, else_branch) ->
+    let* new_guard_branch = eliminate_lexpr guard_branch in
+    let* new_then_branch = eliminate_lexpr then_branch in
+    let* new_else_branch = eliminate_lexpr else_branch in
+    LLIfThenElse (new_guard_branch, new_then_branch, new_else_branch) |> return
+  | LLApplication (left, right) ->
+    let* new_left = eliminate_lexpr left in
+    let* new_right = eliminate_lexpr right in
+    LLApplication (new_left, new_right) |> return
+  | LLConstraint (llexpr, typ) ->
+    let* new_llexpr = eliminate_lexpr llexpr in
+    LLConstraint (new_llexpr, typ) |> return
+  | LLMatch (main_expression, match_cases) ->
+    let* match_free_main_expression = eliminate_lexpr main_expression in
+    let* conditions =
+      map1
+        (fun (pat, _) ->
+          let bound_expr = BoundExpression (pat, match_free_main_expression) in
+          generate_bindings bound_expr)
+        match_cases
+    in
+    List.fold_right2
+      (fun (head_condition, binds) (_, expr) acc ->
+        let* match_free_lexpr = eliminate_lexpr expr in
+        let* acc' = acc in
+        return
+          (optimized_if_then_else
+             head_condition
+             (List.fold_right
+                (fun (name, llexpr) acc ->
+                  LLLetIn (NotRec, PIdentifier name, llexpr, acc))
+                binds
+                match_free_lexpr)
+             acc'))
+      conditions
+      match_cases
+      (LLApplication (LLIdentifier "match_error", LLConstant CUnit) |> return)
+  | LLConstant constant -> LLConstant constant |> return
+  | LLIdentifier name -> LLIdentifier name |> return
+  | _ -> fail "Error: Unexpected expression"
path: BasedML/lib/middleend/match_elimination.ml
user: login: Salvatore112
body: Не хочется отдельное ast для этого делать, эта функция всегда применяется после того  как мы от let in избавляемся
created_at: 2025-03-01T22:14:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,355 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+open Common.StateMonad
+open Llast
+open Ast
+
+type bound_expr = BoundExpression of pattern * llexpr
+
+let rec map1 f = function
+  | [] -> return []
+  | h :: tl -> f h >>= fun c -> map1 f tl >>= fun lst -> return (c :: lst)
+;;
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+let empty_context = { reserved_names = (module Base.String) |> Base.Set.empty }
+
+let rec collect_bindings_from_pat = function
+  | PWildCard -> (module Base.String) |> Base.Set.empty
+  | PConstant _ -> (module Base.String) |> Base.Set.empty
+  | PIdentifier id -> Base.Set.add ((module Base.String) |> Base.Set.empty) id
+  | PCons (left, right) ->
+    let collected_in_left = collect_bindings_from_pat left in
+    let collected_in_right = collect_bindings_from_pat right in
+    Base.Set.union collected_in_left collected_in_right
+  | PConstraint (pat, _) -> collect_bindings_from_pat pat
+  | PTuple pats ->
+    Base.List.fold_left
+      pats
+      ~init:((module Base.String) |> Base.Set.empty)
+      ~f:(fun acc h -> Base.Set.union acc (collect_bindings_from_pat h))
+;;
+
+let show_idname old_name counter =
+  if counter >= 0 then Printf.sprintf "%s_%d" old_name counter else old_name
+;;
+
+let rec get_all_id acc = function
+  | PWildCard | PConstant _ -> acc
+  | PConstraint (pat, _tp) -> get_all_id acc pat
+  | PCons (pat1, pat2) -> get_all_id (get_all_id acc pat2) pat1
+  | PTuple plst -> List.fold_left get_all_id acc plst
+  | PIdentifier x -> x :: acc
+;;
+
+let rec generate_bindings =
+  let optimized_conj operand1 operand2 =
+    match operand1, operand2 with
+    | _, LLConstant (CBool true) | LLConstant (CBool false), _ -> operand1
+    | LLConstant (CBool true), _ | _, LLConstant (CBool false) -> operand2
+    | _ -> LLApplication (LLApplication (LLIdentifier "( && )", operand1), operand2)
+  in
+  function
+  | BoundExpression (PConstant constant, expression) ->
+    ( LLApplication (LLApplication (LLIdentifier "( = )", expression), LLConstant constant)
+    , [] )
+    |> return
+  | BoundExpression (PTuple pattern_list, expression) ->
+    let tuple_helper pattern_list expression_list =
+      let rec step
+        collected_conditions
+        collected_bindings
+        new_pattern_list
+        new_expression_list
+        =
+        match new_pattern_list, new_expression_list with
+        | [], [] -> return (collected_conditions, collected_bindings)
+        | pattern :: rest_patterns, expression :: rest_expressions ->
+          let bound_expr = BoundExpression (pattern, expression) in
+          let* head_condition, bindings = generate_bindings bound_expr in
+          step
+            (optimized_conj collected_conditions head_condition)
+            (List.append collected_bindings bindings)
+            rest_patterns
+            rest_expressions
+        | _ -> fail "Length mismatch"
+      in
+      step (LLConstant (CBool true)) [] pattern_list expression_list
+    in
+    (match expression with
+     | LLTuple elements_list -> tuple_helper pattern_list elements_list
+     | other ->
+       let accessed_fields =
+         List.init (List.length pattern_list) (fun num ->
+           LLApplication
+             (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt num)))
+       in
+       tuple_helper pattern_list accessed_fields)
+  | BoundExpression (PWildCard, _) -> (LLConstant (CBool true), []) |> return
+  | BoundExpression (PCons (left, right), expression) ->
+    (match expression with
+     | LLApplication (LLApplication (LLIdentifier "( :: )", head), tail) ->
+       let bound_left = BoundExpression (left, head) in
+       let bound_right = BoundExpression (right, tail) in
+       let* head_condition, head_bindings = generate_bindings bound_left in
+       let* tail_condition, tail_bindings = generate_bindings bound_right in
+       ( optimized_conj head_condition tail_condition
+       , List.append head_bindings tail_bindings )
+       |> return
+     | other ->
+       let tag_checking =
+         LLApplication
+           (LLApplication (LLIdentifier "check_tag", other), LLConstant (CInt 0))
+       in
+       let* head_condition, head_bindings =
+         let bound_left =
+           BoundExpression
+             ( left
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 0)) )
+         in
+         generate_bindings bound_left
+       in
+       let* tail_condition, tail_bindings =
+         let bound_right =
+           BoundExpression
+             ( right
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 1)) )
+         in
+         generate_bindings bound_right
+       in
+       ( optimized_conj tag_checking (optimized_conj head_condition tail_condition)
+       , List.append head_bindings tail_bindings )
+       |> return)
+  | BoundExpression (PConstraint (pat, _), llexpr) ->
+    let bound_expr = BoundExpression (pat, llexpr) in
+    generate_bindings bound_expr
+  | BoundExpression (PIdentifier name, llexpr) ->
+    (LLConstant (CBool true), [ name, llexpr ]) |> return
+;;
+
+let rec generate_unique_name old_name counter =
+  let* ctx = read in
+  let new_name = old_name, counter in
+  if Base.Set.mem
+       (Base.Set.union
+          ctx.reserved_names
+          (Base.Set.singleton (module Base.String) old_name))
+       (show_idname old_name counter)
+  then generate_unique_name old_name (counter + 1)
+  else
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.add ctx.reserved_names (Printf.sprintf "%s_%d" old_name counter)
+        }
+    in
+    new_name |> return
+;;
+
+let rec match_of_pat_let = function
+  | LLConstant c -> LLConstant c |> return
+  | LLIdentifier id ->
+    let* old_ctx = read in
+    let* _ = write { reserved_names = Base.Set.add old_ctx.reserved_names id } in
+    LLIdentifier id |> return
+  | LLIfThenElse (guard, then_branch, else_branch) ->
+    let* turned_guard = match_of_pat_let guard in
+    let* turned_then_branch = match_of_pat_let then_branch in
+    let* turned_else_branch = match_of_pat_let else_branch in
+    LLIfThenElse (turned_guard, turned_then_branch, turned_else_branch) |> return
+  | LLConstraint (llex, typ) ->
+    let* turned_llexp = match_of_pat_let llex in
+    LLConstraint (turned_llexp, typ) |> return
+  | LLApplication (left, right) ->
+    let* turned_left = match_of_pat_let left in
+    let* turned_right = match_of_pat_let right in
+    LLApplication (turned_left, turned_right) |> return
+  | LLTuple elems ->
+    let* new_elems = map1 match_of_pat_let elems in
+    LLTuple new_elems |> return
+  | LLLetIn (_, pat, outer, inner) ->
+    let* old_ctx = read in
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+        }
+    in
+    let* converted_outer = match_of_pat_let outer in
+    let* converted_inner = match_of_pat_let inner in
+    LLMatch (converted_outer, [ pat, converted_inner ]) |> return
+  | LLMatch (main_exp, cases) ->
+    let* new_main_exp = match_of_pat_let main_exp in
+    let rec case_helper acc = function
+      | [] -> List.rev acc |> return
+      | (pat, expr) :: tl ->
+        let* old_ctx = read in
+        let* _ =
+          write
+            { reserved_names =
+                Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+            }
+        in
+        let* new_expr = match_of_pat_let expr in
+        case_helper ((pat, new_expr) :: acc) tl
+    in
+    let* new_cases = case_helper [] cases in
+    LLMatch (new_main_exp, new_cases) |> return
+;;
+
+let rec eliminate_lexpr =
+  let optimized_if_then_else guard then_branch else_branch =
+    match guard with
+    | LLConstant (CBool true) -> then_branch
+    | LLConstant (CBool false) -> else_branch
+    | _ -> LLIfThenElse (guard, then_branch, else_branch)
+  in
+  function
+  | LLTuple elements ->
+    let* new_elements = map1 eliminate_lexpr elements in
+    LLTuple new_elements |> return
+  | LLIfThenElse (guard_branch, then_branch, else_branch) ->
+    let* new_guard_branch = eliminate_lexpr guard_branch in
+    let* new_then_branch = eliminate_lexpr then_branch in
+    let* new_else_branch = eliminate_lexpr else_branch in
+    LLIfThenElse (new_guard_branch, new_then_branch, new_else_branch) |> return
+  | LLApplication (left, right) ->
+    let* new_left = eliminate_lexpr left in
+    let* new_right = eliminate_lexpr right in
+    LLApplication (new_left, new_right) |> return
+  | LLConstraint (llexpr, typ) ->
+    let* new_llexpr = eliminate_lexpr llexpr in
+    LLConstraint (new_llexpr, typ) |> return
+  | LLMatch (main_expression, match_cases) ->
+    let* match_free_main_expression = eliminate_lexpr main_expression in
+    let* conditions =
+      map1
+        (fun (pat, _) ->
+          let bound_expr = BoundExpression (pat, match_free_main_expression) in
+          generate_bindings bound_expr)
+        match_cases
+    in
+    List.fold_right2
+      (fun (head_condition, binds) (_, expr) acc ->
+        let* match_free_lexpr = eliminate_lexpr expr in
+        let* acc' = acc in
+        return
+          (optimized_if_then_else
+             head_condition
+             (List.fold_right
+                (fun (name, llexpr) acc ->
+                  LLLetIn (NotRec, PIdentifier name, llexpr, acc))
+                binds
+                match_free_lexpr)
+             acc'))
+      conditions
+      match_cases
+      (LLApplication (LLIdentifier "match_error", LLConstant CUnit) |> return)
+  | LLConstant constant -> LLConstant constant |> return
+  | LLIdentifier name -> LLIdentifier name |> return
+  | _ -> fail "Error: Unexpected expression"
+;;
+
+let rec rename_pat = function
+  | PWildCard -> PWildCard |> return
+  | PConstant c -> PConstant c |> return
+  | PConstraint (pat, typ) ->
+    let* new_pat = rename_pat pat in
+    PConstraint (new_pat, typ) |> return
+  | PCons (left, right) ->
+    let* new_left = rename_pat left in
+    let* new_right = rename_pat right in
+    PCons (new_left, new_right) |> return
+  | PTuple pats ->
+    let* new_pats = map1 rename_pat pats in
+    PTuple new_pats |> return
+  | PIdentifier id ->
+    let* old_name, counter = generate_unique_name id 0 in
+    PIdentifier (Printf.sprintf "%s_%d" old_name counter) |> return
+;;
+
+let process_simple_let = function
+  | LLLet (PIdentifier id, args, llexpr) ->
+    let rec get_new_args acc = function
+      | [] -> List.rev acc |> return
+      | _ :: tl ->
+        let* name, counter = generate_unique_name "arg" 0 in
+        let new_name = Printf.sprintf "%s_%d" name counter in
+        get_new_args (new_name :: acc) tl
+    in
+    let rec bind_names_to_patterns base_exp names patterns =
+      match names, patterns with
+      | [], [] -> return base_exp
+      | name :: names_tail, pattern :: patterns_tail ->
+        let* ctx = read in
+        let* _ = write { reserved_names = Base.Set.add ctx.reserved_names name } in
+        let* inner_exp = bind_names_to_patterns base_exp names_tail patterns_tail in
+        return (LLLetIn (NotRec, pattern, LLIdentifier name, inner_exp))
+      | _ -> fail "Error: Mismatch in the lengths of names and patterns lists"
+    in
+    let* ctx = read in
+    let* _ = write { reserved_names = Base.Set.add ctx.reserved_names id } in
+    let* new_names = get_new_args [] args in
+    let* new_llexpr = bind_names_to_patterns llexpr new_names args in
+    let* llexpr_with_no_lets = match_of_pat_let new_llexpr in
+    let* llexpr_with_no_matches = eliminate_lexpr llexpr_with_no_lets in
+    LLLet
+      (PIdentifier id, List.map (fun x -> PIdentifier x) new_names, llexpr_with_no_matches)
+    |> return
+  | _ -> fail "Error: unexpected lllet"
path: BasedML/lib/middleend/match_elimination.ml
user: login: Salvatore112
body: Функция eliminate_match_in_declarations отдельно случай LLLet с произвольными паттернами разбирает, а тут именно _simple let_
created_at: 2025-03-01T22:17:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+  $ dune exec ./match_elimination_demo.exe << EOF
+  > let prog = let (difficult_pattern, nasty_pattern) = (5, 6) in a
+  > EOF
+  let  prog  = (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))
+
+  $ dune exec ./match_elimination_demo.exe << EOF
+  > let prog = let (difficult_pattern, nasty_pattern) = let (difficult_pattern, nasty_pattern) = (5, 6) in a in a
+  > EOF
+  let  prog  = (let  difficult_pattern = ((get_field (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))) 0) in (let  nasty_pattern = ((get_field (let  difficult_pattern = 5 in (let  nasty_pattern = 6 in a))) 1) in a))
+
path: BasedML/test/match_elimination_tests.t
user: login: Salvatore112
body: ME уже добавлен в anf_demo; в anf_tests.t больше примеров
created_at: 2025-03-01T22:18:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Kakadu
body: Далее это на какой фазе?
created_at: 2025-03-02T07:43:24Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,355 @@
+(** Copyright 2024-2025, Pavel Averin, Alexey Efremov *)
+
+(** SPDX-License-Identifier: LGPL-2.1 *)
+
+open Common.StateMonad
+open Llast
+open Ast
+
+type bound_expr = BoundExpression of pattern * llexpr
+
+let rec map1 f = function
+  | [] -> return []
+  | h :: tl -> f h >>= fun c -> map1 f tl >>= fun lst -> return (c :: lst)
+;;
+
+type context = { reserved_names : (string, Base.String.comparator_witness) Base.Set.t }
+
+let empty_context = { reserved_names = (module Base.String) |> Base.Set.empty }
+
+let rec collect_bindings_from_pat = function
+  | PWildCard -> (module Base.String) |> Base.Set.empty
+  | PConstant _ -> (module Base.String) |> Base.Set.empty
+  | PIdentifier id -> Base.Set.add ((module Base.String) |> Base.Set.empty) id
+  | PCons (left, right) ->
+    let collected_in_left = collect_bindings_from_pat left in
+    let collected_in_right = collect_bindings_from_pat right in
+    Base.Set.union collected_in_left collected_in_right
+  | PConstraint (pat, _) -> collect_bindings_from_pat pat
+  | PTuple pats ->
+    Base.List.fold_left
+      pats
+      ~init:((module Base.String) |> Base.Set.empty)
+      ~f:(fun acc h -> Base.Set.union acc (collect_bindings_from_pat h))
+;;
+
+let show_idname old_name counter =
+  if counter >= 0 then Printf.sprintf "%s_%d" old_name counter else old_name
+;;
+
+let rec get_all_id acc = function
+  | PWildCard | PConstant _ -> acc
+  | PConstraint (pat, _tp) -> get_all_id acc pat
+  | PCons (pat1, pat2) -> get_all_id (get_all_id acc pat2) pat1
+  | PTuple plst -> List.fold_left get_all_id acc plst
+  | PIdentifier x -> x :: acc
+;;
+
+let rec generate_bindings =
+  let optimized_conj operand1 operand2 =
+    match operand1, operand2 with
+    | _, LLConstant (CBool true) | LLConstant (CBool false), _ -> operand1
+    | LLConstant (CBool true), _ | _, LLConstant (CBool false) -> operand2
+    | _ -> LLApplication (LLApplication (LLIdentifier "( && )", operand1), operand2)
+  in
+  function
+  | BoundExpression (PConstant constant, expression) ->
+    ( LLApplication (LLApplication (LLIdentifier "( = )", expression), LLConstant constant)
+    , [] )
+    |> return
+  | BoundExpression (PTuple pattern_list, expression) ->
+    let tuple_helper pattern_list expression_list =
+      let rec step
+        collected_conditions
+        collected_bindings
+        new_pattern_list
+        new_expression_list
+        =
+        match new_pattern_list, new_expression_list with
+        | [], [] -> return (collected_conditions, collected_bindings)
+        | pattern :: rest_patterns, expression :: rest_expressions ->
+          let bound_expr = BoundExpression (pattern, expression) in
+          let* head_condition, bindings = generate_bindings bound_expr in
+          step
+            (optimized_conj collected_conditions head_condition)
+            (List.append collected_bindings bindings)
+            rest_patterns
+            rest_expressions
+        | _ -> fail "Length mismatch"
+      in
+      step (LLConstant (CBool true)) [] pattern_list expression_list
+    in
+    (match expression with
+     | LLTuple elements_list -> tuple_helper pattern_list elements_list
+     | other ->
+       let accessed_fields =
+         List.init (List.length pattern_list) (fun num ->
+           LLApplication
+             (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt num)))
+       in
+       tuple_helper pattern_list accessed_fields)
+  | BoundExpression (PWildCard, _) -> (LLConstant (CBool true), []) |> return
+  | BoundExpression (PCons (left, right), expression) ->
+    (match expression with
+     | LLApplication (LLApplication (LLIdentifier "( :: )", head), tail) ->
+       let bound_left = BoundExpression (left, head) in
+       let bound_right = BoundExpression (right, tail) in
+       let* head_condition, head_bindings = generate_bindings bound_left in
+       let* tail_condition, tail_bindings = generate_bindings bound_right in
+       ( optimized_conj head_condition tail_condition
+       , List.append head_bindings tail_bindings )
+       |> return
+     | other ->
+       let tag_checking =
+         LLApplication
+           (LLApplication (LLIdentifier "check_tag", other), LLConstant (CInt 0))
+       in
+       let* head_condition, head_bindings =
+         let bound_left =
+           BoundExpression
+             ( left
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 0)) )
+         in
+         generate_bindings bound_left
+       in
+       let* tail_condition, tail_bindings =
+         let bound_right =
+           BoundExpression
+             ( right
+             , LLApplication
+                 (LLApplication (LLIdentifier "get_field", other), LLConstant (CInt 1)) )
+         in
+         generate_bindings bound_right
+       in
+       ( optimized_conj tag_checking (optimized_conj head_condition tail_condition)
+       , List.append head_bindings tail_bindings )
+       |> return)
+  | BoundExpression (PConstraint (pat, _), llexpr) ->
+    let bound_expr = BoundExpression (pat, llexpr) in
+    generate_bindings bound_expr
+  | BoundExpression (PIdentifier name, llexpr) ->
+    (LLConstant (CBool true), [ name, llexpr ]) |> return
+;;
+
+let rec generate_unique_name old_name counter =
+  let* ctx = read in
+  let new_name = old_name, counter in
+  if Base.Set.mem
+       (Base.Set.union
+          ctx.reserved_names
+          (Base.Set.singleton (module Base.String) old_name))
+       (show_idname old_name counter)
+  then generate_unique_name old_name (counter + 1)
+  else
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.add ctx.reserved_names (Printf.sprintf "%s_%d" old_name counter)
+        }
+    in
+    new_name |> return
+;;
+
+let rec match_of_pat_let = function
+  | LLConstant c -> LLConstant c |> return
+  | LLIdentifier id ->
+    let* old_ctx = read in
+    let* _ = write { reserved_names = Base.Set.add old_ctx.reserved_names id } in
+    LLIdentifier id |> return
+  | LLIfThenElse (guard, then_branch, else_branch) ->
+    let* turned_guard = match_of_pat_let guard in
+    let* turned_then_branch = match_of_pat_let then_branch in
+    let* turned_else_branch = match_of_pat_let else_branch in
+    LLIfThenElse (turned_guard, turned_then_branch, turned_else_branch) |> return
+  | LLConstraint (llex, typ) ->
+    let* turned_llexp = match_of_pat_let llex in
+    LLConstraint (turned_llexp, typ) |> return
+  | LLApplication (left, right) ->
+    let* turned_left = match_of_pat_let left in
+    let* turned_right = match_of_pat_let right in
+    LLApplication (turned_left, turned_right) |> return
+  | LLTuple elems ->
+    let* new_elems = map1 match_of_pat_let elems in
+    LLTuple new_elems |> return
+  | LLLetIn (_, pat, outer, inner) ->
+    let* old_ctx = read in
+    let* _ =
+      write
+        { reserved_names =
+            Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+        }
+    in
+    let* converted_outer = match_of_pat_let outer in
+    let* converted_inner = match_of_pat_let inner in
+    LLMatch (converted_outer, [ pat, converted_inner ]) |> return
+  | LLMatch (main_exp, cases) ->
+    let* new_main_exp = match_of_pat_let main_exp in
+    let rec case_helper acc = function
+      | [] -> List.rev acc |> return
+      | (pat, expr) :: tl ->
+        let* old_ctx = read in
+        let* _ =
+          write
+            { reserved_names =
+                Base.Set.union old_ctx.reserved_names (collect_bindings_from_pat pat)
+            }
+        in
+        let* new_expr = match_of_pat_let expr in
+        case_helper ((pat, new_expr) :: acc) tl
+    in
+    let* new_cases = case_helper [] cases in
+    LLMatch (new_main_exp, new_cases) |> return
+;;
+
+let rec eliminate_lexpr =
+  let optimized_if_then_else guard then_branch else_branch =
+    match guard with
+    | LLConstant (CBool true) -> then_branch
+    | LLConstant (CBool false) -> else_branch
+    | _ -> LLIfThenElse (guard, then_branch, else_branch)
+  in
+  function
+  | LLTuple elements ->
+    let* new_elements = map1 eliminate_lexpr elements in
+    LLTuple new_elements |> return
+  | LLIfThenElse (guard_branch, then_branch, else_branch) ->
+    let* new_guard_branch = eliminate_lexpr guard_branch in
+    let* new_then_branch = eliminate_lexpr then_branch in
+    let* new_else_branch = eliminate_lexpr else_branch in
+    LLIfThenElse (new_guard_branch, new_then_branch, new_else_branch) |> return
+  | LLApplication (left, right) ->
+    let* new_left = eliminate_lexpr left in
+    let* new_right = eliminate_lexpr right in
+    LLApplication (new_left, new_right) |> return
+  | LLConstraint (llexpr, typ) ->
+    let* new_llexpr = eliminate_lexpr llexpr in
+    LLConstraint (new_llexpr, typ) |> return
+  | LLMatch (main_expression, match_cases) ->
+    let* match_free_main_expression = eliminate_lexpr main_expression in
+    let* conditions =
+      map1
+        (fun (pat, _) ->
+          let bound_expr = BoundExpression (pat, match_free_main_expression) in
+          generate_bindings bound_expr)
+        match_cases
+    in
+    List.fold_right2
+      (fun (head_condition, binds) (_, expr) acc ->
+        let* match_free_lexpr = eliminate_lexpr expr in
+        let* acc' = acc in
+        return
+          (optimized_if_then_else
+             head_condition
+             (List.fold_right
+                (fun (name, llexpr) acc ->
+                  LLLetIn (NotRec, PIdentifier name, llexpr, acc))
+                binds
+                match_free_lexpr)
+             acc'))
+      conditions
+      match_cases
+      (LLApplication (LLIdentifier "match_error", LLConstant CUnit) |> return)
+  | LLConstant constant -> LLConstant constant |> return
+  | LLIdentifier name -> LLIdentifier name |> return
+  | _ -> fail "Error: Unexpected expression"
+;;
+
+let rec rename_pat = function
+  | PWildCard -> PWildCard |> return
+  | PConstant c -> PConstant c |> return
+  | PConstraint (pat, typ) ->
+    let* new_pat = rename_pat pat in
+    PConstraint (new_pat, typ) |> return
+  | PCons (left, right) ->
+    let* new_left = rename_pat left in
+    let* new_right = rename_pat right in
+    PCons (new_left, new_right) |> return
+  | PTuple pats ->
+    let* new_pats = map1 rename_pat pats in
+    PTuple new_pats |> return
+  | PIdentifier id ->
+    let* old_name, counter = generate_unique_name id 0 in
+    PIdentifier (Printf.sprintf "%s_%d" old_name counter) |> return
+;;
+
+let process_simple_let = function
+  | LLLet (PIdentifier id, args, llexpr) ->
+    let rec get_new_args acc = function
+      | [] -> List.rev acc |> return
+      | _ :: tl ->
+        let* name, counter = generate_unique_name "arg" 0 in
+        let new_name = Printf.sprintf "%s_%d" name counter in
+        get_new_args (new_name :: acc) tl
+    in
+    let rec bind_names_to_patterns base_exp names patterns =
+      match names, patterns with
+      | [], [] -> return base_exp
+      | name :: names_tail, pattern :: patterns_tail ->
+        let* ctx = read in
+        let* _ = write { reserved_names = Base.Set.add ctx.reserved_names name } in
+        let* inner_exp = bind_names_to_patterns base_exp names_tail patterns_tail in
+        return (LLLetIn (NotRec, pattern, LLIdentifier name, inner_exp))
+      | _ -> fail "Error: Mismatch in the lengths of names and patterns lists"
+    in
+    let* ctx = read in
+    let* _ = write { reserved_names = Base.Set.add ctx.reserved_names id } in
+    let* new_names = get_new_args [] args in
+    let* new_llexpr = bind_names_to_patterns llexpr new_names args in
+    let* llexpr_with_no_lets = match_of_pat_let new_llexpr in
+    let* llexpr_with_no_matches = eliminate_lexpr llexpr_with_no_lets in
+    LLLet
+      (PIdentifier id, List.map (fun x -> PIdentifier x) new_names, llexpr_with_no_matches)
+    |> return
+  | _ -> fail "Error: unexpected lllet"
path: BasedML/lib/middleend/match_elimination.ml
user: login: Kakadu
body: Ну я так и сказал, только короче.
created_at: 2025-03-02T07:44:04Z
author_association: OWNER
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Salvatore112
body: Это всё в сразу одной функции происходит
created_at: 2025-03-02T11:41:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Kakadu
body: Если это всё в одной функции, то как это в лог попало? Сделайте без явного мусора ANF
created_at: 2025-03-02T18:19:47Z
author_association: OWNER
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Salvatore112
body: Что Вам не нравиться? Переименования нужны чтобы убрать паттерны в аргументах, к ANF это никакого отношения не имеет. 
created_at: 2025-03-02T19:21:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,71 +96,104 @@
    test5_0;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/001fac.ml
-  let rec fac_0 n_0  = let anf_app_0 = ( <= ) n_0 1 in
+  let rec fac_0 arg_0  = let n_0 = arg_0 in
+   let anf_app_0 = ( <= ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then 1 else let anf_app_1 = ( - ) n_0 1 in
    let anf_app_2 = fac_0 anf_app_1 in
    let anf_app_3 = ( * ) n_0 anf_app_2 in
    anf_app_3 in
    anf_ifthenelse_4;;
   let  main_0  = let anf_app_0 = fac_0 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/002fac.ml
-  let  ll_0 k_0 n_0 p_0  = let anf_app_0 = ( * ) p_0 n_0 in
+  let  ll_0 arg_0 arg_1 arg_2  = let k_0 = arg_0 in
+   let n_0 = arg_1 in
+   let p_0 = arg_2 in
+   let anf_app_0 = ( * ) p_0 n_0 in
    let anf_app_1 = k_0 anf_app_0 in
    anf_app_1;;
-  let rec fac_cps_0 n_0 k_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fac_cps_0 arg_3 arg_4  = let n_0 = arg_3 in
+   let k_0 = arg_4 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_5 = if anf_app_0 then let anf_app_1 = k_0 1 in
-   anf_app_1 else let anf_app_2 = ( - ) n_0 1 in
-   let anf_app_3 = ll_0 k_0 n_0 in
-   let anf_app_4 = fac_cps_0 anf_app_2 anf_app_3 in
+   anf_app_1 else let anf_app_2 = ll_0 k_0 n_0 in
+   let anf_app_3 = ( - ) n_0 1 in
+   let anf_app_4 = fac_cps_0 anf_app_3 anf_app_2 in
    anf_app_4 in
    anf_ifthenelse_5;;
-  let  ll_1 print_int_0  = print_int_0;;
+  let  ll_1 arg_5  = let print_int_0 = arg_5 in
+   print_int_0;;
   let  main_0  = let anf_app_0 = fac_cps_0 4 ll_1 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_4 = if anf_app_2 then 0 else let anf_app_3 = match_error () in
+   anf_app_3 in
+   anf_ifthenelse_4;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/003fib.ml
-  let rec fib_acc_0 a_0 b_0 n_0  = let anf_app_0 = ( = ) n_0 1 in
+  let rec fib_acc_0 arg_0 arg_1 arg_2  = let a_0 = arg_0 in
+   let b_0 = arg_1 in
+   let n_0 = arg_2 in
+   let anf_app_0 = ( = ) n_0 1 in
    let anf_ifthenelse_4 = if anf_app_0 then b_0 else let anf_app_1 = ( - ) n_0 1 in
    let n1_0 = anf_app_1 in
    let anf_app_2 = ( + ) a_0 b_0 in
    let ab_0 = anf_app_2 in
    let anf_app_3 = fib_acc_0 b_0 ab_0 n1_0 in
    anf_app_3 in
    anf_ifthenelse_4;;
-  let rec fib_0 n_0  = let anf_app_0 = ( < ) n_0 2 in
-   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 1 in
+  let rec fib_0 arg_3  = let n_0 = arg_3 in
+   let anf_app_0 = ( < ) n_0 2 in
+   let anf_ifthenelse_6 = if anf_app_0 then n_0 else let anf_app_1 = ( - ) n_0 2 in
    let anf_app_2 = fib_0 anf_app_1 in
-   let anf_app_3 = ( - ) n_0 2 in
+   let anf_app_3 = ( - ) n_0 1 in
    let anf_app_4 = fib_0 anf_app_3 in
-   let anf_app_5 = ( + ) anf_app_2 anf_app_4 in
+   let anf_app_5 = ( + ) anf_app_4 anf_app_2 in
    anf_app_5 in
    anf_ifthenelse_6;;
   let  main_0  = let anf_app_0 = fib_acc_0 0 1 4 in
    let anf_app_1 = print_int anf_app_0 in
-   let () = anf_app_1 in
-   let anf_app_2 = fib_0 4 in
-   let anf_app_3 = print_int anf_app_2 in
-   let () = anf_app_3 in
-   0;;
+   let anf_app_2 = ( = ) anf_app_1 () in
+   let anf_ifthenelse_9 = if anf_app_2 then let anf_app_3 = fib_0 4 in
+   let anf_app_4 = print_int anf_app_3 in
+   let anf_app_5 = ( = ) anf_app_4 () in
+   let anf_ifthenelse_7 = if anf_app_5 then 0 else let anf_app_6 = match_error () in
+   anf_app_6 in
+   anf_ifthenelse_7 else let anf_app_8 = match_error () in
+   anf_app_8 in
+   anf_ifthenelse_9;;
 
   $ dune exec ./anf_demo.exe < ./manytests/typed/004manyargs.ml
-  let  wrap_0 f_0  = let anf_app_0 = ( = ) 1 1 in
+  let  wrap_0 arg_0  = let f_0 = arg_0 in
+   let anf_app_0 = ( = ) 1 1 in
    let anf_ifthenelse_1 = if anf_app_0 then f_0 else f_0 in
    anf_ifthenelse_1;;
-  let  test3_0 a_0 b_0 c_0  = let anf_app_0 = print_int a_0 in
+  let  test3_0 arg_1 arg_2 arg_3  = let a_0 = arg_1 in
+   let b_0 = arg_2 in
+   let c_0 = arg_3 in
+   let anf_app_0 = print_int a_0 in
    let a_1 = anf_app_0 in
    let anf_app_1 = print_int b_0 in
    let b_1 = anf_app_1 in
    let anf_app_2 = print_int c_0 in
    let c_1 = anf_app_2 in
    0;;
-  let  test10_0 a_2 b_2 c_2 d_0 e_0 f_1 g_0 h_0 i_0 j_0  = let anf_app_0 = ( + ) a_2 b_2 in
+  let  test10_0 arg_4 arg_5 arg_6 arg_7 arg_8 arg_9 arg_10 arg_11 arg_12 arg_13  = let a_2 = arg_4 in
+   let b_2 = arg_5 in
+   let c_2 = arg_6 in
+   let d_0 = arg_7 in
+   let e_0 = arg_8 in
+   let f_1 = arg_9 in
+   let g_0 = arg_10 in
+   let h_0 = arg_11 in
+   let i_0 = arg_12 in
+   let j_0 = arg_13 in
path: BasedML/test/anf_tests.t
user: login: Salvatore112
body: Кажется, я понял о чем Вы, убрал лишние ренейминги
created_at: 2025-03-03T00:29:35Z
author_association: CONTRIBUTOR

PR comments:
user: login: Kakadu
created_at: 2025-03-01T21:55:40Z
body: Когда вы попытаетесь скомпилировать таки первую программу, и поймете что много чего надо переделывать, будет очень весело
author_association: OWNER
user: login: Salvatore112
created_at: 2025-03-01T22:19:20Z
body: > Когда вы попытаетесь скомпилировать таки первую программу, и поймете что много чего надо переделывать, будет очень весело

Можете тогда, пожалуйста, сказать, что Вам не нравиться?
author_association: CONTRIBUTOR
user: login: Kakadu
created_at: 2025-03-02T07:44:54Z
body: > > Когда вы попытаетесь скомпилировать таки первую программу, и поймете что много чего надо переделывать, будет очень весело
> 
> Можете тогда, пожалуйста, сказать, что Вам не нравиться?

Например, что мягкий знак пишется там, где не должен.
author_association: OWNER
user: login: github-actions[bot]
created_at: 2025-03-03T13:15:15Z
body: <!-- add-pr-comment:linter-report -->

Linter report from 2025-03-03 16:15, for mini language BasedML
```

```

author_association: NONE