Skip to content

Commit a7b9cfb

Browse files
authored
Merge pull request #717 from FissoreD/new-inst-prio
[coq.TC.get-inst-prio] new get-inst-prio (#716)
2 parents 7818596 + 30995f3 commit a7b9cfb

File tree

4 files changed

+73
-90
lines changed

4 files changed

+73
-90
lines changed

apps/tc/elpi/tc_aux.elpi

+1-5
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,12 @@ namespace tc {
136136
coq.elpi.predicate ClassStr ArgsSol RuleHead,
137137
make-tc.aux IsPositive Sol RuleHead RuleBody Rule.
138138

139-
pred unwrap-prio i:tc-priority, o:int.
140-
unwrap-prio (tc-priority-given Prio) Prio.
141-
unwrap-prio (tc-priority-computed Prio) Prio.
142-
143139
% returns the priority of an instance from the gref of an instance
144140
pred get-inst-prio i:gref, o:int.
145141
get-inst-prio InstGR Prio :-
146142
coq.env.typeof InstGR InstTy,
147143
get-TC-of-inst-type InstTy ClassGR,
148-
unwrap-prio {coq.TC.get-inst-prio ClassGR InstGR} Prio.
144+
coq.TC.get-inst-prio ClassGR InstGR Prio.
149145

150146
pred get-full-path i:gref, o:string.
151147
get-full-path Gr Res' :-

apps/tc/tests/section_in_out.v

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Section ClassPersistence.
5757
Context (X : Type) (A : X).
5858
Class class (A : X).
5959
Definition x : class A. apply Build_class. Qed.
60+
Hint Resolve x : typeclass_instances.
6061
Elpi TC.AddInstances x.
6162
Goal exists x, class x. eexists. apply _. Qed.
6263
End S1.

src/coq_elpi_builtins.ml

+40-85
Original file line numberDiff line numberDiff line change
@@ -397,96 +397,56 @@ let cs_instance = let open Conv in let open API.AlgebraicData in let open Struct
397397
} |> CConv.(!<)
398398

399399

400-
type tc_priority = Computed of int | UserGiven of int
401-
402-
let tc_priority = let open Conv in let open API.AlgebraicData in declare {
403-
ty = TyName "tc-priority";
404-
doc = "Type class instance priority";
405-
pp = (fun fmt _ -> Format.fprintf fmt "<todo>");
406-
constructors = [
407-
K("tc-priority-given","User given priority",A(int,N),
408-
B (fun i -> UserGiven i),
409-
M (fun ~ok ~ko -> function UserGiven i -> ok i | _ -> ko ()));
410-
K("tc-priority-computed","Coq computed priority", A(int,N),
411-
B (fun i -> Computed i),
412-
M (fun ~ok ~ko -> function Computed i -> ok i | _ -> ko ()));
413-
]} |> CConv.(!<)
414-
415400
type type_class_instance = {
416401
implementation : GlobRef.t;
417-
priority : tc_priority;
402+
priority : int;
418403
}
419404

420405
let tc_instance = let open Conv in let open API.AlgebraicData in declare {
421406
ty = TyName "tc-instance";
422407
doc = "Type class instance with priority";
423408
pp = (fun fmt _ -> Format.fprintf fmt "<todo>");
424409
constructors = [
425-
K("tc-instance","",A(gref,A(tc_priority,N)),
410+
K("tc-instance","",A(gref,A(int,N)),
426411
B (fun implementation priority -> { implementation; priority }),
427412
M (fun ~ok ~ko { implementation; priority } -> ok implementation priority));
428413
]} |> CConv.(!<)
429414

430-
[%%if coq = "8.20"]
431-
let clenv_missing sigma ce cty =
432-
let rec nb_hyp sigma c = match EConstr.kind sigma c with
433-
| Prod(_,_,c2) -> if EConstr.Vars.noccurn sigma 1 c2 then 1+(nb_hyp sigma c2) else nb_hyp sigma c2
434-
| _ -> 0 in
435-
let miss = Clenv.clenv_missing ce in
436-
let nmiss = List.length miss in
437-
let hyps = nb_hyp sigma cty in
438-
nmiss, hyps
439-
[%%else]
440-
let clenv_missing _ ce _ =
441-
let miss, hyps = Clenv.clenv_missing ce in
442-
List.length miss, hyps
443-
[%%endif]
444-
445-
let get_instance_prio gr env sigma (hint_priority : int option) : tc_priority =
446-
match hint_priority with
447-
| Some p -> UserGiven p
448-
| None ->
449-
let merge_context_set_opt sigma ctx =
450-
match ctx with
451-
| None -> sigma
452-
| Some ctx -> Evd.merge_sort_context_set Evd.univ_flexible sigma ctx
453-
in
454-
let fresh_global_or_constr env sigma =
455-
let (c, ctx) = UnivGen.fresh_global_instance env gr in
456-
let ctx = if Environ.is_polymorphic env gr then Some ctx else None in
457-
(EConstr.of_constr c, ctx) in
458-
let c, ctx = fresh_global_or_constr env sigma in
459-
let cty = Retyping.get_type_of env sigma c in
460-
let cty = Reductionops.nf_betaiota env sigma cty in
461-
let sigma' = merge_context_set_opt sigma ctx in
462-
let ce = Clenv.mk_clenv_from env sigma' (c,cty) in
463-
let nmiss, nhyps = clenv_missing sigma' ce cty in
464-
Computed (nhyps + nmiss)
465-
466-
(* TODO: this algorithm is quite inefficient since we have not yet the
467-
possibility to get the implementation of an instance from its gref in
468-
coq. Currently we have to get all the instances of the tc and the find
469-
its implementation.
470-
*)
471-
let get_isntances_of_tc env sigma (tc : GlobRef.t) =
472-
let inst_of_tc = (* contains all the instances of a type class *)
473-
Typeclasses.instances_exn env sigma tc |>
474-
List.fold_left (fun m i -> GlobRef.Map.add i.Typeclasses.is_impl i m) GlobRef.Map.empty in
475-
inst_of_tc
476-
477-
let get_instance env sigma inst_of_tc instance : type_class_instance =
478-
let instances_grefs2istance inst_gr : type_class_instance =
479-
let open Typeclasses in
480-
let user_hint_prio =
481-
(* Note: in general we deal with an instance I of a type class. Here we
482-
look if the user has given a priority to I. However, external
483-
hints are not in the inst_of_tc (the Not_found exception) *)
484-
try (GlobRef.Map.find inst_gr inst_of_tc).is_info.hint_priority
485-
with Not_found -> None in
486-
let priority = get_instance_prio inst_gr env sigma user_hint_prio in
487-
{ implementation = inst_gr; priority }
488-
in
489-
instances_grefs2istance instance
415+
let get_instance_prio env class_gr inst_gr =
416+
let exception STOP in
417+
(* db contains the hints stored in the typeclassses_db *)
418+
let db = Hints.searchtable_map Class_tactics.typeclasses_db in
419+
(* full_hint is the **list** of hints for a typeclass *)
420+
let full_hint = ref None in
421+
(try
422+
(* since we have not a "find" API in Hints.Hint_db to get the value associated to a class gref
423+
we iterate over the list until finding the wanted result *)
424+
(* complexity: O(N) where N is the number of typeclasses *)
425+
Hints.Hint_db.iter (fun gro _ fh ->
426+
Option.iter (fun gr ->
427+
if Environ.QGlobRef.equal env gr class_gr then
428+
(full_hint := Some fh; raise STOP)) gro) db;
429+
with STOP -> ());
430+
match !full_hint with
431+
(* None means that we cannot find the class gref in the db *)
432+
| None -> err Pp.(str"Cannot find the gref" ++ GlobRef.print class_gr ++ str" in typeclass_instances: is it a valid typeclass?")
433+
| Some full_hint ->
434+
let same_inst e =
435+
match Hints.FullHint.name e with
436+
| Some hint_name when Environ.QGlobRef.equal env hint_name inst_gr -> Some (Hints.FullHint.priority e)
437+
| _ -> None
438+
in
439+
(* We look in the list of hint for the one associated to inst_gr, if it does not exists: error *)
440+
(* complexity: O(N) where N is the number of instances of class_gr *)
441+
match List.find_map same_inst full_hint with
442+
| None -> err Pp.(str"Cannot find the priority of " ++ GlobRef.print inst_gr ++
443+
str": either it is not an instance of " ++ GlobRef.print class_gr ++
444+
str" or it is not stored as a hint in typeclasses_instances")
445+
| Some e -> e
446+
447+
let get_instance env class_gr inst_gr : type_class_instance =
448+
let priority = get_instance_prio env class_gr inst_gr in
449+
{ implementation = inst_gr; priority }
490450

491451
let warning_tc_hints = CWarnings.create ~name:"elpi.TC.hints" ~category:elpi_cat Pp.str
492452

@@ -515,8 +475,7 @@ let get_instances (env: Environ.env) (sigma: Evd.evar_map) tc : type_class_insta
515475
| Constr.Const (a, _) -> Some (Names.GlobRef.ConstRef a)
516476
| Constr.Construct (a, _) -> Some (Names.GlobRef.ConstructRef a)
517477
| _ -> None) constrs in
518-
let isnt_of_tc = get_isntances_of_tc env sigma tc in
519-
List.map (get_instance env sigma isnt_of_tc) instances_grefs
478+
List.map (get_instance env tc) instances_grefs
520479

521480
let set_accumulate_to_db_interp, get_accumulate_to_db_interp =
522481
let f = ref (fun _ -> assert false) in
@@ -2771,7 +2730,6 @@ Supported attributes:
27712730
!: topo_sort)),
27722731
DocAbove);
27732732

