Skip to content

Commit 6492a2c

Browse files
Merge PR #20605: Cleanup handling of projection flags
Reviewed-by: ppedrot Co-authored-by: ppedrot <[email protected]>
2 parents 23db471 + d93f460 commit 6492a2c

File tree

5 files changed

+142
-123
lines changed

5 files changed

+142
-123
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
overlay elpi https://github.com/SkySkimmer/coq-elpi simpl-proj-flags 20605
2+
3+
overlay metarocq https://github.com/SkySkimmer/metarocq simpl-proj-flags 20605
4+
5+
overlay lean_importer https://github.com/SkySkimmer/rocq-lean-import simpl-proj-flags 20605
6+
7+
overlay coq_lsp https://github.com/SkySkimmer/coq-lsp simpl-proj-flags 20605

vernac/record.ml

Lines changed: 36 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,18 @@ module DataI = struct
126126
end
127127

128128
module Data = struct
129+
(* XXX move coercion_flags to ComCoercion? *)
130+
type coercion_flags = {
131+
coe_local : bool;
132+
coe_reversible : bool;
133+
}
134+
type instance_flags = {
135+
inst_locality : Hints.hint_locality;
136+
inst_priority : int option;
137+
}
129138
type projection_flags = {
130-
pf_coercion: bool;
131-
pf_reversible: bool;
132-
pf_instance: bool;
133-
pf_priority: int option;
134-
pf_locality: Goptions.option_locality;
139+
pf_coercion: coercion_flags option;
140+
pf_instance: instance_flags option;
135141
pf_canonical: bool;
136142
}
137143
type t =
@@ -473,7 +479,9 @@ let warning_or_error ?loc ~info flags indsp err =
473479
Himsg.explain_type_error env (Evd.from_env env)
474480
(Pretype_errors.of_type_error te))
475481
in
476-
if flags.Data.pf_coercion || flags.Data.pf_instance then user_err ?loc ~info st;
482+
(* XXX flags.pf_canonical? *)
483+
if Option.has_some flags.Data.pf_coercion || Option.has_some flags.Data.pf_instance then
484+
user_err ?loc ~info st;
477485
warn_cannot_define_projection ?loc (hov 0 st)
478486

479487
type field_status =
@@ -523,22 +531,21 @@ let instantiate_possibly_recursive_type ind u ntypes paramdecls fields =
523531
(** Declare projection [ref] over [from] a coercion
524532
or a typeclass instance according to [flags]. *)
525533
let declare_proj_coercion_instance ~flags ref from =
526-
if flags.Data.pf_coercion then begin
527-
let cl = ComCoercion.class_of_global from in
528-
let local = flags.Data.pf_locality = Goptions.OptLocal in
529-
ComCoercion.try_add_new_coercion_with_source ref ~local ~reversible:flags.Data.pf_reversible ~source:cl
530-
end;
531-
if flags.Data.pf_instance then begin
532-
let env = Global.env () in
533-
let sigma = Evd.from_env env in
534-
let info = Typeclasses.{ hint_priority = flags.Data.pf_priority; hint_pattern = None } in
535-
let local =
536-
match flags.Data.pf_locality with
537-
| Goptions.OptLocal -> Hints.Local
538-
| Goptions.(OptDefault | OptExport) -> Hints.Export
539-
| Goptions.OptGlobal -> Hints.SuperGlobal in
540-
Classes.declare_instance ~warn:true env sigma (Some info) local ref
541-
end
534+
let () = match flags.Data.pf_coercion with
535+
| None -> ()
536+
| Some { coe_local=local; coe_reversible=reversible } ->
537+
let cl = ComCoercion.class_of_global from in
538+
ComCoercion.try_add_new_coercion_with_source ref ~local ~reversible ~source:cl
539+
in
540+
let () = match flags.Data.pf_instance with
541+
| None -> ()
542+
| Some { inst_locality; inst_priority } ->
543+
let env = Global.env () in
544+
let sigma = Evd.from_env env in
545+
let info = Typeclasses.{ hint_priority = inst_priority; hint_pattern = None } in
546+
Classes.declare_instance ~warn:true env sigma (Some info) inst_locality ref
547+
in
548+
()
542549

