@@ -83,10 +83,120 @@ 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+ type non_positive_intype = Concrete | Record of symbol | Variant of symbol
87+
88+ type non_positive_description =
89+ | InType of EcIdent .ident option * non_positive_intype
90+ | NonPositiveOcc of ty
91+ | AbstractTypeRestriction
92+ | TypePositionRestriction of ty
93+
94+ type non_positive_context = (symbol * non_positive_description ) list
95+
96+ exception NonPositive of non_positive_context
97+
98+ let with_context ?ident p ctx f =
99+ try f () with NonPositive l -> raise (NonPositive ((EP. basename p, InType (ident, ctx)) :: l))
100+
101+ let non_positive (p : EP.path ) ctx = raise (NonPositive [(EP. basename p, ctx)])
102+ let non_positive' (s : EcIdent.ident ) ctx = raise (NonPositive [(s.id_symb, ctx)])
103+
104+ (* * below, [fct] designates the function that takes a path to a type constructor
105+ and returns the corresponding type declaration *)
106+
107+ (* * Strict positivity enforces the following, for every variant of the datatype p:
108+ - for each subterm (a → b), p ∉ fv(a);
109+ - inductive occurences a₁ a₂ .. aₙ p are such that ∀i. p ∉ fv(aᵢ)
110+
111+ Crucially, this has to be checked whenever p occurs in an instance of
112+ another type constructor.
113+
114+ FIXME: The current implementation prohibits the use of a type which changes
115+ its type arguments like e.g.
116+ {v
117+ type ('a, 'b) t = [
118+ | Elt of 'a
119+ | Swap of ('b, 'a) t
120+ ].
121+ v}
122+ to be used in some places while defining another inductive type. *)
123+
124+ let rec occurs ?(normty = identity) p t =
125+ match (normty t).ty_node with
126+ | Tconstr (p' , _ ) when EcPath. p_equal p p' -> true
127+ | _ -> EcTypes. ty_sub_exists (occurs p) t
128+
129+ (* * Tests whether the first list is a list of type variables, matching the
130+ identifiers of the second list. *)
131+ let ty_params_compat =
132+ List. for_all2 (fun ty (param_id , _ ) ->
133+ match ty.ty_node with
134+ | Tvar id -> EcIdent. id_equal id param_id
135+ | _ -> false )
136+
137+ (* * Ensures all occurrences of type variable [ident] are positive in type
138+ declaration [decl] (with name [p]).
139+ This function provide error context in case the check fails. *)
140+ let rec check_positivity_in_decl fct p decl ident =
141+ let check x () = check_positivity_ident fct p decl.tyd_params ident x
142+ and iter l f = List. iter f l in
143+
144+ match decl.tyd_type with
145+ | Concrete ty -> with_context ~ident p Concrete (check ty)
146+ | Abstract _ -> non_positive p AbstractTypeRestriction
147+ | Datatype { tydt_ctors } ->
148+ iter tydt_ctors @@ fun (name , argty ) ->
149+ iter argty @@ fun ty ->
150+ with_context ~ident p (Variant name) (check ty)
151+ | Record (_ , tys ) ->
152+ iter tys @@ fun (name , ty ) ->
153+ with_context ~ident p (Record name) (check ty)
154+
155+ (* * Ensures all occurrences of type variable [ident] are positive in type [ty] *)
156+ and check_positivity_ident fct p params ident ty =
157+ match ty.ty_node with
158+ | Tglob _ | Tunivar _ | Tvar _ -> ()
159+ | Ttuple tys -> List. iter (check_positivity_ident fct p params ident) tys
160+ | Tconstr (q , args ) when EcPath. p_equal q p ->
161+ if not (ty_params_compat args params) then
162+ non_positive p (TypePositionRestriction ty)
163+ | Tconstr (q , args ) ->
164+ let decl = fct q in
165+ List. iter (check_positivity_ident fct p params ident) args;
166+ List. combine args decl.tyd_params
167+ |> List. filter_map (fun (arg , (ident' , _ )) ->
168+ if EcTypes. var_mem ident arg then Some ident' else None )
169+ |> List. iter (check_positivity_in_decl fct q decl)
170+ | Tfun (from , to_ ) ->
171+ if EcTypes. var_mem ident from then non_positive' ident (NonPositiveOcc ty);
172+ check_positivity_ident fct p params ident to_
173+
174+ (* * Ensures all occurrences of path [p] are positive in type [ty] *)
175+ let rec check_positivity_path fct p ty =
176+ match ty.ty_node with
177+ | Tglob _ | Tunivar _ | Tvar _ -> ()
178+ | Ttuple tys -> List. iter (check_positivity_path fct p) tys
179+ | Tconstr (q , args ) when EcPath. p_equal q p ->
180+ if List. exists (occurs p) args then non_positive p (NonPositiveOcc ty)
181+ | Tconstr (q , args ) ->
182+ let decl = fct q in
183+ List. iter (check_positivity_path fct p) args;
184+ List. combine args decl.tyd_params
185+ |> List. filter_map (fun (arg , (ident , _ )) ->
186+ if occurs p arg then Some ident else None )
187+ |> List. iter (check_positivity_in_decl fct q decl)
188+ | Tfun (from , to_ ) ->
189+ if occurs p from then non_positive p (NonPositiveOcc ty);
190+ check_positivity_path fct p to_
191+
192+ let check_positivity fct dt =
193+ let check ty () = check_positivity_path fct dt.dt_path ty
194+ and iter l f = List. iter f l in
195+ iter dt.dt_ctors @@ fun (name , argty ) ->
196+ iter argty @@ fun ty ->
197+ with_context dt.dt_path (Variant name) (check ty)
198+
199+ let indsc_of_datatype ?(normty = identity) (mode : indmode ) (dt : datatype ) =
90200 let tpath = dt.dt_path in
91201
92202 let rec scheme1 p (pred , fac ) ty =
@@ -103,13 +213,11 @@ let indsc_of_datatype ?normty (mode : indmode) (dt : datatype) =
103213 | scs -> Some (FL. f_let (LTuple xs) fac (FL. f_ands scs))
104214 end
105215
106- | Tconstr (p' , ts ) ->
107- if List. exists (occurs p) ts then raise NonPositive ;
216+ | Tconstr (p' , _ ) ->
108217 if not (EcPath. p_equal p p') then None else
109218 Some (FL. f_app pred [fac] tbool)
110219
111220 | Tfun (ty1 , ty2 ) ->
112- if occurs p ty1 then raise NonPositive ;
113221 let x = fresh_id_of_ty ty1 in
114222 scheme1 p (pred, FL. f_app fac [FL. f_local x ty1] ty2) ty2
115223 |> omap (FL. f_forall [x, GTty ty1])
@@ -152,11 +260,6 @@ let indsc_of_datatype ?normty (mode : indmode) (dt : datatype) =
152260 let form = FL. f_forall [predx, GTty predty] form in
153261 form
154262
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-
160263 in scheme mode (List. map fst dt.dt_tparams, tpath) dt.dt_ctors
161264
162265(* -------------------------------------------------------------------- *)
0 commit comments