Skip to content

Commit 058653a

Browse files
committed
feat: Remove default elim constraints Type -> s
feat: Remove elim constraint Type->s by default fix: Update to have dominance check not be done on same quality Notably, dominance updates between sort variables were not checking if the variables were the same. If both were the same and they were not dominated (e.g. when removing the default Type->s constraint), then it would loop because it would postpone the dominance check. It really doesn't make sense though to update the dominance of a sort variable when adding the reflexive elimination constraint. The dominant will be the same in both cases, and if there is none, then it will be dominated eventually when checking with other sorts. fix: Cleanup delayed_check with sort variables fix: Add Type->s to MaybeSquashed fix: Add elim constraints for projections in non-primitive records chore: Add changelog entry refactor: Use Cmap_env to keep elim constraints from projs
1 parent 2e7ada7 commit 058653a

File tree

5 files changed

+63
-29
lines changed

5 files changed

+63
-29
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- **Changed:**
2+
`Type` does not eliminate to every sort by default
3+
(`#21453 <https://github.com/rocq-prover/rocq/pull/21453>`_,
4+
by Tomas Diaz).

kernel/indTyping.ml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,13 @@ let compute_elim_squash ?(is_real_arg=false) env u info =
135135
| QSort (q, _), (SProp | Prop) ->
136136
if Environ.Internal.is_above_prop env q then info
137137
else add_squash (Sorts.quality u) info
138-
| _, _ -> { info with ind_squashed = Some AlwaysSquashed }
138+
| (Type _ | Set), QSort (q, _) -> add_squash (QVar q) info
139+
| SProp, (Prop | Type _ | Set) ->
140+
{ info with ind_squashed = Some AlwaysSquashed }
141+
| Prop, (Type _ | Set) -> { info with ind_squashed = Some AlwaysSquashed }
142+
(* These cases should not happen because `eliminates_to` above should be true,
143+
* e.g., Type -> (S)Prop, SProp -> SProp, etc. *)
144+
| (Type _ | Set | SProp | Prop), _ -> assert false
139145

140146
let check_context_univs ~ctor env info ctx =
141147
let check_one d (info,env) =

kernel/qGraph.ml

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ module ElimTable = struct
2121

2222
let eliminates_to q q' =
2323
match q, q' with
24-
| QConstant QType, _ -> true
2524
| QConstant q, QConstant q' -> const_eliminates_to q q'
2625
| QVar q, QVar q' -> QVar.equal q q'
2726
| (QConstant _ | QVar _), _ -> false
@@ -159,11 +158,31 @@ let rec update_dominance g q qv =
159158
| Some q' -> update_dominant_if_related g qv q' q in
160159
match QMap.find_opt qv g.delayed_check with
161160
| None -> g'
162-
| Some qs ->
163-
let g' = QSet.fold (fun v g -> Option.bind g (fun g -> update_dominance g q v)) qs g' in
164-
match g' with
165-
| Some graph -> Some { graph with delayed_check = QMap.set qv QSet.empty g.delayed_check }
166-
| None -> None
161+
| Some delayed_qs ->
162+
(* When two sort variables are `set` to each other, e.g. uState, (q1 <-> q2), without being
163+
dominated, then both delay the domination check of each other:
164+
delayed_check[q1] = {q2}
165+
delayed_check[q2] = {q1}
166+
167+
When one of them becomes dominated, e.g. q1 dominated by Type, then we need to clear up
168+
any occurrence of it in the delayed check of the other, e.g. remove q1 from delayed_check[q2].
169+
Otherwise, we end up in a loop. *)
170+
let remove_qv_from_delayed delayed_q delayed_check =
171+
match QMap.find_opt delayed_q delayed_check with
172+
| None -> delayed_check
173+
| Some dqs ->
174+
QMap.set delayed_q (QSet.remove qv dqs) delayed_check
175+
in
176+
let clearup_cyclic_delay graph =
177+
QSet.fold (fun delayed_q acc_graph ->
178+
{ acc_graph with delayed_check = remove_qv_from_delayed delayed_q acc_graph.delayed_check })
179+
delayed_qs graph
180+
in
181+
let g' = Option.map clearup_cyclic_delay g' in
182+
let g' = QSet.fold (fun v g -> Option.bind g (fun g -> update_dominance g q v)) delayed_qs g' in
183+
match g' with
184+
| Some graph -> Some { graph with delayed_check = QMap.set qv QSet.empty g.delayed_check }
185+
| None -> None
167186

