Skip to content

Commit a3aadcc

Browse files
committed
Typecheck pseudo sort poly inductives in kernel using above prop qvar
1 parent a2720ff commit a3aadcc

File tree

8 files changed

+174
-52
lines changed

8 files changed

+174
-52
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: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ let check_univ_leq ?(is_real_arg=false) env u info =
9696
| HasRelevantArg -> info
9797
| NoRelevantArg -> match u with
9898
| Sorts.SProp -> info
99-
| QSort (q,_) -> if Sorts.Quality.equal (QVar q) (Sorts.quality info.ind_univ)
99+
| QSort (q,_) ->
100+
if Environ.Internal.is_above_prop env q
101+
|| Sorts.Quality.equal (QVar q) (Sorts.quality info.ind_univ)
100102
then { info with record_arg_info = HasRelevantArg }
101103
else info
102104
| Prop | Set | Type _ -> { info with record_arg_info = HasRelevantArg }
@@ -109,12 +111,15 @@ let check_univ_leq ?(is_real_arg=false) env u info =
109111
info
110112

111113
| Prop, SProp -> { info with ind_squashed = Some AlwaysSquashed }
112-
| (SProp|Prop), QSort _ -> add_squash (Sorts.quality u) info
114+
| (SProp|Prop), QSort (q,_) ->
115+
if Environ.Internal.is_above_prop env q then info
116+
else add_squash (Sorts.quality u) info
113117
| Prop, (Prop | Set | Type _) -> info
114118

115119
| Set, (SProp | Prop) -> { info with ind_squashed = Some AlwaysSquashed }
116-
| Set, QSort (_, indu) ->
117-
if UGraph.check_leq (universes env) Universe.type0 indu
120+
| Set, QSort (q, indu) ->
121+
if Environ.Internal.is_above_prop env q then info
122+
else if UGraph.check_leq (universes env) Universe.type0 indu (* XXX always true *)
118123
then add_squash qtype info
119124
else { info with missing = u :: info.missing }
120125
| Set, Set -> info
@@ -227,6 +232,11 @@ let check_constructors env_ar_par isrecord params lc (arity,indices,univ_info) =
227232
| _ -> check_univ_leq env_ar_par Sorts.set univ_info
228233
in
229234
let univ_info = Array.fold_left (check_constructor_univs env_ar_par) univ_info splayed_lc in
235+
let () = if univ_info.ind_template then match univ_info.ind_squashed with
236+
| None | Some AlwaysSquashed -> ()
237+
| Some (SometimesSquashed _) ->
238+
CErrors.user_err Pp.(str "Cannot handle sometimes squashed template polymorphic type.")
239+
in
230240
(* generalize the constructors over the parameters *)
231241
let lc = Array.map (fun c -> Term.it_mkProd_or_LetIn c params) lc in
232242
(arity, lc), (indices, splayed_lc), univ_info
@@ -304,7 +314,7 @@ let get_arity c =
304314
| _ -> None
305315

