From 778918ad5157da7d2651b7d47584031d6b054794 Mon Sep 17 00:00:00 2001
From: Valentin Perrelle <valentin.perrelle@cea.fr>
Date: Mon, 1 Aug 2022 23:04:13 +0200
Subject: [PATCH] [kernel] export module type S of Logic_typing.Make
 application to enable first class modules usage

---
 .../ast_queries/logic_parse_string.ml         | 139 ++++++++----------
 .../ast_queries/logic_typing.ml               |  20 +++
 .../ast_queries/logic_typing.mli              |  94 ++++++------
 3 files changed, 133 insertions(+), 120 deletions(-)

diff --git a/src/kernel_services/ast_queries/logic_parse_string.ml b/src/kernel_services/ast_queries/logic_parse_string.ml
index 1b1308c18a1..9f5340c8e6d 100644
--- a/src/kernel_services/ast_queries/logic_parse_string.ml
+++ b/src/kernel_services/ast_queries/logic_parse_string.ml
@@ -70,69 +70,67 @@ let find_var kf kinstr ?label var =
 (** Create a logic typer, the interpretation being done for the given
     kernel_function and stmt (the stmt is used check that loop invariants
     are allowed). *)
-(* It is theoretically possible to use a first-class module instead, but the
-   required signatures are not exported in Logic_typing. *)
-module DefaultLT (X:
-                  sig
-                    val kf: Kernel_function.t
-                    val kinstr: Cil_types.kinstr
-                  end) =
-  Logic_typing.Make
-    (struct
-      let anonCompFieldName = Cabs2cil.anonCompFieldName
-      let conditionalConversion = Cabs2cil.logicConditionalConversion
-
-      let is_loop () =
-        match X.kinstr with
-        | Kglobal -> false
-        | Kstmt s -> Kernel_function.stmt_in_loop X.kf s
-
-      let find_macro _ = raise Not_found
-
-      let find_var ?label var = find_var X.kf X.kinstr ?label var
-
-      let find_enum_tag x =
-        try
-          Globals.Types.find_enum_tag x
-        with Not_found ->
-          (* The ACSL typer tries to parse a string, first as a variable,
-             then as an enum. We report the "Unbound variable" message
-             here, as it is nicer for the user. However, this short-circuits
-             the later stages of resolution, for example global logic
-             variables. *)
-          raise (Unbound ("Unbound variable " ^ x))
-
-      let find_comp_field info s =
-        let field = Cil.getCompField info s in
-        Field(field,NoOffset)
-
-      let find_type = Globals.Types.find_type
-
-      let find_label s = Kernel_function.find_label X.kf s
-      include Logic_env
-
-      let add_logic_function =
-        add_logic_function_gen Logic_utils.is_same_logic_profile
-
-      let remove_logic_info =
-        remove_logic_info_gen Logic_utils.is_same_logic_profile
-
-      let integral_cast ty t =
-        raise
-          (Failure
-             (Format.asprintf
-                "term %a has type %a, but %a is expected."
-                Printer.pp_term t
-                Printer.pp_logic_type Linteger
-                Printer.pp_typ ty))
-
-      let error loc msg =
-        Pretty_utils.ksfprintf (fun e -> raise (Error (loc, e))) msg
-
-      let on_error f rollback x =
-        try f x with Error (loc,msg) as exn -> rollback (loc,msg); raise exn
-
-    end)
+
+let default_typer kf kinstr =
+  let module LT = Logic_typing.Make
+      (struct
+        let anonCompFieldName = Cabs2cil.anonCompFieldName
+        let conditionalConversion = Cabs2cil.logicConditionalConversion
+
+        let is_loop () =
+          match kinstr with
+          | Kglobal -> false
+          | Kstmt s -> Kernel_function.stmt_in_loop kf s
+
+        let find_macro _ = raise Not_found
+
+        let find_var ?label var = find_var kf kinstr ?label var
+
+        let find_enum_tag x =
+          try
+            Globals.Types.find_enum_tag x
+          with Not_found ->
+            (* The ACSL typer tries to parse a string, first as a variable,
+               then as an enum. We report the "Unbound variable" message
+               here, as it is nicer for the user. However, this short-circuits
+               the later stages of resolution, for example global logic
+               variables. *)
+            raise (Unbound ("Unbound variable " ^ x))
+
+        let find_comp_field info s =
+          let field = Cil.getCompField info s in
+          Field(field,NoOffset)
+
+        let find_type = Globals.Types.find_type
+
+        let find_label s = Kernel_function.find_label kf s
+        include Logic_env
+
+        let add_logic_function =
+          add_logic_function_gen Logic_utils.is_same_logic_profile
+
+        let remove_logic_info =
+          remove_logic_info_gen Logic_utils.is_same_logic_profile
+
+        let integral_cast ty t =
+          raise
+            (Failure
+               (Format.asprintf
+                  "term %a has type %a, but %a is expected."
+                  Printer.pp_term t
+                  Printer.pp_logic_type Linteger
+                  Printer.pp_typ ty))
+
+        let error loc msg =
+          Pretty_utils.ksfprintf (fun e -> raise (Error (loc, e))) msg
+
+        let on_error f rollback x =
+          try f x with Error (loc,msg) as exn -> rollback (loc,msg); raise exn
+
+      end)
+  in
+  (module LT : Logic_typing.S)
+
 
 (** Set up the parser for the infamous 'C hack' needed to parse typedefs *)
 let sync_typedefs () =
