Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapting to Coq PR #14598: adding explicit constr_expr/glob_constr node for projections #274

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

src/coq_elpi_config.ml
src/coq_elpi_vernacular_syntax.ml
src/coq_elpi_arg_syntax.ml

Makefile.coq
Makefile.coq.conf
Expand Down
9 changes: 9 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## UNRELEASED

### HOAS
- Change `{{p x}}` is no more interpreted as a primitive projection even if `p`
is the associated constant
- New `{{ x.(p) }}` is interpreted as a primitive projection if `p` is a
primitive projection
- New `{{ x.(@p params) }}` is interpreted as a regular primitive projection
even if `p` is a primitive projection, since primitive projections don't have
parameters and the user wrote some

### API
- New `coq.env.informative?` to know if a type can be eliminated to build
a term of sort `Type`
Expand Down
1 change: 1 addition & 0 deletions _CoqProject.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
-arg -w -arg +elpi.deprecated
-arg -bt

-Q theories elpi
-Q examples elpi.examples
Expand Down
4 changes: 2 additions & 2 deletions src/coq_elpi_builtins.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2156,7 +2156,7 @@ Supported attributes:
let lname = CAst.make @@ Name.Name (Id.of_string name) in
CLocalAssum([lname],Default Glob_term.Explicit, CAst.make @@ CHole(None,Namegen.IntroAnonymous,None)),
(CAst.make @@ CRef(Libnames.qualid_of_string name,None), None))) in
let eta = CAst.(make @@ CLambdaN(binders,make @@ CApp((None,make @@ CRef(Libnames.qualid_of_string (KerName.to_string sd),None)),vars))) in
let eta = CAst.(make @@ CLambdaN(binders,make @@ CApp(make @@ CRef(Libnames.qualid_of_string (KerName.to_string sd),None),vars))) in
let sigma = get_sigma state in
let geta = Constrintern.intern_constr env sigma eta in
let state, teta = Coq_elpi_glob_quotation.gterm2lp ~depth state geta in
Expand Down Expand Up @@ -2186,7 +2186,7 @@ Supported attributes:
let lname = CAst.make @@ Name.Name (Id.of_string name) in
CLocalAssum([lname],Default Glob_term.Explicit, CAst.make @@ CHole(None,Namegen.IntroAnonymous,None)),
(CAst.make @@ CRef(Libnames.qualid_of_string name,None), None))) in
let eta = CAst.(make @@ CLambdaN(binders,make @@ CApp((None,make @@ CRef(Libnames.qualid_of_string (KerName.to_string sd),None)),vars))) in
let eta = CAst.(make @@ CLambdaN(binders,make @@ CApp(make @@ CRef(Libnames.qualid_of_string (KerName.to_string sd),None),vars))) in
let sigma = get_sigma state in
let geta = Constrintern.intern_constr env sigma eta in
let state, teta = Coq_elpi_glob_quotation.gterm2lp ~depth state geta in
Expand Down
45 changes: 21 additions & 24 deletions src/coq_elpi_glob_quotation.ml
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,13 @@ let under_ctx name ty bo gterm2lp ~depth state x =

let type_gen = ref 0

let is_hole x = match DAst.get x with GHole _ -> true | _ -> false

let rec gterm2lp ~depth state x =
debug Pp.(fun () ->
str"gterm2lp: depth=" ++ int depth ++
str " term=" ++Printer.pr_glob_constr_env (get_global_env state) (get_sigma state) x);
match (DAst.get x) (*.CAst.v*) with
| GRef(GlobRef.ConstRef p,_ul) when Structures.PrimitiveProjections.mem p ->
let p = Option.get @@ Structures.PrimitiveProjections.find_opt p in
let hd = in_elpi_gr ~depth state (GlobRef.ConstRef (Projection.Repr.constant p)) in
state, hd
| GRef(gr,_ul) -> state, in_elpi_gr ~depth state gr
| GVar(id) ->
let ctx, _ = Option.default (upcast @@ mk_coq_context ~options:default_options state, []) (get_ctx state) in
Expand Down Expand Up @@ -182,26 +180,25 @@ let rec gterm2lp ~depth state x =

| GEvar(_k,_subst) -> nYI "(glob)HOAS for GEvar"
| GPatVar _ -> nYI "(glob)HOAS for GPatVar"

| GApp(hd,args) -> begin
match DAst.get hd with
| GRef(GlobRef.ConstRef p,_ul) when Structures.PrimitiveProjections.mem p ->
let p = Option.get @@ Structures.PrimitiveProjections.find_opt p in
let p = Projection.make p false in
let npars = Projection.npars p in
begin match CList.skipn npars args with
| _ :: _ as args ->
let state, args = CList.fold_left_map (gterm2lp ~depth) state args in
let state, p = in_elpi_primitive ~depth state (Projection p) in
state, in_elpi_appl ~depth p args
| [] -> CErrors.user_err ~hdr:"elpi quotation"
Pp.(str"Coq primitive projection " ++ Projection.print p ++ str " has not enough arguments");
end
| _ ->
let state, hd = gterm2lp ~depth state hd in
let state, args = CList.fold_left_map (gterm2lp ~depth) state args in
state, in_elpi_appl ~depth hd args
end