2774-
MLData tc_priority;
27752733
MLData tc_instance;
27762734

27772735
MLCode(Pred("coq.TC.declare-instance",
@@ -2817,13 +2775,10 @@ Supported attributes:
28172775
MLCode(Pred("coq.TC.get-inst-prio",
28182776
In(gref, "ClassGR",
28192777
In(gref, "InstGR",
2820-
Out(tc_priority, "InstPrio",
2778+
Out(int, "InstPrio",
28212779
Read (global, "reads the priority of an instance")))),
28222780
(fun class_gr inst_gr _ ~depth { env } _ state ->
2823-
let sigma = get_sigma state in
2824-
let inst_of_tc = get_isntances_of_tc env sigma class_gr in
2825-
let {priority} = get_instance env sigma inst_of_tc inst_gr in
2826-
!: priority)),
2781+
!: (get_instance_prio env class_gr inst_gr))),
28272782
DocAbove);
28282783

28292784
MLCode(Pred("coq.TC.class?",

tests/test_API_TC_CS.v

+31
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,37 @@ Elpi Query lp:{{coq.locate "RewriteRelation" GR, coq.TC.db-for GR L}}.
4444
Elpi Query lp:{{coq.locate "RewriteRelation" GR, coq.TC.class? GR}}.
4545
Elpi Query lp:{{coq.locate "True" GR, not(coq.TC.class? GR)}}.
4646

47+
Module hint_instance.
48+
Class Test : Prop := {}.
49+
50+
Instance instance_c : Test := Build_Test.
51+
Instance instance_g : Test | 4 := Build_Test.
52+
53+
Definition hint_c : Test := Build_Test.
54+
Definition hint_g : Test := Build_Test.
55+
56+
Hint Resolve hint_c : typeclass_instances.
57+
Hint Resolve hint_g | 5 : typeclass_instances.
58+
59+
Elpi Command test.
60+
Elpi Accumulate lp:{{
61+
pred expected o:tc-instance.
62+
expected (tc-instance {{:gref hint_c}} 0).
63+
expected (tc-instance {{:gref instance_c}} 0).
64+
expected (tc-instance {{:gref instance_g}} 4).
65+
% Note: the priority of hint_g is 5, the one given in the hint resolve
66+
expected (tc-instance {{:gref hint_g}} 5).
67+
}}.
68+
Elpi Query lp:{{
69+
coq.TC.db-for {{:gref Test}} L,
70+
std.length L 4, % there are 4 instances for Test
71+
std.findall (expected _) Exp, % get the expected prio
72+
Check = (x\ sigma Exp\ x = expected Exp, std.mem L Exp),
73+
std.forall Exp Check. % check each instance has the expected priority
74+
}}.
75+
76+
End hint_instance.
77+
4778
Axiom C : Type -> Type.
4879

4980
Elpi Query lp:{{ coq.TC.declare-class {{:gref C }} }}.

0 commit comments

Comments
 (0)