@@ -148,10 +146,7 @@ let wrap f parsetree loc =
 
 let code_annot kf stmt s =
   sync_typedefs ();
-  let module LT = DefaultLT(struct
-      let kf = kf
-      let kinstr = Kstmt stmt
-    end) in
+  let module LT = (val default_typer kf (Kstmt stmt) : Logic_typing.S) in
   let loc = Stmt.loc stmt in
   let pa =
     Option.bind
@@ -171,10 +166,7 @@ let default_term_env () =
 
 let term kf ?(loc=Location.unknown) ?(env=default_term_env ()) s =
   sync_typedefs ();
-  let module LT = DefaultLT(struct
-      let kf = kf
-      let kinstr = Kglobal
-    end) in
+  let module LT = (val default_typer kf Kglobal : Logic_typing.S) in
   let pa_expr = Option.map snd (Logic_lexer.lexpr (fst loc, s)) in
   let parse pa_expr = LT.term env pa_expr in
   wrap parse pa_expr loc
@@ -186,10 +178,7 @@ let term_lval kf ?(loc=Location.unknown) ?(env=default_term_env ()) s =
 
 let predicate kf ?(loc=Location.unknown) ?(env=default_term_env ()) s =
   sync_typedefs ();
-  let module LT = DefaultLT(struct
-      let kf = kf
-      let kinstr = Kglobal
-    end) in
+  let module LT = (val default_typer kf Kglobal : Logic_typing.S) in
   let pa_expr = Option.map snd (Logic_lexer.lexpr (fst loc, s)) in
   let parse pa_expr = LT.predicate env pa_expr in
   wrap parse pa_expr loc
diff --git a/src/kernel_services/ast_queries/logic_typing.ml b/src/kernel_services/ast_queries/logic_typing.ml
index cdc7e48ad02..9de89b3bbd5 100644
--- a/src/kernel_services/ast_queries/logic_typing.ml
+++ b/src/kernel_services/ast_queries/logic_typing.ml
@@ -625,6 +625,26 @@ let is_plain_pointer_type t =
 let is_array_type = plain_or_set is_plain_array_type
 let is_pointer_type = plain_or_set is_plain_pointer_type
 
+module type S =
+sig
+  val type_of_field:
+    location -> string -> Cil_types.logic_type ->
+    (term_offset * Cil_types.logic_type)
+  val mk_cast:
+    ?explicit:bool -> Cil_types.term -> Cil_types.logic_type -> Cil_types.term
+  val term : Lenv.t -> Logic_ptree.lexpr -> term
+  val predicate : Lenv.t -> Logic_ptree.lexpr -> predicate
+  val code_annot :
+    Cil_types.location -> string list ->
+    Cil_types.logic_type -> Logic_ptree.code_annot -> code_annotation
+  val type_annot : location -> Logic_ptree.type_annot -> logic_info
+  val model_annot : location -> Logic_ptree.model_annot -> model_info
+  val annot : Logic_ptree.decl -> global_annotation
+  val funspec :
+    string list ->
+    varinfo -> (varinfo list) option -> typ -> Logic_ptree.spec -> funspec
+end
+
 module Make
     (C:
      sig
diff --git a/src/kernel_services/ast_queries/logic_typing.mli b/src/kernel_services/ast_queries/logic_typing.mli
index ef8c2d3c9ff..a9ee8eed4a1 100644
--- a/src/kernel_services/ast_queries/logic_typing.mli
+++ b/src/kernel_services/ast_queries/logic_typing.mli
@@ -147,52 +147,8 @@ type typing_context = {
   *)
 }
 
