From 9d779097bd97468f3f0d995489db4415bf7900b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9lio=20Brun?= <lelio.brun@isae-supaero.fr>
Date: Thu, 3 Feb 2022 15:18:08 +0100
Subject: [PATCH] ast modifs and additional arrow_taint phase to retrieve which
 arrow "protects" / "taints" which variable

---
 offline_tests/test.ml                         |   3 +-
 src/automata.ml                               |   6 +-
 src/backends/Ada/ada_backend_adb.ml           |   5 +-
 src/backends/Ada/ada_backend_ads.ml           |   4 +-
 src/backends/Ada/misc_lustre_function.ml      |   2 +-
 src/backends/C/c_backend_common.ml            |  16 +--
 src/backends/C/c_backend_spec.ml              | 110 +++++++++---------
 src/backends/C/c_backend_src.ml               |   7 +-
 src/backends/EMF/EMF_backend.ml               |   2 +-
 src/backends/Horn/horn_backend_common.ml      |  18 +--
 src/backends/Horn/horn_backend_traces.ml      |   2 +-
 src/causality.ml                              |  14 +--
 src/causality.mli                             |   2 +-
 src/clock_calculus.ml                         |   4 +-
 src/clocks.ml                                 |  35 ++++--
 src/clocks.mli                                |   2 +
 src/compiler_common.ml                        |   7 +-
 src/compiler_stages.ml                        |   4 +
 src/corelang.ml                               |  34 +++++-
 src/corelang.mli                              |   2 +
 src/dune                                      |   1 +
 src/features/machine_types/machine_types.ml   |   2 +-
 src/inliner.ml                                |   6 +-
 src/lustre_types.ml                           |   4 +-
 src/lustre_types.mli                          |   2 +-
 src/machine_code.ml                           |  32 +++--
 src/machine_code_common.ml                    |  15 ++-
 src/machine_code_common.mli                   |   2 +
 src/machine_code_dep.ml                       |   2 +-
 src/machine_code_types.mli                    |   2 +-
 src/normalization.ml                          |  10 +-
 src/optimize_machine.ml                       |   6 +-
 src/parsers/parser_lustre.mly                 |  25 ++--
 src/pathConditions.ml                         |   2 +-
 src/plugins/mpfr/lustrec_mpfr.ml              |   4 +-
 src/plugins/scopes/scopes.ml                  |  13 ++-
 src/printers.ml                               |   2 +-
 .../semantics/cPS_lustre_generator.ml         |   2 +-
 src/typing.ml                                 |  11 +-
 src/utils/dimension.ml                        |  12 ++
 src/utils/dimension.mli                       |   2 +
 41 files changed, 271 insertions(+), 165 deletions(-)

diff --git a/offline_tests/test.ml b/offline_tests/test.ml
index 77d435cc..629eefbb 100644
--- a/offline_tests/test.ml
+++ b/offline_tests/test.ml
@@ -223,7 +223,7 @@ let read_whole_file f =
 
 let has_warning log =
   let open Re.Str in
-  let reg = "Warning: Generating stateful spec for uninitialized state variables." in
+  let reg = "Warning: Generating stateful spec for uninitialized state variable" in
   try
     search_forward (regexp reg) log 0 |> ignore;
     true
@@ -274,6 +274,7 @@ let compile report lustrec fs =
               fail report log
         in
         print_result p f fmt_str check;
+        write_report report;
         report, ok, ko, ninits, i')
       (report, 0, 0, 0, 0) fs
   in
diff --git a/src/automata.ml b/src/automata.ml
index 715af1eb..506b2d7d 100644
--- a/src/automata.ml
+++ b/src/automata.ml
@@ -378,7 +378,7 @@ let node_of_assign_until nused used node aut_id aut_state handler =
         List.map
           copy_var_decl
           (aut_state.incoming_r :: aut_state.incoming_s :: new_var_outputs);
-      node_locals = List.map copy_var_decl (new_var_locals @ handler.hand_locals);
+      node_locals = List.map (fun v -> copy_var_decl v, None) (new_var_locals @ handler.hand_locals);
       node_gencalls = [];
       node_checks = [];
       node_asserts = handler.hand_asserts;
@@ -520,7 +520,7 @@ let expand_node_stmts nused used loc owner node =
       node.node_stmts
   in
   let node' =
-    { node with node_locals = locals' @ node.node_locals; node_stmts = eqs' }
+    { node with node_locals = List.map (fun v -> v, None) locals' @ node.node_locals; node_stmts = eqs' }
   in
   let top_node = mktop_decl loc owner false (Node node') in
   top_types', top_node, top_nodes'
@@ -535,7 +535,7 @@ let rec expand_decls_rec nused top_decls =
       let used name =
         List.exists (fun v -> v.var_id = name) nd.node_inputs
         || List.exists (fun v -> v.var_id = name) nd.node_outputs
-        || List.exists (fun v -> v.var_id = name) nd.node_locals
+        || List.exists (fun (v, _) -> v.var_id = name) nd.node_locals
       in
       let top_types', top_decl', top_nodes' =
         expand_node_stmts
diff --git a/src/backends/Ada/ada_backend_adb.ml b/src/backends/Ada/ada_backend_adb.ml
index cf61062c..2b35098b 100644
--- a/src/backends/Ada/ada_backend_adb.ml
+++ b/src/backends/Ada/ada_backend_adb.ml
@@ -172,8 +172,7 @@ let pp_step_definition env typed_submachines fmt (m, m_spec_opt, guarantees) =
     @param typed_submachines list of all typed machine instances of this machine
     @param fmt the formater to print on @param machine the machine **)
 let pp_reset_definition env typed_submachines fmt (m, m_spec_opt) =
-  let build_assign = function
-    | var ->
+  let build_assign (var, _) =
       mkinstr (MStateAssign (var, mk_default_value var.var_type))
   in
   let env, memory =
@@ -198,7 +197,7 @@ let pp_reset_definition env typed_submachines fmt (m, m_spec_opt) =
     on @param typed_submachines list of all typed machine instances of this
     machine @param m the machine **)
 let pp_file fmt (typed_submachines, ((opt_spec_machine, guarantees), machine)) =
-  let env = List.map (fun x -> x.var_id, pp_state_name) machine.mmemory in
+  let env = List.map (fun (x, _) -> x.var_id, pp_state_name) machine.mmemory in
   let pp_reset fmt =
     if is_machine_statefull machine then
       fprintf
diff --git a/src/backends/Ada/ada_backend_ads.ml b/src/backends/Ada/ada_backend_ads.ml
index dd69ab5a..6ecf0e1c 100644
--- a/src/backends/Ada/ada_backend_ads.ml
+++ b/src/backends/Ada/ada_backend_ads.ml
@@ -119,7 +119,7 @@ let pp_file fmt (typed_submachines, ((m_spec_opt, guarantees), m)) =
       []
     | Some m ->
       List.map
-        (fun x ->
+        (fun (x, _) ->
           pp_var_decl
             (build_pp_var_decl AdaNoMode (Some (true, false, [], [])) x))
         m.mmemory
@@ -129,7 +129,7 @@ let pp_file fmt (typed_submachines, ((m_spec_opt, guarantees), m)) =
      match m_spec_opt with | None -> [] | Some m_spec -> List.map
      (build_pp_var_decl AdaNoMode (Some (true, false, [], []))) (m_spec.mmemory)
      in *)
-  let vars = List.map (build_pp_var_decl AdaNoMode None) m.mmemory in
+  let vars = List.map (fun (x, _) -> build_pp_var_decl AdaNoMode None x) m.mmemory in
   let states =
     List.map
       (build_pp_state_decl_from_subinstance AdaNoMode None)
