Skip to content

Commit 32209c6

Browse files
committed
feat: working stack-based pretty-printing
This commit also fixes a silly shadowing issue on one critical variable during positivity checking. I still need to understand clearly the behaviour of `Format` boxes, which remain quite mysterious. I also have to add a test file for coverage.
1 parent 50d91eb commit 32209c6

File tree

6 files changed

+68
-49
lines changed

6 files changed

+68
-49
lines changed

src/ecHiInductive.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type dterror =
2323
| DTE_TypeError of TT.tyerror
2424
| DTE_DuplicatedCtor of symbol
2525
| DTE_InvalidCTorType of symbol * TT.tyerror
26-
| DTE_NonPositive of (EcPrinting.PPEnv.t -> unit EcPrinting.pp)
26+
| DTE_NonPositive of symbol * EI.non_positive_context
2727
| DTE_Empty
2828

2929
type fxerror =

src/ecHiInductive.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type dterror =
1616
| DTE_TypeError of EcTyping.tyerror
1717
| DTE_DuplicatedCtor of symbol
1818
| DTE_InvalidCTorType of symbol * EcTyping.tyerror
19-
| DTE_NonPositive of (EcPrinting.PPEnv.t -> unit EcPrinting.pp)
19+
| DTE_NonPositive of symbol * non_positive_context
2020
| DTE_Empty
2121

2222
type fxerror =

src/ecInductive.ml

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ open EcTypes
66
open EcDecl
77
open EcCoreFol
88

9-
module PE = EcPrinting
109
module EP = EcPath
1110
module FL = EcCoreFol
1211

@@ -84,45 +83,23 @@ let datatype_ind_path (mode : indmode) (p : EcPath.path) =
8483
EcPath.pqoname (EcPath.prefix p) name
8584

8685
(* -------------------------------------------------------------------- *)
87-
type variant = Concrete | Record of symbol | Variant of symbol
86+
type non_positive_intype = Concrete | Record of symbol | Variant of symbol
8887

89-
type context =
90-
| InType of variant
88+
type non_positive_description =
89+
| InType of EcIdent.ident option * non_positive_intype
9190
| NonPositiveOcc of ty
9291
| AbstractTypeRestriction
9392
| TypePositionRestriction of ty
9493

95-
exception NonPositiveCtx of (EP.path * context) list
94+
type non_positive_context = (symbol * non_positive_description) list
9695

97-
exception NonPositive of (PE.PPEnv.t -> unit PE.pp)
96+
exception NonPositive of non_positive_context
9897

99-
let render_context pp fmt (p, ctx) = match ctx with
100-
| InType Concrete -> Format.fprintf fmt "... in type %a" PE.pp_path p
101-
| InType (Record s) ->
102-
Format.fprintf fmt "... in record field %s of type %a" s PE.pp_path p
103-
| InType (Variant s) ->
104-
Format.fprintf fmt "... in variant %s of type %a" s PE.pp_path p
105-
| NonPositiveOcc ty ->
106-
Format.fprintf fmt "non-positive occurrence of %a in type %a"
107-
(PE.pp_type pp) ty PE.pp_path p
108-
| AbstractTypeRestriction ->
109-
Format.fprintf fmt "unauthorised abstract type constructor %a" PE.pp_path p
110-
| TypePositionRestriction ty ->
111-
Format.fprintf fmt
112-
"recursive occurrence %a in the definition of %a has different \
113-
arguments, which is not allowed."
114-
(PE.pp_type pp) ty PE.pp_path p
98+
let with_context ?ident p ctx f =
99+
try f () with NonPositive l -> raise (NonPositive ((EP.basename p, InType (ident, ctx)) :: l))
115100

