Skip to content

Commit e8e4f0c

Browse files
author
qvermande
committed
declared sort and Pack_ as coercions in HB/structures.v
1 parent 8a72aef commit e8e4f0c

File tree

6 files changed

+171
-24
lines changed

6 files changed

+171
-24
lines changed

Changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
a class that is known to have no instance (for the given type)
88
- **Speedup** `toposort` on `gref` uses OCaml's maps and sets rather than lists
99

10+
- **Change** For a structure `S` on a subject of type `T`, declares `S.sort` as
11+
an Elpi coercion from `S.type` to `T` and `S.pack` as an Elpi coercion from
12+
`T` to `S.type` whenever `T` is not a global type (e.g. a variable). Note
13+
that `S.pack` can cast a `t : T` to `S.type` only if an instance of the
14+
class `S` on `t` is found by type class inference
15+
1016
## [1.7.0] - 2024-01-10
1117

1218
Compatible with

HB/common/synthesis.elpi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ infer-coercion-tgt (w-params.cons ID Ty F) CoeClass :-
154154
@pi-parameter ID Ty x\ infer-coercion-tgt (F x) CoeClass.
155155
infer-coercion-tgt (w-params.nil _ {{ Type }} _) sortclass.
156156
infer-coercion-tgt (w-params.nil _ {{ _ -> _ }} _) funclass.
157-
infer-coercion-tgt (w-params.nil _ T _) (grefclass GR) :- coq.term->gref T GR.
157+
infer-coercion-tgt (w-params.nil _ T _) (grefclass GR) :- coq.term-is-gref? T GR.
158158

159159
pred w-args.check-key i:list term, i:term, i:list (w-args A), o:prop.
160160
w-args.check-key _PS _T [] true :- !.

HB/structure.elpi

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,14 @@ declare Module BSkel Sort :- std.do! [
105105
%]),
106106

107107
if-verbose (coq.say {header} "making coercion from type to target"),
108-
synthesis.infer-coercion-tgt MLwP CoeClass,
109-
if-arg-sort (private.declare-sort-coercion CoeClass Structure
110-
(global (const ArgSortCst))),
111-
private.declare-sort-coercion CoeClass Structure SortProjection,
108+
if (synthesis.infer-coercion-tgt MLwP CoeClass)
109+
(if-arg-sort (private.declare-sort-coercion CoeClass Structure
110+
(global (const ArgSortCst))),
111+
private.declare-sort-coercion CoeClass Structure SortProjection)
112+
(if-arg-sort (private.declare-sort-coercion-elpi (global Structure) (global (const ArgSortCst))),
113+
private.declare-sort-coercion-elpi (global Structure) SortProjection),
114+
115+
private.declare-reverse-coercion-elpi Structure,
112116

