-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathIdentifiersBasicGenerate.v
More file actions
1835 lines (1704 loc) · 97.9 KB
/
Copy pathIdentifiersBasicGenerate.v
File metadata and controls
1835 lines (1704 loc) · 97.9 KB
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
From Stdlib Require Import ZArith.
From Stdlib Require Import Bool.
From Stdlib Require Import Morphisms.
From Stdlib Require Import List.
Require Import Ltac2.Ltac2.
Require Import Ltac2.Bool.
Require Import Ltac2.Printf.
Require Import Rewriter.Language.Pre.
Require Import Rewriter.Language.Language.
Require Import Rewriter.Language.Reify.
Require Import Rewriter.Language.IdentifiersBasicLibrary.
Require Import Rewriter.Util.Prod Rewriter.Util.LetIn.
Require Import Rewriter.Util.ListUtil Rewriter.Util.NatUtil.
Require Import Rewriter.Util.Option.
Require Import Rewriter.Util.Prod.
Require Import Rewriter.Util.CPSNotations.
Require Import Rewriter.Util.Pointed.
Require Import Rewriter.Util.Bool.
Require Import Rewriter.Util.Bool.Reflect.
Require Rewriter.Util.TypeList.
Require Rewriter.Util.PrimitiveHList.
Require Rewriter.Util.Tactics2.Constr.
Require Import Rewriter.Util.Notations.
Require Import Rewriter.Util.Tactics.RunTacticAsConstr.
Require Import Rewriter.Util.Tactics.DebugPrint.
Require Import Rewriter.Util.Tactics.ConstrFail.
Require Import Rewriter.Util.Tactics.Head.
Require Import Rewriter.Util.Tactics.HeadUnderBinders.
Require Import Rewriter.Util.Tactics.PrintGoal.
Require Import Rewriter.Util.Tactics.CacheTerm.
Require Import Rewriter.Util.Tactics2.Notations.
Require Import Rewriter.Util.HProp.
Import Stdlib.Lists.List ListNotations. Local Open Scope bool_scope. Local Open Scope Z_scope.
Import EqNotations.
Module Compilers.
Import Language.Pre.
Import Language.Compilers.
Export Reify.Compilers.
Export IdentifiersBasicLibrary.Compilers.
Module Basic.
Export IdentifiersBasicLibrary.Compilers.Basic.
Ltac eliminate_functional_dependencies term :=
lazymatch term with
| ?A -> ?term => term
| fun _ => ?term => term
| fun name : ?T => ?F
=> let XXX := fresh "XXX" in
let term := constr:(fun XXX : T
=> match XXX return _ with name => F end) in
constr_fail_with ltac:(fun _ => fail 1 "cannot eliminate functional dependencies of" term)
| forall name : ?T, ?F
=> let XXX := fresh "XXX" in
let term := constr:(forall XXX : T,
match XXX return _ with name => F end) in
constr_fail_with ltac:(fun _ => fail 1 "cannot eliminate functional dependencies of" term)
end.
Module ScrapeTactics.
Ltac heuristic_process_rules_proofs rules_proofs :=
let get_prim_fst v :=
lazymatch v with
| PrimitiveProd.Primitive.pair ?x ?y => x
| _ => constr:(PrimitiveProd.Primitive.fst v)
end in
let get_prim_snd v :=
lazymatch v with
| PrimitiveProd.Primitive.pair ?x ?y => y
| _ => constr:(PrimitiveProd.Primitive.snd v)
end in
let get_fst v :=
lazymatch v with
| Datatypes.pair ?x ?y => x
| _ => constr:(Datatypes.fst v)
end in
let get_snd v :=
lazymatch v with
| Datatypes.pair ?x ?y => y
| _ => constr:(Datatypes.snd v)
end in
lazymatch type of rules_proofs with
| PrimitiveHList.hlist (@snd bool Prop) _ => rules_proofs
| PrimitiveProd.Primitive.prod (@snd bool Prop ?lem) _
=> let fst_part := get_prim_fst rules_proofs in
let snd_part := get_prim_snd rules_proofs in
let snd_part := heuristic_process_rules_proofs snd_part in
let rest := lazymatch type of snd_part with PrimitiveHList.hlist (@snd bool Prop) ?rest => rest end in
constr:(PrimitiveProd.Primitive.pair fst_part snd_part
: PrimitiveHList.hlist (@snd bool Prop) (Datatypes.cons lem rest))
| PrimitiveProd.Primitive.prod (PrimitiveHList.hlist (@snd bool Prop) Datatypes.nil) _
=> let snd_part := get_prim_snd rules_proofs in
let snd_part := heuristic_process_rules_proofs snd_part in
snd_part
| PrimitiveProd.Primitive.prod (PrimitiveProd.Primitive.prod ?P1 ?P2) ?rest
=> let fst_part := get_prim_fst rules_proofs in
let snd_part := get_prim_snd rules_proofs in
let fst_fst_part := get_prim_fst fst_part in
let snd_fst_part := get_prim_snd fst_part in
heuristic_process_rules_proofs
(@PrimitiveProd.Primitive.pair
P1 (PrimitiveProd.Primitive.prod P2 rest)
fst_fst_part (@PrimitiveProd.Primitive.pair P2 rest snd_fst_part snd_part))
| PrimitiveProd.Primitive.prod (PrimitiveHList.hlist (@snd bool Prop) (Datatypes.cons ?P ?Ps)) ?rest
=> let fst_part := get_prim_fst rules_proofs in
let snd_part := get_prim_snd rules_proofs in
let fst_fst_part := get_prim_fst fst_part in
let snd_fst_part := get_prim_snd fst_part in
let P1 := constr:(@snd bool Prop P) in
let P2 := constr:(PrimitiveHList.hlist (@snd bool Prop) Ps) in
heuristic_process_rules_proofs
(@PrimitiveProd.Primitive.pair
P1 (PrimitiveProd.Primitive.prod P2 rest)
fst_fst_part (@PrimitiveProd.Primitive.pair P2 rest snd_fst_part snd_part))
| PrimitiveProd.Primitive.prod (Datatypes.prod ?P1 ?P2) ?rest
=> let fst_part := get_prim_fst rules_proofs in
let snd_part := get_prim_snd rules_proofs in
let fst_fst_part := get_fst fst_part in
let snd_fst_part := get_snd fst_part in
heuristic_process_rules_proofs
(@PrimitiveProd.Primitive.pair
P1 (PrimitiveProd.Primitive.prod P2 rest)
fst_fst_part (@PrimitiveProd.Primitive.pair P2 rest snd_fst_part snd_part))
| PrimitiveProd.Primitive.prod (@RewriteRuleNotations.Types.eval_rect ?TT ?T) ?rest
=> let fst_part := get_prim_fst rules_proofs in
let snd_part := get_prim_snd rules_proofs in
let fst_part := heuristic_process_rules_proofs (fst_part : @RewriteRuleNotations.Types.eval_rect TT T) in
heuristic_process_rules_proofs
(@PrimitiveProd.Primitive.pair _ rest fst_part snd_part)
| PrimitiveProd.Primitive.prod ?P ?rest
=> heuristic_process_rules_proofs (rules_proofs : PrimitiveProd.Primitive.prod (@snd bool Prop (RewriteRuleNotations.Types.default_do_again P)) rest)
| Datatypes.prod ?P ?rest
=> let fst_part := get_fst rules_proofs in
let snd_part := get_snd rules_proofs in
heuristic_process_rules_proofs (@PrimitiveProd.Primitive.pair P rest fst_part snd_part)
| Datatypes.unit
=> constr:(rules_proofs : PrimitiveHList.hlist (@snd bool Prop) Datatypes.nil)
| @snd bool Prop ?P
=> constr:(PrimitiveProd.Primitive.pair rules_proofs tt
: PrimitiveHList.hlist (@snd bool Prop) (Datatypes.cons P Datatypes.nil))
| RewriteRuleNotations.Types.eval_rect ?T
=> lazymatch (eval hnf in (_ : rules_proofs_for_eager_type T)) with
| existT _ ?ty ?val
=> heuristic_process_rules_proofs (val : PrimitiveHList.hlist (@snd bool Prop) ty)
end
| ?P => constr:(PrimitiveProd.Primitive.pair rules_proofs tt
: PrimitiveHList.hlist (@snd bool Prop) (Datatypes.cons (RewriteRuleNotations.Types.default_do_again P) Datatypes.nil))
end.
Ltac make_rules_proofsT_with_args :=
idtac;
lazymatch goal with
| [ |- rules_proofsT_with_args ?rules_proofs ]
=> (tryif has_evar rules_proofs
then fail 0 "Unresolved evar in" rules_proofs "Rewrite rules are not allowed to contain evars"
else let res := heuristic_process_rules_proofs rules_proofs in
let T := type of res in
eexists; exact (@id T res))
end.
Module Export Hints.
Local Set Default Proof Mode "Classic".
Global Hint Extern 0 (rules_proofsT_with_args _) => make_rules_proofsT_with_args : typeclass_instances.
End Hints.
Ltac2 scrape_preprocess (t : constr) : constr :=
let t := Compilers.expr.reify_preprocess [] t in
let t := Compilers.expr.reify_ident_preprocess [] t in
t.
Ltac scrape_preprocess t :=
let f := ltac2:(t |- Control.refine (fun () => scrape_preprocess (Option.get (Ltac1.to_constr t)))) in
constr:(ltac:(f t)).
Ltac scrape_data_of_type' scrape_data_of_term so_far T :=
let recr := scrape_data_of_type' scrape_data_of_term in
let T := scrape_preprocess T in
let is_var_T := match constr:(Set) with
| _ => let __ := match constr:(Set) with _ => is_var T end in
true
| _ => false
end in
lazymatch is_var_T with
| true => so_far
| false
=> lazymatch T with
| forall x : ?T, @?F x => recr so_far F
| Type => so_far
| Set => so_far
| Prop => so_far
| Datatypes.list (* hardcoded *) => so_far
| Datatypes.option (* hardcoded *) => so_far
| Datatypes.unit (* hardcoded *) => so_far
| Datatypes.prod (* hardcoded *) => so_far
| ?x = ?y
=> let so_far := scrape_data_of_term so_far x in
scrape_data_of_term so_far y
| ?f ?x
=> let so_far := recr so_far f in
recr so_far x
| fun x : ?T => ?F
=> let so_far := recr so_far T in
let F' := fresh in
eliminate_functional_dependencies
(fun x : T =>
match F return _ with
| F' =>
ltac:(
let F := (eval cbv delta [F'] in F') in
clear F';
let so_far := recr so_far F in
exact so_far)
end)
| ?ty
=> let base_type_list_named := lazymatch so_far with {| ScrapedData.base_type_list_named := ?base_type_list_named |} => base_type_list_named end in
lazymatch base_type_list_named with
| context[InductiveHList.cons {| Named.value := ty |}] (* already present *)
=> so_far
| _ => lazymatch so_far with
| {| ScrapedData.all_ident_named_interped := ?all_ident_named_interped
; ScrapedData.base_type_list_named := ?base_type_list_named |}
=> constr:({| ScrapedData.all_ident_named_interped := all_ident_named_interped
; ScrapedData.base_type_list_named := InductiveHList.cons (without_name ty) base_type_list_named |})
end
end
end
end.
Ltac require_type_or_arrow T :=
lazymatch (eval cbv beta in T) with
| Type => idtac
| Set => idtac
| Prop => idtac
| forall x : ?A, @?F x
=> let __ := constr:(forall x : A,
ltac:(require_type_or_arrow (F x); exact True)) in
idtac
end.
Ltac scrape_data_of_term so_far term :=
let scrape_data_of_type := scrape_data_of_type' scrape_data_of_term in
let recr := scrape_data_of_term in
let term := scrape_preprocess term in
let is_var_term := match constr:(Set) with
| _ => let __ := match constr:(Set) with _ => is_var term end in
true
| _ => false
end in
let is_a_type :=
let T := type of term in
match constr:(Set) with
| _ => let __ := match constr:(Set) with _ => require_type_or_arrow T end in
true
| _ => false
end in
let try_add term :=
let all_ident_named_interped := lazymatch so_far with {| ScrapedData.all_ident_named_interped := ?all_ident_named_interped |} => all_ident_named_interped end in
lazymatch all_ident_named_interped with
| context[InductiveHList.cons {| Named.value := term |}] (* already present *)
=> so_far
| _ => lazymatch so_far with
| {| ScrapedData.all_ident_named_interped := ?all_ident_named_interped
; ScrapedData.base_type_list_named := ?base_type_list_named |}
=> constr:({| ScrapedData.all_ident_named_interped := InductiveHList.cons (without_name term) all_ident_named_interped
; ScrapedData.base_type_list_named := base_type_list_named |})
end
end in
lazymatch is_var_term with
| true => so_far
| false =>
lazymatch is_a_type with
| true => scrape_data_of_type so_far term
| false =>
lazymatch term with
| ident.eagerly ?t => try_add term
| ?f ?x
=> let so_far := recr so_far f in
recr so_far x
| fun x : ?T => ?F
=> let so_far := scrape_data_of_type so_far T in
let F' := fresh in
eliminate_functional_dependencies
(fun x : T =>
match F return _ with
| F' =>
ltac:(
let F := (eval cbv delta [F'] in F') in
clear F';
let so_far := recr so_far F in
exact so_far)
end)
| ?term => try_add term
end
end
end.
Ltac scrape_data_of_type so_far T
:= scrape_data_of_type' scrape_data_of_term so_far T.
(* N.B. We include [bool] here only because some of the tactic
code fails if there is only one base type.
TODO: make this not be the case. *)
Notation initial_type_list :=
([without_name Datatypes.nat
; without_name Datatypes.bool]%hlist)
(only parsing).
Notation initial_term_list :=
([without_name (@ident.literal)
; without_name (@Datatypes.nil)
; without_name (@Datatypes.cons)
; without_name (@Datatypes.Some)
; without_name (@Datatypes.None)
; without_name (@Datatypes.pair)
; without_name (@Datatypes.tt)
; without_name (@prod_rect_nodep)
; without_name (@Thunked.bool_rect)
; without_name (@Thunked.list_case)
; without_name (@Thunked.option_rect)
; with_name ident_nat_rect (@Thunked.nat_rect)
; with_name ident_eager_nat_rect (ident.eagerly (@Thunked.nat_rect))
; with_name ident_nat_rect_arrow (@nat_rect_arrow_nodep)
; with_name ident_eager_nat_rect_arrow (ident.eagerly (@nat_rect_arrow_nodep))
; with_name ident_list_rect (@Thunked.list_rect)
; with_name ident_eager_list_rect (ident.eagerly (@Thunked.list_rect))
; with_name ident_list_rect_arrow (@list_rect_arrow_nodep)
; with_name ident_eager_list_rect_arrow (ident.eagerly (@list_rect_arrow_nodep))
; with_name ident_List_nth_default (@nth_default)
; with_name ident_eager_List_nth_default (ident.eagerly (@nth_default))
]%hlist)
(only parsing).
Ltac scrape_data_of_rulesT rules extra :=
let rec iter so_far ls :=
lazymatch (eval hnf in ls) with
| Datatypes.cons (_, ?T) ?rest
=> let so_far := scrape_data_of_type so_far T in
iter so_far rest
| Datatypes.nil => so_far
| ?term => constr_fail_with ltac:(fun _ => fail 1 "Invalid non-list-of-pair rewrite rules" term)
end in
let so_far :=
iter {| ScrapedData.all_ident_named_interped := initial_term_list
; ScrapedData.base_type_list_named := initial_type_list |}
rules in
let extraT := type of extra in
let so_far := scrape_data_of_type so_far extraT in
let so_far := scrape_data_of_term so_far extra in
so_far.
Ltac build_scrape_data rules_proofs extra :=
let expected_type := uconstr:(PrimitiveHList.hlist (@snd bool Prop) ?[rewrite_rules]) in
lazymatch (type of rules_proofs) with
| PrimitiveHList.hlist _ ?rewrite_rulesT
=> scrape_data_of_rulesT rewrite_rulesT extra
| ?T => constr_fail_with ltac:(fun _ => fail 1 "Unexpected type" T "of rewrite rules proofs" rules_proofs "; expected" expected_type)
end.
Ltac make_scrape_data_via rules_proofs extra :=
let res := build_scrape_data rules_proofs extra in refine res.
Ltac make_scrape_data :=
idtac;
lazymatch goal with
| [ |- ScrapedData.t_with_args ?rules_proofs ?extra ]
=> cbv [ScrapedData.t_with_args];
make_scrape_data_via rules_proofs extra
| [ |- ?G ]
=> let exp := uconstr:(ScrapedData.t_with_args ?[rules_proofs] ?[extra]) in
fail 0 "Unexpected goal:" G "(expected" exp ")"
end.
End ScrapeTactics.
Module Import Tactics.
Ltac ident_basic_assembly_debug_level := Pre.ident_basic_assembly_debug_level.
Ltac check_debug_level_then_Set _ :=
let lvl := ident_basic_assembly_debug_level in
lazymatch type of lvl with
| nat => constr:(Set)
| ?T => constr_run_tac ltac:(fun _ => idtac "Error: ident_basic_assembly_debug_level should have type nat but instead has type" T)
end.
Ltac debug0 tac :=
constr_run_tac tac.
Ltac debug1 tac :=
let lvl := ident_basic_assembly_debug_level in
lazymatch lvl with
| S _ => constr_run_tac tac
| _ => check_debug_level_then_Set ()
end.
Ltac time_if_debug1 :=
let lvl := ident_basic_assembly_debug_level in
lazymatch lvl with
| O => ltac:(fun tac => tac ())
| S _ => ltac:(fun tac => time tac ())
| ?v => ltac:(fun tac => fail 0 "Invalid non-nat ident_basic_assembly_debug_level" v)
end.
Ltac get_min_and_incr min :=
lazymatch min with
| S ?min => let v := get_min_and_incr min in
constr:(S v)
| ?ev => let unif := open_constr:(eq_refl : S _ = ev) in
O
end.
Ltac build_index_of_base base :=
constr:(ltac:(let t := fresh "t" in
let min := open_constr:(_ : Datatypes.nat) in
unshelve (intro t; destruct t;
[ > let v := get_min_and_incr min in refine v .. ]);
exact O)
: base -> Datatypes.nat).
Ltac make_index_of_base base :=
let res := build_index_of_base base in refine res.
Ltac build_base_eq_dec base :=
constr:(ltac:(decide equality)
: forall x y : base, {x = y} + {x <> y}).
Ltac make_base_eq_dec base :=
let res := build_base_eq_dec base in refine res.
Ltac build_eta_base_cps_gen base :=
constr:(ltac:((unshelve eexists; let t := fresh in intro t; destruct t); shelve_unifiable; reflexivity)
: forall (P : base -> Type)
(f : forall t, P t),
{ f' : forall t, P t | forall t, f' t = f t }).
Ltac make_eta_base_cps_gen base := let res := build_eta_base_cps_gen base in refine res.
Ltac build_eta_base_cps eta_base_cps_gen :=
constr:((fun P f => proj1_sig (@eta_base_cps_gen _ f))
: forall {P : _ -> Type} (f : forall t, P t) t, P t).
Ltac make_eta_base_cps eta_base_cps_gen :=
let res := build_eta_base_cps eta_base_cps_gen in refine res.
Ltac build_base_interp eta_base_cps base_type_list index_of_base :=
let eta_base_cps := (eval cbv in eta_base_cps) in
let base_type_list := (eval hnf in base_type_list) in
let index_of_base := (eval cbv in index_of_base) in
(eval cbv [TypeList.nth] in
(fun ty => @eta_base_cps (fun _ => Type) (fun t => TypeList.nth (index_of_base t) base_type_list True) ty)).
Ltac make_base_interp eta_base_cps base_type_list index_of_base :=
let res := build_base_interp eta_base_cps base_type_list index_of_base in refine res.
Ltac find_evar_tail x :=
lazymatch x with
| Datatypes.cons _ ?x => find_evar_tail x
| ?ev => let __ := match goal with _ => is_evar ev end in
ev
end.
Ltac build_all_gen T mk P :=
let res := open_constr:(_ : list T) in
let fill_next v :=
let next := find_evar_tail res in
let __ := open_constr:(eq_refl : next = v) in
constr:(I) in
let __ := open_constr:(
ltac:(intros;
let v' := fresh "v'" in
lazymatch goal with
| [ v : _ |- _ ] => pose v as v'; destruct v
end;
let v := (eval cbv [v'] in v') in
let h := head v in
let v' := mk h in
let __ := fill_next open_constr:(Datatypes.cons v' _) in
constructor)
: P) in
let __ := fill_next uconstr:(Datatypes.nil) in
res.
Ltac build_all_base base :=
build_all_gen base ltac:(fun x => x) (base -> True).
Ltac make_all_base base :=
let res := build_all_base base in refine res.
Ltac build_all_base_and_interp all_base base_interp :=
let all_base := (eval cbv in all_base) in
let base_interp_head := head base_interp in
(eval cbv [List.map base_interp_head] in
(List.map (fun v => (v, base_interp v : Type)) all_base)).
Ltac make_all_base_and_interp all_base base_interp :=
let res := build_all_base_and_interp all_base base_interp in refine res.
Ltac build_base_type_list base_type_list_named :=
let rec iter ls :=
lazymatch (eval hnf in ls) with
| InductiveHList.nil => TypeList.nil
| InductiveHList.cons {| Named.value := ?T |} ?rest
=> let rest := iter rest in
constr:(TypeList.cons T rest)
end in
iter base_type_list_named.
Ltac make_base_type_list base_type_list_named :=
let res := build_base_type_list base_type_list_named in refine res.
Ltac2 reify_base_via_list_opt (base : constr) (base_interp : constr) (all_base_and_interp : constr) :=
let all_base_and_interp := Std.eval_hnf all_base_and_interp in
let all_base_and_interp := Std.eval_cbv (strategy:(beta)) all_base_and_interp in
fun ty
=> let ty := Std.eval_cbv (strategy:(beta)) ty in
Reify.debug_enter_reify "reify_base_via_list" ty;
let rty := match! all_base_and_interp with
| context[Datatypes.cons (?rty, ?ty')]
=> if Constr.equal_nounivs ty ty'
then Some rty
else Control.zero Match_failure
| _ => None
end in
match rty with
| Some rty => Some rty
| None
=> (* work around COQBUG(https://github.com/coq/coq/issues/13962) *)
match! ty with
| ?base_interp' ?t
=> if Constr.equal_nounivs base_interp' base_interp
then Some t
else Control.zero Match_failure
| @base.interp ?base' ?base_interp' (@base.type.type_base ?base' ?t)
=> if Constr.equal_nounivs base_interp' base_interp && Constr.equal_nounivs base' base
then Some t
else Control.zero Match_failure
| @type.interp (base.type ?base') (@base.interp ?base' ?base_interp') (@Compilers.type.base (base.type ?base') (@base.type.type_base ?base' ?t))
=> if Constr.equal_nounivs base_interp' base_interp && Constr.equal_nounivs base' base
then Some t
else Control.zero Match_failure
| _ => None
end
end.
Ltac2 reify_base_via_list (base : constr) (base_interp : constr) (all_base_and_interp : constr) (ty : constr) : constr :=
match reify_base_via_list_opt base base_interp all_base_and_interp ty with
| Some res => res
| None => Control.zero (Reification_failure (fprintf "Unrecognized type: %t" ty))
end.
#[deprecated(since="8.15",note="Use Ltac2 reify_base_via_list instead.")]
Ltac reify_base_via_list base base_interp all_base_and_interp ty :=
let f := ltac2:(base base_interp all_base_and_interp ty
|- Control.refine (fun () => reify_base_via_list (Ltac1.get_to_constr "base" base) (Ltac1.get_to_constr "base_interp" base_interp) (Ltac1.get_to_constr "all_base_and_interp" all_base_and_interp) (Ltac1.get_to_constr "ty" ty))) in
constr:(ltac:(f base base_interp all_base_and_interp ty)).
Ltac2 reify_base_type_via_list (base : constr) (base_interp : constr) (all_base_and_interp : constr) : constr -> constr :=
Compilers.base.reify base (reify_base_via_list base base_interp all_base_and_interp).
#[deprecated(since="8.15",note="Use Ltac2 reify_base_type_via_list instead.")]
Ltac reify_base_type_via_list base base_interp all_base_and_interp :=
Compilers.base.reify base ltac:(reify_base_via_list base base_interp all_base_and_interp).
Ltac2 reify_type_via_list (base : constr) (base_interp : constr) (all_base_and_interp : constr) : constr -> constr :=
Compilers.type.reify (reify_base_type_via_list base base_interp all_base_and_interp) '(base.type $base).
#[deprecated(since="8.15",note="Use Ltac2 reify_type_via_list instead.")]
Ltac reify_type_via_list base base_interp all_base_and_interp :=
Compilers.type.reify ltac:(reify_base_type_via_list base base_interp all_base_and_interp) constr:(base.type base).
Ltac2 reify_pattern_base_type_via_list (base : constr) (base_interp : constr) (all_base_and_interp : constr) : constr -> constr :=
Compilers.pattern.base.reify base (reify_base_via_list base base_interp all_base_and_interp).
#[deprecated(since="8.15",note="Use Ltac2 reify_pattern_base_type_via_list instead.")]
Ltac reify_pattern_base_type_via_list base base_interp all_base_and_interp :=
Compilers.pattern.base.reify base ltac:(reify_base_via_list base base_interp all_base_and_interp).
Ltac2 reify_pattern_type_via_list (base : constr) (base_interp : constr) (all_base_and_interp : constr) : constr -> constr :=
Compilers.type.reify (reify_pattern_base_type_via_list base base_interp all_base_and_interp) '(pattern.base.type $base).
#[deprecated(since="8.15",note="Use Ltac2 reify_pattern_type_via_list instead.")]
Ltac reify_pattern_type_via_list base base_interp all_base_and_interp :=
Compilers.type.reify ltac:(reify_pattern_base_type_via_list base base_interp all_base_and_interp) constr:(pattern.base.type base).
Ltac ident_type_of_interped_type reify_type base_type base_type_interp ident ty :=
let recur := ident_type_of_interped_type reify_type base_type base_type_interp ident in
let is_sort := lazymatch ty with
| forall T : Type, _ => true
| forall T : Set , _ => true
| forall T : Prop, _ => true
| _ => false
end in
lazymatch is_sort with
| true
=> lazymatch ty with
| forall x : ?T, ?F
=> let F' := fresh in
let t := fresh "t" in
constr:(forall t : base_type,
match base_type_interp t return _ with
| x
=> match F return _ with
| F'
=> ltac:(let Fv := (eval cbv [x F'] in F') in
clear x F';
let __ := type of Fv in (* force recomputation of universes *)
let res := recur Fv in
exact res)
end
end)
end
| false
=> let rT := reify_type ty in
constr:(ident rT)
end.
Ltac ident_type_of_interped_type_via_list base base_interp all_base_and_interp is_pattern :=
let reify_type := lazymatch is_pattern with
| false => reify_type_via_list base base_interp all_base_and_interp
| true => reify_pattern_type_via_list base base_interp all_base_and_interp
end in
let base_type := lazymatch is_pattern with
| false => constr:(base.type base)
| true => constr:(pattern.base.type base)
end in
let base_interp_head := head base_interp in
fun lookup is_literal ty ident
=> let base_type_interp := lazymatch is_pattern with
| false => constr:(base.interp base_interp)
| true => constr:(pattern.base.interp base_interp lookup)
end in
let res
:= lazymatch is_literal with
| true
=> let t := fresh "t" in
lazymatch is_pattern with
| false => constr:(forall t : base, base_interp t -> ident (type.base (base.type.type_base t)))
| true => constr:(forall t : base, ident (type.base (pattern.base.type.type_base t)))
end
| false
=> ident_type_of_interped_type reify_type base_type base_type_interp ident ty
end in
(eval cbv [base_interp_head] in res).
Ltac build_base_elim base_type_list_named :=
let base := fresh "base" in
constr:(forall (base : Set),
ltac:(let rec iter ls :=
lazymatch (eval hnf in ls) with
| InductiveHList.nil => exact base
| @InductiveHList.cons _ ?v ?rest
=> lazymatch v with
| with_name name _ => refine (forall (name : base), _)
| without_name ?T
=> let name := fresh "base_" T in
refine (forall name : base, _)
end;
iter rest
end in
iter base_type_list_named)).
Ltac print_ind_of_elim elimT :=
lazymatch elimT with
| forall ind : ?T, ?P
=> idtac "Inductive" ind ":" T ":=";
let P' := fresh in
let __ :=
constr:(
fun ind : T =>
match P return True with
| P' =>
ltac:(
let P := (eval cbv delta [P'] in P') in
let rec iter T :=
let rest := match T with
| ?A -> ?rest => rest
| _ => Datatypes.tt
end in
lazymatch rest with
| Datatypes.tt => idtac "."
| _ => lazymatch T with
| forall ctor : ?ty, _ =>
idtac "|" ctor ":" ty;
iter rest
end
end in
iter P;
exact I)
end) in
idtac
end.
Ltac build_raw_ident_elim all_ident_named_interped :=
let raw_ident := fresh "raw_ident" in
constr:(forall (raw_ident : Set),
ltac:(let rec iter ls :=
lazymatch (eval hnf in ls) with
| InductiveHList.nil => exact raw_ident
| @InductiveHList.cons _ ?v ?rest
=> let name := lazymatch v with
| with_name name _ => fresh "raw_" name
| without_name ?T => fresh "raw_ident_" T
end in
refine (forall name : raw_ident, _);
iter rest
end in
iter all_ident_named_interped)).
Ltac get_ident_type_of_named base base_interp all_base_and_interp is_pattern :=
let get_type := ident_type_of_interped_type_via_list base base_interp all_base_and_interp is_pattern in
fun lookup ident idc
=> let v := lazymatch idc with
| with_name _ ?v => v
| without_name ?v => v
end in
let is_literal := lazymatch v with
| @ident.literal => true
| _ => false
end in
let ty := type of v in
let ty := (eval cbv beta in ty) in
get_type lookup is_literal ty ident.
Ltac build_ident_elim_via base base_interp all_base_and_interp all_ident_named_interped is_pattern :=
let get_type := get_ident_type_of_named base base_interp all_base_and_interp is_pattern in
let ident := lazymatch is_pattern with
| false => fresh "ident"
| true => fresh "pattern_ident"
end in
let base_type := lazymatch is_pattern with
| false => constr:(base.type base)
| true => constr:(pattern.base.type base)
end in
let lookup := fresh in
let identType := constr:(Type) in
let base_interpType := lazymatch type of base_interp with _ -> ?TYPE => TYPE end in
let _enforce_univs := constr:(base_interpType : identType) in
let t := fresh "t" in
let res
:= constr:(forall (lookup : positive -> Type)
(ident : forall t : type.type base_type, identType),
ltac:(let base_type_interp
:= lazymatch is_pattern with
| false => constr:(base.interp base_interp)
| true => constr:(pattern.base.interp base_interp lookup)
end in
let rec iter ls :=
lazymatch (eval hnf in ls) with
| InductiveHList.nil
=> let t := fresh "t" in exact (forall t, ident t)
| @InductiveHList.cons _ ?v ?rest
=> let name
:= lazymatch is_pattern with
| false
=> lazymatch v with
| with_name name _ => fresh name
| without_name ?T => fresh "ident_" T
end
| true
=> lazymatch v with
| with_name name _ => fresh "pattern_" name
| without_name ?T => fresh "pattern_ident_" T
end
end in
let ty := get_type lookup ident v in
refine (forall name : ty, _);
iter rest
end in
iter all_ident_named_interped)) in
eliminate_functional_dependencies res.
Ltac build_ident_elim base base_type_list_named all_ident_named_interped is_pattern :=
(eval cbv beta zeta in
(ltac:(let eta_base_cps_gen := build_eta_base_cps_gen base in
let eta_base_cps := build_eta_base_cps eta_base_cps_gen in
let index_of_base := build_index_of_base base in
let base_type_list := build_base_type_list base_type_list_named in
let base_interp := build_base_interp eta_base_cps base_type_list index_of_base in
let base_interp_name := fresh "temp_base_interp" in
let base_interp := cache_term base_interp base_interp_name in
let all_base := build_all_base base in
let all_base_and_interp := build_all_base_and_interp all_base base_interp in
let ty := build_ident_elim_via base base_interp all_base_and_interp all_ident_named_interped is_pattern in
exact ty))).
Ltac build_baseHasNatAndCorrect base_interp :=
let base_interp_head := head base_interp in
constr:(ltac:(unshelve eexists; hnf; [ constructor | unshelve econstructor ]; cbv -[base_interp_head]; cbv [base_interp_head];
[ match goal with |- nat -> nat => exact (fun x => x) end
| match goal with |- nat -> nat => exact (fun x => x) end
| exact (fun P x v => v)
| exact (fun P x v => v) ])
: { hasNat : base.type.BaseTypeHasNatT _ & @base.BaseHasNatCorrectT _ base_interp hasNat }).
Ltac make_baseHasNatAndCorrect base_interp :=
let res := build_baseHasNatAndCorrect base_interp in refine res.
Ltac make_baseHasNat baseHasNatAndCorrect :=
let res := (eval cbv in (projT1 baseHasNatAndCorrect)) in refine res.
Ltac build_baseHasNat base baseHasNatAndCorrect :=
constr:(ltac:(make_baseHasNat baseHasNatAndCorrect)
: base.type.BaseTypeHasNatT base).
Ltac make_baseHasNatCorrect baseHasNatAndCorrect :=
let res := (eval cbv in (projT2 baseHasNatAndCorrect)) in refine res.
Ltac build_baseHasNatCorrect base_interp baseHasNat baseHasNatAndCorrect :=
constr:(ltac:(make_baseHasNatCorrect baseHasNatAndCorrect)
: @base.BaseHasNatCorrectT _ base_interp baseHasNat).
Ltac build_base_beq_and_reflect base :=
constr:(ltac:(unshelve eexists;
[ let x := fresh "x" in
let y := fresh "y" in
intros x y; destruct x, y
| apply reflect_of_beq;
[ let x := fresh in
let y := fresh in
intros x y; destruct x, y; try reflexivity; instantiate (1:=Datatypes.false);
intro; exfalso; apply Bool.diff_false_true; assumption
| let x := fresh in
let y := fresh in
intros x y ?; subst y; destruct x; reflexivity ] ])
: { base_beq : _ & reflect_rel (@eq base) base_beq }).
Ltac make_base_beq_and_reflect base :=
let res := build_base_beq_and_reflect base in refine res.
Ltac build_base_beq base_beq_and_reflect
:= (eval cbv in (projT1 base_beq_and_reflect)).
Ltac make_base_beq base_beq_and_reflect :=
let res := build_base_beq base_beq_and_reflect in refine res.
Ltac make_reflect_base_beq base_beq_and_reflect := refine (projT2 base_beq_and_reflect).
Ltac build_reflect_base_beq base base_beq base_beq_and_reflect :=
constr:(ltac:(make_reflect_base_beq base_beq_and_reflect)
: reflect_rel (@eq base) base_beq).
Ltac build_base_interp_beq base_interp :=
(eval cbv beta in
(ltac:(let t1 := fresh "t1" in
let t2 := fresh "t2" in
intros t1 t2; destruct t1, t2;
let h := head base_interp in
cbv [h];
first [ refine ((fun T (beq : T -> T -> Datatypes.bool) (_ : reflect_rel (@eq T) beq) => beq) _ _ _)
| exact (fun _ _ => false) ];
lazymatch goal with
| [ |- reflect_rel (@eq ?T) _ ]
=> let exp := uconstr:(reflect_rel (@eq T) ?[beq]) in
fail 0 "Could not find a typeclass instance for boolean equality of" T ":" exp
end)
: forall t1 t2, base_interp t1 -> base_interp t2 -> Datatypes.bool)).
Ltac make_base_interp_beq base_interp := let v := build_base_interp_beq base_interp in refine v.
Ltac build_reflect_base_interp_beq base_interp base_interp_beq :=
constr:(ltac:(let t := fresh "t" in
intro t; destruct t; cbv [base_interp base_interp_beq]; typeclasses eauto)
: forall t, reflect_rel (@eq (base_interp t)) (@base_interp_beq t t)).
Ltac make_reflect_base_interp_beq base_interp base_interp_beq :=
let res := build_reflect_base_interp_beq base_interp base_interp_beq in refine res.
Ltac build_try_make_base_transport_cps base_eq_dec eta_base_cps :=
constr:((fun (P : _ -> Type) (t1 t2 : _)
=> @eta_base_cps
_
(fun t1
=> @eta_base_cps
(fun t2 => ~> option (P t1 -> P t2))
(fun t2
=> match base_eq_dec t1 t2 with
| left pf => (return (Some (rew [fun t2 => P t1 -> P t2] pf in id)))
| right _ => (return None)
end)
t2)
t1)%cps
: @type.try_make_transport_cpsT _).
Ltac make_try_make_base_transport_cps base_eq_dec eta_base_cps :=
let res := build_try_make_base_transport_cps base_eq_dec eta_base_cps in
refine res.
Ltac build_try_make_base_transport_cps_correct try_make_base_transport_cps reflect_base_beq :=
constr:(ltac:(let P := fresh "P" in
let t1 := fresh "t1" in
let t2 := fresh "t2" in
intros P t1 t2; revert P t2; induction t1, t2; cbn;
Reflect.reflect_beq_to_eq_using reflect_base_beq; reflexivity)
: @type.try_make_transport_cps_correctT _ _ try_make_base_transport_cps reflect_base_beq).
Ltac make_try_make_base_transport_cps_correct try_make_base_transport_cps reflect_base_beq :=
let res := build_try_make_base_transport_cps_correct try_make_base_transport_cps reflect_base_beq in
refine res.
Ltac uneta_fun_push_eagerly term :=
let term := (eval cbv beta in term) in
lazymatch term with
| fun a => ?f a => uneta_fun_push_eagerly f
| (fun (a : ?A) => @?f a)
=> lazymatch constr:(
fun a : A
=> ltac:(let f' := uneta_fun_push_eagerly (f a) in
exact f')) with
| fun a => ?f a => uneta_fun_push_eagerly f
| ?f => f
end
| ident.eagerly (?f ?x) => uneta_fun_push_eagerly (ident.eagerly f x)
| ?f ?x => let f' := uneta_fun_push_eagerly f in
let x' := uneta_fun_push_eagerly x in
(eval cbv beta in (f' x'))
| ?f => f
end.
Ltac build_buildEagerIdentAndInterpCorrect ident_interp baseHasNat baseHasNatCorrect reify_ident :=
constr:(ltac:(let ident_interp_head := head ident_interp in
let baseHasNat' := (eval hnf in baseHasNat) in
let baseHasNatCorrect' := (eval hnf in baseHasNatCorrect) in
change baseHasNatCorrect with baseHasNatCorrect';
unshelve econstructor; [ econstructor; intros; shelve | constructor ]; intros;
lazymatch goal with
| [ |- ?ii ?id = ?v ]
=> let id' := (eval cbv in id) in
change (ii id' = v); cbv [ident_interp_head];
change baseHasNat with baseHasNat'; cbv [base.of_nat base.to_nat];
match goal with
| [ |- ?LHS = ?v ] => let v' := uneta_fun_push_eagerly v in change (LHS = v')
end;
lazymatch goal with
| [ |- _ = ?v ]
=> reify_ident v ltac:(fun idc => let unif := constr:(eq_refl : idc = id') in idtac) ltac:(fun _ => fail 0 "could not reify" v "as an ident")
end
end; reflexivity)
: { buildEagerIdent : _ & @ident.BuildInterpEagerIdentCorrectT _ _ _ ident_interp baseHasNat buildEagerIdent baseHasNatCorrect }).
Ltac make_buildEagerIdentAndInterpCorrect ident_interp baseHasNat baseHasNatCorrect reify_ident :=
let res := build_buildEagerIdentAndInterpCorrect ident_interp baseHasNat baseHasNatCorrect reify_ident in refine res.
Ltac make_buildEagerIdent buildEagerIdentAndInterpCorrect :=
let v := (eval hnf in (projT1 buildEagerIdentAndInterpCorrect)) in
exact v.
Ltac build_buildEagerIdent ident baseHasNat buildEagerIdentAndInterpCorrect :=
constr:(ltac:(make_buildEagerIdent buildEagerIdentAndInterpCorrect)
: @ident.BuildEagerIdentT _ ident baseHasNat).
Ltac make_buildInterpEagerIdentCorrect buildEagerIdentAndInterpCorrect :=
refine (projT2 buildEagerIdentAndInterpCorrect).
Ltac build_buildInterpEagerIdentCorrect ident_interp buildEagerIdent baseHasNatCorrect buildEagerIdentAndInterpCorrect :=
constr:(ltac:(make_buildInterpEagerIdentCorrect buildEagerIdentAndInterpCorrect)
: @ident.BuildInterpEagerIdentCorrectT _ _ _ ident_interp _ buildEagerIdent baseHasNatCorrect).
Ltac build_toRestrictedIdentAndCorrect baseHasNat buildEagerIdent :=
constr:(ltac:(unshelve eexists; hnf; [ | split ]; cbv;
let idc := fresh "idc" in
intros ? idc; destruct idc;
try (((instantiate (1 := Datatypes.None) + idtac); reflexivity)))
: { toRestrictedIdent : _
& @ident.ToFromRestrictedIdentT _ _ baseHasNat buildEagerIdent toRestrictedIdent }).
Ltac make_toRestrictedIdentAndCorrect baseHasNat buildEagerIdent :=
let res := build_toRestrictedIdentAndCorrect baseHasNat buildEagerIdent in refine res.
Ltac make_toRestrictedIdent toRestrictedIdentAndCorrect :=
let v := (eval hnf in (projT1 toRestrictedIdentAndCorrect)) in
exact v.
Ltac build_toRestrictedIdent ident baseHasNat toRestrictedIdentAndCorrect :=
constr:(ltac:(make_toRestrictedIdent toRestrictedIdentAndCorrect)
: @ident.ToRestrictedIdentT _ ident baseHasNat).
Ltac make_toFromRestrictedIdent toRestrictedIdentAndCorrect :=
let v := (eval hnf in (projT2 toRestrictedIdentAndCorrect)) in
exact v.
Ltac build_toFromRestrictedIdent baseHasNat buildEagerIdent toRestrictedIdent toRestrictedIdentAndCorrect :=
constr:(ltac:(make_toFromRestrictedIdent toRestrictedIdentAndCorrect)
: @ident.ToFromRestrictedIdentT _ _ baseHasNat buildEagerIdent toRestrictedIdent).
Ltac build_buildIdentAndInterpCorrect ident_interp reify_ident :=
constr:(ltac:(let ident_interp_head := head ident_interp in
unshelve econstructor;
[ econstructor;
lazymatch goal with
| [ |- ?ident (type.base base.type.unit) ] => solve [ constructor ]
| _ => intros; shelve
end
| constructor ];
intros;
lazymatch goal with
| [ |- ?ii ?id = ?v ]
=> let id' := (eval cbv in id) in
change (ii id' = v); cbv [ident_interp_head];
fold (@base.interp);
let v := match goal with |- _ = ?v => v end in
reify_ident
v
ltac:(fun idc => let unif := constr:(eq_refl : idc = id') in idtac)
ltac:(fun _ => fail 0 "could not reify" v "as an ident")
end; reflexivity)
: { buildIdent : _
& @ident.BuildInterpIdentCorrectT _ _ _ buildIdent ident_interp }).
Ltac make_buildIdentAndInterpCorrect ident_interp reify_ident :=
let res := build_buildIdentAndInterpCorrect ident_interp reify_ident in refine res.
Ltac make_buildIdent buildIdentAndInterpCorrect :=
let v := (eval hnf in (projT1 buildIdentAndInterpCorrect)) in
exact v.
Ltac build_buildIdent base_interp ident buildIdentAndInterpCorrect :=
constr:(ltac:(make_buildIdent buildIdentAndInterpCorrect)
: @ident.BuildIdentT _ base_interp ident).
Ltac make_buildInterpIdentCorrect buildIdentAndInterpCorrect :=
refine (projT2 buildIdentAndInterpCorrect).
Ltac build_buildInterpIdentCorrect ident_interp buildIdent buildIdentAndInterpCorrect :=
constr:(ltac:(make_buildInterpIdentCorrect buildIdentAndInterpCorrect)
: @ident.BuildInterpIdentCorrectT _ _ _ buildIdent ident_interp).
Ltac build_ident_is_var_like ident ident_interp var_like_idents :=
(eval cbv beta zeta in
(ltac:(let t := fresh "t" in
let idc := fresh "idc" in
let idc' := fresh "idc'" in
let ident_interp_head := head (@ident_interp) in
intros t idc; pose (@ident_interp _ idc) as idc';
destruct idc; cbn [ident_interp_head] in idc';
let idcv := (eval cbv [idc'] in idc') in
let idc_head := head idcv in
lazymatch (eval hnf in var_like_idents) with
| context[InductiveHList.cons idc_head]
=> refine Datatypes.true
| _ => refine Datatypes.false
end)
: forall {t} (idc : ident t), Datatypes.bool)).
Ltac make_ident_is_var_like ident ident_interp var_like_idents :=