From a2a09b382ee24cbc6c9a51993550384aa1b2ba26 Mon Sep 17 00:00:00 2001
From: Allan Blanchard <allan.blanchard@cea.fr>
Date: Wed, 29 Mar 2023 10:28:34 +0200
Subject: [PATCH] [wp] fix polymorphic definitions compilation - LogicCompiler:
 make sure that return type is computed in the frame - Lang: tau_of_return ->
 tau_of_li_type

---
 src/plugins/wp/Lang.ml                        |  6 +-
 src/plugins/wp/Lang.mli                       |  2 +-
 src/plugins/wp/LogicCompiler.ml               | 89 ++++++++++---------
 .../wp/tests/wp_acsl/oracle/poly.res.oracle   | 61 +++++++++++++
 .../wp_acsl/oracle_qualif/poly.res.oracle     | 25 ++++++
 src/plugins/wp/tests/wp_acsl/poly.c           | 59 ++++++++++++
 6 files changed, 198 insertions(+), 44 deletions(-)
 create mode 100644 src/plugins/wp/tests/wp_acsl/oracle/poly.res.oracle
 create mode 100644 src/plugins/wp/tests/wp_acsl/oracle_qualif/poly.res.oracle
 create mode 100644 src/plugins/wp/tests/wp_acsl/poly.c

diff --git a/src/plugins/wp/Lang.ml b/src/plugins/wp/Lang.ml
index c647b8120ca..91272859fed 100644
--- a/src/plugins/wp/Lang.ml
+++ b/src/plugins/wp/Lang.ml
@@ -225,8 +225,8 @@ let rec tau_of_ltype t =
   | Ltype _ as b when Logic_const.is_boolean_type b -> Logic.Bool
   | Ltype(lt,lts) -> atype lt (List.map tau_of_ltype lts)
 
-let tau_of_return l =
-  match l.l_type with
+let tau_of_li_type ltype =
+  match ltype with
   | None -> Logic.Prop
   | Some t -> tau_of_ltype t
 
@@ -420,7 +420,7 @@ and source =
 
 let tau_of_lfun phi ts =
   match phi with
-  | ACSL f -> tau_of_return f
+  | ACSL f -> tau_of_li_type f.l_type
   | CTOR c ->
     if c.ctor_type.lt_params = [] then Logic.Data(Atype c.ctor_type,[])
     else raise Not_found
diff --git a/src/plugins/wp/Lang.mli b/src/plugins/wp/Lang.mli
index f39c4ae1d63..4c196d1fa5e 100644
--- a/src/plugins/wp/Lang.mli
+++ b/src/plugins/wp/Lang.mli
@@ -158,7 +158,7 @@ val extern_t:
 val tau_of_object : c_object -> tau
 val tau_of_ctype : typ -> tau
 val tau_of_ltype : logic_type -> tau
-val tau_of_return : logic_info -> tau
+val tau_of_li_type : logic_type option -> tau
 val tau_of_lfun : lfun -> tau option list -> tau
 val tau_of_field : field -> tau
 val tau_of_record : field -> tau
diff --git a/src/plugins/wp/LogicCompiler.ml b/src/plugins/wp/LogicCompiler.ml
index 72eaba5ea25..34148ea3695 100644
--- a/src/plugins/wp/LogicCompiler.ml
+++ b/src/plugins/wp/LogicCompiler.ml
@@ -428,6 +428,7 @@ struct
   let occurs_ps x ps = List.exists (F.occursp x) ps
 
   let compile_step
+      (tres: logic_type option)
       (name:string)
       (types:string list)
       (profile:logic_var list)
