Skip to content

Commit 2e0f98e

Browse files
committed
feat: positivity checker seems to work; needs more testing
1 parent dd13978 commit 2e0f98e

File tree

5 files changed

+69
-35
lines changed

5 files changed

+69
-35
lines changed

src/ecDecl.ml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ type ty_body =
3030

3131
type tydecl = {
3232
tyd_params : ty_params;
33-
(* tyd_positivity : bool list; *)
3433
tyd_type : ty_body;
3534
tyd_loca : locality;
3635
}

src/ecInductive.ml

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ type ctors = ctor list
6666

6767
type datatype = {
6868
dt_path : EcPath.path;
69-
dt_tparams : (ty_param * bool) list;
69+
dt_tparams : ty_params;
7070
dt_ctors : ctors
7171
}
7272

@@ -84,48 +84,76 @@ let datatype_ind_path (mode : indmode) (p : EcPath.path) =
8484

8585
(* -------------------------------------------------------------------- *)
8686
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ᵢ) *)
8795

8896
let rec occurs ?(normty = identity) p t =
8997
match (normty t).ty_node with
9098
| Tconstr (p', _) when EcPath.p_equal p p' -> true
9199
| _ -> EcTypes.ty_sub_exists (occurs p) t
92100

93-
(** below, [fct] designates the function that takes a path to a type constructor
94-
and returns the corresponding type declaration *)
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
95116

96-
(** Strict positivity enforces the following, for every variant of the datatype p:
97-
- for each subterm (a → b), p ∉ fv(a);
98-
- recursive occurences a₁ a₂ .. aₙ p are such that ∀i. p ∉ fv(aᵢ) *)
99-
100-
let rec check_positivity_dt fct p ty (q, args) =
101-
let tydecl = fct q in
102-
let inst = EcDecl.ty_instanciate tydecl.tyd_params args in
103-
match tydecl.tyd_type with
104-
| Abstract _ -> ()
105-
| Concrete ty' -> check_positivity_ty fct p ty ty'
106-
| Record (_, fields) ->
107-
List.iter (check_positivity_ty fct p ty) (List.map (inst |- snd) fields)
108-
| Datatype dt -> check_positivity_ctors fct p inst ty dt.tydt_ctors
109-
110-
and check_positivity_ctors fct p inst ty =
111-
List.iter (fun (_variant, parameters) ->
112-
List.iter (check_positivity_ty fct p ty) (List.map inst parameters))
113-
114-
and check_positivity_ty fct p ty traversed_ty =
115-
match traversed_ty.ty_node with
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
116138
| Tglob _ | Tunivar _ -> assert false
117139
| Tvar _ -> ()
118-
| Ttuple tys -> List.iter (check_positivity_ty fct p ty) tys
140+
| Ttuple tys -> List.iter (check_positivity_path fct p) tys
119141
| Tconstr (q, args) when EcPath.p_equal q p ->
120-
if List.exists (fun ty -> occurs p ty) args then
121-
raise (NonPositive traversed_ty)
122-
| Tconstr (q, args) -> check_positivity_dt fct p ty (q, args)
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+
123150
| Tfun (from, to_) ->
124-
if occurs ty from then raise (NonPositive traversed_ty);
125-
check_positivity_ty fct p ty to_
151+
if occurs p from then raise (NonPositive ty);
152+
check_positivity_path fct p to_
126153

127154
let check_positivity fct dt =
128-
check_positivity_ctors fct dt.dt_path identity dt.dt_path dt.dt_ctors
155+
let tys = List.flatten (List.map snd dt.dt_ctors) in
156+
List.iter (check_positivity_path fct dt.dt_path) tys
129157

130158

131159
let indsc_of_datatype ?(normty = identity) (mode : indmode) (dt : datatype) =
@@ -192,7 +220,7 @@ let indsc_of_datatype ?(normty = identity) (mode : indmode) (dt : datatype) =
192220
let form = FL.f_forall [predx, GTty predty] form in
193221
form
194222

195-
in scheme mode (List.map (fst |- fst) dt.dt_tparams, tpath) dt.dt_ctors
223+
in scheme mode (List.map fst dt.dt_tparams, tpath) dt.dt_ctors
196224

197225
(* -------------------------------------------------------------------- *)
198226
let datatype_projectors (tpath, tparams, { tydt_ctors = ctors }) =
@@ -229,7 +257,7 @@ let datatype_projectors (tpath, tparams, { tydt_ctors = ctors }) =
229257
let datatype_as_ty_dtype datatype =
230258
let indsc = indsc_of_datatype `Elim datatype in
231259
let casesc = indsc_of_datatype `Case datatype in
232-
List.map fst datatype.dt_tparams,
260+
datatype.dt_tparams,
233261
{ tydt_ctors = datatype.dt_ctors ;
234262
tydt_schcase = casesc;
235263
tydt_schelim = indsc ; }

src/ecInductive.mli

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ type ctors = ctor list
2222

2323
type datatype = {
2424
dt_path : path;
25-
dt_tparams : (ty_param * bool) list;
26-
dt_positivity : bool array;
25+
dt_tparams : ty_params;
2726
dt_ctors : ctors
2827
}
2928

src/ecTypes.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ let rec ty_check_uni t =
154154
| Tunivar _ -> raise FoundUnivar
155155
| _ -> ty_iter ty_check_uni t
156156

157+
let rec var_mem ?(check_glob = false) id t =
158+
match t.ty_node with
159+
| Tvar id' -> EcIdent.id_equal id id'
160+
| Tglob id' when check_glob -> EcIdent.id_equal id id'
161+
| _ -> ty_sub_exists (var_mem ~check_glob id) t
162+
157163
(* -------------------------------------------------------------------- *)
158164
let symbol_of_ty (ty : ty) =
159165
match ty.ty_node with

src/ecTypes.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ val ty_sub_exists : (ty -> bool) -> ty -> bool
7979
val ty_fold : ('a -> ty -> 'a) -> 'a -> ty -> 'a
8080
val ty_iter : (ty -> unit) -> ty -> unit
8181

82+
val var_mem : ?check_glob:bool -> EcIdent.t -> ty -> bool
83+
8284
(* -------------------------------------------------------------------- *)
8385
val symbol_of_ty : ty -> string
8486
val fresh_id_of_ty : ty -> EcIdent.t

0 commit comments

Comments
 (0)