543550
(* TODO: refactor the declaration part here; this requires some
544551
surgery as Evarutil.finalize is called too early in the path *)
@@ -718,25 +725,25 @@ module Ast = struct
718725
{ name : Names.lident
719726
; is_coercion : coercion_flag
720727
; binders: local_binder_expr list
721-
; cfs : (local_decl_expr * record_field_attr) list
728+
; cfs : (local_decl_expr * Data.projection_flags * notation_declaration list) list
722729
; idbuild : lident
723730
; sort : constr_expr option
724731
; default_inhabitant_id : Id.t option
725732
}
726733

727734
let to_datai { name; idbuild; cfs; sort; default_inhabitant_id; } =
728-
let fs = List.map fst cfs in
735+
let fs = List.map pi1 cfs in
729736
{ DataI.name = name
730737
; constructor_name = idbuild.CAst.v
731738
; arity = sort
732-
; nots = List.map (fun (_, { rf_notation }) -> List.map Metasyntax.prepare_where_notation rf_notation) cfs
739+
; nots = List.map (fun (_, _, rf_notation) -> List.map Metasyntax.prepare_where_notation rf_notation) cfs
733740
; fs
734741
; default_inhabitant_id
735742
}
736743
end
737744

738745
let check_unique_names ~def records =
739-
let extract_name acc (rf_decl, _) = match rf_decl with
746+
let extract_name acc (rf_decl, _, _) = match rf_decl with
740747
Vernacexpr.AssumExpr({CAst.v=Name id},_,_) -> id::acc
741748
| Vernacexpr.DefExpr ({CAst.v=Name id},_,_,_) -> id::acc
742749
| _ -> acc in
@@ -763,47 +770,10 @@ let kind_class =
763770
function Class true -> DefClass | Class false -> RecordClass
764771
| Inductive_kw | CoInductive | Variant | Record | Structure -> NotClass
765772