116-
let render_context_list p l pp fmt () =
117-
Format.fprintf fmt "Could not verify strict positivity of type %a:@;@[<v 2>" PE.pp_path p;
118-
Format.pp_print_list (render_context pp) fmt l;
119-
Format.fprintf fmt "@;@]"
120-
121-
122-
let with_context p ctx f =
123-
try f () with NonPositiveCtx l -> raise (NonPositiveCtx ((p, ctx) :: l))
124-
125-
let non_positive p ctx = raise (NonPositiveCtx [(p, ctx)])
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)])
126103

127104
(** below, [fct] designates the function that takes a path to a type constructor
128105
and returns the corresponding type declaration *)
@@ -165,15 +142,15 @@ let rec check_positivity_in_decl fct p decl ident =
165142
and iter l f = List.iter f l in
166143

167144
match decl.tyd_type with
168-
| Concrete ty -> with_context p (InType Concrete) (check ty)
145+
| Concrete ty -> with_context ~ident p Concrete (check ty)
169146
| Abstract _ -> non_positive p AbstractTypeRestriction
170147
| Datatype { tydt_ctors } ->
171148
iter tydt_ctors @@ fun (name, argty) ->
172149
iter argty @@ fun ty ->
173-
with_context p (InType (Variant name)) (check ty)
150+
with_context ~ident p (Variant name) (check ty)
174151
| Record (_, tys) ->
175152
iter tys @@ fun (name, ty) ->
176-
with_context p (InType (Record name)) (check ty)
153+
with_context ~ident p (Record name) (check ty)
177154

