-
Notifications
You must be signed in to change notification settings - Fork 641
/
constrintern.ml
1784 lines (1608 loc) · 69.9 KB
/
constrintern.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2012 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
open Pp
open Errors
open Util
open Flags
open Names
open Nameops
open Namegen
open Libnames
open Globnames
open Impargs
open Glob_term
open Glob_ops
open Patternops
open Pretyping
open Cases
open Constrexpr
open Constrexpr_ops
open Notation_term
open Notation_ops
open Topconstr
open Nametab
open Notation
open Inductiveops
open Misctypes
open Decl_kinds
(** constr_expr -> glob_constr translation:
- it adds holes for implicit arguments
- it remplaces notations by their value (scopes stuff are here)
- it recognizes global vars from local ones
- it prepares pattern maching problems (a pattern becomes a tree where nodes
are constructor/variable pairs and leafs are variables)
All that at once, fasten your seatbelt!
*)
(* To interpret implicits and arg scopes of variables in inductive
types and recursive definitions and of projection names in records *)
type var_internalization_type =
| Inductive of identifier list (* list of params *)
| Recursive
| Method
| Variable
type var_internalization_data =
(* type of the "free" variable, for coqdoc, e.g. while typing the
constructor of JMeq, "JMeq" behaves as a variable of type Inductive *)
var_internalization_type *
(* impargs to automatically add to the variable, e.g. for "JMeq A a B b"
in implicit mode, this is [A;B] and this adds (A:=A) and (B:=B) *)
identifier list *
(* signature of impargs of the variable *)
Impargs.implicit_status list *
(* subscopes of the args of the variable *)
scope_name option list
type internalization_env =
(var_internalization_data) Idmap.t
type glob_binder = (name * binding_kind * glob_constr option * glob_constr)
let interning_grammar = ref false
(* Historically for parsing grammar rules, but in fact used only for
translator, v7 parsing, and unstrict tactic internalization *)
let for_grammar f x =
interning_grammar := true;
let a = f x in
interning_grammar := false;
a
(**********************************************************************)
(* Locating reference, possibly via an abbreviation *)
let locate_reference qid =
Smartlocate.global_of_extended_global (Nametab.locate_extended qid)
let is_global id =
try
let _ = locate_reference (qualid_of_ident id) in true
with Not_found ->
false
let global_reference_of_reference ref =
locate_reference (snd (qualid_of_reference ref))
let global_reference id =
constr_of_global (locate_reference (qualid_of_ident id))
let construct_reference ctx id =
try
Term.mkVar (let _ = Sign.lookup_named id ctx in id)
with Not_found ->
global_reference id
let global_reference_in_absolute_module dir id =
constr_of_global (Nametab.global_of_path (Libnames.make_path dir id))
(**********************************************************************)
(* Internalization errors *)
type internalization_error =
| VariableCapture of identifier * identifier
| IllegalMetavariable
| NotAConstructor of reference
| UnboundFixName of bool * identifier
| NonLinearPattern of identifier
| BadPatternsNumber of int * int
exception InternalizationError of Loc.t * internalization_error
let explain_variable_capture id id' =
pr_id id ++ str " is dependent in the type of " ++ pr_id id' ++
strbrk ": cannot interpret both of them with the same type"
let explain_illegal_metavariable =
str "Metavariables allowed only in patterns"
let explain_not_a_constructor ref =
str "Unknown constructor: " ++ pr_reference ref
let explain_unbound_fix_name is_cofix id =
str "The name" ++ spc () ++ pr_id id ++
spc () ++ str "is not bound in the corresponding" ++ spc () ++
str (if is_cofix then "co" else "") ++ str "fixpoint definition"
let explain_non_linear_pattern id =
str "The variable " ++ pr_id id ++ str " is bound several times in pattern"
let explain_bad_patterns_number n1 n2 =
str "Expecting " ++ int n1 ++ str (plural n1 " pattern") ++
str " but found " ++ int n2
let explain_internalization_error e =
let pp = match e with
| VariableCapture (id,id') -> explain_variable_capture id id'
| IllegalMetavariable -> explain_illegal_metavariable
| NotAConstructor ref -> explain_not_a_constructor ref
| UnboundFixName (iscofix,id) -> explain_unbound_fix_name iscofix id
| NonLinearPattern id -> explain_non_linear_pattern id
| BadPatternsNumber (n1,n2) -> explain_bad_patterns_number n1 n2
in pp ++ str "."
let error_bad_inductive_type loc =
user_err_loc (loc,"",str
"This should be an inductive type applied to patterns.")
let error_parameter_not_implicit loc =
user_err_loc (loc,"", str
"The parameters do not bind in patterns;" ++ spc () ++ str
"they must be replaced by '_'.")
(**********************************************************************)
(* Pre-computing the implicit arguments and arguments scopes needed *)
(* for interpretation *)
let parsing_explicit = ref false
let empty_internalization_env = Idmap.empty
let compute_explicitable_implicit imps = function
| Inductive params ->
(* In inductive types, the parameters are fixed implicit arguments *)
let sub_impl,_ = List.chop (List.length params) imps in
let sub_impl' = List.filter is_status_implicit sub_impl in
List.map name_of_implicit sub_impl'
| Recursive | Method | Variable ->
(* Unable to know in advance what the implicit arguments will be *)
[]
let compute_internalization_data env ty typ impl =
let impl = compute_implicits_with_manual env typ (is_implicit_args()) impl in
let expls_impl = compute_explicitable_implicit impl ty in
(ty, expls_impl, impl, compute_arguments_scope typ)
let compute_internalization_env env ty =
List.fold_left3
(fun map id typ impl -> Idmap.add id (compute_internalization_data env ty typ impl) map)
empty_internalization_env
(**********************************************************************)
(* Contracting "{ _ }" in notations *)
let rec wildcards ntn n =
if n = String.length ntn then []
else let l = spaces ntn (n+1) in if ntn.[n] = '_' then n::l else l
and spaces ntn n =
if n = String.length ntn then []
else if ntn.[n] = ' ' then wildcards ntn (n+1) else spaces ntn (n+1)
let expand_notation_string ntn n =
let pos = List.nth (wildcards ntn 0) n in
let hd = if pos = 0 then "" else String.sub ntn 0 pos in
let tl =
if pos = String.length ntn then ""
else String.sub ntn (pos+1) (String.length ntn - pos -1) in
hd ^ "{ _ }" ^ tl
(* This contracts the special case of "{ _ }" for sumbool, sumor notations *)
(* Remark: expansion of squash at definition is done in metasyntax.ml *)
let contract_notation ntn (l,ll,bll) =
let ntn' = ref ntn in
let rec contract_squash n = function
| [] -> []
| CNotation (_,"{ _ }",([a],[],[])) :: l ->
ntn' := expand_notation_string !ntn' n;
contract_squash n (a::l)
| a :: l ->
a::contract_squash (n+1) l in
let l = contract_squash 0 l in
(* side effect; don't inline *)
!ntn',(l,ll,bll)
let contract_pat_notation ntn (l,ll) =
let ntn' = ref ntn in
let rec contract_squash n = function
| [] -> []
| CPatNotation (_,"{ _ }",([a],[]),[]) :: l ->
ntn' := expand_notation_string !ntn' n;
contract_squash n (a::l)
| a :: l ->
a::contract_squash (n+1) l in
let l = contract_squash 0 l in
(* side effect; don't inline *)
!ntn',(l,ll)
type intern_env = {
ids: Names.Idset.t;
unb: bool;
tmp_scope: Notation_term.tmp_scope_name option;
scopes: Notation_term.scope_name list;
impls: internalization_env }
(**********************************************************************)
(* Remembering the parsing scope of variables in notations *)
let make_current_scope = function
| (Some tmp_scope,(sc::_ as scopes)) when sc = tmp_scope -> scopes
| (Some tmp_scope,scopes) -> tmp_scope::scopes
| None,scopes -> scopes
let pr_scope_stack = function
| [] -> str "the empty scope stack"
| [a] -> str "scope " ++ str a
| l -> str "scope stack " ++
str "[" ++ prlist_with_sep pr_comma str l ++ str "]"
let error_inconsistent_scope loc id scopes1 scopes2 =
user_err_loc (loc,"set_var_scope",
pr_id id ++ str " is here used in " ++
pr_scope_stack scopes2 ++ strbrk " while it was elsewhere used in " ++
pr_scope_stack scopes1)
let error_expect_binder_notation_type loc id =
user_err_loc (loc,"",
pr_id id ++
str " is expected to occur in binding position in the right-hand side.")
let set_var_scope loc id istermvar env ntnvars =
try
let idscopes,typ = List.assoc id ntnvars in
if istermvar then
(* scopes have no effect on the interpretation of identifiers *)
if !idscopes = None then
idscopes := Some (env.tmp_scope,env.scopes)
else
if make_current_scope (Option.get !idscopes)
<> make_current_scope (env.tmp_scope,env.scopes)
then
error_inconsistent_scope loc id
(make_current_scope (Option.get !idscopes))
(make_current_scope (env.tmp_scope,env.scopes));
match typ with
| NtnInternTypeBinder ->
if istermvar then error_expect_binder_notation_type loc id
| NtnInternTypeConstr ->
(* We need sometimes to parse idents at a constr level for
factorization and we cannot enforce this constraint:
if not istermvar then error_expect_constr_notation_type loc id *)
()
| NtnInternTypeIdent -> ()
with Not_found ->
(* Not in a notation *)
()
let set_type_scope env = {env with tmp_scope = Some Notation.type_scope}
let reset_tmp_scope env = {env with tmp_scope = None}
let rec it_mkGProd loc2 env body =
match env with
(loc1, (na, bk, _, t)) :: tl -> it_mkGProd loc2 tl (GProd (Loc.merge loc1 loc2, na, bk, t, body))
| [] -> body
let rec it_mkGLambda loc2 env body =
match env with
(loc1, (na, bk, _, t)) :: tl -> it_mkGLambda loc2 tl (GLambda (Loc.merge loc1 loc2, na, bk, t, body))
| [] -> body
(**********************************************************************)
(* Utilities for binders *)
let build_impls = function
|Implicit -> (function
|Name id -> Some (id, Impargs.Manual, (true,true))
|Anonymous -> anomaly "Anonymous implicit argument")
|Explicit -> fun _ -> None
let impls_type_list ?(args = []) =
let rec aux acc = function
|GProd (_,na,bk,_,c) -> aux ((build_impls bk na)::acc) c
|_ -> (Variable,[],List.append args (List.rev acc),[])
in aux []
let impls_term_list ?(args = []) =
let rec aux acc = function
|GLambda (_,na,bk,_,c) -> aux ((build_impls bk na)::acc) c
|GRec (_, fix_kind, nas, args, tys, bds) ->
let nb = match fix_kind with |GFix (_, n) -> n | GCoFix n -> n in
let acc' = List.fold_left (fun a (na, bk, _, _) -> (build_impls bk na)::a) acc args.(nb) in
aux acc' bds.(nb)
|_ -> (Variable,[],List.append args (List.rev acc),[])
in aux []
(* Check if in binder "(x1 x2 .. xn : t)", none of x1 .. xn-1 occurs in t *)
let rec check_capture ty = function
| (loc,Name id)::(_,Name id')::_ when occur_glob_constr id ty ->
raise (InternalizationError (loc,VariableCapture (id,id')))
| _::nal ->
check_capture ty nal
| [] ->
()
let locate_if_isevar loc na = function
| GHole _ ->
(try match na with
| Name id -> glob_constr_of_notation_constr loc
(Reserve.find_reserved_type id)
| Anonymous -> raise Not_found
with Not_found -> GHole (loc, Evar_kinds.BinderType na))
| x -> x
let reset_hidden_inductive_implicit_test env =
{ env with impls = Idmap.fold (fun id x ->
let x = match x with
| (Inductive _,b,c,d) -> (Inductive [],b,c,d)
| x -> x
in Idmap.add id x) env.impls Idmap.empty }
let check_hidden_implicit_parameters id impls =
if Idmap.exists (fun _ -> function
| (Inductive indparams,_,_,_) -> List.mem id indparams
| _ -> false) impls
then
errorlabstrm "" (strbrk "A parameter of an inductive type " ++
pr_id id ++ strbrk " is not allowed to be used as a bound variable in the type of its constructor.")
let push_name_env ?(global_level=false) lvar implargs env =
function
| loc,Anonymous ->
if global_level then
user_err_loc (loc,"", str "Anonymous variables not allowed");
env
| loc,Name id ->
check_hidden_implicit_parameters id env.impls ;
set_var_scope loc id false env (let (_,ntnvars) = lvar in ntnvars);
if global_level then Dumpglob.dump_definition (loc,id) true "var"
else Dumpglob.dump_binding loc id;
{env with ids = Idset.add id env.ids; impls = Idmap.add id implargs env.impls}
let intern_generalized_binder ?(global_level=false) intern_type lvar
env (loc, na) b b' t ty =
let ids = (match na with Anonymous -> fun x -> x | Name na -> Idset.add na) env.ids in
let ty, ids' =
if t then ty, ids else
Implicit_quantifiers.implicit_application ids
Implicit_quantifiers.combine_params_freevar ty
in
let ty' = intern_type {env with ids = ids; unb = true} ty in
let fvs = Implicit_quantifiers.generalizable_vars_of_glob_constr ~bound:ids ~allowed:ids' ty' in
let env' = List.fold_left
(fun env (x, l) -> push_name_env ~global_level lvar (Variable,[],[],[])(*?*) env (l, Name x))
env fvs in
let bl = List.map
(fun (id, loc) ->
(loc, (Name id, b, None, GHole (loc, Evar_kinds.BinderType (Name id)))))
fvs
in
let na = match na with
| Anonymous ->
if global_level then na
else
let name =
let id =
match ty with
| CApp (_, (_, CRef (Ident (loc,id))), _) -> id
| _ -> id_of_string "H"
in Implicit_quantifiers.make_fresh ids' (Global.env ()) id
in Name name
| _ -> na
in (push_name_env ~global_level lvar (impls_type_list ty')(*?*) env' (loc,na)), (loc,(na,b',None,ty')) :: List.rev bl
let intern_assumption intern lvar env nal bk ty =
let intern_type env = intern (set_type_scope env) in
match bk with
| Default k ->
let ty = intern_type env ty in
check_capture ty nal;
let impls = impls_type_list ty in
List.fold_left
(fun (env, bl) (loc, na as locna) ->
(push_name_env lvar impls env locna,
(loc,(na,k,None,locate_if_isevar loc na ty))::bl))
(env, []) nal
| Generalized (b,b',t) ->
let env, b = intern_generalized_binder intern_type lvar env (List.hd nal) b b' t ty in
env, b
let intern_local_binder_aux ?(global_level=false) intern lvar (env,bl) = function
| LocalRawAssum(nal,bk,ty) ->
let env, bl' = intern_assumption intern lvar env nal bk ty in
env, bl' @ bl
| LocalRawDef((loc,na as locna),def) ->
let indef = intern env def in
(push_name_env lvar (impls_term_list indef) env locna,
(loc,(na,Explicit,Some(indef),GHole(loc,Evar_kinds.BinderType na)))::bl)
let intern_generalization intern env lvar loc bk ak c =
let c = intern {env with unb = true} c in
let fvs = Implicit_quantifiers.generalizable_vars_of_glob_constr ~bound:env.ids c in
let env', c' =
let abs =
let pi =
match ak with
| Some AbsPi -> true
| None when env.tmp_scope = Some Notation.type_scope
|| List.mem Notation.type_scope env.scopes -> true
| _ -> false
in
if pi then
(fun (id, loc') acc ->
GProd (Loc.merge loc' loc, Name id, bk, GHole (loc', Evar_kinds.BinderType (Name id)), acc))
else
(fun (id, loc') acc ->
GLambda (Loc.merge loc' loc, Name id, bk, GHole (loc', Evar_kinds.BinderType (Name id)), acc))
in
List.fold_right (fun (id, loc as lid) (env, acc) ->
let env' = push_name_env lvar (Variable,[],[],[]) env (loc, Name id) in
(env', abs lid acc)) fvs (env,c)
in c'
(**********************************************************************)
(* Syntax extensions *)
let option_mem_assoc id = function
| Some (id',c) -> id = id'
| None -> false
let find_fresh_name renaming (terms,termlists,binders) id =
let fvs1 = List.map (fun (_,(c,_)) -> free_vars_of_constr_expr c) terms in
let fvs2 = List.flatten (List.map (fun (_,(l,_)) -> List.map free_vars_of_constr_expr l) termlists) in
let fvs3 = List.map snd renaming in
(* TODO binders *)
let fvs = List.flatten (List.map Idset.elements (fvs1@fvs2)) @ fvs3 in
next_ident_away id fvs
let traverse_binder (terms,_,_ as subst)
(renaming,env)=
function
| Anonymous -> (renaming,env),Anonymous
| Name id ->
try
(* Binders bound in the notation are considered first-order objects *)
let _,na = coerce_to_name (fst (List.assoc id terms)) in
(renaming,{env with ids = name_fold Idset.add na env.ids}), na
with Not_found ->
(* Binders not bound in the notation do not capture variables *)
(* outside the notation (i.e. in the substitution) *)
let id' = find_fresh_name renaming subst id in
let renaming' = if id=id' then renaming else (id,id')::renaming in
(renaming',env), Name id'
let make_letins = List.fold_right (fun (loc,(na,b,t)) c -> GLetIn (loc,na,b,c))
let rec subordinate_letins letins = function
(* binders come in reverse order; the non-let are returned in reverse order together *)
(* with the subordinated let-in in writing order *)
| (loc,(na,_,Some b,t))::l ->
subordinate_letins ((loc,(na,b,t))::letins) l
| (loc,(na,bk,None,t))::l ->
let letins',rest = subordinate_letins [] l in
letins',((loc,(na,bk,t)),letins)::rest
| [] ->
letins,[]
let rec subst_iterator y t = function
| GVar (_,id) as x -> if id = y then t else x
| x -> map_glob_constr (subst_iterator y t) x
let subst_aconstr_in_glob_constr loc intern lvar subst infos c =
let (terms,termlists,binders) = subst in
let rec aux (terms,binderopt as subst') (renaming,env) c =
let subinfos = renaming,{env with tmp_scope = None} in
match c with
| NVar id ->
begin
(* subst remembers the delimiters stack in the interpretation *)
(* of the notations *)
try
let (a,(scopt,subscopes)) = List.assoc id terms in
intern {env with tmp_scope = scopt;
scopes = subscopes @ env.scopes} a
with Not_found ->
try
GVar (loc,List.assoc id renaming)
with Not_found ->
(* Happens for local notation joint with inductive/fixpoint defs *)
GVar (loc,id)
end
| NList (x,_,iter,terminator,lassoc) ->
(try
(* All elements of the list are in scopes (scopt,subscopes) *)
let (l,(scopt,subscopes)) = List.assoc x termlists in
let termin = aux subst' subinfos terminator in
List.fold_right (fun a t ->
subst_iterator ldots_var t
(aux ((x,(a,(scopt,subscopes)))::terms,binderopt) subinfos iter))
(if lassoc then List.rev l else l) termin
with Not_found ->
anomaly "Inconsistent substitution of recursive notation")
| NHole (Evar_kinds.BinderType (Name id as na)) ->
let na =
try snd (coerce_to_name (fst (List.assoc id terms)))
with Not_found -> na in
GHole (loc,Evar_kinds.BinderType na)
| NBinderList (x,_,iter,terminator) ->
(try
(* All elements of the list are in scopes (scopt,subscopes) *)
let (bl,(scopt,subscopes)) = List.assoc x binders in
let env,bl = List.fold_left (intern_local_binder_aux intern lvar) (env,[]) bl in
let letins,bl = subordinate_letins [] bl in
let termin = aux subst' (renaming,env) terminator in
let res = List.fold_left (fun t binder ->
subst_iterator ldots_var t
(aux (terms,Some(x,binder)) subinfos iter))
termin bl in
make_letins letins res
with Not_found ->
anomaly "Inconsistent substitution of recursive notation")
| NProd (Name id, NHole _, c') when option_mem_assoc id binderopt ->
let (loc,(na,bk,t)),letins = snd (Option.get binderopt) in
GProd (loc,na,bk,t,make_letins letins (aux subst' infos c'))
| NLambda (Name id,NHole _,c') when option_mem_assoc id binderopt ->
let (loc,(na,bk,t)),letins = snd (Option.get binderopt) in
GLambda (loc,na,bk,t,make_letins letins (aux subst' infos c'))
| t ->
glob_constr_of_notation_constr_with_binders loc
(traverse_binder subst) (aux subst') subinfos t
in aux (terms,None) infos c
let split_by_type ids =
List.fold_right (fun (x,(scl,typ)) (l1,l2,l3) ->
match typ with
| NtnTypeConstr -> ((x,scl)::l1,l2,l3)
| NtnTypeConstrList -> (l1,(x,scl)::l2,l3)
| NtnTypeBinderList -> (l1,l2,(x,scl)::l3)) ids ([],[],[])
let make_subst ids l = List.map2 (fun (id,scl) a -> (id,(a,scl))) ids l
let intern_notation intern env lvar loc ntn fullargs =
let ntn,(args,argslist,bll as fullargs) = contract_notation ntn fullargs in
let ((ids,c),df) = interp_notation loc ntn (env.tmp_scope,env.scopes) in
Dumpglob.dump_notation_location (ntn_loc loc fullargs ntn) ntn df;
let ids,idsl,idsbl = split_by_type ids in
let terms = make_subst ids args in
let termlists = make_subst idsl argslist in
let binders = make_subst idsbl bll in
subst_aconstr_in_glob_constr loc intern lvar
(terms,termlists,binders) ([],env) c
(**********************************************************************)
(* Discriminating between bound variables and global references *)
let string_of_ty = function
| Inductive _ -> "ind"
| Recursive -> "def"
| Method -> "meth"
| Variable -> "var"
let intern_var genv (ltacvars,ntnvars) namedctx loc id =
let (ltacvars,unbndltacvars) = ltacvars in
(* Is [id] an inductive type potentially with implicit *)
try
let ty,expl_impls,impls,argsc = Idmap.find id genv.impls in
let expl_impls = List.map
(fun id -> CRef (Ident (loc,id)), Some (loc,ExplByName id)) expl_impls in
let tys = string_of_ty ty in
Dumpglob.dump_reference loc "<>" (string_of_id id) tys;
GVar (loc,id), make_implicits_list impls, argsc, expl_impls
with Not_found ->
(* Is [id] bound in current term or is an ltac var bound to constr *)
if Idset.mem id genv.ids or List.mem id ltacvars
then
GVar (loc,id), [], [], []
(* Is [id] a notation variable *)
else if List.mem_assoc id ntnvars
then
(set_var_scope loc id true genv ntnvars; GVar (loc,id), [], [], [])
(* Is [id] the special variable for recursive notations *)
else if ntnvars <> [] && id = ldots_var
then
GVar (loc,id), [], [], []
else
(* Is [id] bound to a free name in ltac (this is an ltac error message) *)
try
match List.assoc id unbndltacvars with
| None -> user_err_loc (loc,"intern_var",
str "variable " ++ pr_id id ++ str " should be bound to a term.")
| Some id0 -> Pretype_errors.error_var_not_found_loc loc id0
with Not_found ->
(* Is [id] a goal or section variable *)
let _ = Sign.lookup_named id namedctx in
try
(* [id] a section variable *)
(* Redundant: could be done in intern_qualid *)
let ref = VarRef id in
let impls = implicits_of_global ref in
let scopes = find_arguments_scope ref in
Dumpglob.dump_reference loc "<>" (string_of_qualid (Decls.variable_secpath id)) "var";
GRef (loc, ref), impls, scopes, []
with _ ->
(* [id] a goal variable *)
GVar (loc,id), [], [], []
let find_appl_head_data = function
| GRef (_,ref) as x -> x,implicits_of_global ref,find_arguments_scope ref,[]
| GApp (_,GRef (_,ref),l) as x
when l <> [] & Flags.version_strictly_greater Flags.V8_2 ->
let n = List.length l in
x,List.map (drop_first_implicits n) (implicits_of_global ref),
List.skipn_at_least n (find_arguments_scope ref),[]
| x -> x,[],[],[]
let error_not_enough_arguments loc =
user_err_loc (loc,"",str "Abbreviation is not applied enough.")
let check_no_explicitation l =
let l = List.filter (fun (a,b) -> b <> None) l in
if l <> [] then
let loc = fst (Option.get (snd (List.hd l))) in
user_err_loc
(loc,"",str"Unexpected explicitation of the argument of an abbreviation.")
let dump_extended_global loc = function
| TrueGlobal ref -> Dumpglob.add_glob loc ref
| SynDef sp -> Dumpglob.add_glob_kn loc sp
let intern_extended_global_of_qualid (loc,qid) =
try let r = Nametab.locate_extended qid in dump_extended_global loc r; r
with Not_found -> error_global_not_found_loc loc qid
let intern_reference ref =
Smartlocate.global_of_extended_global
(intern_extended_global_of_qualid (qualid_of_reference ref))
(* Is it a global reference or a syntactic definition? *)
let intern_qualid loc qid intern env lvar args =
match intern_extended_global_of_qualid (loc,qid) with
| TrueGlobal ref ->
GRef (loc, ref), args
| SynDef sp ->
let (ids,c) = Syntax_def.search_syntactic_definition sp in
let nids = List.length ids in
if List.length args < nids then error_not_enough_arguments loc;
let args1,args2 = List.chop nids args in
check_no_explicitation args1;
let subst = make_subst ids (List.map fst args1) in
subst_aconstr_in_glob_constr loc intern lvar (subst,[],[]) ([],env) c, args2
(* Rule out section vars since these should have been found by intern_var *)
let intern_non_secvar_qualid loc qid intern env lvar args =
match intern_qualid loc qid intern env lvar args with
| GRef (loc, VarRef id),_ -> error_global_not_found_loc loc qid
| r -> r
let intern_applied_reference intern env namedctx lvar args = function
| Qualid (loc, qid) ->
let r,args2 = intern_qualid loc qid intern env lvar args in
find_appl_head_data r, args2
| Ident (loc, id) ->
try intern_var env lvar namedctx loc id, args
with Not_found ->
let qid = qualid_of_ident id in
try
let r,args2 = intern_non_secvar_qualid loc qid intern env lvar args in
find_appl_head_data r, args2
with e ->
(* Extra allowance for non globalizing functions *)
if !interning_grammar || env.unb then
(GVar (loc,id), [], [], []),args
else raise e
let interp_reference vars r =
let (r,_,_,_),_ =
intern_applied_reference (fun _ -> error_not_enough_arguments Loc.ghost)
{ids = Idset.empty; unb = false ;
tmp_scope = None; scopes = []; impls = empty_internalization_env} []
(vars,[]) [] r
in r
(**********************************************************************)
(** {5 Cases } *)
(** {6 Elemtary bricks } *)
let apply_scope_env env = function
| [] -> {env with tmp_scope = None}, []
| sc::scl -> {env with tmp_scope = sc}, scl
let rec simple_adjust_scopes n scopes =
(* Note: they can be less scopes than arguments but also more scopes *)
(* than arguments because extra scopes are used in the presence of *)
(* coercions to funclass *)
if n=0 then [] else match scopes with
| [] -> None :: simple_adjust_scopes (n-1) []
| sc::scopes -> sc :: simple_adjust_scopes (n-1) scopes
let find_remaining_scopes pl1 pl2 ref =
let impls_st = implicits_of_global ref in
let len_pl1 = List.length pl1 in
let len_pl2 = List.length pl2 in
let impl_list = if len_pl1 = 0
then select_impargs_size len_pl2 impls_st
else List.skipn_at_least len_pl1 (select_stronger_impargs impls_st) in
let allscs = find_arguments_scope ref in
let scope_list = List.skipn_at_least len_pl1 allscs in
let rec aux = function
|[],l -> l
|_,[] -> []
|h::t,_::tt when is_status_implicit h -> aux (t,tt)
|_::t,h::tt -> h :: aux (t,tt)
in ((try List.firstn len_pl1 allscs with Failure _ -> simple_adjust_scopes len_pl1 allscs),
simple_adjust_scopes len_pl2 (aux (impl_list,scope_list)))
let product_of_cases_patterns ids idspl =
List.fold_right (fun (ids,pl) (ids',ptaill) ->
(ids@ids',
(* Cartesian prod of the or-pats for the nth arg and the tail args *)
List.flatten (
List.map (fun (subst,p) ->
List.map (fun (subst',ptail) -> (subst@subst',p::ptail)) ptaill) pl)))
idspl (ids,[[],[]])
(* @return the first variable that occurs twice in a pattern
naive n2 algo *)
let rec has_duplicate = function
| [] -> None
| x::l -> if List.mem x l then (Some x) else has_duplicate l
let loc_of_lhs lhs =
Loc.merge (fst (List.hd lhs)) (fst (List.last lhs))
let check_linearity lhs ids =
match has_duplicate ids with
| Some id ->
raise (InternalizationError (loc_of_lhs lhs,NonLinearPattern id))
| None ->
()
(* Match the number of pattern against the number of matched args *)
let check_number_of_pattern loc n l =
let p = List.length l in
if n<>p then raise (InternalizationError (loc,BadPatternsNumber (n,p)))
let check_or_pat_variables loc ids idsl =
if List.exists (fun ids' -> not (List.eq_set ids ids')) idsl then
user_err_loc (loc, "", str
"The components of this disjunctive pattern must bind the same variables.")
(** Use only when params were NOT asked to the user.
@return if letin are included *)
let check_constructor_length env loc cstr len_pl pl0 =
let nargs = Inductiveops.mis_constructor_nargs cstr in
let n = len_pl + List.length pl0 in
if n = nargs then false else
(n = (fst (Inductiveops.inductive_nargs (fst cstr))) + Inductiveops.constructor_nrealhyps cstr) ||
(error_wrong_numarg_constructor_loc loc env cstr
(nargs - (Inductiveops.inductive_nparams (fst cstr))))
let add_implicits_check_length fail nargs nargs_with_letin impls_st len_pl1 pl2 =
let impl_list = if len_pl1 = 0
then select_impargs_size (List.length pl2) impls_st
else List.skipn_at_least len_pl1 (select_stronger_impargs impls_st) in
let remaining_args = List.fold_left (fun i x -> if is_status_implicit x then i else succ i) in
let rec aux i = function
|[],l -> let args_len = List.length l + List.length impl_list + len_pl1 in
((if args_len = nargs then false
else args_len = nargs_with_letin || (fst (fail (nargs - List.length impl_list + i))))
,l)
|imp::q as il,[] -> if is_status_implicit imp && maximal_insertion_of imp
then let (b,out) = aux i (q,[]) in (b,RCPatAtom(Loc.ghost,None)::out)
else fail (remaining_args (len_pl1+i) il)
|imp::q,(hh::tt as l) -> if is_status_implicit imp
then let (b,out) = aux i (q,l) in (b,RCPatAtom(Loc.ghost,None)::out)
else let (b,out) = aux (succ i) (q,tt) in (b,hh::out)
in aux 0 (impl_list,pl2)
let add_implicits_check_constructor_length env loc c len_pl1 pl2 =
let nargs = Inductiveops.mis_constructor_nargs c in
let nargs' = (fst (Inductiveops.inductive_nargs (fst c)))
+ Inductiveops.constructor_nrealhyps c in
let impls_st = implicits_of_global (ConstructRef c) in
add_implicits_check_length (error_wrong_numarg_constructor_loc loc env c)
nargs nargs' impls_st len_pl1 pl2
let add_implicits_check_ind_length env loc c len_pl1 pl2 =
let (mib,mip) = Global.lookup_inductive c in
let nparams = mib.Declarations.mind_nparams in
let nargs = mip.Declarations.mind_nrealargs + nparams in
let nparams', nrealargs' = inductive_nargs_env env c in
let impls_st = implicits_of_global (IndRef c) in
add_implicits_check_length (error_wrong_numarg_inductive_loc loc env c)
nargs (nrealargs' + nparams') impls_st len_pl1 pl2
(** Do not raise NotEnoughArguments thanks to preconditions*)
let chop_params_pattern loc ind args with_letin =
let nparams = if with_letin
then fst (Inductiveops.inductive_nargs ind)
else Inductiveops.inductive_nparams ind in
assert (nparams <= List.length args);
let params,args = List.chop nparams args in
List.iter (function PatVar(_,Anonymous) -> ()
| PatVar (loc',_) | PatCstr(loc',_,_,_) -> error_parameter_not_implicit loc') params;
args
let find_constructor loc add_params ref =
let cstr = (function ConstructRef cstr -> cstr
|IndRef _ -> user_err_loc (loc,"find_constructor",str "There is an inductive name deep in a \"in\" clause.")
|_ -> anomaly "unexpected global_reference in pattern") ref in
cstr, (function (ind,_ as c) -> match add_params with
|Some nb_args -> let nb = if nb_args = Inductiveops.constructor_nrealhyps c
then fst (Inductiveops.inductive_nargs ind)
else Inductiveops.inductive_nparams ind in
Util.List.make nb ([],[([],PatVar(Loc.ghost,Anonymous))])
|None -> []) cstr
let find_pattern_variable = function
| Ident (loc,id) -> id
| Qualid (loc,_) as x -> raise (InternalizationError(loc,NotAConstructor x))
let sort_fields mode loc l completer =
(*mode=false if pattern and true if constructor*)
match l with
| [] -> None
| (refer, value)::rem ->
let (nparams, (* the number of parameters *)
base_constructor, (* the reference constructor of the record *)
(max, (* number of params *)
(first_index, (* index of the first field of the record *)
list_proj))) (* list of projections *)
=
let record =
try Recordops.find_projection
(global_reference_of_reference refer)
with Not_found ->
user_err_loc (loc_of_reference refer, "intern", pr_reference refer ++ str": Not a projection")
in
(* elimination of the first field from the projections *)
let rec build_patt l m i acc =
match l with
| [] -> (i, acc)
| (Some name) :: b->
(match m with
| [] -> anomaly "Number of projections mismatch"
| (_, regular)::tm ->
let boolean = not regular in
if ConstRef name = global_reference_of_reference refer
then
if boolean && mode then
user_err_loc (loc, "", str"No local fields allowed in a record construction.")
else build_patt b tm (i + 1) (i, snd acc) (* we found it *)
else
build_patt b tm (if boolean&&mode then i else i + 1)
(if boolean && mode then acc
else fst acc, (i, ConstRef name) :: snd acc))
| None :: b-> (* we don't want anonymous fields *)
if mode then
user_err_loc (loc, "", str "This record contains anonymous fields.")
else build_patt b m (i+1) acc
(* anonymous arguments don't appear in m *)
in
let ind = record.Recordops.s_CONST in
try (* insertion of Constextern.reference_global *)
(record.Recordops.s_EXPECTEDPARAM,
Qualid (loc, shortest_qualid_of_global Idset.empty (ConstructRef ind)),
build_patt record.Recordops.s_PROJ record.Recordops.s_PROJKIND 1 (0,[]))
with Not_found -> anomaly "Environment corruption for records."
in
(* now we want to have all fields of the pattern indexed by their place in
the constructor *)
let rec sf patts accpatt =
match patts with
| [] -> accpatt
| p::q->
let refer, patt = p in
let glob_refer = try global_reference_of_reference refer
with |Not_found ->
user_err_loc (loc_of_reference refer, "intern",
str "The field \"" ++ pr_reference refer ++ str "\" does not exist.") in
let rec add_patt l acc =
match l with
| [] ->
user_err_loc
(loc, "",
str "This record contains fields of different records.")
| (i, a) :: b->
if glob_refer = a
then (i,List.rev_append acc l)
else add_patt b ((i,a)::acc)
in
let (index, projs) = add_patt (snd accpatt) [] in
sf q ((index, patt)::fst accpatt, projs) in
let (unsorted_indexed_pattern, remainings) =
sf rem ([first_index, value], list_proj) in
(* we sort them *)
let sorted_indexed_pattern =
List.sort (fun (i, _) (j, _) -> compare i j) unsorted_indexed_pattern in
(* a function to complete with wildcards *)
let rec complete_list n l =
if n <= 1 then l else complete_list (n-1) (completer n l) in
(* a function to remove indice *)
let rec clean_list l i acc =
match l with
| [] -> complete_list (max - i) acc
| (k, p)::q-> clean_list q k (p::(complete_list (k - i) acc))
in
Some (nparams, base_constructor,
List.rev (clean_list sorted_indexed_pattern 0 []))
(** {6 Manage multiple aliases} *)
(* [merge_aliases] returns the sets of all aliases encountered at this
point and a substitution mapping extra aliases to the first one *)
let merge_aliases (ids,asubst as _aliases) id =
ids@[id], if ids=[] then asubst else (id, List.hd ids)::asubst
let alias_of = function
| ([],_) -> Anonymous
| (id::_,_) -> Name id
let message_redundant_alias (id1,id2) =
if_warn msg_warning
(str "Alias variable " ++ pr_id id1 ++ str " is merged with " ++ pr_id id2)
(** {6 Expanding notations }
@returns a raw_case_pattern_expr :
- no notations and syntactic definition
- global reference and identifeir instead of reference
*)
let rec subst_pat_iterator y t p = match p with
| RCPatAtom (_,id) ->
begin match id with Some x when x = y -> t |_ -> p end
| RCPatCstr (loc,id,l1,l2) ->
RCPatCstr (loc,id,List.map (subst_pat_iterator y t) l1,
List.map (subst_pat_iterator y t) l2)
| RCPatAlias (l,p,a) -> RCPatAlias (l,subst_pat_iterator y t p,a)
| RCPatOr (l,pl) -> RCPatOr (l,List.map (subst_pat_iterator y t) pl)
let drop_notations_pattern looked_for =
let rec drop_syndef env re pats =
let (loc,qid) = qualid_of_reference re in
try
match locate_extended qid with
|SynDef sp ->
let (vars,a) = Syntax_def.search_syntactic_definition sp in
(match a with
| NRef g ->
looked_for g;
let () = assert (vars = []) in
let (_,argscs) = find_remaining_scopes [] pats g in
Some (g, [], List.map2 (in_pat_sc env) argscs pats)
| NApp (NRef g,[]) -> (* special case : Syndef for @Cstr *)
looked_for g;
let () = assert (vars = []) in
let (argscs,_) = find_remaining_scopes pats [] g in
Some (g, List.map2 (in_pat_sc env) argscs pats, [])
| NApp (NRef g,args) ->
looked_for g;