766-
let check_priorities kind records =
767-
let open Vernacexpr in
768-
let isnot_class = kind_class kind <> RecordClass in
769-
let has_priority { Ast.cfs; _ } =
770-
List.exists (fun (_, { rf_priority }) -> not (Option.is_empty rf_priority)) cfs
771-
in
772-
if isnot_class && List.exists has_priority records then
773-
user_err Pp.(str "Priorities only allowed for type class substructures.")
774-
775-
let check_proj_flags kind rf =
776-
let open Vernacexpr in
777-
let pf_coercion, pf_reversible =
778-
match rf.rf_coercion with
779-
| AddCoercion -> true, Option.default true rf.rf_reversible
780-
| NoCoercion ->
781-
if rf.rf_reversible <> None then
782-
Attributes.(unsupported_attributes
783-
[CAst.make ("reversible (without :>)",VernacFlagEmpty)]);
784-
false, false in
785-
let pf_instance =
786-
match rf.rf_instance with NoInstance -> false | BackInstance -> true in
787-
let pf_priority = rf.rf_priority in
788-
let pf_locality =
789-
begin match rf.rf_coercion, rf.rf_instance with
790-
| NoCoercion, NoInstance ->
791-
if rf.rf_locality <> Goptions.OptDefault then
792-
Attributes.(unsupported_attributes
793-
[CAst.make ("locality (without :> or ::)",VernacFlagEmpty)])
794-
| AddCoercion, NoInstance ->
795-
if rf.rf_locality = Goptions.OptExport then
796-
Attributes.(unsupported_attributes
797-
[CAst.make ("export (without ::)",VernacFlagEmpty)])
798-
| _ -> ()
799-
end; rf.rf_locality in
800-
let pf_canonical = rf.rf_canonical in
801-
Data.{ pf_coercion; pf_reversible; pf_instance; pf_priority; pf_locality; pf_canonical }
802-
803-
let extract_record_data kind records =
773+
let extract_record_data records =
804774
let data = List.map Ast.to_datai records in
805775
let decl_data = List.map (fun { Ast.is_coercion; cfs } ->
806-
let proj_flags = List.map (fun (_,rf) -> check_proj_flags kind rf) cfs in
776+
let proj_flags = List.map (fun (_,rf,_) -> rf) cfs in
807777
{ Data.is_coercion; proj_flags })
808778
records
809779
in
@@ -823,8 +793,7 @@ let extract_record_data kind records =
823793
let pre_process_structure udecl kind ~flags ~primitive_proj (records : Ast.t list) =
824794
let def = (kind = Vernacexpr.Class true) in
825795
let indlocs = check_unique_names ~def records in
826-
let () = check_priorities kind records in
827-
let ps, interp_data, decl_data = extract_record_data kind records in
796+
let ps, interp_data, decl_data = extract_record_data records in
828797
let entry =
829798
(* In theory we should be able to use
830799
[Notation.with_notation_protection], due to the call to
@@ -1107,14 +1076,6 @@ let definition_structure ~flags udecl kind ~primitive_proj (records : Ast.t list
11071076
inds
11081077

11091078
module Internal = struct
1110-
type nonrec projection_flags = Data.projection_flags = {
1111-
pf_coercion: bool;
1112-
pf_reversible: bool;
1113-
pf_instance: bool;
1114-
pf_priority: int option;
1115-
pf_locality: Goptions.option_locality;
1116-
pf_canonical: bool;
1117-
}
11181079
let declare_projections = declare_projections
11191080
let declare_structure_entry = declare_structure_entry
11201081
end

vernac/record.mli

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,32 @@ open Vernacexpr
1313
open Constrexpr
1414
open Structures
1515

16+
module Data : sig
17+
type coercion_flags = {
18+
coe_local : bool;
19+
coe_reversible : bool;
20+
}
21+
type instance_flags = {
22+
inst_locality : Hints.hint_locality;
23+
inst_priority : int option;
24+
}
25+
type projection_flags = {
26+
pf_coercion: coercion_flags option;
27+
pf_instance: instance_flags option;
28+
pf_canonical: bool;
29+
}
30+
type t = {
31+
is_coercion : Vernacexpr.coercion_flag;
32+
proj_flags : projection_flags list;
33+
}
34+
end
35+
1636
module Ast : sig
1737
type t =
1838
{ name : Names.lident
1939
; is_coercion : coercion_flag
2040
; binders: local_binder_expr list
21-
; cfs : (local_decl_expr * record_field_attr) list
41+
; cfs : (local_decl_expr * Data.projection_flags * notation_declaration list) list
2242
; idbuild : lident
2343
; sort : constr_expr option
2444
; default_inhabitant_id : Id.t option
@@ -33,21 +53,6 @@ val definition_structure
3353
-> Ast.t list
3454
-> GlobRef.t list
3555

36-
module Data : sig
37-
type projection_flags = {
38-
pf_coercion: bool;
39-
pf_reversible: bool;
40-
pf_instance: bool;
41-
pf_priority: int option;
42-
pf_locality: Goptions.option_locality;
43-
pf_canonical: bool;
44-
}
45-
type t =
46-
{ is_coercion : Vernacexpr.coercion_flag
47-
; proj_flags : projection_flags list
48-
}
49-
end
50-
5156
module RecordEntry : sig
5257

5358
type one_ind_info = {
@@ -96,20 +101,11 @@ val canonical_inhabitant_id : isclass:bool -> Id.t -> Id.t
96101
(* Implementation internals, consult Rocq developers before using;
97102
current user Elpi, see https://github.com/LPCIC/coq-elpi/pull/151 *)
98103
module Internal : sig
99-
type projection_flags = {
100-
pf_coercion: bool;
101-
pf_reversible: bool;
102-
pf_instance: bool;
103-
pf_priority: int option;
104-
pf_locality: Goptions.option_locality;
105-
pf_canonical: bool;
106-
}
107-
108104
val declare_projections
109105
: Names.inductive
110106
-> kind:Decls.definition_object_kind
111107
-> inhabitant_id:Names.Id.t
112-
-> projection_flags list
108+
-> Data.projection_flags list
113109
-> ?fieldlocs:Loc.t option list
114110
-> Impargs.manual_implicits list
115111
-> Structure.projection list

vernac/vernacentries.ml

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,64 @@ module Preprocessed_Mind_decl = struct
10761076
| Inductive of inductive
10771077
end
10781078

1079+
(* Intermediate type while parsing record field flags *)
1080+
type record_field_attr = {
1081+
rf_coercion: coercion_flag; (* the projection is an implicit coercion *)
1082+
rf_reversible: bool option; (* coercion is reversible, if relevant *)
1083+
rf_instance: instance_flag; (* the projection is an instance *)
1084+
rf_priority: int option; (* priority of the instance, if relevant *)
1085+
rf_locality: Goptions.option_locality; (* locality of coercion and instance *)
1086+
rf_canonical: bool; (* use this projection in the search for canonical instances *)
1087+
}
1088+
1089+
let check_proj_flags rf =
1090+
let open Vernacexpr in
1091+
let open Record.Data in
1092+
let () = match rf.rf_coercion, rf.rf_instance with
1093+
| NoCoercion, NoInstance ->
1094+
if rf.rf_locality <> Goptions.OptDefault then
1095+
Attributes.(unsupported_attributes
1096+
[CAst.make ("locality (without :> or ::)",VernacFlagEmpty)])
1097+
| AddCoercion, NoInstance ->
1098+
if rf.rf_locality = Goptions.OptExport then
1099+
Attributes.(unsupported_attributes
1100+
[CAst.make ("export (without ::)",VernacFlagEmpty)])
1101+
| _ -> ()
1102+
in
1103+
let pf_coercion =
1104+
match rf.rf_coercion with
1105+
| AddCoercion ->
1106+
Some {
1107+
coe_local = rf.rf_locality = OptLocal;
1108+
coe_reversible = Option.default true rf.rf_reversible;
1109+
}
1110+
| NoCoercion ->
1111+
if rf.rf_reversible <> None then
1112+
Attributes.(unsupported_attributes
1113+
[CAst.make ("reversible (without :>)",VernacFlagEmpty)]);
1114+
None
1115+
in
1116+
let pf_instance =
1117+
match rf.rf_instance with
1118+
| NoInstance ->
1119+
let () = if Option.has_some rf.rf_priority then
1120+
CErrors.user_err Pp.(str "Priority not allowed without \"::\".")
1121+
in
1122+
None
1123+
| BackInstance ->
1124+
let local =
1125+
match rf.rf_locality with
1126+
| Goptions.OptLocal -> Hints.Local
1127+
| Goptions.(OptDefault | OptExport) -> Hints.Export
1128+
| Goptions.OptGlobal -> Hints.SuperGlobal
1129+
in
1130+
Some {
1131+
inst_locality = local;
1132+
inst_priority = rf.rf_priority;
1133+
}
1134+
in
1135+
{ pf_coercion; pf_instance; pf_canonical = rf.rf_canonical }
1136+
10791137
let preprocess_defclass ~atts udecl (id, bl, c, l) =
10801138
let poly, mode =
10811139
Attributes.(parse Notations.(polymorphic ++ mode_attr) atts)
@@ -1096,10 +1154,14 @@ let preprocess_defclass ~atts udecl (id, bl, c, l) =
10961154
let ((attr, rf_coercion, rf_instance), (lid, ce)) = l in
10971155
let rf_locality = match rf_coercion, rf_instance with
10981156
| AddCoercion, _ | _, BackInstance -> parse option_locality attr
1099-
| _ -> let () = unsupported_attributes attr in Goptions.OptDefault in
1157+
| _ -> let () = unsupported_attributes attr in Goptions.OptDefault
1158+
in
11001159
let f = AssumExpr ((make ?loc:lid.loc @@ Name lid.v), [], ce),
1101-
{ rf_coercion ; rf_reversible = None ; rf_instance ; rf_priority = None ;
1102-
rf_locality ; rf_notation = [] ; rf_canonical = true } in
1160+
check_proj_flags
1161+
{ rf_coercion ; rf_reversible = None ; rf_instance ; rf_priority = None ;
1162+
rf_locality ; rf_canonical = true },
1163+
[]
1164+
in
11031165
let recordl = [id, bl, c, None, [f], None] in
11041166
let kind = Class true in
11051167
let records = vernac_record recordl in
@@ -1142,14 +1204,17 @@ let preprocess_record ~atts udecl kind indl =
11421204
| _ -> Notations.return Goptions.OptDefault in
11431205
Notations.(rev ++ loc ++ canonical_field) in
11441206
let (rf_reversible, rf_locality), rf_canonical = parse attr f.rfu_attrs in
1145-
x,
1146-
{ rf_coercion = f.rfu_coercion;
1147-
rf_reversible;
1148-
rf_instance = f.rfu_instance;
1149-
rf_priority = f.rfu_priority;
1150-
rf_locality;
1151-
rf_notation = f.rfu_notation;
1152-
rf_canonical } in
1207+
let flags = check_proj_flags {
1208+
rf_coercion = f.rfu_coercion;
1209+
rf_reversible;
1210+
rf_instance = f.rfu_instance;
1211+
rf_priority = f.rfu_priority;
1212+
rf_locality;
1213+
rf_canonical;
1214+
}
1215+
in
1216+
x, flags, f.rfu_notation
1217+
in
11531218
let unpack ((id, bl, c, decl), _) = match decl with
11541219
| RecordDecl (oc, fs, ido) ->
11551220
let bl = match bl with
@@ -1234,7 +1299,7 @@ let dump_inductive indl_for_glob decl =
12341299
indl_for_glob;
12351300
match decl with
12361301
| Record { records } ->
1237-
let dump_glob_proj (x, _) = match x with
1302+
let dump_glob_proj (x, _, _) = match x with
12381303
| Vernacexpr.(AssumExpr ({loc;v=Name id}, _, _) | DefExpr ({loc;v=Name id}, _, _, _)) ->
12391304
Dumpglob.dump_definition (make ?loc id) false "proj"
12401305
| _ -> () in

vernac/vernacexpr.mli

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,6 @@ type simple_binder = lident list * constr_expr
209209
type class_binder = lident * constr_expr list
210210
type 'a with_coercion = coercion_flag * 'a
211211
type 'a with_coercion_instance = (Attributes.vernac_flags * coercion_flag * instance_flag) * 'a
212-
(* Attributes of a record field declaration *)
213-
type record_field_attr = {
214-
rf_coercion: coercion_flag; (* the projection is an implicit coercion *)
215-
rf_reversible: bool option; (* coercion is reversible, if relevant *)
216-
rf_instance: instance_flag; (* the projection is an instance *)
217-
rf_priority: int option; (* priority of the instance, if relevant *)
218-
rf_locality: Goptions.option_locality; (* locality of coercion and instance *)
219-
rf_notation: notation_declaration list;
220-
rf_canonical: bool; (* use this projection in the search for canonical instances *)
221-
}
222212
(* Same before parsing the attributes *)
223213
type record_field_attr_unparsed = {
224214
rfu_attrs: Attributes.vernac_flags;

0 commit comments

Comments
 (0)