Skip to content

Commit 2003ab8

Browse files
committed
Typecheck pseudo sort poly inductives in kernel using above prop qvar
We have a back and forth ~~~ elaboration -> econstr with qvar -> cominductive -> inductive entry without qvar -> indtyping -> inductive entry with qvar -> inductive entry without qvar -> declarations ~~~ which should be cleaned up someday.
1 parent 77f93fa commit 2003ab8

File tree

8 files changed

+160
-48
lines changed

8 files changed

+160
-48
lines changed

kernel/environ.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,3 +1043,13 @@ struct
10431043
let hash _env c = GlobRef.CanOrd.hash c
10441044
let canonize _env c = GlobRef.canonize c
10451045
end
1046+
1047+
module Internal = struct
1048+
let for_checking_pseudo_sort_poly env =
1049+
let q = Sorts.QVar.make_var 0 in
1050+
assert (not (Sorts.QVar.Set.mem q env.env_qualities));
1051+
let env = map_universes UGraph.Internal.for_checking_pseudo_sort_poly env in
1052+
{ env with env_qualities = Sorts.QVar.Set.add q env.env_qualities }
1053+
1054+
let is_above_prop env q = UGraph.Internal.is_above_prop env.env_universes q
1055+
end

kernel/environ.mli

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,3 +463,11 @@ val no_link_info : link_info
463463

464464
(** Primitives *)
465465
val set_retroknowledge : env -> Retroknowledge.retroknowledge -> env
466+
467+
module Internal : sig
468+
(** Makes qvar 0 bound and treated as above prop.
469+
Do not use outside kernel inductive typechecking. *)
470+
val for_checking_pseudo_sort_poly : env -> env
471+
472+
val is_above_prop : env -> Sorts.QVar.t -> bool
473+
end

kernel/indTyping.ml

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ let get_arity c =
304304
| _ -> None
305305