| GProj ((ref,us),args,c) when
Structures.PrimitiveProjections.mem ref &&
List.for_all is_hole args ->
let p = Option.get (Structures.PrimitiveProjections.find_opt ref) in
let state, c = gterm2lp ~depth state c in
let state, p = in_elpi_primitive ~depth state (Projection (Names.Projection.make p false)) in
state, in_elpi_appl ~depth p [c]

| GProj ((ref,us),args,c) ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be sure: is this node just about the projection syntax? (because I now have a way to represent primitive projections)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of coq/coq#14598, GProj strictly corresponds to the t.(f args) syntax. However, it is not clear to me what will then be the consensus about the role to give to the GProj, whether it matches CProj (i.e. the t.(f args) syntax) or the Proj kernel syntax (i.e. the "primitive" projections), or if t.(f args) and kernel-primitive get eventually identified.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For instance, in coq/coq#14598, pretyping map GProj to Proj when the projection is registered as primitive and to App if not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I don't know what it implies for elpi. I guess it depends if the elpi way to represent primitive projections is about kernel Proj or about t.(f args).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For instance, in coq/coq#14598, pretyping map GProj to Proj when the projection is registered as primitive and to App if not.

ok, then I'll try to push a commit on top of yours

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I need #256 to go in first, then I'll rebase this one and add a few lines to it

let state, hd = gterm2lp ~depth state (DAst.make (GRef (GlobRef.ConstRef ref,us))) in
let state, args = CList.fold_left_map (gterm2lp ~depth) state args in
let state, c = gterm2lp ~depth state c in
state, in_elpi_appl ~depth hd (args@[c])

| GApp(hd,args) ->
let state, hd = gterm2lp ~depth state hd in
let state, args = CList.fold_left_map (gterm2lp ~depth) state args in
state, in_elpi_appl ~depth hd args

| GLetTuple(kargs,(as_name,oty),t,b) ->
let state, t = gterm2lp ~depth state t in
Expand Down
2 changes: 1 addition & 1 deletion src/coq_elpi_vernacular_syntax.mlg
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ GRAMMAR EXTEND Gram
let ref = Coqlib.lib_ref (String.concat "." (snd id)) in
let path = Nametab.path_of_global ref in
let f = Libnames.qualid_of_path ~loc:(fst id) path in
CAst.make ~loc Constrexpr.(CAppExpl((None,f,None),[])) } ] ]
CAst.make ~loc Constrexpr.(CAppExpl((f,None),[])) } ] ]
;
END

Expand Down
27 changes: 17 additions & 10 deletions tests/test_HOAS.v
Original file line number Diff line number Diff line change
Expand Up @@ -247,30 +247,37 @@ Module P.
Set Primitive Projections.

Unset Auto Template Polymorphism.
Record foo (A : Type) := { p1 : nat; p2 : A }.
Definition x : foo bool := {| p1 := 3; p2 := false |}.
Record foo {A : Type} := { p1 : nat; p2 : A }.
Definition x : foo := {| p1 := 3; p2 := false |}.

Unset Primitive Projections.
End P.

Elpi Command primitive_proj.
Elpi Accumulate lp:{{
main [trm (global (indt I)), trm T, int N, trm V] :-
main [str Kind, trm (global (indt I)), trm T, int N, trm V] :- std.do! [
coq.env.projections I [_,_],
coq.env.primitive-projections I [some (pr _ 1), some (pr _ 2)],
T = app[primitive (proj P N),A],
coq.say P N A,
coq.env.projections I [some P1, some P2],
if (Kind = "primitive")
(std.assert! (T = app[primitive (proj P N),A]) "not prim proj", coq.say P N A, coq.say {coq.term->string (primitive (proj P N))})
(std.assert! (T = app[global(const X), _, A], (X = P1 ; X = P2)) "not regular proj"), coq.say X A,
coq.say {coq.term->string T},
coq.say {coq.term->string (primitive (proj P N))},
{{:gref P.p1 }} = const C,
std.assert! ( {{:gref P.p1 }} = const C) "wrong gref",
std.assert! ( {{ @P.p1 }} = global (const C)) "wrong global",
coq.env.const C BO _,
coq.say BO,
std.assert! (unwind {whd T []} V) "wrong value".
std.assert! (unwind {whd T []} V) "wrong value",
].
}}.
Elpi Typecheck.

Elpi primitive_proj (P.foo) (P.p1 _ P.x) 1 (3%nat).
Elpi primitive_proj (P.foo) (P.p2 _ P.x) 2 (false).
Elpi primitive_proj "primitive" (@P.foo) (P.x.(P.p1)) 1 (3%nat).
Elpi primitive_proj "primitive" (@P.foo) (P.x.(P.p2)) 2 (false).
Elpi primitive_proj "regular" (@P.foo) (P.p1 P.x) 1 (3%nat).
Elpi primitive_proj "regular" (@P.foo) (P.p2 P.x) 2 (false).
Elpi primitive_proj "regular" (@P.foo) (P.x.(@P.p1 bool)) 1 (3%nat).
Elpi primitive_proj "regular" (@P.foo) (P.x.(@P.p2 bool)) 2 (false).

(* glob of ifte *)

Expand Down