@@ -83,10 +83,80 @@ let datatype_ind_path (mode : indmode) (p : EcPath.path) =
8383 EcPath. pqoname (EcPath. prefix p) name
8484
8585(* -------------------------------------------------------------------- *)
86- exception NonPositive
87-
88- let indsc_of_datatype ?normty (mode : indmode ) (dt : datatype ) =
89- let normty = odfl (identity : ty -> ty ) normty in
86+ exception NonPositive of ty
87+ exception NonPositiveAbstract of EcPath. path
88+ exception NonPositiveParams of ty
89+
90+ (* * below, [fct] designates the function that takes a path to a type constructor
91+ and returns the corresponding type declaration *)
92+ (* * Strict positivity enforces the following, for every variant of the datatype p:
93+ - for each subterm (a → b), p ∉ fv(a);
94+ - inductive occurences a₁ a₂ .. aₙ p are such that ∀i. p ∉ fv(aᵢ) *)
95+
96+ let rec occurs ?(normty = identity) p t =
97+ match (normty t).ty_node with
98+ | Tconstr (p' , _ ) when EcPath. p_equal p p' -> true
99+ | _ -> EcTypes. ty_sub_exists (occurs p) t
100+
101+ let ty_params_compat =
102+ List. for_all2 (fun ty (param_id , _ ) ->
103+ match ty.ty_node with
104+ | Tvar id -> EcIdent. id_equal id param_id
105+ | _ -> false )
106+
107+ let rec check_positivity_in_decl fct p decl ident =
108+ let tys_to_inspect =
109+ match decl.tyd_type with
110+ | Concrete ty -> [ ty ]
111+ | Abstract _ -> raise @@ NonPositiveAbstract p
112+ | Datatype { tydt_ctors } -> List. flatten (List. map snd tydt_ctors)
113+ | Record (_ , tys ) -> List. map snd tys
114+ in
115+ List. iter (check_positivity_ident fct p decl.tyd_params ident) tys_to_inspect
116+
117+ (* * Ensures all occurrences of type variable [ident] are positive in type [ty] *)
118+ and check_positivity_ident fct p params ident ty = match ty.ty_node with
119+ | Tglob _ | Tunivar _ -> assert false
120+ | Tvar _ -> ()
121+ | Ttuple tys -> List. iter (check_positivity_ident fct p params ident) tys
122+ | Tconstr (q , args ) when EcPath. p_equal q p ->
123+ if not (ty_params_compat args params) then raise @@ NonPositiveParams ty
124+ | Tconstr (q , args ) ->
125+ let decl = fct q in
126+ List. combine args decl.tyd_params
127+ |> List. filter_map
128+ (fun (arg , (ident , _ )) -> if EcTypes. var_mem ident arg then Some ident else None )
129+ |> List. iter (check_positivity_in_decl fct q decl)
130+ | Tfun (from , to_ ) ->
131+ if EcTypes. var_mem ident from then raise @@ NonPositive ty;
132+ check_positivity_ident fct p params ident to_
133+
134+
135+ (* * Ensures all occurrences of path [p] are positive in type [ty] *)
136+ let rec check_positivity_path fct p ty =
137+ match ty.ty_node with
138+ | Tglob _ | Tunivar _ -> assert false
139+ | Tvar _ -> ()
140+ | Ttuple tys -> List. iter (check_positivity_path fct p) tys
141+ | Tconstr (q , args ) when EcPath. p_equal q p ->
142+ if List. exists (occurs p) args then raise (NonPositive ty)
143+ | Tconstr (q , args ) ->
144+ let decl = fct q in
145+ List. combine args decl.tyd_params
146+ |> List. filter_map
147+ (fun (arg , (ident , _ )) -> if occurs p arg then Some ident else None )
148+ |> List. iter (check_positivity_in_decl fct q decl)
149+
150+ | Tfun (from , to_ ) ->
151+ if occurs p from then raise (NonPositive ty);
152+ check_positivity_path fct p to_
153+
154+ let check_positivity fct dt =
155+ let tys = List. flatten (List. map snd dt.dt_ctors) in
156+ List. iter (check_positivity_path fct dt.dt_path) tys
157+
158+
159+ let indsc_of_datatype ?(normty = identity) (mode : indmode ) (dt : datatype ) =
90160 let tpath = dt.dt_path in
91161
92162 let rec scheme1 p (pred , fac ) ty =
@@ -103,13 +173,11 @@ let indsc_of_datatype ?normty (mode : indmode) (dt : datatype) =
103173 | scs -> Some (FL. f_let (LTuple xs) fac (FL. f_ands scs))
104174 end
105175
106- | Tconstr (p' , ts ) ->
107- if List. exists (occurs p) ts then raise NonPositive ;
176+ | Tconstr (p' , _ ) ->
108177 if not (EcPath. p_equal p p') then None else
109178 Some (FL. f_app pred [fac] tbool)
110179
111180 | Tfun (ty1 , ty2 ) ->
112- if occurs p ty1 then raise NonPositive ;
113181 let x = fresh_id_of_ty ty1 in
114182 scheme1 p (pred, FL. f_app fac [FL. f_local x ty1] ty2) ty2
115183 |> omap (FL. f_forall [x, GTty ty1])
@@ -152,11 +220,6 @@ let indsc_of_datatype ?normty (mode : indmode) (dt : datatype) =
152220 let form = FL. f_forall [predx, GTty predty] form in
153221 form
154222
155- and occurs p t =
156- match (normty t).ty_node with
157- | Tconstr (p' , _ ) when EcPath. p_equal p p' -> true
158- | _ -> EcTypes. ty_sub_exists (occurs p) t
159-
160223 in scheme mode (List. map fst dt.dt_tparams, tpath) dt.dt_ctors
161224
162225(* -------------------------------------------------------------------- *)
0 commit comments