113117
if-verbose (coq.say {header} "exporting unification hints"),
114118
ClassAlias => Factories => GRDepsClauses =>
@@ -137,24 +141,26 @@ declare Module BSkel Sort :- std.do! [
137141

138142
log.coq.env.import-module "Exports" Exports,
139143

140-
if-verbose (coq.say {header} "declaring on_ abbreviation"),
144+
if (var CoeClass)
145+
(if-verbose (coq.say {header} "could not declare the `on_`, `copy` and `on` abbreviations because the target of sort is not a coercion class"))
146+
(if-verbose (coq.say {header} "declaring on_ abbreviation"),
141147

142-
private.mk-infer-key CoeClass ClassProjection NilwP (global Structure) PhClass,
148+
private.mk-infer-key CoeClass ClassProjection NilwP (global Structure) PhClass,
143149

144-
phant.add-abbreviation "on_" PhClass _ ClassOfAbbrev,
145-
(pi c\ coq.notation.abbreviation ClassOfAbbrev [c] (ClassOfAbbrev_ c)),
150+
phant.add-abbreviation "on_" PhClass _ ClassOfAbbrev,
151+
(pi c\ coq.notation.abbreviation ClassOfAbbrev [c] (ClassOfAbbrev_ c)),
146152

147-
if-verbose (coq.say {header} "declaring `copy` abbreviation"),
153+
if-verbose (coq.say {header} "declaring `copy` abbreviation"),
148154

149-
coq.mk-app (global ClassName) {params->holes NilwP} AppClassHoles,
150-
@global! => log.coq.notation.add-abbreviation "copy" 2
151-
{{fun T C => (lp:(ClassOfAbbrev_ C) : (lp:AppClassHoles T)) }} tt _,
155+
coq.mk-app (global ClassName) {params->holes NilwP} AppClassHoles,
156+
@global! => log.coq.notation.add-abbreviation "copy" 2
157+
{{fun T C => (lp:(ClassOfAbbrev_ C) : (lp:AppClassHoles T)) }} tt _,
152158

153-
if-verbose (coq.say {header} "declaring on abbreviation"),
159+
if-verbose (coq.say {header} "declaring on abbreviation"),
154160

155-
@global! => log.coq.notation.add-abbreviation "on" 1
156-
{{fun T => (lp:{{ ClassOfAbbrev_ {{_}} }} : (lp:AppClassHoles T)) }} tt
157-
_OnAbbrev,
161+
@global! => log.coq.notation.add-abbreviation "on" 1
162+
{{fun T => (lp:{{ ClassOfAbbrev_ {{_}} }} : (lp:AppClassHoles T)) }} tt
163+
_OnAbbrev),
158164

159165
log.coq.env.end-module-name Module ModulePath,
160166

@@ -276,6 +282,47 @@ export-operations Structure ProjSort ProjClass MLwP EX1 EX2 MLToExport :- std.do
276282
std.map LMwPToExport w-params_1 MLToExport,
277283
].
278284

