Skip to content

Commit 8930c48

Browse files
committed
Make the typeclass implementation fully compatible with universe polymorphism.
This essentially means storing the abstract universe context in the typeclass data, and abstracting it when necessary.
1 parent 9938aed commit 8930c48

File tree

5 files changed

+64
-40
lines changed

5 files changed

+64
-40
lines changed

API/API.mli

+1
Original file line numberDiff line numberDiff line change
@@ -3048,6 +3048,7 @@ end
30483048
module Typeclasses :
30493049
sig
30503050
type typeclass = Typeclasses.typeclass = {
3051+
cl_univs : Univ.AUContext.t;
30513052
cl_impl : Globnames.global_reference;
30523053
cl_context : (Globnames.global_reference * bool) option list * Context.Rel.t;
30533054
cl_props : Context.Rel.t;

pretyping/typeclasses.ml

+36-29
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ type direction = Forward | Backward
5757

5858
(* This module defines type-classes *)
5959
type typeclass = {
60+
(* Universe quantification *)
61+
cl_univs : Univ.AUContext.t;
62+
6063
(* The class implementation *)
6164
cl_impl : global_reference;
6265

@@ -111,23 +114,11 @@ let new_instance cl info glob poly impl =
111114
let classes : typeclasses ref = Summary.ref Refmap.empty ~name:"classes"
112115
let instances : instances ref = Summary.ref Refmap.empty ~name:"instances"
113116

114-
let typeclass_univ_instance (cl,u') =
115-
let subst =
116-
let u =
117-
match cl.cl_impl with
118-
| ConstRef c ->
119-
let cb = Global.lookup_constant c in
120-
Univ.AUContext.instance (Declareops.constant_polymorphic_context cb)
121-
| IndRef c ->
122-
let mib,oib = Global.lookup_inductive c in
123-
Univ.AUContext.instance (Declareops.inductive_polymorphic_context mib)
124-
| _ -> Univ.Instance.empty
125-
in Array.fold_left2 (fun subst u u' -> Univ.LMap.add u u' subst)
126-
Univ.LMap.empty (Univ.Instance.to_array u) (Univ.Instance.to_array u')
127-
in
128-
let subst_ctx = Context.Rel.map (subst_univs_level_constr subst) in
129-
{ cl with cl_context = fst cl.cl_context, subst_ctx (snd cl.cl_context);
130-
cl_props = subst_ctx cl.cl_props}, u'
117+
let typeclass_univ_instance (cl, u) =
118+
assert (Univ.AUContext.size cl.cl_univs == Univ.Instance.length u);
119+
let subst_ctx c = Context.Rel.map (subst_instance_constr u) c in
120+
{ cl with cl_context = on_snd subst_ctx cl.cl_context;
121+
cl_props = subst_ctx cl.cl_props}
131122

132123
let class_info c =
133124
try Refmap.find c !classes
@@ -185,29 +176,43 @@ let subst_class (subst,cl) =
185176
do_subst_ctx ctx in
186177
let do_subst_projs projs = List.smartmap (fun (x, y, z) ->
187178
(x, y, Option.smartmap do_subst_con z)) projs in
188-
{ cl_impl = do_subst_gr cl.cl_impl;
179+
{ cl_univs = cl.cl_univs;
180+
cl_impl = do_subst_gr cl.cl_impl;
189181
cl_context = do_subst_context cl.cl_context;
190182
cl_props = do_subst_ctx cl.cl_props;
191183
cl_projs = do_subst_projs cl.cl_projs;
192184
cl_strict = cl.cl_strict;
193185
cl_unique = cl.cl_unique }
194186

187+
(** FIXME: share this with Cooking somewhere in a nicely packed API *)
188+
let lift_abstract_context subst abs_ctx auctx =
189+
let open Univ in
190+
let len = LMap.cardinal subst in
191+
let rec gen_subst i acc =
192+
if i < 0 then acc
193+
else
194+
let acc = LMap.add (Level.var i) (Level.var (i + len)) acc in
195+
gen_subst (pred i) acc
196+
in
197+
let subst = gen_subst (AUContext.size auctx - 1) subst in
198+
let auctx = Univ.subst_univs_level_abstract_universe_context subst auctx in
199+
subst, AUContext.union abs_ctx auctx
200+
195201
let discharge_class (_,cl) =
196202
let repl = Lib.replacement_context () in
197203
let rel_of_variable_context ctx = List.fold_right
198204
( fun (decl,_) (ctx', subst) ->
199205
let decl' = decl |> NamedDecl.map_constr (substn_vars 1 subst) |> NamedDecl.to_rel_decl in
200206
(decl' :: ctx', NamedDecl.get_id decl :: subst)
201207
) ctx ([], []) in
202-
let discharge_rel_context subst n rel =
208+
let discharge_rel_context (subst, usubst) n rel =
203209
let rel = Context.Rel.map (Cooking.expmod_constr repl) rel in
204-
let ctx, _ =
205-
List.fold_right
206-
(fun decl (ctx, k) ->
207-
RelDecl.map_constr (substn_vars k subst) decl :: ctx, succ k
208-
)
209-
rel ([], n)
210-
in ctx
210+
let fold decl (ctx, k) =
211+
let map c = subst_univs_level_constr usubst (substn_vars k subst c) in
212+
RelDecl.map_constr map decl :: ctx, succ k
213+
in
214+
let ctx, _ = List.fold_right fold rel ([], n) in
215+
ctx
211216
in
212217
let abs_context cl =
213218
match cl.cl_impl with
@@ -229,10 +234,12 @@ let discharge_class (_,cl) =
229234
if cl_impl' == cl.cl_impl then cl else
230235
let ctx, usubst, uctx = abs_context cl in
231236
let ctx, subst = rel_of_variable_context ctx in
232-
let context = discharge_context ctx subst cl.cl_context in
233-
let props = discharge_rel_context subst (succ (List.length (fst cl.cl_context))) cl.cl_props in
237+
let usubst, cl_univs' = lift_abstract_context usubst uctx cl.cl_univs in
238+
let context = discharge_context ctx (subst, usubst) cl.cl_context in
239+
let props = discharge_rel_context (subst, usubst) (succ (List.length (fst cl.cl_context))) cl.cl_props in
234240
let discharge_proj (x, y, z) = x, y, Option.smartmap Lib.discharge_con z in
235-
{ cl_impl = cl_impl';
241+
{ cl_univs = cl_univs';
242+
cl_impl = cl_impl';
236243
cl_context = context;
237244
cl_props = props;
238245
cl_projs = List.smartmap discharge_proj cl.cl_projs;

pretyping/typeclasses.mli

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ type direction = Forward | Backward
1616

1717
(** This module defines type-classes *)
1818
type typeclass = {
19+
(** The toplevel universe quantification in which the typeclass lives. In
20+
particular, [cl_props] and [cl_context] are quantified over it. *)
21+
cl_univs : Univ.AUContext.t;
22+
1923
(** The class implementation: a record parameterized by the context with defs in it or a definition if
2024
the class is a singleton. This acts as the class' global identifier. *)
2125
cl_impl : global_reference;
@@ -64,7 +68,7 @@ val class_info : global_reference -> typeclass (** raises a UserError if not a c
6468
val dest_class_app : env -> evar_map -> EConstr.constr -> (typeclass * EConstr.EInstance.t) * constr list
6569

6670
(** Get the instantiated typeclass structure for a given universe instance. *)
67-
val typeclass_univ_instance : typeclass puniverses -> typeclass puniverses
71+
val typeclass_univ_instance : typeclass puniverses -> typeclass
6872

6973
(** Just return None if not a class *)
7074
val class_of_constr : evar_map -> EConstr.constr -> (EConstr.rel_context * ((typeclass * EConstr.EInstance.t) * constr list)) option

vernac/classes.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ let new_instance ?(abstract=false) ?(global=false) ?(refine= !refine_instance) p
164164
let ctx'' = ctx' @ ctx in
165165
let (k, u), args = Typeclasses.dest_class_app (push_rel_context ctx'' env) !evars (EConstr.of_constr c) in
166166
let u = EConstr.EInstance.kind !evars u in
167-
let cl, u = Typeclasses.typeclass_univ_instance (k, u) in
167+
let cl = Typeclasses.typeclass_univ_instance (k, u) in
168168
let _, args =
169169
List.fold_right (fun decl (args, args') ->
170170
match decl with

vernac/record.ml

+21-9
Original file line numberDiff line numberDiff line change
@@ -517,8 +517,18 @@ let declare_class finite def cum poly ctx id idbuild paramimpls params arity
517517
| None -> None)
518518
params, params
519519
in
520+
let univs, ctx_context, fields =
521+
if poly then
522+
let usubst, auctx = Univ.abstract_universes ctx in
523+
let map c = Vars.subst_univs_level_constr usubst c in
524+
let fields = Context.Rel.map map fields in
525+
let ctx_context = on_snd (fun d -> Context.Rel.map map d) ctx_context in
526+
auctx, ctx_context, fields
527+
else Univ.AUContext.empty, ctx_context, fields
528+
in
520529
let k =
521-
{ cl_impl = impl;
530+
{ cl_univs = univs;
531+
cl_impl = impl;
522532
cl_strict = !typeclasses_strict;
523533
cl_unique = !typeclasses_unique;
524534
cl_context = ctx_context;
@@ -529,10 +539,11 @@ let declare_class finite def cum poly ctx id idbuild paramimpls params arity
529539

530540

531541
let add_constant_class cst =
532-
let ty = Universes.unsafe_type_of_global (ConstRef cst) in
542+
let ty, univs = Global.type_of_global_in_context (Global.env ()) (ConstRef cst) in
533543
let ctx, arity = decompose_prod_assum ty in
534544
let tc =
535-
{ cl_impl = ConstRef cst;
545+
{ cl_univs = univs;
546+
cl_impl = ConstRef cst;
536547
cl_context = (List.map (const None) ctx, ctx);
537548
cl_props = [LocalAssum (Anonymous, arity)];
538549
cl_projs = [];
@@ -546,12 +557,13 @@ let add_inductive_class ind =
546557
let mind, oneind = Global.lookup_inductive ind in
547558
let k =
548559
let ctx = oneind.mind_arity_ctxt in
549-
let inst = Univ.AUContext.instance (Declareops.inductive_polymorphic_context mind) in
550-
let ty = Inductive.type_of_inductive
551-
(push_rel_context ctx (Global.env ()))
552-
((mind,oneind),inst)
553-
in
554-
{ cl_impl = IndRef ind;
560+
let univs = Declareops.inductive_polymorphic_context mind in
561+
let env = push_context ~strict:false (Univ.AUContext.repr univs) (Global.env ()) in
562+
let env = push_rel_context ctx env in
563+
let inst = Univ.make_abstract_instance univs in
564+
let ty = Inductive.type_of_inductive env ((mind, oneind), inst) in
565+
{ cl_univs = univs;
566+
cl_impl = IndRef ind;
555567
cl_context = List.map (const None) ctx, ctx;
556568
cl_props = [LocalAssum (Anonymous, ty)];
557569
cl_projs = [];

0 commit comments

Comments
 (0)