306306
let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes with
307-
| Monomorphic_ind_entry | Polymorphic_ind_entry _ -> None
307+
| Monomorphic_ind_entry | Polymorphic_ind_entry _ -> mie, None
308308
| Template_ind_entry {univs=(template_univs, _ as template_context); pseudo_sort_poly} ->
309309
let params = mie.mind_entry_params in
310310
let ind =
@@ -334,7 +334,7 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
334334
(** params *)
335335
(* for each non-letin param, find whether it binds a template univ *)
336336
let template_params =
337-
CList.filter_map (fun param ->
337+
CList.map (fun param ->
338338
match param with
339339
| LocalDef (_,b,t) ->
340340
check_not_appearing b;
@@ -352,8 +352,8 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
352352
in
353353
let bound_in_params =
354354
List.fold_left (fun bound_in_params -> function
355-
| None -> bound_in_params
356-
| Some l ->
355+
| Some None | None -> bound_in_params
356+
| Some (Some l) ->
357357
if Level.Set.mem l bound_in_params then
358358
CErrors.user_err Pp.(str "Non-linear template level " ++ Level.raw_pr l)
359359
else Level.Set.add l bound_in_params)
@@ -371,15 +371,15 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
371371
in
372372

373373
(** arity *)
374-
let () =
374+
let arity_for_pseudo_poly =
375375
(* don't use get_arity, we allow constant template poly (eg eq) *)
376376
let (decls, s) = Term.decompose_prod_decls ind.mind_entry_arity in
377377
let () = if not (isSort s) then
378378
CErrors.user_err Pp.(str "Template polymorphic inductive's type must be a syntactic arity.")
379379
in
380380
check_not_appearing_rel_ctx decls;
381381
match destSort s with
382-
| SProp | Prop | Set -> ()
382+
| SProp | Prop | Set -> None
383383
| QSort _ -> assert false
384384
| Type u ->
385385
(* forbid template poly with an increment on a template univ in the conclusion
@@ -394,13 +394,49 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
394394
if has_increment then
395395
CErrors.user_err
396396
Pp.(str "Template polymorphism with conclusion strictly larger than a bound universe not supported.")
397+
else Some (decls, u)
397398
in
398399

399400
(** ctors *)
400401
let () = List.iter check_not_appearing ind.mind_entry_lc in
401402

402-
Some {
403-
template_param_arguments = List.rev_map Option.has_some template_params;
403+
(* for typechecking pseudo sort poly, replace Type@{u} with Type@{Var 0 | u}
404+
in the conclusion and for the bound univs which appear in the conclusion
405+
XXX it would be nicer to have the higher layers send us qvars instead *)
406+
let mie = match pseudo_sort_poly, arity_for_pseudo_poly with
407+
| TemplateUnivOnly, _ -> mie
408+
| TemplatePseudoSortPoly, None ->
409+
CErrors.user_err Pp.(str "Invalid pseudo sort poly template inductive.")
410+
| TemplatePseudoSortPoly, Some (indices, concl) ->
411+
let concl_bound_univs = Level.Set.inter template_univs (Universe.levels concl) in
412+
let bound_qvar = Sorts.QVar.make_var 0 in
413+
let params = List.map (fun param ->
414+
match param with
415+
| LocalDef _ -> param (* letin *)
416+
| LocalAssum (na, t) ->
417+
match get_arity t with
418+
| None -> param
419+
| Some (decls, l) ->
420+
if Level.Set.mem l concl_bound_univs then
421+
let l = Universe.make l in
422+
LocalAssum (na, it_mkProd_or_LetIn (mkSort (Sorts.qsort bound_qvar l)) decls)
423+
else param)
424+
params
425+
in
426+
let arity = it_mkProd_or_LetIn (mkSort (Sorts.qsort bound_qvar concl)) indices in
427+
{ mie with
428+
mind_entry_params = params;
429+
mind_entry_inds =
430+
[{ind with
431+
mind_entry_arity = arity;
432+
}];
433+
}
434+
in
435+
436+
let template_assums = CList.filter_map (fun x -> x) template_params in
437+
438+
mie, Some {
439+
template_param_arguments = List.rev_map Option.has_some template_assums;
404440
template_context;
405441
template_pseudo_sort_poly = pseudo_sort_poly;
406442
}
@@ -421,7 +457,7 @@ let abstract_packets env usubst ((arity,lc),(indices,splayed_lc),univ_info) =
421457

422458
let arity =
423459
if univ_info.ind_template then
424-
TemplateArity { template_level = univ_info.ind_univ; }
460+
TemplateArity { template_level = ind_univ; }
425461
else
426462
RegularArity {mind_user_arity = arity; mind_sort = ind_univ}
427463
in
@@ -450,17 +486,15 @@ let typecheck_inductive env ~sec_univs (mie:mutual_inductive_entry) =
450486
assert (List.is_empty (Environ.rel_context env));
451487

452488
(* universes *)
453-
let template = get_template mie in
489+
let mie, template = get_template mie in
454490

455491
let env_univs =
456492
match mie.mind_entry_universes with
457493
| Template_ind_entry {univs=ctx; pseudo_sort_poly} ->
494+
let env = Environ.push_context_set ~strict:false ctx env in
458495
begin match pseudo_sort_poly with
459-
| TemplatePseudoSortPoly ->
460-
(* For that particular case, we typecheck the inductive in an environment
461-
where the universes introduced by the definition are only [>= Prop] *)
462-
Environ.push_floating_context_set ctx env
463-
| TemplateUnivOnly -> Environ.push_context_set ~strict:false ctx env
496+
| TemplatePseudoSortPoly -> Environ.Internal.for_checking_pseudo_sort_poly env
497+
| TemplateUnivOnly -> env
464498
end
465499
| Monomorphic_ind_entry -> env
466500
| Polymorphic_ind_entry ctx -> push_context ctx env
@@ -532,8 +566,19 @@ let typecheck_inductive env ~sec_univs (mie:mutual_inductive_entry) =
532566

533567
(* Abstract universes *)
534568
let usubst, univs = match mie.mind_entry_universes with
535-
| Monomorphic_ind_entry | Template_ind_entry _ ->
536-
UVars.empty_sort_subst, Monomorphic
569+
| Monomorphic_ind_entry ->
570+
UVars.empty_sort_subst, Monomorphic
571+
| Template_ind_entry info -> begin match info.pseudo_sort_poly with
572+
| TemplateUnivOnly -> UVars.empty_sort_subst, Monomorphic
573+
| TemplatePseudoSortPoly ->
574+
(* replace Type@{Var 0 | u} back to Type@{u}
575+
XXX it would be nicer to keep the qvar in the declared structure *)
576+
let qsubst =
577+
Sorts.QVar.Map.singleton (Sorts.QVar.make_var 0) Sorts.Quality.(QConstant QType)
578+
in
579+
let usubst = Univ.empty_level_subst in
580+
(qsubst, usubst), Monomorphic
581+
end
537582
| Polymorphic_ind_entry uctx ->
538583
let (inst, auctx) = UVars.abstract_universes uctx in
539584
let inst = UVars.make_instance_subst inst in

kernel/inductive.ml

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,16 @@ let no_sort_variable () =
118118

119119
type template_univ =
120120
| TemplateProp
121+
| TemplateAboveProp of Sorts.QVar.t * Universe.t
121122
| TemplateUniv of Universe.t
122123

123124
let max_template_universe u v = match u, v with
124125
| TemplateProp, x | x, TemplateProp -> x
126+
| TemplateAboveProp (q1,u), TemplateAboveProp (q2,v) ->
127+
if Sorts.QVar.equal q1 q2 then TemplateAboveProp (q1, Universe.sup u v)
128+
else TemplateUniv (Universe.sup u v)
129+
| TemplateAboveProp (_, u), TemplateUniv v
130+
| TemplateUniv u, TemplateAboveProp (_,v)
125131
| TemplateUniv u, TemplateUniv v -> TemplateUniv (Universe.sup u v)
126132

127133
(* cons_subst add the mapping [u |-> su] in subst if [u] is not *)
@@ -191,32 +197,34 @@ let subst_univs_sort (subs, pseudo_sort_poly) = function
191197
let u = Universe.repr u in
192198
let supern u n = iterate Universe.super n u in
193199
let map (u, n) =
194-
if Level.is_set u then Some (Universe.type0, n)
200+
if Level.is_set u then TemplateUniv (supern Universe.type0 n)
195201
else match Level.Map.find u subs, pseudo_sort_poly with
196202
| TemplateProp, TemplatePseudoSortPoly ->
197203
if Int.equal n 0 then
198204
(* This is an instantiation of a template universe by Prop, ignore it *)
199-
None
205+
TemplateProp
200206
else
201207
(* Prop + S n actually means Set + S n *)
202-
Some (Universe.type0, n)
208+
TemplateUniv (supern Universe.type0 n)
209+
| TemplateAboveProp (q, u), TemplatePseudoSortPoly ->
210+
TemplateAboveProp (q, supern u n)
203211
| TemplateProp, TemplateUnivOnly ->
204212
(* exploit Prop <= Set *)
205-
Some (Universe.type0, n)
206-
| TemplateUniv v, _ -> Some (v,n)
213+
TemplateUniv (supern Universe.type0 n)
214+
| TemplateAboveProp (_, u), TemplateUnivOnly ->
215+
TemplateUniv (supern u n)
216+
| TemplateUniv v, _ -> TemplateUniv (supern v n)
207217
| exception Not_found ->
208218
(* Either an unbound template universe due to missing arguments, or a
209219
global one appearing in the inductive arity. *)
210-
Some (Universe.make u, n)
220+
TemplateUniv (supern (Universe.make u) n)
211221
in
212-
let u = List.filter_map map u in
213-
match u with
214-
| [] ->
215-
(* No constraints, fall in Prop *)
222+
let u = List.map map u in
223+
match List.fold_left max_template_universe TemplateProp u with
224+
| TemplateProp ->
216225
Sorts.prop
217-
| (u,n) :: rest ->
218-
let fold accu (u, n) = Universe.sup accu (supern u n) in
219-
Sorts.sort_of_univ (List.fold_left fold (supern u n) rest)
226+
| TemplateUniv u -> Sorts.sort_of_univ u
227+
| TemplateAboveProp (q,u) -> Sorts.qsort q u
220228

221229
let get_arity c =
222230
let decls, c = Term.decompose_prod_decls c in

kernel/inductive.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ val instantiate_inductive_constraints :
4848

4949
type template_univ =
5050
| TemplateProp
51+
| TemplateAboveProp of Sorts.QVar.t * Universe.t
5152
| TemplateUniv of Universe.t
5253

5354
type param_univs = (expected:Univ.Level.t -> template_univ) list

kernel/typeops.ml

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,32 @@ let infer_assumption env t ty =
6363
with TypeError _ ->
6464
error_assumption env (make_judge t ty)
6565

66+
let nf_relevance env = function
67+
| Sorts.RelevanceVar q as r ->
68+
if Environ.Internal.is_above_prop env q then Sorts.Relevant
69+
else r
70+
| (Sorts.Irrelevant | Sorts.Relevant) as r -> r
71+
72+
let check_relevance env r r' =
73+
Sorts.relevance_equal (nf_relevance env r) (nf_relevance env r')
74+
6675
let check_assumption env x t ty =
6776
let r = x.binder_relevance in
6877
let r' = infer_assumption env t ty in
69-
if Sorts.relevance_equal r r' then ()
78+
if check_relevance env r r' then ()
7079
else
7180
error_bad_binder_relevance env r' (RelDecl.LocalAssum (x, t))
7281

73-
let check_binding_relevance na1 na2 =
82+
let check_binding_relevance env na1 na2 =
7483
(* Since we know statically the relevance here, we are stricter *)
75-
assert (Sorts.relevance_equal (binder_relevance na1) (binder_relevance na2))
84+
assert (check_relevance env (binder_relevance na1) (binder_relevance na2))
7685

7786
let esubst u s c =
7887
Vars.esubst Vars.lift_substituend s (subst_instance_constr u c)
7988

8089
exception ArgumentsMismatch
8190

82-
let instantiate_context u subst nas ctx =
91+
let instantiate_context env u subst nas ctx =
8392
let open Context.Rel.Declaration in
8493
let instantiate_relevance na =
8594
{ na with binder_relevance = UVars.subst_instance_relevance u na.binder_relevance }
@@ -91,15 +100,15 @@ let instantiate_context u subst nas ctx =
91100
let subst = Esubst.subs_liftn i subst in
92101
let na = instantiate_relevance na in
93102
let ty = esubst u subst ty in
94-
let () = check_binding_relevance na nas.(i) in
103+
let () = check_binding_relevance env na nas.(i) in
95104
LocalAssum (nas.(i), ty) :: ctx
96105
| LocalDef (na, ty, bdy) :: ctx ->
97106
let ctx = instantiate (pred i) ctx in
98107
let subst = Esubst.subs_liftn i subst in
99108
let na = instantiate_relevance na in
100109
let ty = esubst u subst ty in
101110
let bdy = esubst u subst bdy in
102-
let () = check_binding_relevance na nas.(i) in
111+
let () = check_binding_relevance env na nas.(i) in
103112
LocalDef (nas.(i), ty, bdy) :: ctx
104113
in
105114
instantiate (Array.length nas - 1) ctx
@@ -397,7 +406,9 @@ let make_param_univs env indu spec args argtys =
397406
| Prop -> TemplateProp
398407
| Set -> TemplateUniv Universe.type0
399408
| Type u -> TemplateUniv u
400-
| QSort _ -> assert false)
409+
| QSort (q,u) ->
410+
assert (Environ.Internal.is_above_prop env q);
411+
TemplateAboveProp (q,u))
401412
argtys
402413

403414
let type_of_inductive_knowing_parameters env (ind,u as indu) args argst =
@@ -473,8 +484,9 @@ let check_branch_types env (_mib, mip) ci u pms c _ct lft (pctx, p) =
473484
error_ill_formed_branch env c ((ci.ci_ind, i + 1), u) brt expbrt
474485

475486
let should_invert_case env r ci =
476-
Sorts.relevance_equal r Sorts.Relevant &&
487+
check_relevance env r Sorts.Relevant &&
477488
let mib,mip = lookup_mind_specif env ci.ci_ind in
489+
(* mind_relevance cannot be a pseudo sort poly variable so don't use check_relevance *)
478490
Sorts.relevance_equal mip.mind_relevance Sorts.Irrelevant &&
479491
(* NB: it's possible to have 2 ctors or arguments to 1 ctor by unsetting univ checks
480492
but we don't do special reduction in such cases
@@ -522,7 +534,7 @@ let type_of_case env (mib, mip as specif) ci u pms (pctx, pnas, p, rp, pt) iv c
522534
in
523535
let () =
524536
let expected = Sorts.relevance_of_sort sp in
525-
if Sorts.relevance_equal rp expected then ()
537+
if check_relevance env rp expected then ()
526538
else
527539
error_bad_case_relevance env expected (ci, u, pms, ((pnas, p), rp), iv, c, lf)
528540
in
@@ -601,15 +613,15 @@ let type_of_global_in_context env r =
601613
let check_assum_annot env s x t =
602614
let r = x.binder_relevance in
603615
let r' = Sorts.relevance_of_sort s in
604-
if Sorts.relevance_equal r' r
616+
if check_relevance env r' r
605617
then ()
606618
else error_bad_binder_relevance env r' (RelDecl.LocalAssum (x, t))
607619

608620

609621
let check_let_annot env s x c t =
610622
let r = x.binder_relevance in
611623
let r' = Sorts.relevance_of_sort s in
612-
if Sorts.relevance_equal r' r
624+
if check_relevance env r' r
613625
then ()
614626
else error_bad_binder_relevance env r' (RelDecl.LocalDef (x, c, t))
615627

@@ -652,7 +664,7 @@ and execute_aux tbl env cstr =
652664
| Proj (p, r, c) ->
653665
let ct = execute tbl env c in
654666
let r', ty = type_of_projection env p (self c) ct in
655-
assert (Sorts.relevance_equal r r');
667+
assert (check_relevance env r r');
656668
ty
657669

658670
(* Lambda calculus operators *)
@@ -752,7 +764,7 @@ and execute_aux tbl env cstr =
752764
in
753765
let realdecls = LocalAssum (Context.make_annot Anonymous mip.mind_relevance, self) :: realdecls in
754766
let realdecls =
755-
try instantiate_context u paramsubst nas realdecls
767+
try instantiate_context env u paramsubst nas realdecls
756768
with ArgumentsMismatch -> error_elim_arity env (ci.ci_ind, u) (HConstr.self c) None
757769
in
758770
let p_env = Environ.push_rel_context realdecls env in
@@ -768,7 +780,7 @@ and execute_aux tbl env cstr =
768780
let (ctx, cty) = mip.mind_nf_lc.(i) in
769781
let ctx, _ = List.chop mip.mind_consnrealdecls.(i) ctx in
770782
let ctx =
771-
try instantiate_context u paramsubst nas ctx
783+
try instantiate_context env u paramsubst nas ctx
772784
with ArgumentsMismatch ->
773785
(* Despite the name, the toplevel message is reasonable *)
774786
error_elim_arity env (ci.ci_ind, u) (self c) None

0 commit comments

Comments
 (0)