@@ -435,10 +436,11 @@ struct
       (cc : env -> 'a -> 'b)
       (filter : 'b -> var -> bool)
       (data : 'a)
-    : var list * trigger list * pred list * 'b * sig_param list =
+    : tau * var list * trigger list * pred list * 'b * sig_param list =
     let frame = logic_frame name types in
     in_frame frame
       begin fun () ->
+        let tres = Lang.tau_of_li_type tres in
         let env,domain,sigv = profile_env Logic_var.Map.empty [] [] profile in
         let env = default_label env labels in
         let result = cc env data in
@@ -464,7 +466,7 @@ struct
                  (Sigma.domain sigma) acc)
             frame.labels (parp,sigp)
         in
-        parm , frame.triggers , domain , result , sigm
+        tres, parm , frame.triggers , domain , result , sigm
       end ()
 
   let cc_term : (env -> Cil_types.term -> term) ref
@@ -505,9 +507,9 @@ struct
 
   let compile_lemma cluster name ~kind types labels lemma =
     let qs,prop = strip_forall [] lemma in
-    let xs,tgs,domain,prop,_ =
+    let _,xs,tgs,domain,prop,_ =
       let cc_pred = pred `Positive in
-      compile_step name types qs labels cc_pred in_pred prop in
+      compile_step None name types qs labels cc_pred in_pred prop in
     let weak = Wp_parameters.WeakIntModel.get () in
     let lemma = if weak then prop else F.p_hyps domain prop in
     {
@@ -557,37 +559,45 @@ struct
   (* -------------------------------------------------------------------------- *)
 
   let compile_lbpure cluster l =
-    let lfun = ACSL l in
-    let tau = Lang.tau_of_return l in
-    let parp,sigp = Lang.local profile_sig l.l_profile in
-    let ldef = {
-      d_lfun = lfun ;
-      d_types = List.length l.l_tparams ;
-      d_params = parp ;
-      d_cluster = cluster ;
-      d_definition = Logic tau ;
-    } in
-    Definitions.update_symbol ldef ;
-    Signature.update l (SIG sigp) ;
-    parp,sigp
+    let frame = logic_frame l.l_var_info.lv_name l.l_tparams in
+    in_frame frame
+      begin fun () ->
+        let lfun = ACSL l in
+        let tau = Lang.tau_of_li_type l.l_type in
+        let parp,sigp = Lang.local profile_sig l.l_profile in
+        let ldef = {
+          d_lfun = lfun ;
+          d_types = List.length l.l_tparams ;
+          d_params = parp ;
+          d_cluster = cluster ;
+          d_definition = Logic tau ;
+        } in
+        Definitions.update_symbol ldef ;
+        Signature.update l (SIG sigp) ;
+        parp,sigp
+      end ()
 
   (* -------------------------------------------------------------------------- *)
   (* --- Compiling Abstract Logic Function (in axiomatic with no reads)     --- *)
   (* -------------------------------------------------------------------------- *)
 
   let compile_lbnone cluster l vars =
-    let lfun = ACSL l in
-    let tau = Lang.tau_of_return l in
-    let parm,sigm = Lang.local (profile_mem l) vars in
-    let ldef = {
-      d_lfun = lfun ;
-      d_types = List.length l.l_tparams ;
-      d_params = parm ;
-      d_cluster = cluster ;
-      d_definition = Logic tau ;
-    } in
-    Definitions.define_symbol ldef ;
-    type_for_signature l ldef sigm ; SIG sigm
+    let frame = logic_frame l.l_var_info.lv_name l.l_tparams in
+    in_frame frame
+      begin fun () ->
+        let lfun = ACSL l in
+        let tau = Lang.tau_of_li_type l.l_type in
+        let parm,sigm = Lang.local (profile_mem l) vars in
+        let ldef = {
+          d_lfun = lfun ;
+          d_types = List.length l.l_tparams ;
+          d_params = parm ;
+          d_cluster = cluster ;
+          d_definition = Logic tau ;
+        } in
+        Definitions.define_symbol ldef ;
+        type_for_signature l ldef sigm ; SIG sigm
+      end ()
 
   (* -------------------------------------------------------------------------- *)
   (* --- Compiling Logic Function with Reads                                --- *)
@@ -596,9 +606,8 @@ struct
   let compile_lbreads cluster l ts =
     let lfun = ACSL l in
     let name = l.l_var_info.lv_name in
-    let tau = Lang.tau_of_return l in
-    let xs,_,_,(),s =
-      compile_step name l.l_tparams l.l_profile l.l_labels
+    let tau,xs,_,_,(),s =
+      compile_step l.l_type name l.l_tparams l.l_profile l.l_labels
         reads in_reads ts
     in
     let ldef = {
@@ -616,15 +625,16 @@ struct
   (* -------------------------------------------------------------------------- *)
 
   let compile_rec name l cc filter data =
+    let tau = l.l_type in
     let types = l.l_tparams in
     let profile = l.l_profile in
     let labels = l.l_labels in
-    let result = compile_step name types profile labels cc filter data in
+    let result = compile_step tau name types profile labels cc filter data in
     if LogicUsage.is_recursive l then
       begin
-        let (_,_,_,_,s) = result in
+        let (_,_,_,_,_,s) = result in
         Signature.update l (SIG s) ;
-        compile_step name types profile labels cc filter data
+        compile_step tau name types profile labels cc filter data
       end
     else result
 
@@ -634,8 +644,7 @@ struct
 
   let compile_lbterm cluster l t =
     let name = l.l_var_info.lv_name in
-    let tau = Lang.tau_of_return l in
-    let xs,_,_,r,s = compile_rec name l term in_term t in
+    let tau,xs,_,_,r,s = compile_rec name l term in_term t in
     match F.repr r with
     | Qed.Logic.Kint c -> CST c
     | _ ->
@@ -657,7 +666,7 @@ struct
     let lfun = ACSL l in
     let name = l.l_var_info.lv_name in
     let cc_pred = pred `Positive in
-    let xs,_,_,r,s = compile_rec name l cc_pred in_pred p in
+    let _,xs,_,_,r,s = compile_rec name l cc_pred in_pred p in
     let ldef = {
       d_lfun = lfun ;
       d_types = List.length l.l_tparams ;
@@ -690,9 +699,9 @@ struct
     (* Compile cases with default definition and collect used chunks *)
     let support = List.fold_left
         (fun support (case,labels,types,lemma) ->
-           let _,_,_,_,s =
+           let _,_,_,_,_,s =
              let cc_pred = pred `Positive in
-             compile_step case types [] labels cc_pred in_pred lemma in
+             compile_step l.l_type case types [] labels cc_pred in_pred lemma in
            let labels_used = LogicUsage.get_induction_labels l case in
            List.fold_left (heap_case labels_used) support s)
         Heap.Map.empty cases in
diff --git a/src/plugins/wp/tests/wp_acsl/oracle/poly.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle/poly.res.oracle
new file mode 100644
index 00000000000..57483d894cb
--- /dev/null
+++ b/src/plugins/wp/tests/wp_acsl/oracle/poly.res.oracle
@@ -0,0 +1,61 @@
+# frama-c -wp [...]
+[kernel] Parsing poly.c (with preprocessing)
+[wp] Running WP plugin...
+[wp] Warning: Missing RTE guards
+------------------------------------------------------------
+  Global
+------------------------------------------------------------
+
+Lemma test2_ko:
+Prove: (L_x_bar i_0 s_0)!=(concat (elt i_0) s_0)
+
+------------------------------------------------------------
+
+Lemma test2_ok:
+Prove: (L_x_bar i_0 s_0)=(concat (elt i_0) s_0)
+
+------------------------------------------------------------
+
+Lemma test_ko:
+Prove: (L_bar i_0 s_0)!=(concat (elt i_0) s_0)
+
+------------------------------------------------------------
+
+Lemma test_ok:
+Prove: (L_bar i_0 s_0)=(concat (elt i_0) s_0)
+
+------------------------------------------------------------
+
+Lemma testp2_ko:
+Prove: (L_x_foo a_0 s_0)!=(concat (elt a_0) s_0)
+
+------------------------------------------------------------
+
+Lemma testp2_ok:
+Prove: (L_x_foo a_0 s_0)=(concat (elt a_0) s_0)
+
+------------------------------------------------------------
+
+Lemma testp_ko:
+Prove: (L_foo a_0 s_0)!=(concat (elt a_0) s_0)
+
+------------------------------------------------------------
+
+Lemma testp_ok:
+Prove: (L_foo a_0 s_0)=(concat (elt a_0) s_0)
+
+------------------------------------------------------------
+------------------------------------------------------------
+  Function main
+------------------------------------------------------------
+
+Goal Assertion (file poly.c, line 57):
+Prove: P_P(1, [ 1 ]).
+
+------------------------------------------------------------
+
+Goal Assertion (file poly.c, line 58):
+Assume { (* Assertion *) Have: P_P(1, [ 1 ]). }
+Prove: P_Y(1, [ 1 ]).
+
+------------------------------------------------------------
diff --git a/src/plugins/wp/tests/wp_acsl/oracle_qualif/poly.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle_qualif/poly.res.oracle
new file mode 100644
index 00000000000..a807b4a2348
--- /dev/null
+++ b/src/plugins/wp/tests/wp_acsl/oracle_qualif/poly.res.oracle
@@ -0,0 +1,25 @@
+# frama-c -wp [...]
+[kernel] Parsing poly.c (with preprocessing)
+[wp] Running WP plugin...
+[wp] Warning: Missing RTE guards
+[wp] 10 goals scheduled
+[wp] [Unsuccess] typed_check_lemma_test2_ko (Alt-Ergo) (Cached)
+[wp] [Valid] typed_check_lemma_test2_ok (Alt-Ergo) (Cached)
+[wp] [Unsuccess] typed_check_lemma_test_ko (Alt-Ergo) (Cached)
+[wp] [Valid] typed_check_lemma_test_ok (Alt-Ergo) (Cached)
+[wp] [Unsuccess] typed_check_lemma_testp2_ko (Alt-Ergo) (Cached)
+[wp] [Valid] typed_check_lemma_testp2_ok (Alt-Ergo) (Cached)
+[wp] [Unsuccess] typed_check_lemma_testp_ko (Alt-Ergo) (Cached)
+[wp] [Valid] typed_check_lemma_testp_ok (Alt-Ergo) (Cached)
+[wp] [Unsuccess] typed_main_assert (Alt-Ergo) (Cached)
+[wp] [Valid] typed_main_assert_2 (Alt-Ergo) (Cached)
+[wp] Proved goals:    5 / 10
+  Alt-Ergo:        5
+  Unsuccess:       5
+------------------------------------------------------------
+ Axiomatics                WP     Alt-Ergo  Total   Success
+  Lemma                     -        4        8      50.0%
+------------------------------------------------------------
+ Functions                 WP     Alt-Ergo  Total   Success
+  main                      -        1        2      50.0%
+------------------------------------------------------------
diff --git a/src/plugins/wp/tests/wp_acsl/poly.c b/src/plugins/wp/tests/wp_acsl/poly.c
new file mode 100644
index 00000000000..9ab4bf54c90
--- /dev/null
+++ b/src/plugins/wp/tests/wp_acsl/poly.c
@@ -0,0 +1,59 @@
+/*@ logic \list<A> foo<A> (A i, \list<A> s) = \Cons (i, s);
+
+    logic \list<integer> bar (integer i, \list<integer> s) =
+      foo(i, s);
+
+    check lemma test_ok: \forall integer i; \forall \list<integer> s;
+      bar (i, s) == \Cons (i, s);
+
+    check lemma test_ko: \forall integer i; \forall \list<integer> s;
+      bar (i, s) != \Cons (i, s);
+
+    check lemma testp_ok <A>: \forall A a; \forall \list<A> s;
+      foo (a, s) == \Cons (a, s);
+
+    check lemma testp_ko <A>: \forall A a; \forall \list<A> s;
+      foo (a, s) != \Cons (a, s);
+*/
+
+/*@ axiomatic X {
+      logic \list<A> x_foo<A>(A i, \list<A> s) reads \nothing ;
+      logic \list<integer> x_bar (integer i, \list<integer> s) reads \nothing ;
+
+      axiom x_foo_value<A>:
+        \forall A i, \list<A> s ;
+          x_foo(i, s) == \Cons(i, s) ;
+
+      axiom x_bar_value:
+        \forall integer i, \list<integer> s ;
+          x_bar(i, s) == x_foo(i, s) ;
+    }
+
+   check lemma test2_ok: \forall integer i; \forall \list<integer> s;
+      x_bar (i, s) == \Cons (i, s);
+
+    check lemma test2_ko: \forall integer i; \forall \list<integer> s;
+      x_bar (i, s) != \Cons (i, s);
+
+    check lemma testp2_ok <A>: \forall A a; \forall \list<A> s;
+      x_foo (a, s) == \Cons (a, s);
+
+    check lemma testp2_ko <A>: \forall A a; \forall \list<A> s;
+      x_foo (a, s) != \Cons (a, s);
+*/
+
+/*@ inductive P<A>(A i, \list<A> s){
+    case one<B>:
+      \forall B b, \list<B> s ; \Cons(b, s) == [| b |] ==> P(b, s);
+    }
+*/
+
+/*@ axiomatic Y {
+      predicate Y<A>(A i, \list<A> s);
+    }
+*/
+
+int main(void){
+  //@ assert P(1, [| 1 |]) ;
+  //@ assert Y(1, [| 1 |]) ;
+}
-- 
GitLab