diff --git a/src/plugins/e-acsl/src/analyses/analyses_datatype.ml b/src/plugins/e-acsl/src/analyses/analyses_datatype.ml index ff6fc08f5e8d05749968825aaf6463db4c5df880..b8bbaba9d265107e15c83e773c664ffa7a4cba63 100644 --- a/src/plugins/e-acsl/src/analyses/analyses_datatype.ml +++ b/src/plugins/e-acsl/src/analyses/analyses_datatype.ml @@ -420,6 +420,9 @@ module LF_env let add li profile ival = LFProf.Hashtbl.add tbl (li,profile) ival + let add_pred li profile = LFProf.Hashtbl.add tbl (li,profile) + (Ival Ival.zero_or_one) + exception Recursive let contain li = object diff --git a/src/plugins/e-acsl/src/analyses/analyses_datatype.mli b/src/plugins/e-acsl/src/analyses/analyses_datatype.mli index 9cafe69c93a70301e49ffe2d73ccf84a3d6120c4..302d05c2656634b1096d1a4aa2b47c4e9011123b 100644 --- a/src/plugins/e-acsl/src/analyses/analyses_datatype.mli +++ b/src/plugins/e-acsl/src/analyses/analyses_datatype.mli @@ -111,6 +111,8 @@ module LF_env : sig val add : logic_info -> Profile.t -> ival -> unit + val add_pred : logic_info -> Profile.t -> unit + val is_rec : logic_info -> bool val replace : logic_info -> Profile.t -> ival -> unit diff --git a/src/plugins/e-acsl/src/analyses/interval.ml b/src/plugins/e-acsl/src/analyses/interval.ml index 833d84ed21d5755e1b3763d8da9ac37b62d9d232..f2937821bc68e16241c86164a9964f1a9e12c215 100644 --- a/src/plugins/e-acsl/src/analyses/interval.ml +++ b/src/plugins/e-acsl/src/analyses/interval.ml @@ -739,28 +739,36 @@ let rec infer ~force ~logic_env t = (fun arg -> get_res (infer ~force ~logic_env arg)) args) in - (match li.l_body with - | LBpred p -> - let logic_env = Logic_env.make profile in - ignore (infer_predicate ~logic_env p); - Ival Ival.zero_or_one - | LBterm t' when LF_env.is_rec li -> - let widened_profile = widen_profile profile in - Widened_profile.add profile li widened_profile; - (try LF_env.find li widened_profile - with Not_found -> - fixpoint ~infer li widened_profile t' (Ival Ival.bottom)) - | LBterm t' -> - let logic_env = Logic_env.make profile in - (* If the logic function returns a C type, then its application - ranges inside this C type *) - (match li.l_type with - | Some (Ctype typ) -> - ignore ((infer ~force ~logic_env t')); - interv_of_typ typ; - | None | Some (Linteger | Lreal | Ltype _ | Lvar _ | Larrow _) -> - get_res (infer ~force ~logic_env t')) - | _ -> assert false) + if LF_env.is_rec li then + let widened_profile = widen_profile profile in + Widened_profile.add profile li widened_profile; + (match li.l_body with + | LBpred p -> + LF_env.add_pred li widened_profile; + infer_predicate + ~logic_env:(Logic_env.make widened_profile) p; + Ival Ival.zero_or_one + | LBterm t' -> + (try LF_env.find li widened_profile + with Not_found -> + fixpoint ~infer li widened_profile t' (Ival Ival.bottom)) + | _ -> assert false) + else + let logic_env = Logic_env.make profile in + (match li.l_body with + | LBpred p -> + ignore (infer_predicate ~logic_env p); + Ival Ival.zero_or_one + | LBterm t' -> + (* If the logic function returns a C type, then its application + ranges inside this C type *) + (match li.l_type with + | Some (Ctype typ) -> + ignore ((infer ~force ~logic_env t')); + interv_of_typ typ; + | None | Some (Linteger | Lreal | Ltype _ | Lvar _ | Larrow _) -> + get_res (infer ~force ~logic_env t')) + | _ -> assert false) | LBnone when li.l_var_info.lv_name = "\\sum" || li.l_var_info.lv_name = "\\product" -> (match args with @@ -1011,15 +1019,22 @@ and infer_predicate ~logic_env p = match p.pred_content with | Pfalse | Ptrue -> () | Papp(li, _, args) -> + let profile = + Profile.make + li.l_profile + (List.map + (fun arg -> get_res (infer ~force:false ~logic_env arg)) + args) + in (match li.l_body with + | LBpred p when LF_env.is_rec li -> + let widened_profile = widen_profile profile in + Widened_profile.add profile li widened_profile; + (try ignore (LF_env.find li widened_profile) + with Not_found -> + LF_env.add_pred li widened_profile; + infer_predicate ~logic_env:(Logic_env.make widened_profile) p) | LBpred p -> - let profile = - Profile.make - li.l_profile - (List.map - (fun arg -> get_res (infer ~force:false ~logic_env arg)) - args) - in let logic_env = Logic_env.make profile in ignore (infer_predicate ~logic_env p) | LBnone -> () diff --git a/src/plugins/e-acsl/src/analyses/typing.ml b/src/plugins/e-acsl/src/analyses/typing.ml index 88a168eb010bc49502d7fa635c930a9e3f5092fa..523a4eb5ca11bc61727d914b181166d2eea54322 100644 --- a/src/plugins/e-acsl/src/analyses/typing.ml +++ b/src/plugins/e-acsl/src/analyses/typing.ml @@ -208,6 +208,19 @@ end = struct end +module Recursive_pred : sig + val add: Profile.t -> logic_info -> unit + val is_done: Profile.t -> logic_info -> bool +end = struct + let known = ref LFProf.Set.empty + + let add profile li = + known := LFProf.Set.add (li, profile) !known + + let is_done profile li = LFProf.Set.mem (li, profile) !known + +end + (******************************************************************************) (** {2 Coercion rules} *) (******************************************************************************) @@ -558,6 +571,7 @@ let rec type_term li.l_profile (List.map (Interval.get_from_profile ~profile) args) in + let new_profile = Interval.get_widened_profile new_profile li in Stack.push (fun () -> ignore (type_predicate ~profile:new_profile p)) @@ -768,15 +782,20 @@ and type_predicate ~profile p = begin match li.l_body with | LBpred p -> - List.iter - (fun x -> ignore (type_term ~use_gmp_opt: true ~profile x)) - args; - let new_profile = - Profile.make - li.l_profile - (List.map (Interval.get_from_profile ~profile) args) - in - type_predicate ~profile:new_profile p; + List.iter + (fun x -> ignore (type_term ~use_gmp_opt: true ~profile x)) + args; + let new_profile = + Profile.make + li.l_profile + (List.map (Interval.get_from_profile ~profile) args) + in + let new_profile = Interval.get_widened_profile new_profile li in + if Recursive_pred.is_done new_profile li + then () + else + (Recursive_pred.add new_profile li; + ignore (type_predicate ~profile:new_profile p)) | LBnone -> () | LBreads _ -> () | LBinductive _ -> ()