diff --git a/src/backends/Ada/misc_lustre_function.ml b/src/backends/Ada/misc_lustre_function.ml
index b14c8535..b2686b21 100644
--- a/src/backends/Ada/misc_lustre_function.ml
+++ b/src/backends/Ada/misc_lustre_function.ml
@@ -25,7 +25,7 @@ let get_machine machines instance =
 (** Extract all the inputs and outputs. @param machine the machine @return a
     list of all the var_decl of a macine **)
 let get_all_vars_machine m =
-  m.mmemory @ m.mstep.step_inputs @ m.mstep.step_outputs @ m.mstatic
+  List.map fst m.mmemory @ m.mstep.step_inputs @ m.mstep.step_outputs @ m.mstatic
 
 (** Check if a type is polymorphic. @param typ the type @return true if its
     polymorphic **)
diff --git a/src/backends/C/c_backend_common.ml b/src/backends/C/c_backend_common.ml
index 8f462db5..4707881d 100644
--- a/src/backends/C/c_backend_common.ml
+++ b/src/backends/C/c_backend_common.ml
@@ -48,7 +48,7 @@ let mk_local n m =
     exists (var_is name) m.mstep.step_inputs
     || exists (var_is name) m.mstep.step_outputs
     || exists (var_is name) m.mstep.step_locals
-    || exists (var_is name) m.mmemory
+    || exists (fun (x, _) -> var_is name x) m.mmemory
   in
   mk_new_name used n
 
@@ -75,7 +75,7 @@ let mk_mem_reset = mk_local "mem_reset"
 let mk_instance m =
   let used name =
     let open List in
-    exists (var_is name) m.mstep.step_inputs || exists (var_is name) m.mmemory
+    exists (var_is name) m.mstep.step_inputs || exists (fun (x, _) -> var_is name x) m.mmemory
   in
   mk_new_name used "inst"
 
@@ -84,7 +84,7 @@ let mk_instance m =
 let mk_attribute m =
   let used name =
     let open List in
-    exists (var_is name) m.mstep.step_inputs || exists (var_is name) m.mmemory
+    exists (var_is name) m.mstep.step_inputs || exists (fun (x, _) -> var_is name x) m.mmemory
   in
   mk_new_name used "attr"
 
@@ -110,7 +110,7 @@ let reset_loop_counter () = loop_cpt := -1
 
 let mk_loop_var m () =
   let vars =
-    m.mstep.step_inputs @ m.mstep.step_outputs @ m.mstep.step_locals @ m.mmemory
+    m.mstep.step_inputs @ m.mstep.step_outputs @ m.mstep.step_locals @ List.map fst m.mmemory
   in
   let rec aux () =
     incr loop_cpt;
@@ -800,7 +800,7 @@ let pp_machine_struct ?(ghost = false) fmt m =
           ~pp_sep:pp_print_semicolon
           ~pp_eol:pp_print_semicolon'
           ~pp_epilogue:(fun fmt () -> fprintf fmt "}@] _reg;")
-          pp_c_decl_struct_var)
+          (fun fmt (x, _) -> pp_c_decl_struct_var fmt x))
       m.mmemory
       (pp_print_list
          ~pp_open_box:pp_open_vbox0
@@ -1255,7 +1255,8 @@ let pp_static_declare_macro ?(ghost = false) fmt ((m, attr, inst) as macro) =
     List.filter (fun vdecl -> vdecl.var_dec_const) m.mstep.step_locals
   in
   let array_mem =
-    List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory
+    List.filter_map (fun (v, _) -> if Types.is_array_type v.var_type then Some v else None)
+      m.mmemory
   in
   fprintf
     fmt
@@ -1298,7 +1299,8 @@ let pp_static_link_instance ?(ghost = false) fmt (i, (m, _)) =
    it to a pointer (see pp_registers_struct) *)
 let pp_static_link_macro ?(ghost = false) fmt (m, _, inst) =
   let array_mem =
-    List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory
+    List.filter_map (fun (v, _) -> if Types.is_array_type v.var_type then Some v else None)
+      m.mmemory
   in
   fprintf
     fmt
diff --git a/src/backends/C/c_backend_spec.ml b/src/backends/C/c_backend_spec.ml
index e8b8352f..a17f9b8c 100644
--- a/src/backends/C/c_backend_spec.ml
+++ b/src/backends/C/c_backend_spec.ml
@@ -476,32 +476,41 @@ module PrintSpec = struct
     | Memory ResetFlag ->
       vdecl_to_val reset_flag
 
-  let find_arrow loc m =
-    match
-      List.find_opt (fun (_, (td, _)) -> Arrow.td_is_arrow td) m.minstances
-    with
-    | Some (f, _) ->
-      Some f
-    | None ->
-      Error.pp_warning loc (fun fmt ->
-          pp_print_string
-            fmt
-            "Generating stateful spec for uninitialized state variables.");
-      None
-
-  let rec has_memory_val m v =
-    let has_mem = has_memory_val m in
-    match v.value_desc with
-    | Var v ->
-      is_memory m v
-    | Array vl | Fun (_, vl) ->
-      List.exists has_mem vl
-    | Access (t, i) | Power (t, i) ->
-      has_mem t || has_mem i
-    | _ ->
-      false
+  let find_arrow_val =
+    let bad_inits = Hashtbl.create 32 in
+    let rec find_arrow_val loc m v =
+      let find = find_arrow_val loc m in
+      match v.value_desc with
+      | Var v ->
+        begin match find_tainter_arrow m v with
+          | Some (Some a) ->
+            Some a
+          | Some None ->
+            if not (Hashtbl.mem bad_inits v) then begin
+              Hashtbl.add bad_inits v ();
+              Error.pp_warning loc (fun fmt ->
+                  fprintf fmt
+                    "Generating stateful spec for uninitialized state variable %s."
+                    v.var_id);
+            end;
+            None
+          | None -> None
+        end
+      | Array vl | Fun (_, vl) ->
+        List.find_map find vl
+      | Access (t, i) | Power (t, i) ->
+        begin match find t with
+          | None -> find i
+          | a -> a
+        end
+      | _ ->
+        None
+    in
+    find_arrow_val
 
-  let has_memory_expr m = function Val v -> has_memory_val m v | _ -> false
+  let find_arrow loc m = function
+    | Val v -> find_arrow_val loc m v
+    | _ -> None
 
   let pp_spec mode m fmt f =
     let rec pp_spec mode fmt f =
@@ -546,18 +555,16 @@ module PrintSpec = struct
             fmt
             (Spec_common.type_of_value a, val_of_expr a, val_of_expr b)
         in