306316
let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes with
307-
| Monomorphic_ind_entry | Polymorphic_ind_entry _ -> None
317+
| Monomorphic_ind_entry | Polymorphic_ind_entry _ -> mie, None
308318
| Template_ind_entry {univs=(template_univs, _ as template_context); pseudo_sort_poly} ->
309319
let params = mie.mind_entry_params in
310320
let ind =
@@ -334,7 +344,7 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
334344
(** params *)
335345
(* for each non-letin param, find whether it binds a template univ *)
336346
let template_params =
337-
CList.filter_map (fun param ->
347+
CList.map (fun param ->
338348
match param with
339349
| LocalDef (_,b,t) ->
340350
check_not_appearing b;
@@ -352,8 +362,8 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
352362
in
353363
let bound_in_params =
354364
List.fold_left (fun bound_in_params -> function
355-
| None -> bound_in_params
356-
| Some l ->
365+
| Some None | None -> bound_in_params
366+
| Some (Some l) ->
357367
if Level.Set.mem l bound_in_params then
358368
CErrors.user_err Pp.(str "Non-linear template level " ++ Level.raw_pr l)
359369
else Level.Set.add l bound_in_params)
@@ -371,15 +381,15 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
371381
in
372382

373383
(** arity *)
374-
let () =
384+
let arity_for_pseudo_poly =
375385
(* don't use get_arity, we allow constant template poly (eg eq) *)
376386
let (decls, s) = Term.decompose_prod_decls ind.mind_entry_arity in
377387
let () = if not (isSort s) then
378388
CErrors.user_err Pp.(str "Template polymorphic inductive's type must be a syntactic arity.")
379389
in
380390
check_not_appearing_rel_ctx decls;
381391
match destSort s with
382-
| SProp | Prop | Set -> ()
392+
| SProp | Prop | Set -> None
383393
| QSort _ -> assert false
384394
| Type u ->
385395
(* forbid template poly with an increment on a template univ in the conclusion
@@ -394,13 +404,49 @@ let get_template (mie:mutual_inductive_entry) = match mie.mind_entry_universes w
394404
if has_increment then
395405
CErrors.user_err
396406
Pp.(str "Template polymorphism with conclusion strictly larger than a bound universe not supported.")
407+
else Some (decls, u)
397408
in
398409

399410
(** ctors *)
400411
let () = List.iter check_not_appearing ind.mind_entry_lc in
401412

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

422468
let arity =
423469
if univ_info.ind_template then
424-
TemplateArity { template_level = univ_info.ind_univ; }
470+
TemplateArity { template_level = ind_univ; }
425471
else
426472
RegularArity {mind_user_arity = arity; mind_sort = ind_univ}
427473
in
@@ -450,17 +496,15 @@ let typecheck_inductive env ~sec_univs (mie:mutual_inductive_entry) =
450496
assert (List.is_empty (Environ.rel_context env));
451497

452498
(* universes *)
453-
let template = get_template mie in
499+
let mie, template = get_template mie in
454500

455501
let env_univs =
456502
match mie.mind_entry_universes with
457503
| Template_ind_entry {univs=ctx; pseudo_sort_poly} ->
504+
let env = Environ.push_context_set ~strict:false ctx env in
458505
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
506+
| TemplatePseudoSortPoly -> Environ.Internal.for_checking_pseudo_sort_poly env
507+
| TemplateUnivOnly -> env
464508
end
465509
| Monomorphic_ind_entry -> env
466510
| Polymorphic_ind_entry ctx -> push_context ctx env
@@ -532,8 +576,19 @@ let typecheck_inductive env ~sec_univs (mie:mutual_inductive_entry) =
532576

533577
(* Abstract universes *)
534578
let usubst, univs = match mie.mind_entry_universes with
535-
| Monomorphic_ind_entry | Template_ind_entry _ ->
536-
UVars.empty_sort_subst, Monomorphic
579+
| Monomorphic_ind_entry ->
580+
UVars.empty_sort_subst, Monomorphic
581+
| Template_ind_entry info -> begin match info.pseudo_sort_poly with
582+
| TemplateUnivOnly -> UVars.empty_sort_subst, Monomorphic
583+
| TemplatePseudoSortPoly ->
584+
(* replace Type@{Var 0 | u} back to Type@{u}
585+
XXX it would be nicer to keep the qvar in the declared structure *)
586+
let qsubst =
587+
Sorts.QVar.Map.singleton (Sorts.QVar.make_var 0) Sorts.Quality.(QConstant QType)
588+
in
589+
let usubst = Univ.empty_level_subst in
590+
(qsubst, usubst), Monomorphic
591+
end
537592
| Polymorphic_ind_entry uctx ->
538593
let (inst, auctx) = UVars.abstract_universes uctx in
539594
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

0 commit comments

Comments
 (0)