-module Make
-    (C :
-     sig
-       val is_loop: unit -> bool
-       (** whether the annotation we want to type is contained in a loop.
-           Only useful when creating objects of type [code_annotation]. *)
-
-       val anonCompFieldName : string
-       val conditionalConversion : typ -> typ -> typ
-       val find_macro : string -> Logic_ptree.lexpr
-       val find_var : ?label:string -> string -> logic_var
-       (** see corresponding field in {!Logic_typing.typing_context}. *)
-
-       val find_enum_tag : string -> exp * typ
-       val find_type : type_namespace -> string -> typ
-       val find_comp_field: compinfo -> string -> offset
-       val find_label : string -> stmt ref
-
-       val remove_logic_function : string -> unit
-       val remove_logic_info: logic_info -> unit
-       val remove_logic_type: string -> unit
-       val remove_logic_ctor: string -> unit
-
-       val add_logic_function: logic_info -> unit
-       val add_logic_type: string -> logic_type_info -> unit
-       val add_logic_ctor: string -> logic_ctor_info -> unit
-
-       val find_all_logic_functions : string -> Cil_types.logic_info list
-       val find_logic_type: string -> logic_type_info
-       val find_logic_ctor: string -> logic_ctor_info
 
-       (** What to do when we have a term of type Integer in a context
-           expecting a C integral type.
-           @raise Failure to reject such conversion
-           @since Nitrogen-20111001
-       *)
-       val integral_cast: Cil_types.typ -> Cil_types.term -> Cil_types.term
-
-       (** raises an error at the given location and with the given message.
-           @since Magnesium-20151001 *)
-       val error: location -> ('a,Format.formatter,unit, 'b) format4 -> 'a
-
-       (** see {!Logic_typing.typing_context}. *)
-       val on_error: ('a -> 'b) -> ((location * string) -> unit) -> 'a -> 'b
-
-     end) :
+module type S =
 sig
 
   (** @since Nitrogen-20111001 *)
@@ -245,6 +201,54 @@ sig
 
 end
 
+module Make
+    (C :
+     sig
+       val is_loop: unit -> bool
+       (** whether the annotation we want to type is contained in a loop.
+           Only useful when creating objects of type [code_annotation]. *)
+
+       val anonCompFieldName : string
+       val conditionalConversion : typ -> typ -> typ
+       val find_macro : string -> Logic_ptree.lexpr
+       val find_var : ?label:string -> string -> logic_var
+       (** see corresponding field in {!Logic_typing.typing_context}. *)
+
+       val find_enum_tag : string -> exp * typ
+       val find_type : type_namespace -> string -> typ
+       val find_comp_field: compinfo -> string -> offset
+       val find_label : string -> stmt ref
+
+       val remove_logic_function : string -> unit
+       val remove_logic_info: logic_info -> unit
+       val remove_logic_type: string -> unit
+       val remove_logic_ctor: string -> unit
+
+       val add_logic_function: logic_info -> unit
+       val add_logic_type: string -> logic_type_info -> unit
+       val add_logic_ctor: string -> logic_ctor_info -> unit
+
+       val find_all_logic_functions : string -> Cil_types.logic_info list
+       val find_logic_type: string -> logic_type_info
+       val find_logic_ctor: string -> logic_ctor_info
+
+       (** What to do when we have a term of type Integer in a context
+           expecting a C integral type.
+           @raise Failure to reject such conversion
+           @since Nitrogen-20111001
+       *)
+       val integral_cast: Cil_types.typ -> Cil_types.term -> Cil_types.term
+
+       (** raises an error at the given location and with the given message.
+           @since Magnesium-20151001 *)
+       val error: location -> ('a,Format.formatter,unit, 'b) format4 -> 'a
+
+       (** see {!Logic_typing.typing_context}. *)
+       val on_error: ('a -> 'b) -> ((location * string) -> unit) -> 'a -> 'b
+
+     end) : S
+
+
 (** append the Old and Post labels in the environment *)
 val append_old_and_post_labels: Lenv.t -> Lenv.t
 
-- 
GitLab