-        if has_memory_expr m b then
-          let inst = find_arrow Location.dummy m in
-          pp_print_option
-            ~none:pp_eq
-            (fun fmt inst ->
-              pp_paren
-                (pp_implies (pp_not (pp_initialization pp_access')) pp_eq)
-                fmt
-                ((Arrow.arrow_id, (mem_in, inst)), ()))
-            fmt
-            inst
-        else pp_eq fmt ()
+        let inst = find_arrow Location.dummy m b in
+        pp_print_option
+          ~none:pp_eq
+          (fun fmt inst ->
+             pp_paren
+               (pp_implies (pp_not (pp_initialization pp_access')) pp_eq)
+               fmt
+               ((Arrow.arrow_id, (mem_in, inst)), ()))
+          fmt
+          inst
       | GEqual (a, b) ->
         pp_assign_spec
           ~pp_op:pp_gequal
@@ -584,18 +591,16 @@ module PrintSpec = struct
         pp_forall (pp_locals m) pp_spec' fmt (xs, a)
       | Ternary (e, a, b) ->
         let pp_ite fmt () = pp_ite pp_expr pp_spec' pp_spec' fmt (e, a, b) in
-        if has_memory_expr m e then
-          let inst = find_arrow Location.dummy m in
-          pp_print_option
-            ~none:pp_ite
-            (fun fmt inst ->
-              pp_paren
-                (pp_implies (pp_not (pp_initialization pp_access')) pp_ite)
-                fmt
-                ((Arrow.arrow_id, (mem_in, inst)), ()))
-            fmt
-            inst
-        else pp_ite fmt ()
+        let inst = find_arrow Location.dummy m e in
+        pp_print_option
+          ~none:pp_ite
+          (fun fmt inst ->
+             pp_paren
+               (pp_implies (pp_not (pp_initialization pp_access')) pp_ite)
+               fmt
+               ((Arrow.arrow_id, (mem_in, inst)), ()))
+          fmt
+          inst
       | Predicate p ->
         pp_predicate mode m mem_in mem_in' mem_out mem_out' fmt p
       | StateVarPack ResetFlag ->
@@ -624,7 +629,7 @@ module PrintSpec = struct
             fmt
             (v.var_type, v', v')
         in
-        let inst = find_arrow Location.dummy m in
+        let inst = find_arrow Location.dummy m (Val v') in
         pp_print_option
           ~none:pp_eq
           (fun fmt inst ->
@@ -745,7 +750,7 @@ let pp_transition_footprint_lemma m fmt t =
   let stateless = fst (get_stateless_status m) in
   let mems =
     ISet.(
-      diff (of_list (List.map (fun v -> v.var_id) m.mmemory)) t.tmem_footprint)
+      diff (of_list (List.map (fun (v, _) -> v.var_id) m.mmemory)) t.tmem_footprint)
   in
   let insts =
     IMap.(
@@ -756,7 +761,8 @@ let pp_transition_footprint_lemma m fmt t =
   let memories =
     List.map
       (fun v -> { v with var_type = { v.var_type with tid = -1 } })
-      (List.filter (fun v -> ISet.mem v.var_id mems) m.mmemory)
+      (List.filter_map (fun (v, _) -> if ISet.mem v.var_id mems then Some v else None)
+         m.mmemory)
   in
   let mems_empty = ISet.is_empty mems in
   let insts_empty = IMap.is_empty insts in
diff --git a/src/backends/C/c_backend_src.ml b/src/backends/C/c_backend_src.ml
index df21ed74..13713085 100644
--- a/src/backends/C/c_backend_src.ml
+++ b/src/backends/C/c_backend_src.ml
@@ -489,7 +489,8 @@ module Main (Mod : MODIFIERS_SRC) = struct
     fprintf fmt "free (_alloc->_reg.%s);" vdecl.var_id
 
   let array_mems m =
-    List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory
+    List.filter_map (fun (v, _) -> if Types.is_array_type v.var_type then Some v else None)
+      m.mmemory
 
   let pp_alloc_code fmt m =
     fprintf
@@ -722,7 +723,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
       ~pp_array_mem:(pp_c_decl_array_mem self)
       ~array_mems:(array_mems m)
       ~pp_init_mpfr_local:(pp_initialize m self (pp_c_var_read m))
-      ~mpfr_locals:m.mmemory
+      ~mpfr_locals:(List.map fst m.mmemory)
       ~pp_extra:(fun fmt () ->
         pp_print_list
           ~pp_open_box:pp_open_vbox0
@@ -745,7 +746,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
       ~pp_array_mem:(pp_c_decl_array_mem self)
       ~array_mems:(array_mems m)
       ~pp_clear_mpfr_local:(pp_clear m self (pp_c_var_read m))
-      ~mpfr_locals:m.mmemory
+      ~mpfr_locals:(List.map fst m.mmemory)
       ~pp_extra:(fun fmt () ->
         pp_print_list
           ~pp_open_box:pp_open_vbox0
diff --git a/src/backends/EMF/EMF_backend.ml b/src/backends/EMF/EMF_backend.ml
index a605cd13..3aea2cb7 100644
--- a/src/backends/EMF/EMF_backend.ml
+++ b/src/backends/EMF/EMF_backend.ml
@@ -480,7 +480,7 @@ let pp_machine fmt m =
   fprintf fmt "\"inputs\": [%a],@ " pp_emf_vars_decl m.mstep.step_inputs;
   fprintf fmt "\"outputs\": [%a],@ " pp_emf_vars_decl m.mstep.step_outputs;
   fprintf fmt "\"locals\": [%a],@ " pp_emf_vars_decl m.mstep.step_locals;
-  fprintf fmt "\"mems\": [%a],@ " pp_emf_vars_decl m.mmemory;
+  fprintf fmt "\"mems\": [%a],@ " pp_emf_vars_decl (List.map fst m.mmemory);
   fprintf fmt "\"original_name\": \"%s\",@ " m.mname.node_id;
   fprintf fmt "\"instrs\": {@[<v 0> %a@]@ },@ " (pp_emf_instrs m) instrs;
   (match m.mspec.mnode_spec with
diff --git a/src/backends/Horn/horn_backend_common.ml b/src/backends/Horn/horn_backend_common.ml
index f2107000..e85a160d 100644
--- a/src/backends/Horn/horn_backend_common.ml
+++ b/src/backends/Horn/horn_backend_common.ml
@@ -98,12 +98,12 @@ let rename_next = rename (fun n -> n ^ "_x")
 let rename_next_list = List.map rename_next
 
 let local_memory_vars machine =
-  rename_machine_list machine.mname.node_id machine.mmemory
+  rename_machine_list machine.mname.node_id (List.map fst machine.mmemory)
 
 let instances_memory_vars ?(without_arrow = false) machines machine =
-  let rec aux fst prefix m =
-    (if not fst then
-     rename_machine_list (concat prefix m.mname.node_id) m.mmemory
+  let rec aux first prefix m =
+    (if not first then
+     rename_machine_list (concat prefix m.mname.node_id) (List.map fst m.mmemory)
     else [])
     @ List.fold_left
         (fun accu (id, (n, _)) ->
@@ -113,7 +113,7 @@ let instances_memory_vars ?(without_arrow = false) machines machine =
             let machine_n = get_machine machines name in
             aux
               false
-              (concat prefix (if fst then id else concat m.mname.node_id id))
+              (concat prefix (if first then id else concat m.mname.node_id id))
               machine_n
             @ accu)
         []
@@ -123,7 +123,7 @@ let instances_memory_vars ?(without_arrow = false) machines machine =
 
 (* Extract the arrows of a given node/machine *)
 let arrow_vars machines machine : Lustre_types.var_decl list =
-  let rec aux fst prefix m =
+  let rec aux first prefix m =
     List.fold_left
       (fun accu (id, (n, _)) ->
         let name = node_name n in
@@ -132,14 +132,14 @@ let arrow_vars machines machine : Lustre_types.var_decl list =
           rename_machine_list
             (concat
                prefix
-               (concat (if fst then id else concat m.mname.node_id id) "_arrow"))
-            arrow_machine.mmemory
+               (concat (if first then id else concat m.mname.node_id id) "_arrow"))
+            (List.map fst arrow_machine.mmemory)
           @ accu
         else
           let machine_n = get_machine machines name in
           aux
             false
-            (concat prefix (if fst then id else concat m.mname.node_id id))
+            (concat prefix (if first then id else concat m.mname.node_id id))
             machine_n
           @ accu)
       []
diff --git a/src/backends/Horn/horn_backend_traces.ml b/src/backends/Horn/horn_backend_traces.ml
index afbba341..42b89726 100644
--- a/src/backends/Horn/horn_backend_traces.ml
+++ b/src/backends/Horn/horn_backend_traces.ml
@@ -29,7 +29,7 @@ open Horn_backend_printers
 (* Compute memories associated to each machine *)
 let compute_mems machines m =
   let rec aux prefix m =
-    List.map (fun mem -> prefix, mem) m.mmemory
+    List.map (fun (mem, _) -> prefix, mem) m.mmemory
     @ List.fold_left
         (fun accu (id, (n, _)) ->
           let name = node_name n in
diff --git a/src/causality.ml b/src/causality.ml
index d02e2cb0..1a4b2701 100644
--- a/src/causality.ml
+++ b/src/causality.ml
@@ -151,13 +151,13 @@ module ExprDep = struct
 
   let node_local_variables nd =
     List.fold_left
-      (fun locals v -> ISet.add v.var_id locals)
+      (fun locals (v, _) -> ISet.add v.var_id locals)
       ISet.empty
       nd.node_locals
 
   let node_constant_variables nd =
     List.fold_left
-      (fun locals v ->
+      (fun locals (v, _) ->
         if v.var_dec_const then ISet.add v.var_id locals else locals)
       ISet.empty
       nd.node_locals
@@ -175,7 +175,7 @@ module ExprDep = struct
         nd.node_outputs
     in
     List.fold_left
-      (fun vars v -> ISet.add v.var_id vars)
+      (fun vars (v, _) -> ISet.add v.var_id vars)
       inoutputs
       nd.node_locals
 
@@ -522,7 +522,7 @@ module CycleDetection = struct
 
   let mk_copy_var n id =
     let used name =
-      List.exists (fun v -> v.var_id = name) n.node_locals
+      List.exists (fun (v, _) -> v.var_id = name) n.node_locals
       || List.exists (fun v -> v.var_id = name) n.node_inputs
       || List.exists (fun v -> v.var_id = name) n.node_outputs
     in
@@ -784,7 +784,7 @@ let global_dependency node =
     ( {
         node with
         node_stmts = List.map (fun eq -> Eq eq) eqs';
-        node_locals = vdecls' @ node.node_locals;
+        node_locals = List.map (fun v -> v, None) vdecls' @ node.node_locals;
       },
       g_non_mems )
   with Error (DataCycle _ as exc) -> raise (Error exc)
@@ -805,7 +805,7 @@ module VarClockDep = struct
     let g = new_graph () in
     let g =
       List.fold_left
-        (fun g var_decl ->
+        (fun g (var_decl, _) ->
           let deps = get_clock_dep var_decl.var_clock in
           add_edges [ var_decl.var_id ] deps g)
         g
@@ -814,7 +814,7 @@ module VarClockDep = struct
     let sorted, no_deps =
       TopologicalDepGraph.fold
         (fun vid (accu, remaining) ->
-          let select v = v.var_id = vid in
+          let select (v, _) = v.var_id = vid in
           let selected, not_selected = List.partition select remaining in
           selected @ accu, not_selected)
         g
diff --git a/src/causality.mli b/src/causality.mli
index 6b72661f..72bbc518 100644
--- a/src/causality.mli
+++ b/src/causality.mli
@@ -32,7 +32,7 @@ end
 (* A module to sort dependencies among local variables when relying on clocked
    declarations *)
 module VarClockDep : sig
-  val sort : var_decl list -> var_decl list
+  val sort : (var_decl * 'a) list -> (var_decl * 'a) list
 end
 
 module ExprDep : sig
diff --git a/src/clock_calculus.ml b/src/clock_calculus.ml
index 1f2bf34f..ab5bfcea 100644
--- a/src/clock_calculus.ml
+++ b/src/clock_calculus.ml
@@ -684,7 +684,7 @@ let clock_node env loc nd =
   (* let is_main = nd.node_id = !Options.main_node in *)
   let new_env = clock_var_decl_list env false nd.node_inputs in
   let new_env = clock_var_decl_list new_env true nd.node_outputs in
-  let new_env = clock_var_decl_list new_env true nd.node_locals in
+  let new_env = clock_var_decl_list new_env true (List.map fst nd.node_locals) in
   let eqs, _ = get_node_eqs nd in
   (* TODO XXX: perform the clocking on auts. For the moment, it is ignored *)
   List.iter (clock_eq new_env) eqs;
@@ -803,7 +803,7 @@ let uneval_top_generics decl =
   | Node nd ->
     (* A node could contain first-order carrier variable in local vars. This is
        not the case for types. *)
-    uneval_node_generics (nd.node_inputs @ nd.node_locals @ nd.node_outputs)
+    uneval_node_generics (nd.node_inputs @ List.map fst nd.node_locals @ nd.node_outputs)
   | ImportedNode nd ->
     uneval_node_generics (nd.nodei_inputs @ nd.nodei_outputs)
   | Const _ | Include _ | Open _ | TypeDef _ ->
diff --git a/src/clocks.ml b/src/clocks.ml
index d0d4abf4..f7585213 100644
--- a/src/clocks.ml
+++ b/src/clocks.ml
@@ -291,13 +291,34 @@ let constrained_vars_of_clock ck =
   aux [] ck
 
 let eq_carrier cr1 cr2 =
-  match (carrier_repr cr1).carrier_desc, (carrier_repr cr2).carrier_desc with
-  | Carry_const id1, Carry_const id2 ->
-    id1 = id2
-  | _ ->
-    cr1.carrier_id = cr2.carrier_id
-
-let equal ck1 ck2 = (repr ck1).cid = (repr ck2).cid
+  let cr1' = carrier_repr cr1 in
+  let cr2' = carrier_repr cr2 in
+  cr1.carrier_id = cr2.carrier_id
+  || cr1'.carrier_id = cr2'.carrier_id
+  || cr1'.carrier_desc = cr2'.carrier_desc
+
+let rec eq_clock ck1 ck2 =
+  let ck1' = repr ck1 in
+  let ck2' = repr ck2 in
+  ck1.cid = ck2.cid
+  || ck1'.cid = ck2'.cid
+  || match ck1'.cdesc, ck2'.cdesc with
+  | Carrow (ck11, ck12), Carrow (ck21, ck22) ->
+    eq_clock ck11 ck21 && eq_clock ck12 ck22
+  | Ctuple cks1, Ctuple cks2 ->
+    begin try List.for_all2 eq_clock cks1 cks2 with Invalid_argument _ -> false end
+  | Con (ck1, cr1, x1), Con (ck2, cr2, x2) ->
+    eq_clock ck1 ck2 && eq_carrier cr1 cr2 && x1 = x2
+  | Ccarrying (cr1, ck1), Ccarrying (cr2, ck2) ->
+    eq_carrier cr1 cr2 && eq_clock ck1 ck2
+  | Cunivar, _ | _, Cunivar -> true
+  | _ -> false
+
+let equal ck1 ck2 =
+  (* let ck1 = repr ck1 in *)
+  (* let ck2 = repr ck2 in *)
+  (* ck1.cid = ck2.cid  *)
+  eq_clock ck1 ck2
 
 (* Returns the clock root of a clock *)
 let rec root ck =
diff --git a/src/clocks.mli b/src/clocks.mli
index 2272fbe6..69502461 100644
--- a/src/clocks.mli
+++ b/src/clocks.mli
@@ -46,6 +46,8 @@ type error =
    complexity. *)
 val pp : Format.formatter -> t -> unit
 
+val print_ck_long : Format.formatter -> t -> unit
+
 val pp_suffix : Format.formatter -> t -> unit
 
 val new_var : bool -> t
diff --git a/src/compiler_common.ml b/src/compiler_common.ml
index 19d91e06..ba31aefd 100644
--- a/src/compiler_common.ml
+++ b/src/compiler_common.ml
@@ -241,7 +241,7 @@ let resolve_contracts prog =
             let imp_in = imp_nd.node_inputs in
             let imp_out = imp_nd.node_outputs in
             let imp_locals = imp_nd.node_locals in
-            let locals = imp_in @ imp_out @ imp_locals @ locals in
+            let locals = imp_in @ imp_out @ List.map fst imp_locals @ locals in
             let imp_c = get_node_contract imp_nd in
             (* Assigning in and out *)
             let mk_def vars_l e =
@@ -310,6 +310,7 @@ let resolve_contracts prog =
             false)
         (accu_contracts @ prog)
     in
+    let node_locals = List.map (fun v -> v, None) node_locals in
     let nd =
       {
         node_id = mk_new_name used (id ^ "_contract");
@@ -356,7 +357,7 @@ let resolve_contracts prog =
             let nd =
               {
                 nd with
-                node_locals = nd.node_locals @ locals;
+                node_locals = nd.node_locals @ List.map (fun v -> v, None) locals;
                 node_stmts = nd.node_stmts @ stmts;
                 node_spec = Some (Contract c);
               }
@@ -418,7 +419,7 @@ let update_vdecl_parents_prog prog =
       | Node nd ->
         List.iter
           (update_vdecl_parents nd.node_id)
-          (nd.node_inputs @ nd.node_outputs @ nd.node_locals)
+          (nd.node_inputs @ nd.node_outputs @ List.map fst nd.node_locals)
       | ImportedNode ind ->
         List.iter
           (update_vdecl_parents ind.nodei_id)
diff --git a/src/compiler_stages.ml b/src/compiler_stages.ml
index 01ae12b1..a86c7440 100644
--- a/src/compiler_stages.ml
+++ b/src/compiler_stages.ml
@@ -190,6 +190,10 @@ let stage1 params prog dirname basename extension =
   Log.report ~level:3 (fun fmt ->
       fprintf fmt "@[<v 2>@ %a@]@ " Printers.pp_prog prog);
 
+  (* Initialization check phase *)
+  Log.report ~level:1 (fun fmt -> fprintf fmt "@ .. initialization check@ ");
+  let prog = Arrow_taint.arrow_taint_prog prog in
+
   (* Compatibility with Lusi *)
   (* If compiling a lusi, generate the lusic. If this is a lus file, Check the
      existence of a lusi (Lustre Interface file) *)
diff --git a/src/corelang.ml b/src/corelang.ml
index 62b47a30..8f49132f 100644
--- a/src/corelang.ml
+++ b/src/corelang.ml
@@ -56,6 +56,34 @@ let dummy_clock_dec = { ck_dec_desc = Ckdec_any; ck_dec_loc = Location.dummy }
 (************************************************************)
 (* *)
 
+let fv_expr e =
+  let open ISet in
+  let rec fv s e = match e.expr_desc with
+    | Expr_ident x ->
+      add x s
+    | Expr_tuple es
+    | Expr_array es ->
+      List.fold_left fv s es
+    | Expr_ite (e1, e2, e3) ->
+      fv (fv (fv s e1) e2) e3
+    | Expr_arrow (e1, e2)
+    | Expr_fby (e1, e2) ->
+      fv (fv s e1) e2
+    | Expr_access (e1, d)
+    | Expr_power (e1, d) ->
+      union (fv s e1) (Dimension.fv d)
+    | Expr_pre e ->
+      fv s e
+    | Expr_when (e, x, _) ->
+      fv (add x s) e
+    | Expr_merge (x, br) ->
+      List.fold_left (fun s (_, e) -> fv s e) (add x s) br
+    | Expr_appl (x, e, r) ->
+      fv (add x (Option.fold ~none:s ~some:(fv s) r)) e
+    | Expr_const _ -> s
+  in
+  fv ISet.empty e
+
 let mktyp loc d = { ty_dec_desc = d; ty_dec_loc = loc }
 
 let mkclock loc d = { ck_dec_desc = d; ck_dec_loc = loc }
@@ -754,7 +782,7 @@ let rec is_eq_expr e1 e2 =
   | _ ->
     false
 
-let get_node_vars nd = nd.node_inputs @ nd.node_locals @ nd.node_outputs
+let get_node_vars nd = nd.node_inputs @ List.map fst nd.node_locals @ nd.node_outputs
 
 let mk_new_node_name nd id =
   let used_vars = get_node_vars nd in
@@ -894,7 +922,7 @@ let copy_node nd =
     node_clock = Clocks.new_var true;
     node_inputs = List.map copy_var_decl nd.node_inputs;
     node_outputs = List.map copy_var_decl nd.node_outputs;
-    node_locals = List.map copy_var_decl nd.node_locals;
+    node_locals = List.map (fun (v, i) -> copy_var_decl v, i) nd.node_locals;
     node_gencalls = [];
     node_checks = [];
     node_stateless = None;
@@ -1105,7 +1133,7 @@ let rename_node f_node f_var nd =
   let rename_stmts = rename_stmts f_node f_var in
   let inputs = rename_vars nd.node_inputs in
   let outputs = rename_vars nd.node_outputs in
-  let locals = rename_vars nd.node_locals in
+  let locals = List.map (fun (v, i) -> rename_var v, Option.map f_var i) nd.node_locals in
   let gen_calls = List.map rename_expr nd.node_gencalls in
   let node_checks = List.map (Dimension.rename f_node f_var) nd.node_checks in
   let node_asserts =
diff --git a/src/corelang.mli b/src/corelang.mli
index b6612ad9..1b6f9c80 100644
--- a/src/corelang.mli
+++ b/src/corelang.mli
@@ -39,6 +39,8 @@ module VSet : sig
 end
 with type elt = var_decl
 
+val fv_expr : expr -> ISet.t
+
 val dummy_type_dec : type_dec
 
 val dummy_clock_dec : clock_dec
diff --git a/src/dune b/src/dune
index 2d02e713..02546538 100644
--- a/src/dune
+++ b/src/dune
@@ -46,6 +46,7 @@
   backends
   lustrec_mpfr
   normalization
+  arrow_taint
   machine_types
   splitting
   compiler_common
diff --git a/src/features/machine_types/machine_types.ml b/src/features/machine_types/machine_types.ml
index 57745ad0..50765873 100644
--- a/src/features/machine_types/machine_types.ml
+++ b/src/features/machine_types/machine_types.ml
@@ -459,7 +459,7 @@ let load prog =
         match top.top_decl_desc with
         | Node nd ->
           (* Format.eprintf "Registeing node %s@." nd.node_id; *)
-          let vars = nd.node_inputs @ nd.node_outputs @ nd.node_locals in
+          let vars = nd.node_inputs @ nd.node_outputs @ List.map fst nd.node_locals in
           let constrained_vars = register_node vars nd.node_annot in
           check_node nd constrained_vars;
 
diff --git a/src/inliner.ml b/src/inliner.ml
index 8a15a094..e1b15397 100644
--- a/src/inliner.ml
+++ b/src/inliner.ml
@@ -180,7 +180,7 @@ let inline_call node loc uid args reset locals caller =
         let vdecl' = rename_var vdecl in
         { vdecl' with var_dec_value = Some (Corelang.expr_of_dimension arg) })
       static_inputs
-    @ List.map rename_var node.node_locals
+    @ List.map ( fun (v, _) -> rename_var v) node.node_locals
   in
   (* checking we are at the appropriate (early) step: node_checks and
      node_gencalls should be empty (not yet assigned) *)
@@ -359,13 +359,13 @@ and inline_node ?(selection_on_annotation = false) node nodes =
             (Eq { eq with eq_rhs = eq_rhs' } :: new_stmts') @ stmts,
             asserts' @ asserts,
             annots' @ annots ))
-        (node.node_locals, [], node.node_asserts, node.node_annot)
+        (List.map fst node.node_locals, [], node.node_asserts, node.node_annot)
         eqs
     in
     let inlined =
       {
         node with
-        node_locals = new_locals;
+        node_locals = List.map (fun v -> v, None) new_locals;
         node_stmts = stmts;
         node_asserts = asserts;
         node_annot = annots;
diff --git a/src/lustre_types.ml b/src/lustre_types.ml
index cc5d978b..79b38408 100644
--- a/src/lustre_types.ml
+++ b/src/lustre_types.ml
@@ -173,7 +173,7 @@ type node_desc = {
   mutable node_clock : Clocks.t;
   node_inputs : var_decl list;
   node_outputs : var_decl list;
-  node_locals : var_decl list;
+  node_locals : (var_decl * ident option) list;
   mutable node_gencalls : expr list;
   mutable node_checks : Dimension.t list;
   node_asserts : assert_t list;
@@ -257,7 +257,7 @@ let node_as_contract nd =
        unprocessed one could. So we conservatively merge elements, to enable
        printing unprocessed contracts *)
     let consts, locals =
-      List.partition (fun v -> v.var_dec_const) nd.node_locals
+      List.partition (fun v -> v.var_dec_const) (List.map fst nd.node_locals)
     in
     {
       c with
diff --git a/src/lustre_types.mli b/src/lustre_types.mli
index 160e2572..d533bbfe 100644
--- a/src/lustre_types.mli
+++ b/src/lustre_types.mli
@@ -162,7 +162,7 @@ type node_desc = {
   mutable node_clock : Clocks.t;
   node_inputs : var_decl list;
   node_outputs : var_decl list;
-  node_locals : var_decl list;
+  node_locals : (var_decl * ident option) list;
   mutable node_gencalls : expr list;
   mutable node_checks : Dimension.t list;
   node_asserts : assert_t list;
diff --git a/src/machine_code.ml b/src/machine_code.ml
index 1d149421..02cd4fbf 100644
--- a/src/machine_code.ml
+++ b/src/machine_code.ml
@@ -147,17 +147,15 @@ let rec translate_act env (y, expr) =
     let c = translate_guard c in
     let t, spec_t = translate_act (y, t) in
     let e, spec_e = translate_act (y, e) in
-    mk_conditional ~lustre_eq c [ t ] [ e ], mk_conditional_tr c spec_t spec_e
+    mk_conditional ~lustre_eq c [ t ] [ e ],
+    mk_conditional_tr c spec_t spec_e
   | Expr_merge (x, hl) ->
     let var_x = env.get_var x in
     let hl, spec_hl =
-      List.(
-        split
-          (map
-             (fun (t, h) ->
-               let h, spec_h = translate_act (y, h) in
-               (t, [ h ]), (t, spec_h))
-             hl))
+      List.fold_right (fun (t, h) (hl, spec_hl) ->
+          let h, spec_h = translate_act (y, h) in
+          (t, [ h ]) :: hl, (t, spec_h) :: spec_hl)
+        hl ([], [])
     in
     mk_branch' ~lustre_eq var_x hl, mk_branch_tr var_x spec_hl
   | _ ->
@@ -178,6 +176,8 @@ let get_memories env = List.fold_left (get_memory env) VSet.empty
 type machine_ctx = {
   (* memories *)
   m : ISet.t;
+  (* arrows *)
+  a: ident IMap.t;
   (* Reset instructions *)
   si : instr_t list;
   (* Instances *)
@@ -199,7 +199,7 @@ type machine_ctx = {
 }
 
 let ctx_init =
-  { m = ISet.empty; si = []; j = IMap.empty; s = []; mp = []; t = [] }
+  { m = ISet.empty; a = IMap.empty; si = []; j = IMap.empty; s = []; mp = []; t = [] }
 
 (****************************************************************)
 (* Main function to translate equations into this machine context we are
@@ -320,7 +320,10 @@ let translate_eq env ctx nd inputs locals outputs i eq =
         (mk_transition ~inst false (node_name td) [ vdecl_to_val var_x ])
         { ctx with j = IMap.add inst (td, []) ctx.j }
     in
-    { ctx with si = mkinstr (MSetReset inst) :: ctx.si }
+    { ctx with
+      si = mkinstr (MSetReset inst) :: ctx.si;
+      a = IMap.add x inst ctx.a
+    }
   | [ x ], Expr_pre e when env.is_local x ->
     let var_x = env.get_var x in
     let e = translate_expr e in
@@ -576,7 +579,7 @@ let translate_decl nd sch =
   let new_locals, assert_instrs, nd_node_asserts = process_asserts nd in
 
   (* Build the env: variables visible in the current scope *)
-  let locals = nd.node_locals @ new_locals in
+  let locals = List.map fst nd.node_locals @ new_locals in
   (* let locals = VSet.of_list locals_list in *)
   (* let inout_vars = nd.node_inputs @ nd.node_outputs in *)
   let env = build_env nd.node_inputs locals nd.node_outputs in
@@ -655,10 +658,15 @@ let translate_decl nd sch =
           ])
       MClearReset
   in
+  let find_arrow v =
+    match List.assoc_opt v nd.node_locals with
+    | Some (Some x) -> IMap.find_opt x ctx.a
+    | _ -> None
+  in
   let mnode_spec = Utils.option_map (translate_spec env) nd.node_spec in
   {
     mname = nd;
-    mmemory = VSet.elements mems;
+    mmemory = VSet.fold (fun x xs -> (x, find_arrow x) :: xs) mems [];
     mcalls = mmap;
     minstances =
       List.filter (fun (_, (n, _)) -> not (Stateless.check_node n)) mmap;
diff --git a/src/machine_code_common.ml b/src/machine_code_common.ml
index f3d1a1c3..9ceeb9d6 100644
--- a/src/machine_code_common.ml
+++ b/src/machine_code_common.ml
@@ -7,7 +7,12 @@ open Format
 
 let print_statelocaltag = true
 
-let is_memory m id = List.exists (fun o -> o.var_id = id.var_id) m.mmemory
+let find_tainter_arrow m id =
+  List.find_opt (fun (x, _) -> x.var_id = id.var_id) m.mmemory
+  |> Option.map snd
+
+let is_memory m id =
+  Option.is_some (find_tainter_arrow m id)
 
 let is_reset_flag id = id.var_id = "_reset"
 
@@ -248,7 +253,7 @@ let get_node_def id m =
 
 (* merge log: machine_vars was in 44686 *)
 let machine_vars m =
-  m.mstep.step_inputs @ m.mstep.step_locals @ m.mstep.step_outputs @ m.mmemory
+  m.mstep.step_inputs @ m.mstep.step_locals @ m.mstep.step_outputs @ List.map fst m.mmemory
 
 let pp_step m fmt s =
   fprintf
@@ -327,7 +332,7 @@ let pp_machine fmt m =
      : %a@ step     :@   @[<v 2>%a@]@ spec     : @[<v>%t@ %a@ @ %a@]@ annot    \
      : @[%a@]@]@ "
     m.mname.node_id
-    (pp_comma_list Printers.pp_var)
+    (pp_comma_list (fun fmt (x, _) -> Printers.pp_var fmt x))
     m.mmemory
     (pp_comma_list pp_instance)
     m.minstances
@@ -423,7 +428,7 @@ let arrow_machine =
      reprendre le type des variables non ? *)
   {
     mname = Arrow.arrow_desc;
-    mmemory = [ var_state ];
+    mmemory = [ var_state, None ];
     mcalls = [];
     minstances = [];
     minit = [ mkinstr (MStateAssign (var_state, cst true)) ];
@@ -565,7 +570,7 @@ let get_const_assign m id =
 let value_of_ident loc m id =
   (* is is a state var *)
   try
-    let v = List.find (fun v -> v.var_id = id) m.mmemory in
+    let v, _ = List.find (fun (v, _) -> v.var_id = id) m.mmemory in
     mk_val (Var v) v.var_type
   with Not_found -> (
     try
diff --git a/src/machine_code_common.mli b/src/machine_code_common.mli
index b920f694..e6e07d35 100644
--- a/src/machine_code_common.mli
+++ b/src/machine_code_common.mli
@@ -4,6 +4,8 @@ open Machine_code_types
 
 val pp_val : machine_t -> Format.formatter -> value_t -> unit
 
+val find_tainter_arrow : machine_t -> var_decl -> ident option option
+
 val is_memory : machine_t -> var_decl -> bool
 
 val is_reset_flag : var_decl -> bool
diff --git a/src/machine_code_dep.ml b/src/machine_code_dep.ml
index 36d94768..b93760fb 100644
--- a/src/machine_code_dep.ml
+++ b/src/machine_code_dep.ml
@@ -69,4 +69,4 @@ let compute_unused_variables m =
        (* Format.printf "unused: %a@;coi of %s: %a@." ISet.pp unused x.var_id ISet.pp coi; *)
        ISet.diff unused coi)
     (List.fold_left (fun s v -> ISet.add v.var_id s) ISet.empty m.mstep.step_locals)
-    (m.mstep.step_outputs @ m.mmemory)
+    (m.mstep.step_outputs @ List.map fst m.mmemory)
diff --git a/src/machine_code_types.mli b/src/machine_code_types.mli
index 45736d90..d96d6fc8 100644
--- a/src/machine_code_types.mli
+++ b/src/machine_code_types.mli
@@ -71,7 +71,7 @@ type machine_spec = {
 
 type machine_t = {
   mname : node_desc;
-  mmemory : var_decl list;
+  mmemory : (var_decl * ident option) list;
   mcalls : (ident * static_call) list;
   (* map from stateful/stateless instance to node, no internals *)
   minstances : (ident * static_call) list;
diff --git a/src/normalization.ml b/src/normalization.ml
index e039d11f..a8ef1a02 100644
--- a/src/normalization.ml
+++ b/src/normalization.ml
@@ -732,7 +732,7 @@ let normalize_spec parentid (in_vars, out_vars, l_vars) s =
 *)
 let normalize_node ?(first=true) node =
   reset_cpt_fresh ();
-  let orig_vars = node.node_inputs @ node.node_outputs @ node.node_locals in
+  let orig_vars = node.node_inputs @ node.node_outputs @ List.map fst node.node_locals in
   let not_is_orig_var v = List.for_all (( != ) v) orig_vars in
   let norm_ctx =
     {
@@ -758,7 +758,7 @@ let normalize_node ?(first=true) node =
     | Some (Contract s) ->
       let new_locals, new_outs, new_stmts, s' =
         normalize_spec node.node_id
-          (node.node_inputs, node.node_outputs, node.node_locals)
+          (node.node_inputs, node.node_outputs, List.map fst node.node_locals)
           s
       in
       (* Format.eprintf "Normalization bounded new locals: %a@." Printers.pp_vars new_locals;
@@ -792,7 +792,7 @@ let normalize_node ?(first=true) node =
 
   (* we filter out inout
      vars and initial locals ones *)
-  let node_locals = node.node_locals @ new_locals in
+  let node_locals = node.node_locals @ List.map (fun v -> v, None) new_locals in
 
   (* we add again, at the
      beginning of the list the
@@ -808,7 +808,9 @@ let normalize_node ?(first=true) node =
   let new_annots =
     if !Options.traces then
       let diff_vars =
-        List.filter (fun v -> not (List.mem v node.node_locals)) node_locals
+        let node_locals' = List.map fst node_locals in
+        let node_node_locals' = List.map fst node.node_locals in
+        List.filter (fun v -> not (List.mem v node_node_locals')) node_locals'
       in
       let norm_traceability =
         {
diff --git a/src/optimize_machine.ml b/src/optimize_machine.ml
index da5a941f..9171eb51 100644
--- a/src/optimize_machine.ml
+++ b/src/optimize_machine.ml
@@ -738,7 +738,7 @@ let machine_cse subst machine =
   let assigned = assigns_instrs instrs VSet.empty in
   {
     machine with
-    mmemory = List.filter (fun vdecl -> VSet.mem vdecl assigned) machine.mmemory;
+    mmemory = List.filter (fun (v, _) -> VSet.mem v assigned) machine.mmemory;
     mstep =
       {
         machine.mstep with
@@ -1185,7 +1185,7 @@ let elim_prog_variables prog removed_table =
               (fun v (_, eq) (accu_locals, accu_defs) ->
                 let locals =
                   try
-                    List.find (fun v' -> v'.var_id = v) nd.node_locals
+                    List.find (fun v' -> v'.var_id = v) (List.map fst nd.node_locals)
                     :: accu_locals
                   with Not_found -> accu_locals
                   (* Variable v shall be a global constant, we do no need to
@@ -1212,7 +1212,7 @@ let elim_prog_variables prog removed_table =
                     when List.exists (fun v -> v.var_id = lhs) vars_to_replace
                     ->
                     (* We remove the def *)
-                    List.filter (fun v -> v.var_id <> lhs) locals, res_stmts
+                    List.filter (fun (v, _) -> v.var_id <> lhs) locals, res_stmts
                   | _ ->
                     (* When more than one lhs we just keep the equation and do
                        not delete it *)
diff --git a/src/parsers/parser_lustre.mly b/src/parsers/parser_lustre.mly
index 5038be55..588f4f19 100644
--- a/src/parsers/parser_lustre.mly
+++ b/src/parsers/parser_lustre.mly
@@ -28,13 +28,18 @@ let mkdim_appl_u loc f x = mkdim_appl loc f [x]
 
 let mkarraytype = List.fold_left (fun t d -> Tydec_array (d, t))
 
+let mkvdecl const typ clock expr (id, loc) =
+  mkvar_decl loc
+    (id,
+     mktyp loc (match typ with Some t -> t | None -> Tydec_any),
+     (match clock with Some ck -> ck | None -> mkclock loc Ckdec_any),
+     const, expr, None)
+
 let mkvdecls const typ clock expr =
-  List.map (fun (id, loc) ->
-      mkvar_decl loc
-        (id,
-         mktyp loc (match typ with Some t -> t | None -> Tydec_any),
-         (match clock with Some ck -> ck | None -> mkclock loc Ckdec_any),
-         const, expr, None))
+  List.map (mkvdecl const typ clock expr)
+
+let mkvdecls_locals const typ clock expr =
+  List.map (fun id_loc -> mkvdecl const typ clock expr id_loc, None)
 
 (* let mkannots annots = { annots = annots; annot_loc = get_loc () } *)
 
@@ -318,7 +323,7 @@ automaton:
 
 handler:
 | STATE x=UIDENT COL ul=unless* l=locals LET ss=stmt_list TEL ut=until*
-  { Automata.mkhandler $sloc x ul ut l ss }
+  { Automata.mkhandler $sloc x ul ut (List.map fst l) ss }
 
 unless:
 | UNLESS e=expr RESTART s=UIDENT { $sloc, e, true, s  }
@@ -577,12 +582,12 @@ vdecl:
 
 local_vdecl:
 | xs=ident_list /* Useless no ?*/
-  { mkvdecls false None None None xs }
+  { mkvdecls_locals false None None None xs }
 | xs=ident_list COL t=typeconst c=clock?
-  { mkvdecls false (Some t) c None xs }
+  { mkvdecls_locals false (Some t) c None xs }
 | CONST x=vdecl_ident t=preceded(COL, typeconst)? EQ e=expr
   /* static parameters don't have clocks */
-  { mkvdecls true t None (Some e) [x] }
+  { mkvdecls_locals true t None (Some e) [x] }
 
 cdecl:
 | x=const_ident EQ c=signed_const
diff --git a/src/pathConditions.ml b/src/pathConditions.ml
index 68d6de05..9720da97 100644
--- a/src/pathConditions.ml
+++ b/src/pathConditions.ml
@@ -370,7 +370,7 @@ let mcdc_top_decl td =
         Node
           {
             nd with
-            node_locals = nd.node_locals @ fresh_vars;
+            node_locals = nd.node_locals @ List.map (fun v -> v, None) fresh_vars;
             node_stmts = nd.node_stmts @ fresh_eqs;
             node_annot = nd.node_annot @ fresh_annots;
           };
diff --git a/src/plugins/mpfr/lustrec_mpfr.ml b/src/plugins/mpfr/lustrec_mpfr.ml
index 334886c5..ccb2c6d0 100644
--- a/src/plugins/mpfr/lustrec_mpfr.ml
+++ b/src/plugins/mpfr/lustrec_mpfr.ml
@@ -333,7 +333,7 @@ let inject_node node =
   let inputs_outputs = node.node_inputs @ node.node_outputs in
   let norm_ctx = node.node_id, get_node_vars node in
   let is_local v = List.for_all (( != ) v) inputs_outputs in
-  let orig_vars = inputs_outputs @ node.node_locals in
+  let orig_vars = inputs_outputs @ List.map fst node.node_locals in
   let defs, vars =
     let eqs, auts = get_node_eqs node in
     if auts != [] then assert false;
@@ -359,7 +359,7 @@ let inject_node node =
       (vars, [], [])
       node.node_asserts
   in
-  let new_locals = List.filter is_local vars in
+  let new_locals = List.filter_map (fun v -> if is_local v then Some (v, None) else None) vars in
   (* Compute traceability info: - gather newly bound variables - compute the
      associated expression without aliases *)
   (* let diff_vars = List.filter (fun v -> not (List.mem v node.node_locals))
diff --git a/src/plugins/scopes/scopes.ml b/src/plugins/scopes/scopes.ml
index 85693b13..be6743f8 100644
--- a/src/plugins/scopes/scopes.ml
+++ b/src/plugins/scopes/scopes.ml
@@ -19,9 +19,10 @@ let rec compute_scopes ?(first = true) prog root_node : scope_t list =
   (* Format.eprintf "Compute scope of %s@." main_node; *)
   try
     let node = get_node root_node prog in
-    let all_vars = node.node_inputs @ node.node_locals @ node.node_outputs in
+    let locals = List.map fst node.node_locals in
+    let all_vars = node.node_inputs @ locals @ node.node_outputs in
     let local_vars =
-      if first then node.node_locals else node.node_inputs @ node.node_locals
+      if first then locals else node.node_inputs @ locals
     in
     let local_scopes = List.map (fun x -> [], x) local_vars in
     let sub_scopes =
@@ -84,7 +85,7 @@ let get_node_vdecl_of_name name node =
   try
     List.find
       (fun v -> v.var_id = name)
-      (node.node_inputs @ node.node_outputs @ node.node_locals)
+      (node.node_inputs @ node.node_outputs @ List.map fst node.node_locals)
   with Not_found ->
     Format.eprintf "Cannot find variable %s in node %s@." name node.node_id;
     assert false
@@ -239,7 +240,7 @@ let update_machine main_node machine scopes =
     (if machine.mname.node_id = main_node then []
     else machine.mstep.step_inputs)
     (* @ machine.mstep.step_outputs *)
-    @ machine.mmemory
+    @ List.map fst machine.mmemory
     @ machine.mstep.step_locals
   in
   let selection =
@@ -258,7 +259,7 @@ let update_machine main_node machine scopes =
   in
   {
     machine with
-    mmemory = machine.mmemory @ List.map fst new_mems;
+    mmemory = machine.mmemory @ List.map (fun (v, _) -> v, None) new_mems;
     mstep =
       {
         machine.mstep with
@@ -279,7 +280,7 @@ let rec is_valid_path path nodename prog machines =
     let res =
       List.exists
         (fun v -> v.var_id = vid)
-        (m.mmemory @ m.mstep.step_inputs @ m.mstep.step_locals)
+        (List.map fst m.mmemory @ m.mstep.step_inputs @ m.mstep.step_locals)
     in
     (* if not res then *)
     (* Format.eprintf "Variable %s cannot be found in machine %s@.Local vars are
diff --git a/src/printers.ml b/src/printers.ml
index 24df7295..73ba93b3 100644
--- a/src/printers.ml
+++ b/src/printers.ml
@@ -612,7 +612,7 @@ let pp_node fmt nd =
         fprintf
           fmt
           "@[<v 4>var %a@]@ "
-          (pp_print_list (fun fmt v -> fprintf fmt "%a;" pp_node_var v))
+          (pp_print_list (fun fmt (v, _) -> fprintf fmt "%a;" pp_node_var v))
           locals)
     nd.node_locals;
   (* Checks *)
diff --git a/src/tools/stateflow/semantics/cPS_lustre_generator.ml b/src/tools/stateflow/semantics/cPS_lustre_generator.ml
index b5b9f5ec..e228aae7 100644
--- a/src/tools/stateflow/semantics/cPS_lustre_generator.ml
+++ b/src/tools/stateflow/semantics/cPS_lustre_generator.ml
@@ -397,7 +397,7 @@ end) : TransformerType = struct
              node_clock = Clocks.new_var true;
              node_inputs = inputs;
              node_outputs = outputs;
-             node_locals = mk_locals vars';
+             node_locals = List.map (fun v -> v, None) (mk_locals vars');
              (* TODO: add global vars *)
              node_gencalls = [];
              node_checks = [];
diff --git a/src/typing.ml b/src/typing.ml
index 71dc0883..96605223 100644
--- a/src/typing.ml
+++ b/src/typing.ml
@@ -916,16 +916,17 @@ struct
     (* Format.eprintf "Typing node %s@." nd.node_id; *)
     let is_main = nd.node_id = !Options.main_node in
     (* In contracts, outputs are considered as input values *)
+    let locals_vars = List.map fst nd.node_locals in
     let vd_env_ol =
-      if nd.node_iscontract then nd.node_locals
-      else nd.node_outputs @ nd.node_locals
+      if nd.node_iscontract then locals_vars
+      else nd.node_outputs @ locals_vars
     in
-    let vd_env = nd.node_inputs @ nd.node_outputs @ nd.node_locals in
+    let vd_env = nd.node_inputs @ nd.node_outputs @ locals_vars in
     check_vd_env vd_env;
     let init_env = env in
     let delta_env = type_var_decl_list vd_env init_env nd.node_inputs in
     let delta_env = type_var_decl_list vd_env delta_env nd.node_outputs in
-    let delta_env = type_var_decl_list vd_env delta_env nd.node_locals in
+    let delta_env = type_var_decl_list vd_env delta_env locals_vars in
     let new_env = Env.overwrite env delta_env in
     let undefined_vars_init =
       List.fold_left (fun uvs v -> ISet.add v.var_id uvs) ISet.empty vd_env_ol
@@ -964,7 +965,7 @@ struct
     (* check that table is empty *)
     let local_consts =
       List.fold_left
-        (fun res vdecl ->
+        (fun res (vdecl, _) ->
           if vdecl.var_dec_const then ISet.add vdecl.var_id res else res)
         ISet.empty
         nd.node_locals
diff --git a/src/utils/dimension.ml b/src/utils/dimension.ml
index 36e23a55..32b0f423 100644
--- a/src/utils/dimension.ml
+++ b/src/utils/dimension.ml
@@ -10,6 +10,7 @@
 (********************************************************************)
 
 open Format
+open Utils
 
 type t = { mutable dim_desc : dim_desc; dim_loc : Location.t; dim_id : int }
 
@@ -27,6 +28,17 @@ exception Unify of t * t
 
 exception InvalidDimension
 
+let fv d =
+  let open ISet in
+  let rec fv s d = match d.dim_desc with
+    | Dident x -> add x s
+    | Dappl (_, ds) -> List.fold_left fv s ds
+    | Dite (d1, d2, d3) -> fv (fv (fv s d1) d2) d3
+    | Dlink d -> fv s d
+    | _ -> s
+  in
+  fv ISet.empty d
+
 let new_id = ref (-1)
 
 let mkdim loc dim =
diff --git a/src/utils/dimension.mli b/src/utils/dimension.mli
index 3b66b13d..a8419e14 100644
--- a/src/utils/dimension.mli
+++ b/src/utils/dimension.mli
@@ -16,6 +16,8 @@ exception Unify of t * t
 
 exception InvalidDimension
 
+val fv : t -> ISet.t
+
 val mkdim : Location.t -> dim_desc -> t
 
 val mkdim_ident : Location.t -> ident -> t
-- 
GitLab