285+
pred mk-sort-coercion-aux i:term, i:term, i:term, i:list term, o:prop.
286+
mk-sort-coercion-aux (prod _N _T Body) Structure P Args Clause :-
287+
Clause = (pi x\ C x),
288+
pi x\ mk-sort-coercion-aux (Body x) Structure P [x | Args] (C x).
289+
290+
mk-sort-coercion-aux _ Structure P Args Clause :-
291+
std.rev Args ArgsRev,
292+
Clause =
293+
(pi ctx v t e r argsAll w\ (coercion ctx v (app [Structure | ArgsRev]) e r :-
294+
coq.say "try sort coercion",
295+
std.append ArgsRev [v] argsAll,
296+
coq.mk-app P argsAll w,
297+
coq.say "find coercion from sort",
298+
coq.elaborate-skeleton w e r ok,
299+
coq.ltac.collect-goals r [] [],
300+
coq.say "sort coercion succeeds")).
301+
302+
pred mk-sort-coercion i:term, i:term, o:prop.
303+
mk-sort-coercion Structure P Clause :-
304+
std.assert-ok! (coq.typecheck Structure T) "anomaly: mk-sort-coercion",
305+
mk-sort-coercion-aux T Structure P [] Clause.
306+
307+
pred mk-reverse-coercion-aux i:term, i:term, i:term, i:list term, o:prop.
308+
mk-reverse-coercion-aux (prod _N _T Body) Structure G Args (pi x\ C x) :-
309+
pi x\ mk-reverse-coercion-aux (Body x) Structure G [x | Args] (C x).
310+
311+
mk-reverse-coercion-aux _ Structure G Args Clause :-
312+
std.rev Args ArgsRev,
313+
Clause =
314+
(pi ctx v t e r c argsAll w\ (coercion ctx v t (app [Structure | ArgsRev]) r :-
315+
std.append ArgsRev [v, c] argsAll,
316+
coq.mk-app G argsAll w,
317+
coq.elaborate-skeleton w e r ok,
318+
coq.ltac.collect-goals r [] [])).
319+
320+
pred mk-reverse-coercion i:gref, o:prop.
321+
mk-reverse-coercion Structure Clause :-
322+
coq.env.typeof Structure T,
323+
get-constructor Structure G,
324+
mk-reverse-coercion-aux T (global Structure) (global G) [] Clause.
325+
279326
pred mk-coe-class-body
280327
i:factoryname, % From class
281328
i:factoryname, % To class
@@ -428,18 +475,23 @@ declare-unification-hints SortProj ClassProj CurrentClass NewJoins :- std.do! [
428475

429476
% For each mixin we declare a field and apply the mixin to its dependencies
430477
% (that are previously declared fields recorded via field-for-mixin)
431-
pred synthesize-fields i:term, i:list (w-args mixinname), o:record-decl.
432-
synthesize-fields _T [] end-record.
433-
synthesize-fields T [triple M Args _|ML] (field _ Name MTy Fields) :- std.do! [
478+
% Keeps track of whether every field is in Prop
479+
pred synthesize-fields i:term, i:list (w-args mixinname), o:record-decl, o:bool.
480+
synthesize-fields _T [] end-record tt.
481+
synthesize-fields T [triple M Args V|ML] (field _ Name MTy Fields) B :- std.do! [
482+
if (coq.typecheck {mk-app (global M) {std.append Args [V]} } {{ Prop }} ok)
483+
(B = B2)
484+
(B = ff),
434485
Name is {gref->modname M 2 "_"} ^ "_mixin",
435486
if-verbose (coq.say {header} "typing class field" M),
436487
std.assert! (synthesis.infer-all-gref-deps Args T M MTy) "anomaly: a field type cannot be solved",
437-
@pi-decl `m` MTy m\ mixin-src T M m => synthesize-fields T ML (Fields m)
488+
@pi-decl `m` MTy m\ mixin-src T M m => synthesize-fields T ML (Fields m) B2
438489
].
439490

440491
pred synthesize-fields.body i:list term, i:term, i:list (w-args mixinname), o:indt-decl.
441-
synthesize-fields.body _Params T ML (record "axioms_" {{ Type }} "Class" FS) :-
442-
synthesize-fields T ML FS.
492+
synthesize-fields.body _Params T ML (record "axioms_" Ty "Class" FS) :-
493+
synthesize-fields T ML FS B,
494+
if (B = tt) (Ty = {{ Prop }}) (Ty = {{ Type }}).
443495

444496
pred mk-record+sort-field i:sort, i:name, i:term, i:(term -> record-decl), o:indt-decl.
445497
pred mk-record+sort-field i:universe, i:name, i:term, i:(term -> record-decl), o:indt-decl.
@@ -495,6 +547,27 @@ declare-sort-coercion CoeClass StructureName (global Proj) :-
495547

496548
log.coq.coercion.declare (coercion Proj 0 StructureName CoeClass).
497549

550+
% Declares "sort" as a Coercion in elpi's coercion db Proj : Structurename >-> CoeClass.
551+
pred declare-sort-coercion-elpi i:term, i:term.
552+
declare-sort-coercion-elpi Structure Proj :-
553+
554+
if-verbose (coq.say {header} "declare sort coercion in elpi"),
555+
556+
%TODO: log.coq.coercion-elpi.declare
557+
mk-sort-coercion Structure Proj Clause,
558+
coq.elpi.accumulate _ "coercion.db" (clause _ _ Clause).
559+
560+
% Declares a reverse coercion for the sort projection in elpi's coercion db
561+
pred declare-reverse-coercion-elpi i:gref.
562+
declare-reverse-coercion-elpi Structure :-
563+
564+
if-verbose (coq.say {header} "declare reverse coercion in elpi"),
565+
566+
%TODO: log.coq.coercion-elpi.declare
567+
mk-reverse-coercion Structure Clause,
568+
coq.elpi.accumulate _ "coercion.db" (clause _ _ Clause).
569+
570+
498571
pred if-class-already-exists-error i:id, i:list class, i:list mixinname.
499572
if-class-already-exists-error _ [] _.
500573
if-class-already-exists-error N [class _ S ML1wP|CS] ML2 :-

_CoqProject.test-suite

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ tests/unit/struct.v
9696
tests/factory_when_notation.v
9797

9898
tests/saturate_on.v
99+
tests/coercion.v
99100

100101
-R tests HB.tests
101102
-R examples HB.examples
102103

103-
-Q . HB
104+
-Q . HB

structures.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Definition ignore_disabled {T T'} (x : T) (x' : T') := x'.
1616

1717
(* ********************* structures ****************************** *)
1818
From elpi Require Import elpi.
19+
From elpi.apps Require Import coercion.
1920

2021
Register unify as hb.unify.
2122
Register id_phant as hb.id.
@@ -618,6 +619,7 @@ HB.structure Definition StructureName params :=
618619
*)
619620

620621
#[arguments(raw)] Elpi Command HB.structure.
622+
Elpi Accumulate Db coercion.db.
621623
Elpi Accumulate Db hb.db.
622624
Elpi Accumulate File "HB/common/stdpp.elpi".
623625
Elpi Accumulate File "HB/common/database.elpi".

tests/coercion.v

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
From Coq Require Import ssreflect.
2+
From HB Require Import structures.
3+
4+
HB.mixin Record isSigma (T : Type) (P : T -> Prop) (x : T) := {
5+
_ : P x
6+
}.
7+
8+
#[short(type="sigType")]
9+
HB.structure Definition Sig (T : Type) (P : T -> Prop) := {x of isSigma T P x}.
10+
11+
Section Sigma.
12+
13+
Check fun (T : Type) (P : T -> Prop) (x : sigType T P) => x : T.
14+
Check fun (T : Type) (P : T -> Prop) (x : T) (Px : Sig T P x) => x : sigType T P.
15+
Fail Check fun (T : Type) (P : T -> Prop) (x : T) => x : sigType T P.
16+
17+
Axioms (A B B' C : Type) (AtoB : A -> B) (BtoB' : B -> B').
18+
Axioms (P : A -> Prop) (CtoAP : C -> sigType A P).
19+
Coercion AtoB : A >-> B.
20+
Coercion BtoB' : B >-> B'.
21+
(* does postcompose automatically with Coq coercions*)
22+
Check fun (x : sigType A P) => x : B.
23+
Check fun (x : sigType A P) => x : B'.
24+
25+
(* testing a Coq coercion to sigType *)
26+
Coercion CtoAP : C >-> sigType.
27+
Check fun (x : C) => x : sigType A P.
28+
29+
(* does not precompose automatically with Coq coercions *)
30+
Fail Check fun (x : C) => x : A.
31+
Check fun (x : C) => (x : sigType A P) : A.
32+
Check fun (x : C) => (x : sigType A P) : B.
33+
34+
Axioms (x : A) (Px : Sig A P x).
35+
36+
(* should not work indeed *)
37+
Fail Check (x : sigType A P).
38+
39+
(* this works though ...*)
40+
Succeed Check (let Px' := Px in x : sigType A P).
41+
42+
HB.instance Definition _ := Px.
43+
Fail Check x : sigType A P.
44+
45+
End Sigma.
46+
47+
HB.mixin Record isSigmaT (P : Type -> Prop) (x : Type) := { _ : P x }.
48+
#[short(type="sigTType")]
49+
HB.structure Definition SigT (P : Type -> Prop) := {x of isSigmaT P x}.
50+
51+
Section SigmaT.
52+
53+
Axioms (X : Type) (PT : Type -> Prop) (PX : SigT PT X).
54+
55+
(* should not work indeed *)
56+
Fail Check (X : sigTType PT).
57+
58+
(* this works though now ... cf my next point*)
59+
Succeed Check (let PX' := PX in X : sigTType PT).
60+
61+
(* Now this works *)
62+
HB.instance Definition _ := PX.
63+
Succeed Check X : sigTType PT.
64+
65+
End SigmaT.

0 commit comments

Comments
 (0)