168187
let update_dominance_if_valid g (q1,k,q2) =
169188
match k with
@@ -173,6 +192,8 @@ let update_dominance_if_valid g (q1,k,q2) =
173192
else
174193
match q1, q2 with
175194
| (Quality.QConstant _ | Quality.QVar _), Quality.QConstant _ -> assert false
195+
| Quality.QVar qv1, Quality.QVar qv2 when QVar.equal qv1 qv2 -> assert false
196+
(* It makes no sense to update or delay the dominance of a sort variable when it eliminates to itself *)
176197
| Quality.QVar qv1, Quality.QVar qv2 ->
177198
(* 3 cases:
178199
- if [qv1] is a global, treat as constants.
@@ -183,7 +204,7 @@ let update_dominance_if_valid g (q1,k,q2) =
183204
(match QMap.find_opt qv1 g.dominant with
184205
| None ->
185206
let add_delayed qs =
186-
Some { g with delayed_check = QMap.set qv1 (QSet.add qv2 qs) g.delayed_check }
207+
Some { g with delayed_check = QMap.add qv1 (QSet.add qv2 qs) g.delayed_check }
187208
in
188209
(match QMap.find_opt qv1 g.delayed_check with
189210
| None -> add_delayed QSet.empty
@@ -232,8 +253,9 @@ let enforce_constraint (q1, k, q2) g =
232253
if ignore_constraints g then g else
233254
let e = lazy (G.get_explanation (q1,to_graph_cstr k,q2) g.graph) in
234255
raise @@ EliminationError (QualityInconsistency (None, (k, q1, q2, Some (Path e))))
235-
| Some g ->
236-
dominance_check g (q1, k, q2)
256+
| Some graph ->
257+
if Quality.equal q1 q2 then graph
258+
else dominance_check graph (q1, k, q2)
237259

238260
let merge_constraints csts g = ElimConstraints.fold enforce_constraint csts g
239261

@@ -248,16 +270,11 @@ exception AlreadyDeclared = G.AlreadyDeclared
248270

249271
let add_quality q g =
250272
let graph = G.add q g.graph in
251-
let g = enforce_constraint (Quality.qtype, ElimConstraint.ElimTo, q) { g with graph } in
252-
let (paths,ground_and_global_sorts) =
273+
let ground_and_global_sorts =
253274
if Quality.is_qglobal q
254-
then (RigidPaths.add_elim_to Quality.qtype q g.rigid_paths, Quality.Set.add q g.ground_and_global_sorts)
255-
else (g.rigid_paths,g.ground_and_global_sorts) in
256-
(* As Type ~> s, set Type to be the dominant sort of q if q is a variable. *)
257-
let dominant = match q with
258-
| Quality.QVar qv -> QMap.add qv Quality.qtype g.dominant
259-
| Quality.QConstant _ -> g.dominant in
260-
{ g with rigid_paths = paths; ground_and_global_sorts; dominant }
275+
then Quality.Set.add q g.ground_and_global_sorts
276+
else g.ground_and_global_sorts in
277+
{ g with graph; ground_and_global_sorts }
261278

262279
let enforce_eliminates_to s1 s2 g =
263280
enforce_constraint (s1, ElimConstraint.ElimTo, s2) g
@@ -307,9 +324,10 @@ let merge g g' =
307324
(fun q acc -> try add_quality q acc with _ -> acc) qs g in
308325
Quality.Set.fold
309326
(fun q -> Quality.Set.fold
310-
(fun q' acc -> if eliminates_to g' q q'
311-
then enforce_eliminates_to q q' acc
312-
else acc) qs) qs g
327+
(fun q' acc -> if Quality.equal q q' then acc
328+
else if eliminates_to g' q q'
329+
then enforce_eliminates_to q q' acc
330+
else acc) qs) qs g
313331

314332
let is_empty g = QVar.Set.is_empty (qvar_domain g)
315333

test-suite/success/sort_poly.v

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Module Inductives.
112112
Inductive foo2@{s; |} := Foo2 : Type@{s;Set} -> foo2.
113113
Check foo2_rect.
114114

115-
Inductive foo3@{s; |} (A:Type@{s;Set}) := Foo3 : A -> foo3 A.
115+
Inductive foo3@{s;|} (A:Type@{s;Set}) : Type := Foo3 : A -> foo3 A.
116116
Check foo3_rect.
117117

118118
Fail Inductive foo4@{s;u v|v < u} : Type@{v} := C (_:Type@{s;u}).
@@ -210,10 +210,13 @@ Module Inductives.
210210
Fail Record R5@{s; |} (A:Type@{s;Set}) : SProp := { R5f1 : A}.
211211
#[warnings="-non-primitive-record"]
212212
Record R5@{s; |} (A:Type@{s;Set}) : SProp := { R5f1 : A}.
213+
Fail Check R5f1.
213214
Definition R5f1_sprop (A:SProp) (r:R5 A) : A := let (f) := r in f.
214215
Fail Definition R5f1_prop (A:Prop) (r:R5 A) : A := let (f) := r in f.
215216

216-
Record R6@{s; |} (A:Type@{s;Set}) := { R6f1 : A; R6f2 : nat }.
217+
(* This is now invalid since Type does not eliminate to arbitrary sorts by default *)
218+
Fail Record R6@{s; |} (A:Type@{s;Set}) := { R6f1 : A; R6f2 : nat }.
219+
Record R6@{s; |Type->s} (A:Type@{s;Set}) := { R6f1 : A; R6f2 : nat }.
217220
Check fun (A:SProp) (x y : R6 A) =>
218221
eq_refl : Conversion.box _ x.(R6f1 _) = Conversion.box _ y.(R6f1 _).
219222
Fail Check fun (A:Prop) (x y : R6 A) =>
@@ -286,7 +289,10 @@ Module Inductives.
286289

287290
Arguments exist3 {_ _}.
288291

289-
Definition π1@{s s';u v|} {A:Type@{s;u}} {P:A -> Type@{s';v}} (p : sigma3@{_ _ Type;_ _} A P) : A :=
292+
(* This is now invalid since Type does not eliminate to arbitrary sorts by default *)
293+
Fail Definition π1@{s s';u v|} {A:Type@{s;u}} {P:A -> Type@{s';v}} (p : sigma3@{_ _ Type;_ _} A P) : A :=
290294
match p return A with exist3 a _ => a end.
291-
295+
Definition π1@{s s';u v|Type -> s} {A:Type@{s;u}} {P:A -> Type@{s';v}} (p : sigma3@{_ _ Type;_ _} A P) : A :=
296+
match p return A with exist3 a _ => a end.
297+
(* s s' ; u v |= Type -> s *)
292298
End Inductives.

test-suite/success/sort_poly_extraction.v

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Definition foo1 := foo@{Type SProp|}.
3131

3232
Inductive T@{s| |} : Type@{s|Set} := O : T | S : T -> T.
3333

34-
Inductive box@{s1 s2| |} (A : Type@{s1|Set}) (B : Type@{s2|Set}) : Type@{Set} := Box : A -> B -> box A B.
34+
Inductive box@{s1 s2; |Type->s1, Type->s2} (A : Type@{s1;Set}) (B : Type@{s2;Set}) : Type@{Set} := Box : A -> B -> box A B.
3535

3636
Definition bar (A : Type) (x : A) := 0.
3737

@@ -44,11 +44,11 @@ Extraction TestCompile Foo.
4444
(* Check module subtyping *)
4545

4646
Module Type S.
47-
Inductive box@{s1 s2| |} (A : Type@{s1|Set}) (B : Type@{s2|Set}) : Type@{Set} := Box : A -> B -> box A B.
47+
Inductive box@{s1 s2; |Type->s1, Type->s2} (A : Type@{s1;Set}) (B : Type@{s2;Set}) : Type@{Set} := Box : A -> B -> box A B.
4848
End S.
4949

5050
Module Bar : S.
51-
Inductive box@{s1 s2| |} (A : Type@{s1|Set}) (B : Type@{s2|Set}) : Type@{Set} := Box : A -> B -> box A B.
51+
Inductive box@{s1 s2; |Type->s1, Type->s2} (A : Type@{s1;Set}) (B : Type@{s2;Set}) : Type@{Set} := Box : A -> B -> box A B.
5252
End Bar.
5353

5454
Extraction TestCompile Bar.

0 commit comments

Comments
 (0)