178155
(** Ensures all occurrences of type variable [ident] are positive in type [ty] *)
179156
and check_positivity_ident fct p params ident ty =
@@ -186,17 +163,17 @@ and check_positivity_ident fct p params ident ty =
186163
| Tconstr (q, args) ->
187164
let decl = fct q in
188165
List.combine args decl.tyd_params
189-
|> List.filter_map (fun (arg, (ident, _)) ->
190-
if EcTypes.var_mem ident arg then Some ident else None)
166+
|> List.filter_map (fun (arg, (ident', _)) ->
167+
if EcTypes.var_mem ident arg then Some ident' else None)
191168
|> List.iter (check_positivity_in_decl fct q decl)
192169
| Tfun (from, to_) ->
193-
if EcTypes.var_mem ident from then non_positive p (NonPositiveOcc ty);
170+
if EcTypes.var_mem ident from then non_positive' ident (NonPositiveOcc ty);
194171
check_positivity_ident fct p params ident to_
195172

196173
(** Ensures all occurrences of path [p] are positive in type [ty] *)
197174
let rec check_positivity_path fct p ty =
198175
match ty.ty_node with
199-
| Tglob _ | Tunivar _ | Tvar _ -> ()
176+
| Tglob _ | Tunivar _ | Tvar _ -> ()
200177
| Ttuple tys -> List.iter (check_positivity_path fct p) tys
201178
| Tconstr (q, args) when EcPath.p_equal q p ->
202179
if List.exists (occurs p) args then non_positive p (NonPositiveOcc ty)
@@ -211,10 +188,11 @@ let rec check_positivity_path fct p ty =
211188
check_positivity_path fct p to_
212189

213190
let check_positivity fct dt =
214-
let tys = List.flatten (List.map snd dt.dt_ctors) in
215-
try List.iter (check_positivity_path fct dt.dt_path) tys
216-
with NonPositiveCtx l ->
217-
raise (NonPositive (render_context_list dt.dt_path l))
191+
let check ty () = check_positivity_path fct dt.dt_path ty
192+
and iter l f = List.iter f l in
193+
iter dt.dt_ctors @@ fun (name, argty) ->
194+
iter argty @@ fun ty ->
195+
with_context dt.dt_path (Variant name) (check ty)
218196

219197
let indsc_of_datatype ?(normty = identity) (mode : indmode) (dt : datatype) =
220198
let tpath = dt.dt_path in

src/ecInductive.mli

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,17 @@ val datatype_proj_name : symbol -> symbol
4343
val datatype_proj_path : path -> symbol -> path
4444

4545
(* -------------------------------------------------------------------- *)
46-
exception NonPositive of (EcPrinting.PPEnv.t -> unit EcPrinting.pp)
46+
type non_positive_intype = Concrete | Record of symbol | Variant of symbol
47+
48+
type non_positive_description =
49+
| InType of EcIdent.ident option * non_positive_intype
50+
| NonPositiveOcc of ty
51+
| AbstractTypeRestriction
52+
| TypePositionRestriction of ty
53+
54+
type non_positive_context = (symbol * non_positive_description) list
55+
56+
exception NonPositive of non_positive_context
4757

4858
val check_positivity : (path -> tydecl) -> datatype -> unit
4959
(** Evaluates whether a given datatype protype satisfies the strict

src/ecScope.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,8 +2255,9 @@ module Ty = struct
22552255
ELI.check_positivity ty_from_ctor datatype;
22562256
let tparams, tydt = ELI.datatype_as_ty_dtype datatype in
22572257
(tparams, Datatype tydt)
2258-
with ELI.NonPositive f ->
2259-
EHI.dterror loc env (EHI.DTE_NonPositive f))
2258+
with ELI.NonPositive ctx ->
2259+
let symbol = basename datatype.dt_path in
2260+
EHI.dterror loc env (EHI.DTE_NonPositive (symbol, ctx)))
22602261

22612262
| PTYD_Record rt ->
22622263
let record = EHI.trans_record env (mk_loc loc (args,name)) rt in

src/ecUserMessages.ml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ module InductiveError : sig
573573
val pp_fxerror : env -> Format.formatter -> fxerror -> unit
574574
end = struct
575575
open EcHiInductive
576+
open EcInductive
576577
open TypingError
577578

578579
let pp_rcerror env fmt error =
@@ -591,6 +592,35 @@ end = struct
591592
| RCE_Empty ->
592593
msg "this record type is empty"
593594

595+
let format_intype fmt p (tyvar, ctx) =
596+
(match ctx with
597+
| Concrete -> Format.fprintf fmt "... in type %s" p
598+
| Record s -> Format.fprintf fmt "... in record field %s of type %s" s p
599+
| Variant s -> Format.fprintf fmt "... in variant %s of type %s" s p);
600+
let subty tyvar =
601+
Format.fprintf fmt " (in an instance of type variable %a)"
602+
EcIdent.pp_ident tyvar
603+
in
604+
Option.iter subty tyvar
605+
606+
let format_context pp fmt (p, ctx) = match ctx with
607+
| InType (tyvar, ctx) -> format_intype fmt p (tyvar, ctx)
608+
| NonPositiveOcc ty ->
609+
Format.fprintf fmt "non-positive occurrence of %s in type %a"
610+
p (EcPrinting.pp_type pp) ty
611+
| AbstractTypeRestriction ->
612+
Format.fprintf fmt "unauthorised abstract type constructor %s" p
613+
| TypePositionRestriction ty ->
614+
Format.fprintf fmt
615+
"recursive occurrence %a in the definition of %s has different \
616+
arguments, which is not allowed."
617+
(EcPrinting.pp_type pp) ty p
618+
619+
let format_context_list p l pp fmt =
620+
Format.fprintf fmt "Could not verify strict positivity of type %s:@.@;<0 2>@[<v>" p;
621+
Format.pp_print_list (format_context pp) fmt l;
622+
Format.fprintf fmt "@;@]"
623+
594624
let pp_dterror env fmt error =
595625
let msg x = Format.fprintf fmt x in
596626
let env1 = EcPrinting.PPEnv.ofenv env in
@@ -609,7 +639,7 @@ end = struct
609639
| DTE_Empty ->
610640
msg "the datatype may be empty"
611641

612-
| DTE_NonPositive f -> f env1 fmt ()
642+
| DTE_NonPositive (s, ctx) -> format_context_list s ctx env1 fmt
613643

614644
let pp_fxerror env fmt error =
615645
match error with

0 commit comments

Comments
 (0)