Source file includecore.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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
open Asttypes
open Path
open Types
open Mode
open Typedtree
type position = Errortrace.position = First | Second
type primitive_mismatch =
| Name
| Arity
| No_alloc of position
| Builtin
| Effects
| Coeffects
| Native_name
| Result_repr
| Argument_repr of int
| Layout_poly_attr
type layout_poly_coercion =
| Instantiate_lhs_to_rhs of { index_lhs: int; index_rhs: int }
| Instantiate_lhs of { index_lhs: int; arg: Jkind_types.Sort.t option }
type value_mismatch =
| Primitive_mismatch of primitive_mismatch
| Not_a_primitive
| Type of Errortrace.moregen_error
| Zero_alloc of Zero_alloc.error
| Modality of Mode.Modality.error
| Mode of Mode.Value.error
| Layout_poly_coercion of layout_poly_coercion
exception Dont_match of value_mismatch
type mmodes =
| All
| Specific :
((Mode.allowed * 'r) Mode.Value.t * Typedtree.held_locks option) *
('l * Mode.allowed) Mode.Value.t ->
mmodes
let child_close_over_coercion_opt id c =
match c with
| None -> None
| Some (locks, lid, loc) -> Some (locks, Longident.Ldot (lid, id), loc)
let child_modes id = function
| All -> All
| Specific ((m0, c), m1) ->
let c = child_close_over_coercion_opt id c in
Specific ((m0, c), m1)
let child_modes_with_modalities id ~modalities:(moda0, moda1) = function
| All ->
begin match Mode.Modality.sub moda0 moda1 with
| Ok () -> Ok All
| Error e -> Error e
end
| Specific ((m0, c), m1)->
let c = child_close_over_coercion_opt id c in
begin match Mode.Modality.to_const_opt moda1 with
| None ->
assert (moda0 == moda1);
Mode.Value.submode_exn m0 m1;
Ok All
| Some moda1 ->
let m0 = Mode.Modality.apply moda0 m0 in
let m1 = Mode.Modality.Const.apply moda1 m1 in
Ok (Specific ((m0, c), m1))
end
let check_modes env ?(crossing = Crossing.max) ~item ?typ = function
| All -> Ok ()
| Specific ((m0, c), m1) ->
let m0 =
match c with
| None -> m0 |> Mode.Value.disallow_right
| Some (locks, lid, loc) ->
let m0 = Crossing.apply_left crossing m0 in
Env.walk_locks ~env ~loc lid ~item typ (m0, locks)
in
let m1 = Crossing.apply_right crossing m1 in
Mode.Value.submode m0 m1
let native_repr_args nra1 nra2 =
let rec loop i nra1 nra2 =
match nra1, nra2 with
| [], [] -> None
| [], _ :: _ -> assert false
| _ :: _, [] -> assert false
| (_, nr1) :: nra1, (_, nr2) :: nra2 ->
if not (Primitive.equal_native_repr nr1 nr2) then Some (Argument_repr i)
else loop (i+1) nra1 nra2
in
loop 1 nra1 nra2
let primitive_descriptions pd1 pd2 =
let open Primitive in
if not (String.equal pd1.prim_name pd2.prim_name) then
Some Name
else if not (Int.equal pd1.prim_arity pd2.prim_arity) then
Some Arity
else if (not pd1.prim_alloc) && pd2.prim_alloc then
Some (No_alloc First)
else if pd1.prim_alloc && (not pd2.prim_alloc) then
Some (No_alloc Second)
else if not
(Bool.equal pd1.prim_is_layout_poly
pd2.prim_is_layout_poly) then
Some Layout_poly_attr
else if not (Bool.equal pd1.prim_c_builtin pd2.prim_c_builtin) then
Some Builtin
else if not (Primitive.equal_effects pd1.prim_effects pd2.prim_effects) then
Some Effects
else if not
(Primitive.equal_coeffects
pd1.prim_coeffects pd2.prim_coeffects) then
Some Coeffects
else if not (String.equal pd1.prim_native_name pd2.prim_native_name) then
Some Native_name
else if not
(match pd1.prim_native_repr_res, pd2.prim_native_repr_res with
| (_, nr1), (_, nr2) -> Primitive.equal_native_repr nr1 nr2) then
Some Result_repr
else
native_repr_args pd1.prim_native_repr_args pd2.prim_native_repr_args
let moregeneral_lpoly env pat_lpoly subj_lpoly ty1 ty2 =
let pat_refs =
Ctype.moregeneral env true pat_lpoly subj_lpoly ty1 ty2
in
let subj_index = List.mapi (fun i v -> (v, i + 1)) subj_lpoly in
let subj_rest =
List.fold_left
(fun (i, subj_rest) r ->
let i = i + 1 in
let v, subj_rest = match subj_rest with
| v :: rest -> v, rest
| [] ->
let = List.length pat_refs - i + 1 in
raise (Dont_match (Layout_poly_coercion (Extra_lhs { extra })))
in
(match r with
| Some (Jkind_types.Sort.Var v') when v' == v -> ()
| Some (Jkind_types.Sort.Var v') ->
let j = List.assq v' subj_index in
raise (Dont_match (Layout_poly_coercion
(Instantiate_lhs_to_rhs { index_lhs = i; index_rhs = j })))
| _ ->
raise (Dont_match (Layout_poly_coercion
(Instantiate_lhs { index_lhs = i; arg = r }))));
(i, subj_rest))
(0, subj_lpoly)
pat_refs
|> snd
in
match subj_rest with
| [] -> ()
| _ ->
raise (Dont_match (Layout_poly_coercion
(Extra_rhs { extra = List.length subj_rest })))
let value_descriptions ~loc env name
~mmodes
(vd1 : Types.value_description)
(vd2 : Types.value_description) =
Builtin_attributes.check_alerts_inclusion
~def:vd1.val_loc
~use:vd2.val_loc
loc
vd1.val_attributes vd2.val_attributes
name;
begin match Zero_alloc.sub vd1.val_zero_alloc vd2.val_zero_alloc with
| Ok () -> ()
| Error e -> raise (Dont_match (Zero_alloc e))
end;
let crossing = Ctype.crossing_of_ty env vd2.val_type in
let modalities = vd1.val_modalities, vd2.val_modalities in
let modes =
match child_modes_with_modalities name ~modalities mmodes with
| Ok modes -> modes
| Error e -> raise (Dont_match (Modality e))
in
begin match check_modes env ~crossing ~item:Value ~typ:vd1.val_type modes with
| Ok () -> ()
| Error e -> raise (Dont_match (Mode e))
end;
let val_lpoly1 = Lpoly.get_exn vd1.val_lpoly in
let val_lpoly2 = Lpoly.get_exn vd2.val_lpoly in
match vd1.val_kind with
| Val_prim p1 -> begin
assert (List.is_empty val_lpoly1);
match vd2.val_kind with
| Val_prim p2 -> begin
let locality = [ Mode.Locality.global; Mode.Locality.local ] in
let forkable = [ Mode.Forkable.forkable; Mode.Forkable.unforkable ] in
let yielding = [ Mode.Yielding.unyielding; Mode.Yielding.yielding ] in
List.iter (fun loc ->
List.iter (fun fork ->
List.iter (fun yield ->
let ty1, _, _, _ = Ctype.instance_prim env p1 vd1.val_type in
let ty2, mode_l2, mode_fy2, _ =
Ctype.instance_prim env p2 vd2.val_type
in
let mode_f2 = Option.map fst mode_fy2 in
let mode_y2 = Option.map snd mode_fy2 in
Option.iter (Mode.Locality.equate_exn loc) mode_l2;
Option.iter (Mode.Forkable.equate_exn fork) mode_f2;
Option.iter (Mode.Yielding.equate_exn yield) mode_y2;
try
moregeneral_lpoly env val_lpoly1 val_lpoly2 ty1 ty2
with Ctype.Moregen err ->
raise (Dont_match (Type err))
) yielding
) forkable
) locality;
match primitive_descriptions p1 p2 with
| None -> Tcoerce_none
| Some err -> raise (Dont_match (Primitive_mismatch err))
end
| _ ->
let ty1, mode_l1, _, sort1 = Ctype.instance_prim env p1 vd1.val_type in
(try moregeneral_lpoly env val_lpoly1 val_lpoly2 ty1 vd2.val_type
with Ctype.Moregen err -> raise (Dont_match (Type err)));
let pc =
{pc_desc = p1; pc_type = vd2.Types.val_type;
pc_poly_mode = Option.map Mode.Locality.disallow_right mode_l1;
pc_poly_sort=sort1;
pc_env = env; pc_loc = vd1.Types.val_loc; } in
Tcoerce_primitive pc
end
| _ ->
match moregeneral_lpoly env
val_lpoly1 val_lpoly2 vd1.val_type vd2.val_type with
| exception Ctype.Moregen err -> raise (Dont_match (Type err))
| () -> begin
match vd2.val_kind with
| Val_prim _ -> raise (Dont_match Not_a_primitive)
| _ -> Tcoerce_none
end
let is_absrow env ty =
match get_desc ty with
| Tconstr(Pident _, _, _) ->
begin match get_desc (Ctype.expand_head env ty) with
| Tobject _|Tvariant _ -> true
| _ -> false
end
| _ -> false
let choose ord first second =
match ord with
| First -> first
| Second -> second
let choose_other ord first second =
match ord with
| First -> choose Second first second
| Second -> choose First first second
type privacy_mismatch =
| Private_type_abbreviation
| Private_variant_type
| Private_record_type
| Private_record_unboxed_product_type
| Private_extensible_variant
| Private_row_type
type type_kind =
| Kind_abstract
| Kind_record
| Kind_record_unboxed_product
| Kind_variant
| Kind_open
let of_kind = function
| Type_abstract _ -> Kind_abstract
| Type_record (_, _, _) -> Kind_record
| Type_record_unboxed_product (_, _, _) -> Kind_record_unboxed_product
| Type_variant (_, _, _) -> Kind_variant
| Type_open -> Kind_open
type kind_mismatch = type_kind * type_kind
type label_mismatch =
| Type of Errortrace.equality_error
| Mutability of position
| Atomicity of position
| Modality of Modality.equate_error
type record_change =
(Types.label_declaration, Types.label_declaration, label_mismatch)
Diffing_with_keys.change
type record_mismatch =
| Label_mismatch of record_change list
| Inlined_representation of position
| Float_representation of position
| Ufloat_representation of position
| Mixed_representation of position
| Mixed_representation_with_flat_floats of position
| Representation_shape_mismatch
type constructor_mismatch =
| Type of Errortrace.equality_error
| Arity
| Inline_record of record_change list
| Kind of position
| Explicit_return_type of position
| Modality of int * Modality.equate_error
type extension_constructor_mismatch =
| Constructor_privacy
| Constructor_mismatch of Ident.t
* Types.extension_constructor
* Types.extension_constructor
* constructor_mismatch
type private_variant_mismatch =
| Only_outer_closed
| Missing of position * string
| Presence of string
| Incompatible_types_for of string
| Types of Errortrace.equality_error
type private_object_mismatch =
| Missing of string
| Types of Errortrace.equality_error
type variant_change =
(Types.constructor_declaration as 'l, 'l, constructor_mismatch)
Diffing_with_keys.change
type unsafe_mode_crossing_mismatch =
| Mode_crossing_only_on of position
| Bounds_not_equal of unsafe_mode_crossing * unsafe_mode_crossing
type type_mismatch =
| Arity
| Privacy of privacy_mismatch
| Kind of kind_mismatch
| Constraint of Errortrace.equality_error
| Manifest of Errortrace.equality_error
| Parameter_jkind of type_expr * Jkind.Violation.t
| Private_variant of type_expr * type_expr * private_variant_mismatch
| Private_object of type_expr * type_expr * private_object_mismatch
| Variance
| Record_mismatch of record_mismatch
| Variant_mismatch of variant_change list
| Unboxed_representation of position * attributes
| Extensible_representation of position
| With_null_representation of position
| Jkind of Jkind.Violation.t
| Unsafe_mode_crossing of unsafe_mode_crossing_mismatch
type jkind_mismatch =
| Manifest_missing
| Manifest_mismatch
let report_modality_sub_error first second ppf e =
let Modality.Error (ax, {left; right}) = e in
let print_modality id ppf m =
Printtyp.modality
~id:(fun ppf -> Format_doc.pp_print_string ppf id) ax ppf m
in
Format_doc.fprintf ppf "%s is %a and %s is %a."
(String.capitalize_ascii second)
(print_modality "empty") right
first
(print_modality "not") left
let report_mode_sub_error ~pp got expected ppf e =
let ({ left; right } : _ Mode.simple_error) = Mode.Value.print_error pp e in
let open Format_doc in
let open_box = dprintf "@[<hov 2>" in
let reopen_box = dprintf "@]@ %t" open_box in
fprintf ppf "%t%s " open_box (String.capitalize_ascii got);
begin match left ppf with
| Mode -> fprintf ppf "%tbut %s " reopen_box expected
| Mode_with_hint -> fprintf ppf ".%tHowever, %s " reopen_box expected
end;
ignore (right ppf);
fprintf ppf ".@]"
let report_modality_equate_error first second ppf
((equate_step, sub_error) : Modality.equate_error) =
match equate_step with
| Left_le_right -> report_modality_sub_error first second ppf sub_error
| Right_le_left -> report_modality_sub_error second first ppf sub_error
module Style = Misc.Style
module Fmt = Format_doc
let report_primitive_mismatch first second ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
match (err : primitive_mismatch) with
| Name ->
pr "The names of the primitives are not the same"
| Arity ->
pr "The syntactic arities of these primitives were not the same.@ \
(They must have the same number of arrows present in the source.)"
| No_alloc ord ->
pr "%s primitive is %a but %s is not"
(String.capitalize_ascii (choose ord first second))
Style.inline_code "[@@noalloc]"
(choose_other ord first second)
| Builtin ->
pr "The two primitives differ in whether they are builtins"
| Effects ->
pr "The two primitives have different effect annotations"
| Coeffects ->
pr "The two primitives have different coeffect annotations"
| Native_name ->
pr "The native names of the primitives are not the same"
| Result_repr ->
pr "The two primitives' results have different representations"
| Argument_repr n ->
pr "The two primitives' %d%s arguments have different representations"
n (Misc.ordinal_suffix n)
| Layout_poly_attr ->
pr "The two primitives have different [@@layout_poly] attributes"
let report_value_mismatch ~pp first second env ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
pr "@ ";
match (err : value_mismatch) with
| Primitive_mismatch pm ->
report_primitive_mismatch first second ppf pm
| Not_a_primitive ->
pr "The implementation is not a primitive."
| Type trace ->
let msg = Fmt.Doc.msg in
Printtyp.report_moregen_error ppf Type_scheme env trace
(msg "The type")
(msg "is not compatible with the type")
| Zero_alloc e -> Zero_alloc.print_error ppf e
| Modality e -> report_modality_sub_error first second ppf e
| Mode e ->
let got = first ^ " is" in
let expected = second ^ " is" in
report_mode_sub_error ~pp got expected ppf e
| Layout_poly_coercion (Extra_lhs { }) ->
pr "%s has %d more layout parameter%s that %s not used,@ \
which is not supported yet."
first extra
(if extra = 1 then "" else "s")
(if extra = 1 then "is" else "are")
| Layout_poly_coercion (Extra_rhs { }) ->
pr "%s has %d more layout parameter%s that %s not used,@ \
which is not supported yet."
second extra
(if extra = 1 then "" else "s")
(if extra = 1 then "is" else "are")
| Layout_poly_coercion (Instantiate_lhs_to_rhs { index_lhs; index_rhs }) ->
pr "The layout parameter at position %d in %s@ \
corresponds to the parameter at position %d in %s,@ \
which is not supported yet."
index_lhs first index_rhs second
| Layout_poly_coercion (Instantiate_lhs { index_lhs; arg }) ->
let format_got ppf = match arg with
| None -> Fmt.fprintf ppf "an unconstrained layout variable"
| Some s ->
Fmt.fprintf ppf "layout %a"
(Style.as_inline_code Jkind_types.Sort.format) s
in
pr "The layout parameter at position %d in %s@ \
is instantiated with %t,@ \
which is not supported yet." index_lhs first format_got
let report_type_inequality env ppf err =
let msg = Fmt.Doc.msg in
Printtyp.report_equality_error ppf Type_scheme env err
(msg "The type")
(msg "is not equal to the type")
let report_privacy_mismatch ppf err =
let singular, item =
match err with
| Private_type_abbreviation -> true, "type abbreviation"
| Private_variant_type -> false, "variant constructor(s)"
| Private_record_type -> true, "record constructor"
| Private_record_unboxed_product_type -> true, "unboxed record constructor"
| Private_extensible_variant -> true, "extensible variant"
| Private_row_type -> true, "row type"
in Format_doc.fprintf ppf "%s %s would be revealed."
(if singular then "A private" else "Private")
item
let report_label_mismatch first second env ppf err =
match (err : label_mismatch) with
| Type err ->
report_type_inequality env ppf err
| Mutability ord ->
Format_doc.fprintf ppf "%s is mutable and %s is not."
(String.capitalize_ascii (choose ord first second))
(choose_other ord first second)
| Atomicity ord ->
Format_doc.fprintf ppf "%s is atomic and %s is not."
(String.capitalize_ascii (choose ord first second))
(choose_other ord first second)
| Modality err_ -> report_modality_equate_error first second ppf err_
let pp_record_diff first second prefix decl env ppf (x : record_change) =
match x with
| Delete cd ->
Fmt.fprintf ppf "%aAn extra field, %a, is provided in %s %s."
prefix x Style.inline_code (Ident.name cd.delete.ld_id) first decl
| Insert cd ->
Fmt.fprintf ppf "%aA field, %a, is missing in %s %s."
prefix x Style.inline_code (Ident.name cd.insert.ld_id) first decl
| Change Type {got=lbl1; expected=lbl2; reason} ->
Fmt.fprintf ppf
"@[<hv>%aFields do not match:@;<1 2>\
%a@ is not the same as:\
@;<1 2>%a@ %a@]"
prefix x
(Style.as_inline_code Printtyp.label) lbl1
(Style.as_inline_code Printtyp.label) lbl2
(report_label_mismatch first second env) reason
| Change Name n ->
Fmt.fprintf ppf "%aFields have different names, %a and %a."
prefix x
Style.inline_code n.got
Style.inline_code n.expected
| Swap sw ->
Fmt.fprintf ppf "%aFields %a and %a have been swapped."
prefix x
Style.inline_code sw.first
Style.inline_code sw.last
| Move {name; got; expected } ->
Fmt.fprintf ppf
"@[<2>%aField %a has been moved@ from@ position %d@ to %d.@]"
prefix x Style.inline_code name expected got
let report_patch pr_diff first second decl env ppf patch =
let nl ppf () = Fmt.fprintf ppf "@," in
let no_prefix _ppf _ = () in
match patch with
| [ elt ] ->
Fmt.fprintf ppf "@[<hv>%a@]"
(pr_diff first second no_prefix decl env) elt
| _ ->
let pp_diff = pr_diff first second Diffing_with_keys.prefix decl env in
Fmt.fprintf ppf "@[<hv>%a@]"
(Fmt.pp_print_list ~pp_sep:nl pp_diff) patch
let report_record_mismatch first second decl env ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
match err with
| Label_mismatch patch ->
report_patch pp_record_diff first second decl env ppf patch
| Inlined_representation ord ->
pr "@[<hv>Their internal representations differ:@ %s %s %s.@]"
(choose ord first second) decl
"is an inlined record"
| Float_representation ord ->
pr "@[<hv>Their internal representations differ:@ %s %s %s.@]"
(choose ord first second) decl
"uses unboxed float representation"
| Ufloat_representation ord ->
pr "@[<hv>Their internal representations differ:@ %s %s %s.@]"
(choose ord first second) decl
"uses float# representation"
| Mixed_representation ord ->
pr "@[<hv>Their internal representations differ:@ %s %s %s.@]"
(choose ord first second) decl
"uses mixed representation"
| Mixed_representation_with_flat_floats ord ->
pr "@[<hv>Their internal representations differ:@ %s %s %s.@]"
(choose ord first second) decl
"uses a mixed representation where boxed floats are stored flat"
| Representation_shape_mismatch ->
pr "@[<hv>Their internal representations differ:@;\
This is likely caused by a layout mismatch in a later definition.@]"
let report_constructor_mismatch first second decl env ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
match (err : constructor_mismatch) with
| Type err -> report_type_inequality env ppf err
| Arity -> pr "They have different arities."
| Inline_record err ->
report_patch pp_record_diff first second decl env ppf err
| Kind ord ->
pr "%s uses inline records and %s doesn't."
(String.capitalize_ascii (choose ord first second))
(choose_other ord first second)
| Explicit_return_type ord ->
pr "%s has explicit return type and %s doesn't."
(String.capitalize_ascii (choose ord first second))
(choose_other ord first second)
| Modality (i, err) ->
pr "Modality mismatch at argument position %i:@ %a"
(i + 1) (report_modality_equate_error first second) err
let pp_variant_diff first second prefix decl env ppf (x : variant_change) =
match x with
| Delete cd ->
Fmt.fprintf ppf "%aAn extra constructor, %a, is provided in %s %s."
prefix x Style.inline_code (Ident.name cd.delete.cd_id) first decl
| Insert cd ->
Fmt.fprintf ppf "%aA constructor, %a, is missing in %s %s."
prefix x Style.inline_code (Ident.name cd.insert.cd_id) first decl
| Change Type {got; expected; reason} ->
Printtyp.wrap_printing_env ~error:true env (fun () ->
Fmt.fprintf ppf
"@[<hv>%aConstructors do not match:@;<1 2>\
%a@ is not the same as:\
@;<1 2>%a@ %a@]"
prefix x
(Style.as_inline_code Printtyp.constructor) got
(Style.as_inline_code Printtyp.constructor) expected
(report_constructor_mismatch first second decl env) reason)
| Change Name n ->
Fmt.fprintf ppf
"%aConstructors have different names, %a and %a."
prefix x
Style.inline_code n.got
Style.inline_code n.expected
| Swap sw ->
Fmt.fprintf ppf
"%aConstructors %a and %a have been swapped."
prefix x
Style.inline_code sw.first
Style.inline_code sw.last
| Move {name; got; expected} ->
Fmt.fprintf ppf
"@[<2>%aConstructor %a has been moved@ from@ position %d@ to %d.@]"
prefix x Style.inline_code name expected got
let report_extension_constructor_mismatch first second decl env ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
match (err : extension_constructor_mismatch) with
| Constructor_privacy ->
pr "Private extension constructor(s) would be revealed."
| Constructor_mismatch (id, ext1, ext2, err) ->
let constructor =
Style.as_inline_code (Printtyp.extension_only_constructor id)
in
pr "@[<hv>Constructors do not match:@;<1 2>%a@ is not the same as:\
@;<1 2>%a@ %a@]"
constructor ext1
constructor ext2
(report_constructor_mismatch first second decl env) err
let report_private_variant_mismatch first second decl env ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
let pp_tag ppf x = Fmt.fprintf ppf "`%s" x in
match (err : private_variant_mismatch) with
| Only_outer_closed ->
pr "%s is private and closed, but %s is not closed"
(String.capitalize_ascii second) first
| Missing (ord, name) ->
pr "The constructor %a is only present in %s %s."
Style.inline_code name (choose ord first second) decl
| Presence s ->
pr "The tag %a is present in the %s %s,@ but might not be in the %s"
(Style.as_inline_code pp_tag) s second decl first
| Incompatible_types_for s -> pr "Types for tag `%s are incompatible" s
| Types err ->
report_type_inequality env ppf err
let report_private_object_mismatch env ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
match (err : private_object_mismatch) with
| Missing s ->
pr "The implementation is missing the method %a" Style.inline_code s
| Types err -> report_type_inequality env ppf err
let report_kind_mismatch first second ppf (kind1, kind2) =
let pr fmt = Fmt.fprintf ppf fmt in
let kind_to_string = function
| Kind_abstract -> "abstract"
| Kind_record -> "a record"
| Kind_record_unboxed_product -> "an unboxed record"
| Kind_variant -> "a variant"
| Kind_open -> "an extensible variant" in
pr "%s is %s, but %s is %s."
(String.capitalize_ascii first)
(kind_to_string kind1)
second
(kind_to_string kind2)
let print_unsafe_mode_crossing ppf umc =
Fmt.fprintf ppf "mod %a@ %a"
Mode.Crossing.print umc.unsafe_mod_bounds
Jkind.With_bounds.format umc.unsafe_with_bounds
let report_unsafe_mode_crossing_mismatch first second ppf e =
let pr fmt = Fmt.fprintf ppf fmt in
match e with
| Mode_crossing_only_on ord ->
pr "%s has [%@%@unsafe_allow_any_mode_crossing], but %s does not"
(choose ord first second)
(choose_other ord first second)
| Bounds_not_equal (first_umc, second_umc) ->
pr "Both specify [%@%@unsafe_allow_any_mode_crossing], but their \
bounds are not equal@,\
@[%s has:@ %a@]@ \
@[but %s has:@ %a@]"
first print_unsafe_mode_crossing first_umc
second print_unsafe_mode_crossing second_umc
let report_type_mismatch first second decl env ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
pr "@ ";
match err with
| Arity ->
pr "They have different arities."
| Privacy err ->
report_privacy_mismatch ppf err
| Kind err ->
report_kind_mismatch first second ppf err
| Constraint err ->
pr "Their parameters differ:@,";
report_type_inequality env ppf err
| Manifest err ->
report_type_inequality env ppf err
| Parameter_jkind (ty, v) ->
pr "The problem is in the kinds of a parameter:@,";
Jkind.Violation.report_with_offender
~offender:(fun pp -> Printtyp.type_expr pp ty)
env ppf v
| Private_variant (_ty1, _ty2, mismatch) ->
report_private_variant_mismatch first second decl env ppf mismatch
| Private_object (_ty1, _ty2, mismatch) ->
report_private_object_mismatch env ppf mismatch
| Variance ->
pr "Their variances do not agree."
| Record_mismatch err ->
report_record_mismatch first second decl env ppf err
| Variant_mismatch err ->
report_patch pp_variant_diff first second decl env ppf err
| Unboxed_representation (ord, attrs) ->
pr "Their internal representations differ:@ %s %s %s."
(choose ord first second) decl
"uses unboxed representation";
if Builtin_attributes.has_unboxed attrs then
pr "@ Hint: %s %s has [%@unboxed]. Did you mean [%@%@unboxed]?"
(choose ord second first) decl
| Extensible_representation ord ->
pr "Their internal representations differ:@ %s %s %s."
(choose ord first second) decl
"is extensible"
| With_null_representation ord ->
pr "Their internal representations differ:@ %s %s %s."
(choose ord first second) decl
"has a constructor represented as a null pointer";
pr "@ Hint: add [%@%@or_null] or [%@%@or_null_reexport]."
| Jkind v ->
Jkind.Violation.report_with_name ~name:first
env ppf v
| Unsafe_mode_crossing mismatch ->
pr "They have different unsafe mode crossing behavior:@,@[<v 2>%a@]"
(fun ppf (first, second, mismatch) ->
report_unsafe_mode_crossing_mismatch first second ppf mismatch)
(first, second, mismatch)
let report_jkind_mismatch first second ppf err =
let pr fmt = Fmt.fprintf ppf fmt in
pr "@ ";
match err with
| Manifest_missing ->
pr "The %s is abstract, but %s is not." first second
| Manifest_mismatch ->
pr "Their definitions are not equal."
let compare_unsafe_mode_crossing ~env umc1 umc2 =
match umc1, umc2 with
| None, None -> None
| Some _, None -> Some (Unsafe_mode_crossing (Mode_crossing_only_on First))
| None, Some _ -> Some (Unsafe_mode_crossing (Mode_crossing_only_on Second))
| Some umc1, Some umc2 ->
if equal_unsafe_mode_crossing
~type_equal:(Ctype.type_equal env)
umc1 umc2
then None
else
Some (
Unsafe_mode_crossing (
Bounds_not_equal (umc1, umc2)))
module Record_diffing = struct
let compare_labels env params1 params2
(ld1 : Types.label_declaration)
(ld2 : Types.label_declaration) =
let err =
match ld1.ld_mutable, ld2.ld_mutable with
| Immutable, Immutable -> None
| Mutable _, Immutable -> Some (Mutability First)
| Immutable, Mutable _ -> Some (Mutability Second)
| Mutable { mode = m1; atomic = atomic1 },
Mutable { mode = m2; atomic = atomic2 } ->
begin match atomic1, atomic2 with
| Atomic, Nonatomic -> Some (Atomicity First)
| Nonatomic, Atomic -> Some (Atomicity Second)
| Atomic, Atomic | Nonatomic, Nonatomic ->
let open Mode.Value.Comonadic in
equate_exn m1 legacy;
equate_exn m2 legacy;
None
end
in
begin match err with
| Some err -> Some err
| None ->
match Modality.Const.equate ld1.ld_modalities ld2.ld_modalities with
| Ok () ->
let tl1 = params1 @ [ld1.ld_type] in
let tl2 = params2 @ [ld2.ld_type] in
begin
match Ctype.equal env true tl1 tl2 with
| exception Ctype.Equality err ->
Some (Type err : label_mismatch)
| () -> None
end
| Error e -> Some (Modality e : label_mismatch)
end
let rec equal ~loc env params1 params2
(labels1 : Types.label_declaration list)
(labels2 : Types.label_declaration list) =
match labels1, labels2 with
| [], [] -> true
| _ :: _ , [] | [], _ :: _ -> false
| ld1 :: rem1, ld2 :: rem2 ->
if Ident.name ld1.ld_id <> Ident.name ld2.ld_id
then false
else begin
Builtin_attributes.check_deprecated_mutable_inclusion
~def:ld1.ld_loc
~use:ld2.ld_loc
loc
ld1.ld_attributes ld2.ld_attributes
(Ident.name ld1.ld_id);
match compare_labels env params1 params2 ld1 ld2 with
| Some _ -> false
| None ->
equal ~loc env
(ld1.ld_type::params1) (ld2.ld_type::params2)
rem1 rem2
end
module Defs = struct
type left = Types.label_declaration
type right = left
type diff = label_mismatch
type state = type_expr list * type_expr list
end
module Diff = Diffing_with_keys.Define(Defs)
let update (d:Diff.change) (params1,params2 as st) =
match d with
| Insert _ | Change _ | Delete _ -> st
| Keep (x,y,_) ->
x.data.ld_type::params1, y.data.ld_type::params2
let test _loc env (params1,params2)
({pos; data=lbl1}: Diff.left)
({data=lbl2; _ }: Diff.right)
=
let name1, name2 = Ident.name lbl1.ld_id, Ident.name lbl2.ld_id in
if name1 <> name2 then
let types_match =
match compare_labels env params1 params2 lbl1 lbl2 with
| Some _ -> false
| None -> true
in
Error
(Diffing_with_keys.Name {types_match; pos; got=name1; expected=name2})
else
match compare_labels env params1 params2 lbl1 lbl2 with
| Some reason ->
Error (
Diffing_with_keys.Type {pos; got=lbl1; expected=lbl2; reason}
)
| None -> Ok ()
let weight: Diff.change -> _ = function
| Insert _ -> 10
| Delete _ -> 10
| Keep _ -> 0
| Change (_,_,Diffing_with_keys.Name t ) ->
if t.types_match then 10 else 15
| Change _ -> 10
let key (x: Defs.left) = Ident.name x.ld_id
let diffing loc env params1 params2 cstrs_1 cstrs_2 =
let module Compute = Diff.Simple(struct
let key_left = key
let key_right = key
let update = update
let test = test loc env
let weight = weight
end)
in
Compute.diff (params1,params2) cstrs_1 cstrs_2
let compare ~loc env params1 params2 l r =
if equal ~loc env params1 params2 l r then
None
else
Some (diffing loc env params1 params2 l r)
let find_mismatch_in_mixed_record_representations
(s1 : mixed_product_shape) (s2 : mixed_product_shape)
=
if Types.equal_mixed_product_shape_up_to_scannable_axes s1 s2
then None
else
let has_float_boxed_on_read fields =
Array.exists (function
| Float_boxed -> true
| _ -> false)
fields
in
if has_float_boxed_on_read s1
then Some (Mixed_representation_with_flat_floats First)
else if has_float_boxed_on_read s2
then Some (Mixed_representation_with_flat_floats Second)
else
Some Representation_shape_mismatch
let compare_with_representation (type rep) ~loc
(record_form : rep record_form) env params1 params2 l r
(rep1 : rep) (rep2 : rep) =
if not (equal ~loc env params1 params2 l r) then
let patch = diffing loc env params1 params2 l r in
Some (Record_mismatch (Label_mismatch patch))
else
match record_form with
| Legacy ->
begin match rep1, rep2 with
| Record_unboxed, Record_unboxed -> None
| Record_unboxed, _ -> Some (Unboxed_representation (First, []))
| _, Record_unboxed -> Some (Unboxed_representation (Second, []))
| Record_inlined _, Record_inlined _ -> None
| Record_inlined _, _ ->
Some (Record_mismatch (Inlined_representation First))
| _, Record_inlined _ ->
Some (Record_mismatch (Inlined_representation Second))
| Record_float, Record_float -> None
| Record_float, _ ->
Some (Record_mismatch (Float_representation First))
| _, Record_float ->
Some (Record_mismatch (Float_representation Second))
| Record_ufloat, Record_ufloat -> None
| Record_ufloat, _ ->
Some (Record_mismatch (Ufloat_representation First))
| _, Record_ufloat ->
Some (Record_mismatch (Ufloat_representation Second))
| Record_mixed m1, Record_mixed m2 ->
begin match find_mismatch_in_mixed_record_representations m1 m2 with
| None -> None
| Some mismatch -> Some (Record_mismatch mismatch)
end
| Record_mixed _, _ ->
Some (Record_mismatch (Mixed_representation First))
| _, Record_mixed _ ->
Some (Record_mismatch (Mixed_representation Second))
| Record_boxed, Record_boxed -> None
| Record_dummy _, _ | _, Record_dummy _ ->
Misc.fatal_error
"compare_with_representation: dummy record representation"
end
| Unboxed_product ->
begin match rep1, rep2 with
| Record_unboxed_product, Record_unboxed_product -> None
end
end
let rec find_map_idx f ?(off = 0) l =
match l with
| [] -> None
| x :: xs -> begin
match f x with
| None -> find_map_idx f ~off:(off+1) xs
| Some y -> Some (off, y)
end
let get_error = function
| Ok () -> None
| Error e -> Some e
module Variant_diffing = struct
let compare_constructor_arguments ~loc env params1 params2 arg1 arg2 =
match arg1, arg2 with
| Types.Cstr_tuple arg1, Types.Cstr_tuple arg2 ->
if List.length arg1 <> List.length arg2 then
Some (Arity : constructor_mismatch)
else begin
let type_and_mode (ca : Types.constructor_argument) = ca.ca_type, ca.ca_modalities in
let arg1_tys, arg1_gfs = List.split (List.map type_and_mode arg1)
and arg2_tys, arg2_gfs = List.split (List.map type_and_mode arg2)
in
match Ctype.equal env true (params1 @ arg1_tys) (params2 @ arg2_tys) with
| exception Ctype.Equality err -> Some (Type err)
| () -> List.combine arg1_gfs arg2_gfs
|> find_map_idx
(fun (x,y) -> get_error @@ Modality.Const.equate x y)
|> Option.map (fun (i, err) -> Modality (i, err))
end
| Types.Cstr_record l1, Types.Cstr_record l2 ->
Option.map
(fun rec_err -> Inline_record rec_err)
(Record_diffing.compare env ~loc params1 params2 l1 l2)
| Types.Cstr_record _, _ -> Some (Kind First : constructor_mismatch)
| _, Types.Cstr_record _ -> Some (Kind Second : constructor_mismatch)
let compare_constructors ~loc env params1 params2 res1 res2 args1 args2 =
match res1, res2 with
| Some r1, Some r2 ->
begin match Ctype.equal env true [r1] [r2] with
| exception Ctype.Equality err -> Some (Type err)
| () -> compare_constructor_arguments ~loc env [r1] [r2] args1 args2
end
| Some _, None -> Some (Explicit_return_type First)
| None, Some _ -> Some (Explicit_return_type Second)
| None, None ->
compare_constructor_arguments ~loc env params1 params2 args1 args2
let equal ~loc env params1 params2
(cstrs1 : Types.constructor_declaration list)
(cstrs2 : Types.constructor_declaration list) =
List.length cstrs1 = List.length cstrs2 &&
List.for_all2 (fun (cd1:Types.constructor_declaration)
(cd2:Types.constructor_declaration) ->
Ident.name cd1.cd_id = Ident.name cd2.cd_id
&&
begin
Builtin_attributes.check_alerts_inclusion
~def:cd1.cd_loc
~use:cd2.cd_loc
loc
cd1.cd_attributes cd2.cd_attributes
(Ident.name cd1.cd_id)
;
match compare_constructors ~loc env params1 params2
cd1.cd_res cd2.cd_res cd1.cd_args cd2.cd_args with
| Some _ -> false
| None -> true
end) cstrs1 cstrs2
module Defs = struct
type left = Types.constructor_declaration
type right = left
type diff = constructor_mismatch
type state = type_expr list * type_expr list
end
module D = Diffing_with_keys.Define(Defs)
let update _ st = st
let weight: D.change -> _ = function
| Insert _ -> 10
| Delete _ -> 10
| Keep _ -> 0
| Change (_,_,Diffing_with_keys.Name t) ->
if t.types_match then 10 else 15
| Change _ -> 10
let test loc env (params1,params2)
({pos; data=cd1}: D.left)
({data=cd2; _}: D.right) =
let name1, name2 = Ident.name cd1.cd_id, Ident.name cd2.cd_id in
if name1 <> name2 then
let types_match =
match compare_constructors ~loc env params1 params2
cd1.cd_res cd2.cd_res cd1.cd_args cd2.cd_args with
| Some _ -> false
| None -> true
in
Error
(Diffing_with_keys.Name {types_match; pos; got=name1; expected=name2})
else
match compare_constructors ~loc env params1 params2
cd1.cd_res cd2.cd_res cd1.cd_args cd2.cd_args with
| Some reason ->
Error (Diffing_with_keys.Type {pos; got=cd1; expected=cd2; reason})
| None -> Ok ()
let diffing loc env params1 params2 cstrs_1 cstrs_2 =
let key (x:Defs.left) = Ident.name x.cd_id in
let module Compute = D.Simple(struct
let key_left = key
let key_right = key
let test = test loc env
let update = update
let weight = weight
end)
in
Compute.diff (params1,params2) cstrs_1 cstrs_2
let compare ~loc env params1 params2 l r =
if equal ~loc env params1 params2 l r then
None
else
Some (diffing loc env params1 params2 l r)
let compare_with_representation ~loc env params1 params2
cstrs1 cstrs2 rep1 rep2
=
let err = compare ~loc env params1 params2 cstrs1 cstrs2 in
let attrs_of_only cstrs =
match cstrs with
| [cstr] -> cstr.Types.cd_attributes
| _ -> []
in
match err, rep1, rep2 with
| None, Variant_unboxed, Variant_unboxed
| None, Variant_boxed _, Variant_boxed _
| None, Variant_extensible, Variant_extensible
| None, Variant_with_null, Variant_with_null -> None
| Some err, _, _ ->
Some (Variant_mismatch err)
| None, Variant_unboxed, Variant_boxed _ ->
Some (Unboxed_representation (First, attrs_of_only cstrs2))
| None, Variant_boxed _, Variant_unboxed ->
Some (Unboxed_representation (Second, attrs_of_only cstrs1))
| None, Variant_extensible, _ ->
Some (Extensible_representation First)
| None, _, Variant_extensible ->
Some (Extensible_representation Second)
| None, Variant_with_null, _ ->
Some (With_null_representation First)
| None, _, Variant_with_null ->
Some (With_null_representation Second)
end
let privacy_mismatch env decl1 decl2 =
match decl1.type_private, decl2.type_private with
| Private, Public -> begin
match decl1.type_kind, decl2.type_kind with
| Type_record _, Type_record _ -> Some Private_record_type
| Type_record_unboxed_product _, Type_record_unboxed_product _ ->
Some Private_record_unboxed_product_type
| Type_variant _, Type_variant _ -> Some Private_variant_type
| Type_open, Type_open -> Some Private_extensible_variant
| Type_abstract _, Type_abstract _
when Option.is_some decl2.type_manifest -> begin
match decl1.type_manifest with
| Some ty1 -> begin
let ty1 = Ctype.expand_head env ty1 in
match get_desc ty1 with
| Tvariant row when Btype.is_constr_row ~allow_ident:true
(row_more row) ->
Some Private_row_type
| Tobject (fi, _) when Btype.is_constr_row ~allow_ident:true
(snd (Ctype.flatten_fields fi)) ->
Some Private_row_type
| _ ->
Some Private_type_abbreviation
end
| None ->
None
end
| _, _ ->
None
end
| _, _ ->
None
let private_variant env row1 row2 =
let r1, r2, pairs =
Ctype.merge_row_fields (row_fields row1) (row_fields row2)
in
let row1_closed = row_closed row1 in
let row2_closed = row_closed row2 in
let err =
if row2_closed && not row1_closed then Some Only_outer_closed
else begin
match row2_closed, Ctype.filter_row_fields false r1 with
| true, (s, _) :: _ ->
Some (Missing (Second, s) : private_variant_mismatch)
| _, _ -> None
end
in
if err <> None then err else
let err =
let missing =
List.find_opt
(fun (_,f) ->
match row_field_repr f with
| Rabsent | Reither _ -> false
| Rpresent _ -> true)
r2
in
match missing with
| None -> None
| Some (s, _) -> Some (Missing (First, s) : private_variant_mismatch)
in
if err <> None then err else
let rec loop tl1 tl2 pairs =
match pairs with
| [] -> begin
match Ctype.equal env false tl1 tl2 with
| exception Ctype.Equality err ->
Some (Types err : private_variant_mismatch)
| () -> None
end
| (s, f1, f2) :: pairs -> begin
match row_field_repr f1, row_field_repr f2 with
| Rpresent to1, Rpresent to2 -> begin
match to1, to2 with
| Some t1, Some t2 ->
loop (t1 :: tl1) (t2 :: tl2) pairs
| None, None ->
loop tl1 tl2 pairs
| Some _, None | None, Some _ ->
Some (Incompatible_types_for s)
end
| Rpresent to1, Reither(const2, ts2, _) -> begin
match to1, const2, ts2 with
| Some t1, false, [t2] -> loop (t1 :: tl1) (t2 :: tl2) pairs
| None, true, [] -> loop tl1 tl2 pairs
| _, _, _ -> Some (Incompatible_types_for s)
end
| Rpresent _, Rabsent ->
Some (Missing (Second, s) : private_variant_mismatch)
| Reither(const1, ts1, _), Reither(const2, ts2, _) ->
if const1 = const2 && List.length ts1 = List.length ts2 then
loop (ts1 @ tl1) (ts2 @ tl2) pairs
else
Some (Incompatible_types_for s)
| Reither _, Rpresent _ ->
Some (Presence s)
| Reither _, Rabsent ->
Some (Missing (Second, s) : private_variant_mismatch)
| Rabsent, (Reither _ | Rabsent) ->
loop tl1 tl2 pairs
| Rabsent, Rpresent _ ->
Some (Missing (First, s) : private_variant_mismatch)
end
in
loop [] [] pairs
let private_object env fields1 fields2 =
let pairs, _miss1, miss2 = Ctype.associate_fields fields1 fields2 in
let err =
match miss2 with
| [] -> None
| (f, _, _) :: _ -> Some (Missing f)
in
if err <> None then err else
let tl1, tl2 =
List.split (List.map (fun (_,_,t1,_,t2) -> t1, t2) pairs)
in
begin
match Ctype.equal env false tl1 tl2 with
| exception Ctype.Equality err -> Some (Types err)
| () -> None
end
let type_manifest env ty1 ty2 priv2 kind2 =
let ty1' = Ctype.expand_head env ty1 and ty2' = Ctype.expand_head env ty2 in
match get_desc ty1', get_desc ty2' with
| Tvariant row1, Tvariant row2
when is_absrow env (row_more row2) -> begin
assert (Ctype.is_equal env false [ty1] [row_more row2]);
match private_variant env row1 row2 with
| None -> None
| Some err -> Some (Private_variant(ty1, ty2, err))
end
| Tobject (fi1, _), Tobject (fi2, _)
when is_absrow env (snd (Ctype.flatten_fields fi2)) -> begin
let (fields2,rest2) = Ctype.flatten_fields fi2 in
let (fields1,_) = Ctype.flatten_fields fi1 in
assert (Ctype.is_equal env false [ty1] [rest2]);
match private_object env fields1 fields2 with
| None -> None
| Some err -> Some (Private_object(ty1, ty2, err))
end
| _ -> begin
let is_private_abbrev_2 =
match priv2, kind2 with
| Private, Type_abstract _ -> begin
match get_desc ty2' with
| Tvariant row ->
not (is_absrow env (row_more row))
| Tobject (fi, _) ->
not (is_absrow env (snd (Ctype.flatten_fields fi)))
| _ -> true
end
| _, _ -> false
in
match
if is_private_abbrev_2 then
Ctype.equal_private env ty1 ty2
else
Ctype.equal env false [ty1] [ty2]
with
| exception Ctype.Equality err -> Some (Manifest err)
| () -> None
end
let type_declarations ?(equality = false) ~loc env ~mark name
decl1 path decl2 =
Builtin_attributes.check_alerts_inclusion
~def:decl1.type_loc
~use:decl2.type_loc
loc
decl1.type_attributes decl2.type_attributes
name;
if decl1.type_arity <> decl2.type_arity then Some Arity else
let err =
match Ctype.equal ~do_jkind_check:false env true
decl1.type_params decl2.type_params with
| exception Ctype.Equality err -> Some (Constraint err)
| () -> None
in
if err <> None then err else
let decl1 = Ctype.generic_instance_declaration decl1 in
let decl2 = Ctype.generic_instance_declaration decl2 in
let rigidity_info = Ctype.Rigidify.rigidify_list decl2.type_params in
let err =
match
List.iter2 (Ctype.unify env) decl1.type_params decl2.type_params
with
| exception Ctype.Unify err ->
let get_jkind_violation = function
| Errortrace.Bad_jkind (ty, v) -> Some (Parameter_jkind (ty, v))
| _ -> None
in
begin match List.find_map get_jkind_violation err.trace with
| Some _ as err -> err
| None -> Misc.fatal_errorf_doc
"Unification in type_declarations failed, \
but not with Bad_jkind:@;<1 2>%t"
(fun ppf ->
Printtyp.report_unification_error ppf env err
(Fmt.doc_printf "The type")
(Fmt.doc_printf "does not unify with the type"))
end
| () -> None
in
if err <> None then err else
let err =
match privacy_mismatch env decl1 decl2 with
| Some err -> Some (Privacy err)
| None -> None
in
if err <> None then err else
let err = match (decl1.type_manifest, decl2.type_manifest) with
(_, None) -> None
| (Some ty1, Some ty2) ->
type_manifest env ty1 ty2 decl2.type_private decl2.type_kind
| (None, Some ty2) ->
let ty1 =
Btype.newgenty (Tconstr(path, decl2.type_params, ref Mnil))
in
match Ctype.equal env false [ty1] [ty2] with
| exception Ctype.Equality err -> Some (Manifest err)
| () -> None
in
if err <> None then err else
let mark_and_compare_records record_form labels1 rep1 labels2 rep2 =
if mark then begin
let mark usage lbls =
List.iter (fun lbl -> Env.mark_label_used usage lbl.Types.ld_uid) lbls
in
let usage : Env.label_usage =
if decl2.type_private = Public then Env.Exported
else Env.Exported_private
in
mark usage labels1;
if equality then mark Env.Exported labels2
end;
Record_diffing.compare_with_representation ~loc record_form env
decl1.type_params decl2.type_params
labels1 labels2
rep1 rep2
in
let err = match (decl1.type_kind, decl2.type_kind) with
(_, Type_abstract _) ->
if Option.is_none decl2.type_manifest then
match Ctype.check_decl_jkind env decl1 decl2.type_jkind with
| Ok _ -> None
| Error v -> Some (Jkind v)
else None
| (Type_variant (cstrs1, rep1, umc1), Type_variant (cstrs2, rep2, umc2)) -> begin
if mark then begin
let mark usage cstrs =
List.iter (fun cstr ->
Env.mark_constructor_used usage cstr.Types.cd_uid
) cstrs
in
let usage : Env.constructor_usage =
if decl2.type_private = Public then Env.Exported
else Env.Exported_private
in
mark usage cstrs1;
if equality then mark Env.Exported cstrs2
end;
Misc.Stdlib.Option.first_some
(Variant_diffing.compare_with_representation ~loc env
decl1.type_params
decl2.type_params
cstrs1
cstrs2
rep1
rep2)
(fun () -> compare_unsafe_mode_crossing ~env umc1 umc2)
end
| (Type_record(labels1,rep1,umc1), Type_record(labels2,rep2,umc2)) -> begin
Misc.Stdlib.Option.first_some
(mark_and_compare_records Legacy labels1 rep1 labels2 rep2)
(fun () -> compare_unsafe_mode_crossing ~env umc1 umc2)
end
| (Type_record_unboxed_product(labels1,rep1,umc1),
Type_record_unboxed_product(labels2,rep2,umc2)) -> begin
Misc.Stdlib.Option.first_some
(mark_and_compare_records Unboxed_product labels1 rep1 labels2 rep2)
(fun () -> compare_unsafe_mode_crossing ~env umc1 umc2)
end
| (Type_open, Type_open) -> None
| (_, _) -> Some (Kind (of_kind decl1.type_kind, of_kind decl2.type_kind))
in
if err <> None then err else
match Ctype.Rigidify.all_distinct_vars_with_original_jkinds env rigidity_info with
| Unification_failure { name; ty }
-> Misc.fatal_errorf_doc
"Unification failure in type inclusion rigidity check:@;\
%s unified with %a."
(match name with None -> "_" | Some n -> "'" ^ n)
Printtyp.type_expr ty
| Jkind_mismatch { original_jkind; inferred_jkind; ty } ->
let context = Ctype.mk_jkind_context_always_principal env in
Some (Parameter_jkind
(ty, Jkind.Violation.of_ ~context env
(Not_a_subjkind (Jkind.disallow_right original_jkind,
Jkind.disallow_left inferred_jkind,
[]))))
| All_good ->
let abstr = Btype.type_kind_is_abstract decl2 && decl2.type_manifest = None in
let need_variance =
abstr || decl1.type_private = Private || decl1.type_kind = Type_open in
if not need_variance then None else
let abstr = abstr || decl2.type_private = Private in
let opn = decl2.type_kind = Type_open && decl2.type_manifest = None in
let constrained ty = not (Btype.is_Tvar ty) in
if List.for_all2
(fun ty (v1,v2) ->
let open Variance in
let imp a b = not a || b in
let (co1,cn1) = get_upper v1 and (co2,cn2) = get_upper v2 in
(if abstr then (imp co1 co2 && imp cn1 cn2)
else if opn || constrained ty then (co1 = co2 && cn1 = cn2)
else true) &&
let (p1,n1,j1) = get_lower v1 and (p2,n2,j2) = get_lower v2 in
imp abstr (imp p2 p1 && imp n2 n1 && imp j2 j1))
decl2.type_params (List.combine decl1.type_variance decl2.type_variance)
then None else Some Variance
let extension_constructors ~loc env ~mark id ext1 ext2 =
if mark then begin
let usage : Env.constructor_usage =
if ext2.ext_private = Public then Env.Exported
else Env.Exported_private
in
Env.mark_extension_used usage ext1.ext_uid
end;
let ty1 =
Btype.newgenty (Tconstr(ext1.ext_type_path, ext1.ext_type_params, ref Mnil))
in
let ty2 =
Btype.newgenty (Tconstr(ext2.ext_type_path, ext2.ext_type_params, ref Mnil))
in
let tl1 = ty1 :: ext1.ext_type_params in
let tl2 = ty2 :: ext2.ext_type_params in
match Ctype.equal env true tl1 tl2 with
| exception Ctype.Equality err ->
Some (Constructor_mismatch (id, ext1, ext2, Type err))
| () ->
let r =
Variant_diffing.compare_constructors ~loc env
ext1.ext_type_params ext2.ext_type_params
ext1.ext_ret_type ext2.ext_ret_type
ext1.ext_args ext2.ext_args
in
match r with
| Some r -> Some (Constructor_mismatch (id, ext1, ext2, r))
| None ->
match ext1.ext_private, ext2.ext_private with
| Private, Public -> Some Constructor_privacy
| _, _ -> None
let jkind_declarations ~loc env name
(decl1 : Types.jkind_declaration) (decl2 : Types.jkind_declaration) =
Builtin_attributes.check_alerts_inclusion
~def:decl1.jkind_loc
~use:decl2.jkind_loc
loc
decl1.jkind_attributes decl2.jkind_attributes
name;
match decl1.jkind_manifest, decl2.jkind_manifest with
| _, None -> None
| None, Some _ -> Some Manifest_missing
| Some k1, Some k2 ->
if Jkind.Const.equal env k1 k2
then None
else Some Manifest_mismatch