-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathjkind.ml
1533 lines (1287 loc) · 51.5 KB
/
jkind.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
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Chris Casinghino, Jane Street, New York *)
(* *)
(* Copyright 2021 Jane Street Group LLC *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* CR layouts v2.8: remove this *)
module Legacy = struct
type const =
| Any
| Value
| Void
| Immediate64
| Immediate
| Float64
let const_of_attribute : Builtin_attributes.jkind_attribute -> _ = function
| Immediate -> Immediate
| Immediate64 -> Immediate64
(** The function name is suffixed with "unchecked" to suggest that
it doesn't check whether the layouts extension is enabled.
It should be inverse to [string_of_const].
*)
let const_of_user_written_annotation_unchecked annot =
match Jane_asttypes.jkind_to_string annot with
| "any" -> Some Any
| "value" -> Some Value
| "void" -> Some Void
| "immediate64" -> Some Immediate64
| "immediate" -> Some Immediate
| "float64" -> Some Float64
| _ -> None
let string_of_const const =
match const with
| Any -> "any"
| Value -> "value"
| Void -> "void"
| Immediate64 -> "immediate64"
| Immediate -> "immediate"
| Float64 -> "float64"
let equal_const c1 c2 =
match c1, c2 with
| Any, Any -> true
| Value, Value -> true
| Void, Void -> true
| Immediate64, Immediate64 -> true
| Immediate, Immediate -> true
| Float64, Float64 -> true
| (Any | Value | Void | Immediate64 | Immediate | Float64), _ -> false
end
module Sub_result = struct
type t =
| Equal
| Sub
| Not_sub
let combine sr1 sr2 =
match sr1, sr2 with
| Equal, Equal -> Equal
| Equal, Sub | Sub, Equal | Sub, Sub -> Sub
| Not_sub, _ | _, Not_sub -> Not_sub
end
(* A *sort* is the information the middle/back ends need to be able to
compile a manipulation (storing, passing, etc) of a runtime value. *)
module Sort = struct
(* CR layouts v2.8: Refactor to use a Const module *)
type const =
| Void
| Value
| Float64
type t =
| Var of var
| Const of const
and var = t option ref
(* To record changes to sorts, for use with `Types.{snapshot, backtrack}` *)
type change = var * t option
let change_log : (change -> unit) ref = ref (fun _ -> ())
let log_change change = !change_log change
let undo_change (v, t_op) = v := t_op
let var_name : var -> string =
let next_id = ref 1 in
let named = ref [] in
fun v ->
match List.assq_opt v !named with
| Some name -> name
| None ->
let id = !next_id in
let name = "'_representable_layout_" ^ Int.to_string id in
next_id := id + 1;
named := (v, name) :: !named;
name
let set : var -> t option -> unit =
fun v t_op ->
log_change (v, !v);
v := t_op
let void = Const Void
let value = Const Value
let float64 = Const Float64
let some_value = Some value
let of_const = function Void -> void | Value -> value | Float64 -> float64
let of_var v = Var v
let new_var () = Var (ref None)
(* Post-condition: If the result is a [Var v], then [!v] is [None]. *)
let rec get : t -> t = function
| Const _ as t -> t
| Var r as t -> (
match !r with
| None -> t
| Some s ->
let result = get s in
if result != s then set r (Some result);
(* path compression *)
result)
let memoized_value : t option = Some (Const Value)
let memoized_void : t option = Some (Const Void)
let memoized_float64 : t option = Some (Const Float64)
let[@inline] get_memoized = function
| Value -> memoized_value
| Void -> memoized_void
| Float64 -> memoized_float64
let rec get_default_value : t -> const = function
| Const c -> c
| Var r -> (
match !r with
| None ->
set r memoized_value;
Value
| Some s ->
let result = get_default_value s in
set r (get_memoized result);
(* path compression *)
result)
let default_to_value t = ignore (get_default_value t)
(***********************)
(* equality *)
type equate_result =
| Unequal
| Equal_mutated_first
| Equal_mutated_second
| Equal_no_mutation
let swap_equate_result = function
| Equal_mutated_first -> Equal_mutated_second
| Equal_mutated_second -> Equal_mutated_first
| (Unequal | Equal_no_mutation) as r -> r
let equal_const_const c1 c2 =
match c1, c2 with
| Void, Void | Value, Value | Float64, Float64 -> Equal_no_mutation
| (Void | Value | Float64), _ -> Unequal
let rec equate_var_const v1 c2 =
match !v1 with
| Some s1 -> equate_sort_const s1 c2
| None ->
set v1 (Some (of_const c2));
Equal_mutated_first
and equate_var v1 s2 =
match s2 with
| Const c2 -> equate_var_const v1 c2
| Var v2 -> equate_var_var v1 v2
and equate_var_var v1 v2 =
if v1 == v2
then Equal_no_mutation
else
match !v1, !v2 with
| Some s1, _ -> swap_equate_result (equate_var v2 s1)
| _, Some s2 -> equate_var v1 s2
| None, None ->
set v1 (Some (of_var v2));
Equal_mutated_first
and equate_sort_const s1 c2 =
match s1 with
| Const c1 -> equal_const_const c1 c2
| Var v1 -> equate_var_const v1 c2
let equate_tracking_mutation s1 s2 =
match s1 with
| Const c1 -> swap_equate_result (equate_sort_const s2 c1)
| Var v1 -> equate_var v1 s2
(* Don't expose whether or not mutation happened; we just need that for [Jkind] *)
let equate s1 s2 =
match equate_tracking_mutation s1 s2 with
| Unequal -> false
| Equal_mutated_first | Equal_mutated_second | Equal_no_mutation -> true
let equal_const c1 c2 =
match c1, c2 with
| Void, Void | Value, Value | Float64, Float64 -> true
| Void, (Value | Float64) | Value, (Void | Float64) | Float64, (Value | Void)
->
false
let rec is_void_defaulting = function
| Const Void -> true
| Var v -> (
match !v with
(* CR layouts v5: this should probably default to void now *)
| None ->
set v some_value;
false
| Some s -> is_void_defaulting s)
| Const Value -> false
| Const Float64 -> false
(*** pretty printing ***)
let string_of_const = function
| Value -> "value"
| Void -> "void"
| Float64 -> "float64"
let to_string s =
match get s with Var v -> var_name v | Const c -> string_of_const c
let format ppf t = Format.fprintf ppf "%s" (to_string t)
(*** debug printing **)
module Debug_printers = struct
open Format
let rec t ppf = function
| Var v -> fprintf ppf "Var %a" var v
| Const c ->
fprintf ppf
(match c with
| Void -> "Void"
| Value -> "Value"
| Float64 -> "Float64")
and opt_t ppf = function
| Some s -> fprintf ppf "Some %a" t s
| None -> fprintf ppf "None"
and var ppf v = fprintf ppf "{ contents = %a }" opt_t !v
end
let for_function = value
let for_predef_value = value
let for_block_element = value
let for_probe_body = value
let for_poly_variant = value
let for_record = value
let for_constructor_arg = value
let for_object = value
let for_lazy_body = value
let for_tuple_element = value
let for_instance_var = value
let for_class_arg = value
let for_method = value
let for_initializer = value
let for_module = value
let for_tuple = value
let for_array_get_result = value
let for_array_element = value
let for_list_element = value
end
type sort = Sort.t
(* A *layout* of a type describes the way values of that type are stored at
runtime, including details like width, register convention, calling
convention, etc. A layout may be *representable* or *unrepresentable*. The
middle/back ends are unable to cope with values of types with an
unrepresentable layout. The only unrepresentable layout is `any`, which is
the top of the layout lattice. *)
module Layout = struct
module Const = struct
type t =
| Sort of Sort.const
| Any
let equal c1 c2 =
match c1, c2 with
| Sort s1, Sort s2 -> Sort.equal_const s1 s2
| Any, Any -> true
| (Any | Sort _), _ -> false
let sub c1 c2 : Sub_result.t =
match c1, c2 with
| _ when equal c1 c2 -> Equal
| _, Any -> Sub
| Any, Sort _ | Sort _, Sort _ -> Not_sub
end
type t =
| Sort of Sort.t
| Any
let max = Any
let equate_or_equal ~allow_mutation t1 t2 =
match t1, t2 with
| Sort s1, Sort s2 -> (
match Sort.equate_tracking_mutation s1 s2 with
| (Equal_mutated_first | Equal_mutated_second) when not allow_mutation ->
Misc.fatal_errorf "Jkind.equal: Performed unexpected mutation"
| Unequal -> false
| Equal_no_mutation | Equal_mutated_first | Equal_mutated_second -> true)
| Any, Any -> true
| (Any | Sort _), _ -> false
let sub t1 t2 : Sub_result.t =
match t1, t2 with
| Any, Any -> Equal
| _, Any -> Sub
| Any, _ -> Not_sub
| Sort s1, Sort s2 -> if Sort.equate s1 s2 then Equal else Not_sub
let intersection t1 t2 =
match t1, t2 with
| _, Any -> Some t1
| Any, _ -> Some t2
| Sort s1, Sort s2 -> if Sort.equate s1 s2 then Some t1 else None
let of_new_sort_var () =
let sort = Sort.new_var () in
Sort sort, sort
let value = Sort Sort.value
let void = Sort Sort.void
let float64 = Sort Sort.float64
module Debug_printers = struct
open Format
let t ppf = function
| Any -> fprintf ppf "Any"
| Sort s -> fprintf ppf "Sort %a" Sort.Debug_printers.t s
end
end
(* Whether or not a type is external to the garbage collector *)
(* CR layouts: Since this is a mode, the definition here should probably
move over to mode.ml *)
module Externality = struct
type t =
| External (* not managed by the garbage collector *)
| External64 (* not managed by the garbage collector on 64-bit systems *)
| Internal (* managed by the garbage collector *)
(* CR layouts v2.8: Either use this or remove it *)
let _to_string = function
| External -> "external"
| External64 -> "external64"
| Internal -> "internal"
let max = Internal
let min = External
let equal e1 e2 =
match e1, e2 with
| External, External -> true
| External64, External64 -> true
| Internal, Internal -> true
| (External | External64 | Internal), _ -> false
let sub t1 t2 : Sub_result.t =
match t1, t2 with
| External, External -> Equal
| External, (External64 | Internal) -> Sub
| External64, External -> Not_sub
| External64, External64 -> Equal
| External64, Internal -> Sub
| Internal, (External | External64) -> Not_sub
| Internal, Internal -> Equal
let intersection t1 t2 =
match t1, t2 with
| External, (External | External64 | Internal)
| (External64 | Internal), External ->
External
| External64, (External64 | Internal) | Internal, External64 -> External64
| Internal, Internal -> Internal
module Debug_printers = struct
open Format
let t ppf = function
| External -> fprintf ppf "External"
| External64 -> fprintf ppf "External64"
| Internal -> fprintf ppf "Internal"
end
end
module Const = struct
type t =
{ layout : Layout.Const.t;
externality : Externality.t
}
(* CR layouts v2.8: remove this *)
let to_legacy_jkind { layout; externality } : Legacy.const =
match layout, externality with
| Any, _ -> Any
| Sort Value, Internal -> Value
| Sort Value, External64 -> Immediate64
| Sort Value, External -> Immediate
| Sort Void, _ -> Void
| Sort Float64, _ -> Float64
(* CR layouts v2.8: do a better job here *)
let to_string t = Legacy.string_of_const (to_legacy_jkind t)
let sub { layout = lay1; externality = ext1 }
{ layout = lay2; externality = ext2 } =
Sub_result.combine (Layout.Const.sub lay1 lay2) (Externality.sub ext1 ext2)
end
module Desc = struct
type t =
| Const of Const.t
| Var of Sort.var (* all modes will be [max] *)
let format ppf =
let open Format in
function
| Const c -> fprintf ppf "%s" (Const.to_string c)
| Var v -> fprintf ppf "%s" (Sort.var_name v)
(* considers sort variables < Any. Two sort variables are in a [sub]
relationship only when they are equal.
Never does mutation.
Pre-condition: no filled-in sort variables. *)
let sub d1 d2 : Sub_result.t =
match d1, d2 with
| Const c1, Const c2 -> Const.sub c1 c2
| Var _, Const { layout = Any; externality = Internal } -> Sub
| Var v1, Var v2 -> if v1 == v2 then Equal else Not_sub
| Const _, Var _ | Var _, Const _ -> Not_sub
end
module Jkind_desc = struct
type t =
{ layout : Layout.t;
externality : Externality.t
}
let max = { layout = Layout.max; externality = Externality.max }
let equate_or_equal ~allow_mutation { layout = lay1; externality = ext1 }
{ layout = lay2; externality = ext2 } =
Layout.equate_or_equal ~allow_mutation lay1 lay2
&& Externality.equal ext1 ext2
let sub { layout = layout1; externality = externality1 }
{ layout = layout2; externality = externality2 } =
Sub_result.combine
(Layout.sub layout1 layout2)
(Externality.sub externality1 externality2)
let intersection { layout = lay1; externality = ext1 }
{ layout = lay2; externality = ext2 } =
Option.bind (Layout.intersection lay1 lay2) (fun layout ->
Some { layout; externality = Externality.intersection ext1 ext2 })
let of_new_sort_var () =
let layout, sort = Layout.of_new_sort_var () in
{ layout; externality = Externality.max }, sort
let any = max
let value = { layout = Layout.value; externality = Externality.max }
let void = { layout = Layout.void; externality = Externality.min }
let immediate64 = { layout = Layout.value; externality = External64 }
let immediate = { layout = Layout.value; externality = External }
let float64 = { layout = Layout.float64; externality = External }
(* Post-condition: If the result is [Var v], then [!v] is [None]. *)
let get { layout; externality } : Desc.t =
match layout with
| Any -> Const { layout = Any; externality }
| Sort s -> (
match Sort.get s with
(* This match isn't as silly as it looks: those are
different constructors on the left than on the right *)
| Const s -> Const { layout = Sort s; externality }
| Var v -> Var v)
module Debug_printers = struct
open Format
let t ppf { layout; externality } =
fprintf ppf "{ layout = %a;@ externality = %a }" Layout.Debug_printers.t
layout Externality.Debug_printers.t externality
end
end
(*** reasons for jkinds **)
type concrete_jkind_reason =
| Match
| Constructor_declaration of int
| Label_declaration of Ident.t
| Unannotated_type_parameter
| Record_projection
| Record_assignment
| Let_binding
| Function_argument
| Function_result
| Structure_item_expression
| V1_safety_check
| External_argument
| External_result
| Statement
| Wildcard
| Unification_var
type value_creation_reason =
| Class_let_binding
| Tuple_element
| Probe
| Package_hack
| Object
| Instance_variable
| Object_field
| Class_field
| Boxed_record
| Boxed_variant
| Extensible_variant
| Primitive of Ident.t
| Type_argument
| Tuple
| Row_variable
| Polymorphic_variant
| Arrow
| Tfield
| Tnil
| First_class_module
| Separability_check
| Univar
| Polymorphic_variant_field
| Default_type_jkind
| Float_record_field
| Existential_type_variable
| Array_element
| Lazy_expression
| Class_argument
| Structure_element
| Debug_printer_argument
| V1_safety_check
| Captured_in_object
| Unknown of string
type immediate_creation_reason =
| Empty_record
| Enumeration
| Primitive of Ident.t
| Immediate_polymorphic_variant
| Gc_ignorable_check
| Value_kind
type immediate64_creation_reason =
| Local_mode_cross_check
| Gc_ignorable_check
| Separability_check
type void_creation_reason = V1_safety_check
type any_creation_reason =
| Missing_cmi of Path.t
| Initial_typedecl_env
| Dummy_jkind
| Type_expression_call
| Inside_of_Tarrow
| Wildcard
| Unification_var
type float64_creation_reason = Primitive of Ident.t
type annotation_context =
| Type_declaration of Path.t
| Type_parameter of Path.t * string option
| With_constraint of string
| Newtype_declaration of string
| Constructor_type_parameter of Path.t * string
| Univar of string
| Type_variable of string
| Type_wildcard of Location.t
type creation_reason =
| Annotated of annotation_context * Location.t
| Value_creation of value_creation_reason
| Immediate_creation of immediate_creation_reason
| Immediate64_creation of immediate64_creation_reason
| Void_creation of void_creation_reason
| Any_creation of any_creation_reason
| Float64_creation of float64_creation_reason
| Concrete_creation of concrete_jkind_reason
| Imported
type interact_reason =
| Gadt_equation of Path.t
| Tyvar_refinement_intersection
(* CR layouts: this needs to carry a type_expr, but that's loopy *)
| Subjkind
(* A history of conditions placed on a jkind.
INVARIANT: at most one sort variable appears in this history.
This is a natural consequence of producing this history by comparing
jkinds.
*)
type history =
| Interact of
{ reason : interact_reason;
lhs_jkind : Jkind_desc.t;
lhs_history : history;
rhs_jkind : Jkind_desc.t;
rhs_history : history
}
| Creation of creation_reason
type t =
{ jkind : Jkind_desc.t;
history : history
}
let fresh_jkind jkind ~why = { jkind; history = Creation why }
(******************************)
(* constants *)
let any_dummy_jkind =
{ jkind = Jkind_desc.max; history = Creation (Any_creation Dummy_jkind) }
let value_v1_safety_check =
{ jkind = Jkind_desc.value;
history = Creation (Value_creation V1_safety_check)
}
(* CR layouts: Should we be doing more memoization here? *)
let any ~why =
match why with
| Dummy_jkind -> any_dummy_jkind (* share this one common case *)
| _ -> fresh_jkind Jkind_desc.any ~why:(Any_creation why)
let void ~why = fresh_jkind Jkind_desc.void ~why:(Void_creation why)
let value ~(why : value_creation_reason) =
match why with
| V1_safety_check -> value_v1_safety_check
| _ -> fresh_jkind Jkind_desc.value ~why:(Value_creation why)
let immediate64 ~why =
fresh_jkind Jkind_desc.immediate64 ~why:(Immediate64_creation why)
let immediate ~why =
fresh_jkind Jkind_desc.immediate ~why:(Immediate_creation why)
let float64 ~why = fresh_jkind Jkind_desc.float64 ~why:(Float64_creation why)
(******************************)
(*** user errors ***)
type error =
| Insufficient_level of
{ jkind : Legacy.const;
required_layouts_level : Language_extension.maturity
}
| Unknown_jkind of Jane_asttypes.const_jkind
| Multiple_jkinds of
{ from_annotation : Legacy.const;
from_attribute : Legacy.const
}
exception User_error of Location.t * error
let raise ~loc err = raise (User_error (loc, err))
(*** extension requirements ***)
(* The [annotation_context] parameter can be used to allow annotations / kinds
in different contexts to be enabled with different extension settings.
At some points in time, we will not care about the context, and so this
parameter might effectively be unused.
*)
(* CR layouts: When everything is stable, remove this function. *)
let get_required_layouts_level (context : annotation_context)
(jkind : Legacy.const) : Language_extension.maturity =
match context, jkind with
| _, (Value | Immediate | Immediate64 | Any | Float64) -> Stable
| _, Void -> Alpha
(******************************)
(* construction *)
let of_new_sort_var ~why =
let jkind, sort = Jkind_desc.of_new_sort_var () in
fresh_jkind jkind ~why:(Concrete_creation why), sort
let of_new_sort ~why = fst (of_new_sort_var ~why)
(* CR layouts v2.8: remove this function *)
let of_const ~why : Legacy.const -> t = function
| Any -> fresh_jkind Jkind_desc.any ~why
| Immediate -> fresh_jkind Jkind_desc.immediate ~why
| Immediate64 -> fresh_jkind Jkind_desc.immediate64 ~why
| Value -> fresh_jkind Jkind_desc.value ~why
| Void -> fresh_jkind Jkind_desc.void ~why
| Float64 -> fresh_jkind Jkind_desc.float64 ~why
let const_of_user_written_annotation ~context Location.{ loc; txt = annot } =
match Legacy.const_of_user_written_annotation_unchecked annot with
| None -> raise ~loc (Unknown_jkind annot)
| Some const ->
let required_layouts_level = get_required_layouts_level context const in
if not (Language_extension.is_at_least Layouts required_layouts_level)
then
raise ~loc (Insufficient_level { jkind = const; required_layouts_level });
const
let of_annotated_const ~context ~const ~const_loc =
of_const ~why:(Annotated (context, const_loc)) const
let of_annotation ~context (annot : _ Location.loc) =
let const = const_of_user_written_annotation ~context annot in
let jkind = of_annotated_const ~const ~const_loc:annot.loc ~context in
jkind, (const, annot)
let of_annotation_option_default ~default ~context =
Option.fold ~none:(default, None) ~some:(fun annot ->
let t, annot = of_annotation ~context annot in
t, Some annot)
let of_attribute ~context
(attribute : Builtin_attributes.jkind_attribute Location.loc) =
let const = Legacy.const_of_attribute attribute.txt in
of_annotated_const ~context ~const ~const_loc:attribute.loc, const
let of_type_decl ~context (decl : Parsetree.type_declaration) =
let jkind_of_annotation =
Jane_syntax.Layouts.of_type_declaration decl
|> Option.map (fun (annot, attrs) ->
let t, const = of_annotation ~context annot in
t, const, attrs)
in
let jkind_of_attribute =
Builtin_attributes.jkind decl.ptype_attributes
|> Option.map (fun attr ->
let t, const = of_attribute ~context attr in
(* This is a bit of a lie: the "annotation" here is being
forged based on the jkind attribute. But: the jkind
annotation is just used in printing/untypeast, and the
all strings valid to use as a jkind attribute are
valid (and equivalent) to write as an annotation, so
this lie is harmless.
*)
let annot =
Location.map
(fun attr ->
Builtin_attributes.jkind_attribute_to_string attr
|> Jane_asttypes.jkind_of_string)
attr
in
t, (const, annot), decl.ptype_attributes)
in
match jkind_of_annotation, jkind_of_attribute with
| None, None -> None
| (Some _ as x), None | None, (Some _ as x) -> x
| Some (_, (from_annotation, _), _), Some (_, (from_attribute, _), _) ->
raise ~loc:decl.ptype_loc
(Multiple_jkinds { from_annotation; from_attribute })
let of_type_decl_default ~context ~default (decl : Parsetree.type_declaration) =
match of_type_decl ~context decl with
| Some (t, const, attrs) -> t, Some const, attrs
| None -> default, None, decl.ptype_attributes
let for_boxed_record ~all_void =
if all_void then immediate ~why:Empty_record else value ~why:Boxed_record
let for_boxed_variant ~all_voids =
if all_voids then immediate ~why:Enumeration else value ~why:Boxed_variant
(******************************)
(* elimination and defaulting *)
let get_default_value { jkind = { layout; externality }; _ } : Const.t =
match layout with
| Any -> { layout = Any; externality }
| Sort s -> { layout = Sort (Sort.get_default_value s); externality }
let default_to_value t = ignore (get_default_value t)
let get t = Jkind_desc.get t.jkind
(* CR layouts: this function is suspect; it seems likely to reisenberg
that refactoring could get rid of it *)
let sort_of_jkind l =
match get l with
| Const { layout = Sort s; _ } -> Sort.of_const s
| Const { layout = Any; _ } -> Misc.fatal_error "Jkind.sort_of_jkind"
| Var v -> Sort.of_var v
(*********************************)
(* pretty printing *)
let to_string jkind =
match get jkind with Const c -> Const.to_string c | Var v -> Sort.var_name v
let format ppf t = Format.fprintf ppf "%s" (to_string t)
(***********************************)
(* jkind histories *)
let printtyp_path = ref (fun _ _ -> assert false)
let set_printtyp_path f = printtyp_path := f
module Report_missing_cmi : sig
(* used both in format_history and in Violation.report_general *)
val report_missing_cmi : Format.formatter -> Path.t option -> unit
end = struct
open Format
(* CR layouts: Remove this horrible (but useful) heuristic once we have
transitive dependencies in jenga. *)
let missing_cmi_hint ppf type_path =
let root_module_name p = p |> Path.head |> Ident.name in
let delete_trailing_double_underscore s =
if Misc.Stdlib.String.ends_with ~suffix:"__" s
then String.sub s 0 (String.length s - 2)
else s
in
(* A heuristic for guessing at a plausible library name for an identifier
with a missing .cmi file; definitely less likely to be right outside of
Jane Street. *)
let guess_library_name : Path.t -> string option = function
| Pdot _ as p ->
Some
(match root_module_name p with
| "Location" | "Longident" -> "ocamlcommon"
| mn ->
mn |> String.lowercase_ascii |> delete_trailing_double_underscore)
| Pident _ | Papply _ | Pextra_ty _ -> None
in
Option.iter
(fprintf ppf "@,Hint: Adding \"%s\" to your dependencies might help.")
(guess_library_name type_path)
let report_missing_cmi ppf = function
| Some p ->
fprintf ppf "@,No .cmi file found containing %a." !printtyp_path p;
missing_cmi_hint ppf p
| None -> ()
end
include Report_missing_cmi
(* CR layouts: should this be configurable? In the meantime, you
may want to change these to experiment / debug. *)
(* should we print histories at all? *)
let display_histories = false
(* should we print histories in a way users can understand?
The alternative is to print out all the data, which may be useful
during debugging. *)
let flattened_histories = true
(* This module is just to keep all the helper functions more locally
scoped. *)
module Format_history : sig
val format_history :
intro:(Format.formatter -> unit) -> Format.formatter -> t -> unit
end = struct
(* CR layouts: all the output in this section is subject to change;
actually look closely at error messages once this is activated *)
open Format
let format_concrete_jkind_reason ppf : concrete_jkind_reason -> unit =
function
| Match -> fprintf ppf "matched on"
| Constructor_declaration idx ->
fprintf ppf "used as constructor field %d" idx
| Label_declaration lbl ->
fprintf ppf "used in the declaration of the record field \"%a\""
Ident.print lbl
| Unannotated_type_parameter ->
fprintf ppf "appears as an unannotated type parameter"
| Record_projection -> fprintf ppf "used as the record in a projection"
| Record_assignment -> fprintf ppf "used as the record in an assignment"
| Let_binding -> fprintf ppf "bound by a `let`"
| Function_argument -> fprintf ppf "used as a function argument"
| Function_result -> fprintf ppf "used as a function result"
| Structure_item_expression ->
fprintf ppf "used in an expression in a structure"
| V1_safety_check -> fprintf ppf "part of the v1 safety check"
| External_argument ->
fprintf ppf "used as an argument in an external declaration"
| External_result ->
fprintf ppf "used as the result of an external declaration"
| Statement -> fprintf ppf "used as a statement"
| Wildcard -> fprintf ppf "a _ in a type"
| Unification_var -> fprintf ppf "a fresh unification variable"
let format_annotation_context ppf : annotation_context -> unit = function
| Type_declaration p ->
fprintf ppf "the declaration of the type %a" !printtyp_path p
| Type_parameter (path, var) ->
let var_string = match var with None -> "_" | Some v -> "'" ^ v in
fprintf ppf "@[%s@ in the declaration of the type@ %a@]" var_string
!printtyp_path path
| With_constraint s -> fprintf ppf "the `with` constraint for %s" s
| Newtype_declaration name ->
fprintf ppf "the abstract type declaration for %s" name
| Constructor_type_parameter (cstr, name) ->
fprintf ppf "@[%s@ in the declaration of constructor@ %a@]" name
!printtyp_path cstr
| Univar name -> fprintf ppf "the universal variable %s" name
| Type_variable name -> fprintf ppf "the type variable %s" name
| Type_wildcard loc ->
fprintf ppf "the wildcard _ at %a" Location.print_loc loc
let format_any_creation_reason ppf : any_creation_reason -> unit = function
| Missing_cmi p -> fprintf ppf "a missing .cmi file for %a" !printtyp_path p
| Initial_typedecl_env ->
fprintf ppf "a dummy layout used in checking mutually recursive datatypes"
| Dummy_jkind ->
fprintf ppf
"@[a dummy layout that should have been overwritten;@ Please notify \
the Jane Street compilers group if you see this output."
(* CR layouts: Improve output or remove this constructor ^^ *)
| Type_expression_call ->
fprintf ppf "a call to [type_expression] via the ocaml API"
| Inside_of_Tarrow -> fprintf ppf "argument or result of a Tarrow"
| Wildcard -> fprintf ppf "a _ in a type"
| Unification_var -> fprintf ppf "a fresh unification variable"
let format_immediate_creation_reason ppf : immediate_creation_reason -> _ =
function
| Empty_record -> fprintf ppf "a record containing all void elements"
| Enumeration ->
fprintf ppf "an enumeration variant (all constructors are constant)"