-
Notifications
You must be signed in to change notification settings - Fork 460
/
Copy pathctype.ml
4246 lines (3876 loc) · 145 KB
/
ctype.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 *)
(* *)
(* Xavier Leroy and Jerome Vouillon, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* 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. *)
(* *)
(**************************************************************************)
(* Operations on core types *)
open Misc
open Asttypes
open Types
open Btype
(*
Type manipulation after type inference
======================================
If one wants to manipulate a type after type inference (for
instance, during code generation or in the debugger), one must
first make sure that the type levels are correct, using the
function [correct_levels]. Then, this type can be correctly
manipulated by [apply], [expand_head] and [moregeneral].
*)
(*
General notes
=============
- As much sharing as possible should be kept : it makes types
smaller and better abbreviated.
When necessary, some sharing can be lost. Types will still be
printed correctly (+++ TO DO...), and abbreviations defined by a
class do not depend on sharing thanks to constrained
abbreviations. (Of course, even if some sharing is lost, typing
will still be correct.)
- All nodes of a type have a level : that way, one know whether a
node need to be duplicated or not when instantiating a type.
- Levels of a type are decreasing (generic level being considered
as greatest).
- The level of a type constructor is superior to the binding
time of its path.
- Recursive types without limitation should be handled (even if
there is still an occur check). This avoid treating specially the
case for objects, for instance. Furthermore, the occur check
policy can then be easily changed.
*)
(**** Errors ****)
exception Unify of (type_expr * type_expr) list
exception Tags of label * label
let () =
Location.register_error_of_exn
(function
| Tags (l, l') ->
Some
Location.
(errorf ~loc:(in_file !input_name)
"In this program,@ variant constructors@ #%s and #%s@ \
have the same hash value.@ Change one of them." l l'
)
| _ -> None
)
exception Subtype of
(type_expr * type_expr) list * (type_expr * type_expr) list
exception Cannot_expand
exception Cannot_apply
exception Recursive_abbrev
(* GADT: recursive abbrevs can appear as a result of local constraints *)
exception Unification_recursive_abbrev of (type_expr * type_expr) list
(**** Type level management ****)
let current_level = ref 0
let nongen_level = ref 0
let global_level = ref 1
let saved_level = ref []
type levels =
{ current_level: int; nongen_level: int; global_level: int;
saved_level: (int * int) list; }
let save_levels () =
{ current_level = !current_level;
nongen_level = !nongen_level;
global_level = !global_level;
saved_level = !saved_level }
let set_levels l =
current_level := l.current_level;
nongen_level := l.nongen_level;
global_level := l.global_level;
saved_level := l.saved_level
let get_current_level () = !current_level
let init_def level = current_level := level; nongen_level := level
let begin_def () =
saved_level := (!current_level, !nongen_level) :: !saved_level;
incr current_level; nongen_level := !current_level
let begin_class_def () =
saved_level := (!current_level, !nongen_level) :: !saved_level;
incr current_level
let raise_nongen_level () =
saved_level := (!current_level, !nongen_level) :: !saved_level;
nongen_level := !current_level
let end_def () =
let (cl, nl) = List.hd !saved_level in
saved_level := List.tl !saved_level;
current_level := cl; nongen_level := nl
let reset_global_level () =
global_level := !current_level + 1
let increase_global_level () =
let gl = !global_level in
global_level := !current_level;
gl
let restore_global_level gl =
global_level := gl
(**** Whether a path points to an object type (with hidden row variable) ****)
let is_object_type path =
let name =
match path with Path.Pident id -> Ident.name id
| Path.Pdot(_, s,_) -> s
| Path.Papply _ -> assert false
in name.[0] = '#'
(**** Control tracing of GADT instances *)
let trace_gadt_instances = ref false
let check_trace_gadt_instances env =
not !trace_gadt_instances && Env.has_local_constraints env &&
(trace_gadt_instances := true; cleanup_abbrev (); true)
let reset_trace_gadt_instances b =
if b then trace_gadt_instances := false
let wrap_trace_gadt_instances env f x =
let b = check_trace_gadt_instances env in
let y = f x in
reset_trace_gadt_instances b;
y
(**** Abbreviations without parameters ****)
(* Shall reset after generalizing *)
let simple_abbrevs = ref Mnil
let proper_abbrevs path tl abbrev =
if tl <> [] || !trace_gadt_instances ||
is_object_type path
then abbrev
else simple_abbrevs
(**** Some type creators ****)
(* Re-export generic type creators *)
let newty2 = Btype.newty2
let newty desc = newty2 !current_level desc
let newvar ?name () = newty2 !current_level (Tvar name)
let newvar2 ?name level = newty2 level (Tvar name)
let new_global_var ?name () = newty2 !global_level (Tvar name)
let newobj fields = newty (Tobject (fields, ref None))
let newconstr path tyl = newty (Tconstr (path, tyl, ref Mnil))
let none = newty (Ttuple []) (* Clearly ill-formed type *)
(**** Representative of a type ****)
(* Re-export repr *)
let repr = repr
(**** Type maps ****)
module TypePairs =
Hashtbl.Make (struct
type t = type_expr * type_expr
let equal (t1, t1') (t2, t2') = (t1 == t2) && (t1' == t2')
let hash (t, t') = t.id + 93 * t'.id
end)
(**** unification mode ****)
type unification_mode =
| Expression (* unification in expression *)
| Pattern (* unification in pattern which may add local constraints *)
let umode = ref Expression
let generate_equations = ref false
let assume_injective = ref false
let variant_is_subtype = ref (fun _env _row _p1 -> false)
let set_mode_pattern ~generate ~injective f =
let old_unification_mode = !umode
and old_gen = !generate_equations
and old_inj = !assume_injective in
try
umode := Pattern;
generate_equations := generate;
assume_injective := injective;
let ret = f () in
umode := old_unification_mode;
generate_equations := old_gen;
assume_injective := old_inj;
ret
with e ->
umode := old_unification_mode;
generate_equations := old_gen;
assume_injective := old_inj;
raise e
(*** Checks for type definitions ***)
let in_current_module = function
| Path.Pident _ -> true
| Path.Pdot _ | Path.Papply _ -> false
let in_pervasives p =
in_current_module p &&
try ignore (Env.find_type p Env.initial_safe_string); true
with Not_found -> false
let is_datatype decl=
match decl.type_kind with
Type_record _ | Type_variant _ | Type_open -> true
| Type_abstract -> false
(**********************************************)
(* Miscellaneous operations on object types *)
(**********************************************)
(* Note:
We need to maintain some invariants:
* cty_self must be a Tobject
* ...
*)
type fields = (string * Types.field_kind * Types.type_expr) list
(**** Object field manipulation. ****)
let object_fields ty =
match (repr ty).desc with
Tobject (fields, _) -> fields
| _ -> assert false
let flatten_fields (ty : Types.type_expr) : fields * _ =
let rec flatten (l : fields) ty =
let ty = repr ty in
match ty.desc with
Tfield(s, k, ty1, ty2) ->
flatten ((s, k, ty1)::l) ty2
| _ ->
(l, ty)
in
let (l, r) = flatten [] ty in
(List.sort (fun (n, _, _) (n', _, _) -> compare n n') l, r)
let build_fields level =
List.fold_right
(fun (s, k, ty1) ty2 -> newty2 level (Tfield(s, k, ty1, ty2)))
let associate_fields
(fields1 : fields )
(fields2 : fields ) : _ * fields * fields =
let rec associate p s s' : fields * fields -> _ =
function
(l, []) ->
(List.rev p, (List.rev s) @ l, List.rev s')
| ([], l') ->
(List.rev p, List.rev s, (List.rev s') @ l')
| ((n, k, t)::r, (n', k', t')::r') when n = n' ->
associate ((n, k, t, k', t')::p) s s' (r, r')
| ((n, k, t)::r, ((n', _k', _t')::_ as l')) when n < n' ->
associate p ((n, k, t)::s) s' (r, l')
| (((_n, _k, _t)::_ as l), (n', k', t')::r') (* when n > n' *) ->
associate p s ((n', k', t')::s') (l, r')
in
associate [] [] [] (fields1, fields2)
(**** Check whether an object is open ****)
(* +++ The abbreviation should eventually be expanded *)
let rec object_row ty =
let ty = repr ty in
match ty.desc with
Tobject (t, _) -> object_row t
| Tfield(_, _, _, t) -> object_row t
| _ -> ty
let opened_object ty =
match (object_row ty).desc with
| Tvar _ | Tunivar _ | Tconstr _ -> true
| _ -> false
let concrete_object ty =
match (object_row ty).desc with
| Tvar _ -> false
| _ -> true
(**** Close an object ****)
let close_object ty =
let rec close ty =
let ty = repr ty in
match ty.desc with
Tvar _ ->
link_type ty (newty2 ty.level Tnil)
| Tfield(_, _, _, ty') -> close ty'
| _ -> assert false
in
match (repr ty).desc with
Tobject (ty, _) -> close ty
| _ -> assert false
(**** Row variable of an object type ****)
let row_variable ty =
let rec find ty =
let ty = repr ty in
match ty.desc with
Tfield (_, _, _, ty) -> find ty
| Tvar _ -> ty
| _ -> assert false
in
match (repr ty).desc with
Tobject (fi, _) -> find fi
| _ -> assert false
(**** Object name manipulation ****)
(* +++ Bientot obsolete *)
let set_object_name id rv params ty =
match (repr ty).desc with
Tobject (_fi, nm) ->
set_name nm (Some (Path.Pident id, rv::params))
| _ ->
assert false
let remove_object_name ty =
match (repr ty).desc with
Tobject (_, nm) -> set_name nm None
| Tconstr (_, _, _) -> ()
| _ -> fatal_error "Ctype.remove_object_name"
(**** Hiding of private methods ****)
let hide_private_methods ty =
match (repr ty).desc with
Tobject (fi, nm) ->
nm := None;
let (fl, _) = flatten_fields fi in
List.iter
(function (_, k, _) ->
match field_kind_repr k with
Fvar r -> set_kind r Fabsent
| _ -> ())
fl
| _ ->
assert false
(*******************************)
(* Operations on class types *)
(*******************************)
(*******************************************)
(* Miscellaneous operations on row types *)
(*******************************************)
type row_fields = (Asttypes.label * Types.row_field) list
type row_pairs = (Asttypes.label * Types.row_field * Types.row_field) list
let sort_row_fields : row_fields -> row_fields = List.sort (fun (p,_) (q,_) -> compare (p : string) q)
let rec merge_rf (r1 : row_fields) (r2 : row_fields) (pairs : row_pairs) (fi1 : row_fields) (fi2 : row_fields) =
match fi1, fi2 with
(l1,f1 as p1)::fi1', (l2,f2 as p2)::fi2' ->
if l1 = l2 then merge_rf r1 r2 ((l1,f1,f2)::pairs) fi1' fi2' else
if l1 < l2 then merge_rf (p1::r1) r2 pairs fi1' fi2 else
merge_rf r1 (p2::r2) pairs fi1 fi2'
| [], _ -> (List.rev r1, List.rev_append r2 fi2, pairs)
| _, [] -> (List.rev_append r1 fi1, List.rev r2, pairs)
let merge_row_fields (fi1 : row_fields) (fi2 : row_fields) : row_fields * row_fields * row_pairs =
match fi1, fi2 with
[], _ | _, [] -> (fi1, fi2, [])
| [p1], _ when not (List.mem_assoc (fst p1) fi2) -> (fi1, fi2, [])
| _, [p2] when not (List.mem_assoc (fst p2) fi1) -> (fi1, fi2, [])
| _ -> merge_rf [] [] [] (sort_row_fields fi1) (sort_row_fields fi2)
let rec filter_row_fields erase = function
[] -> []
| (_l,f as p)::fi ->
let fi = filter_row_fields erase fi in
match row_field_repr f with
Rabsent -> fi
| Reither(_,_,false,e) when erase -> set_row_field e Rabsent; fi
| _ -> p :: fi
(**************************************)
(* Check genericity of type schemes *)
(**************************************)
exception Non_closed of type_expr * bool
let free_variables = ref []
let really_closed = ref None
let rec free_vars_rec real ty =
let ty = repr ty in
if ty.level >= lowest_level then begin
ty.level <- pivot_level - ty.level;
begin match ty.desc, !really_closed with
Tvar _, _ ->
free_variables := (ty, real) :: !free_variables
| Tconstr (path, tl, _), Some env ->
begin try
let (_, body, _) = Env.find_type_expansion path env in
if (repr body).level <> generic_level then
free_variables := (ty, real) :: !free_variables
with Not_found -> ()
end;
List.iter (free_vars_rec true) tl
(* Do not count "virtual" free variables
| Tobject(ty, {contents = Some (_, p)}) ->
free_vars_rec false ty; List.iter (free_vars_rec true) p
*)
| Tobject (ty, _), _ ->
free_vars_rec false ty
| Tfield (_, _, ty1, ty2), _ ->
free_vars_rec true ty1; free_vars_rec false ty2
| Tvariant row, _ ->
let row = row_repr row in
iter_row (free_vars_rec true) row;
if not (static_row row) then free_vars_rec false row.row_more
| _ ->
iter_type_expr (free_vars_rec true) ty
end;
end
let free_vars ?env ty =
free_variables := [];
really_closed := env;
free_vars_rec true ty;
let res = !free_variables in
free_variables := [];
really_closed := None;
res
let free_variables ?env ty =
let tl = List.map fst (free_vars ?env ty) in
unmark_type ty;
tl
let closed_type ty =
match free_vars ty with
[] -> ()
| (v, real) :: _ -> raise (Non_closed (v, real))
let closed_parameterized_type params ty =
List.iter mark_type params;
let ok =
try closed_type ty; true with Non_closed _ -> false in
List.iter unmark_type params;
unmark_type ty;
ok
let closed_type_decl decl =
try
List.iter mark_type decl.type_params;
begin match decl.type_kind with
Type_abstract ->
()
| Type_variant v ->
List.iter
(fun {cd_args; cd_res; _} ->
match cd_res with
| Some _ -> ()
| None ->
match cd_args with
| Cstr_tuple l -> List.iter closed_type l
| Cstr_record l -> List.iter (fun l -> closed_type l.ld_type) l
)
v
| Type_record(r, _rep) ->
List.iter (fun l -> closed_type l.ld_type) r
| Type_open -> ()
end;
begin match decl.type_manifest with
None -> ()
| Some ty -> closed_type ty
end;
unmark_type_decl decl;
None
with Non_closed (ty, _) ->
unmark_type_decl decl;
Some ty
let closed_extension_constructor ext =
try
List.iter mark_type ext.ext_type_params;
begin match ext.ext_ret_type with
| Some _ -> ()
| None -> iter_type_expr_cstr_args closed_type ext.ext_args
end;
unmark_extension_constructor ext;
None
with Non_closed (ty, _) ->
unmark_extension_constructor ext;
Some ty
type closed_class_failure =
CC_Method of type_expr * bool * string * type_expr
| CC_Value of type_expr * bool * string * type_expr
(**********************)
(* Type duplication *)
(**********************)
(* Duplicate a type, preserving only type variables *)
let duplicate_type ty =
Subst.type_expr Subst.identity ty
(* Same, for class types *)
(*****************************)
(* Type level manipulation *)
(*****************************)
(*
It would be a bit more efficient to remove abbreviation expansions
rather than generalizing them: these expansions will usually not be
used anymore. However, this is not possible in the general case, as
[expand_abbrev] (via [subst]) requires these expansions to be
preserved. Does it worth duplicating this code ?
*)
let rec generalize ty =
let ty = repr ty in
if (ty.level > !current_level) && (ty.level <> generic_level) then begin
set_level ty generic_level;
begin match ty.desc with
Tconstr (_, _, abbrev) ->
iter_abbrev generalize !abbrev
| _ -> ()
end;
iter_type_expr generalize ty
end
let generalize ty =
simple_abbrevs := Mnil;
generalize ty
(* Generalize the structure and lower the variables *)
let rec generalize_structure var_level ty =
let ty = repr ty in
if ty.level <> generic_level then begin
if is_Tvar ty && ty.level > var_level then
set_level ty var_level
else if
ty.level > !current_level &&
match ty.desc with
Tconstr (p, _, abbrev) ->
not (is_object_type p) && (abbrev := Mnil; true)
| _ -> true
then begin
set_level ty generic_level;
iter_type_expr (generalize_structure var_level) ty
end
end
let generalize_structure var_level ty =
simple_abbrevs := Mnil;
generalize_structure var_level ty
let forward_try_expand_once = (* Forward declaration *)
ref (fun _env _ty -> raise Cannot_expand)
(*
Lower the levels of a type (assume [level] is not
[generic_level]).
*)
(*
The level of a type constructor must be greater than its binding
time. That way, a type constructor cannot escape the scope of its
definition, as would be the case in
let x = ref []
module M = struct type t let _ = (x : t list ref) end
(without this constraint, the type system would actually be unsound.)
*)
let get_level env p =
try
match (Env.find_type p env).type_newtype_level with
| None -> Path.binding_time p
| Some (x, _) -> x
with
| Not_found ->
(* no newtypes in predef *)
Path.binding_time p
let rec normalize_package_path env p =
let t =
try (Env.find_modtype p env).mtd_type
with Not_found -> None
in
match t with
| Some (Mty_ident p) -> normalize_package_path env p
| Some (Mty_signature _ | Mty_functor _ | Mty_alias _) | None ->
match p with
Path.Pdot (p1, s, n) ->
(* For module aliases *)
let p1' = Env.normalize_path None env p1 in
if Path.same p1 p1' then p else
normalize_package_path env (Path.Pdot (p1', s, n))
| _ -> p
let rec update_level env level expand ty =
let ty = repr ty in
if ty.level > level then begin
begin match Env.gadt_instance_level env ty with
Some lv -> if level < lv then raise (Unify [(ty, newvar2 level)])
| None -> ()
end;
match ty.desc with
Tconstr(p, _tl, _abbrev) when level < get_level env p ->
(* Try first to replace an abbreviation by its expansion. *)
begin try
(* if is_newtype env p then raise Cannot_expand; *)
link_type ty (!forward_try_expand_once env ty);
update_level env level expand ty
with Cannot_expand ->
(* +++ Levels should be restored... *)
(* Format.printf "update_level: %i < %i@." level (get_level env p); *)
if level < get_level env p then raise (Unify [(ty, newvar2 level)]);
iter_type_expr (update_level env level expand) ty
end
| Tconstr(_, _ :: _, _) when expand ->
begin try
link_type ty (!forward_try_expand_once env ty);
update_level env level expand ty
with Cannot_expand ->
set_level ty level;
iter_type_expr (update_level env level expand) ty
end
| Tpackage (p, nl, tl) when level < Path.binding_time p ->
let p' = normalize_package_path env p in
if Path.same p p' then raise (Unify [(ty, newvar2 level)]);
log_type ty; ty.desc <- Tpackage (p', nl, tl);
update_level env level expand ty
| Tobject(_, ({contents=Some(p, _tl)} as nm))
when level < get_level env p ->
set_name nm None;
update_level env level expand ty
| Tvariant row ->
let row = row_repr row in
begin match row.row_name with
| Some (p, _tl) when level < get_level env p ->
log_type ty;
ty.desc <- Tvariant {row with row_name = None}
| _ -> ()
end;
set_level ty level;
iter_type_expr (update_level env level expand) ty
| Tfield(lab, _, ty1, _)
when lab = dummy_method && (repr ty1).level > level ->
raise (Unify [(ty1, newvar2 level)])
| _ ->
set_level ty level;
(* XXX what about abbreviations in Tconstr ? *)
iter_type_expr (update_level env level expand) ty
end
(* First try without expanding, then expand everything,
to avoid combinatorial blow-up *)
let update_level env level ty =
let ty = repr ty in
if ty.level > level then begin
let snap = snapshot () in
try
update_level env level false ty
with Unify _ ->
backtrack snap;
update_level env level true ty
end
(* Generalize and lower levels of contravariant branches simultaneously *)
let rec generalize_expansive env var_level visited ty =
let ty = repr ty in
if ty.level = generic_level || ty.level <= var_level then () else
if not (Hashtbl.mem visited ty.id) then begin
Hashtbl.add visited ty.id ();
match ty.desc with
Tconstr (path, tyl, abbrev) ->
let variance =
try (Env.find_type path env).type_variance
with Not_found -> List.map (fun _ -> Variance.may_inv) tyl in
abbrev := Mnil;
List.iter2
(fun v t ->
if Variance.(mem May_weak v)
then generalize_structure var_level t
else generalize_expansive env var_level visited t)
variance tyl
| Tpackage (_, _, tyl) ->
List.iter (generalize_structure var_level) tyl
| Tarrow (_, t1, t2, _) ->
generalize_structure var_level t1;
generalize_expansive env var_level visited t2
| _ ->
iter_type_expr (generalize_expansive env var_level visited) ty
end
let generalize_expansive env ty =
simple_abbrevs := Mnil;
try
generalize_expansive env !nongen_level (Hashtbl.create 7) ty
with Unify ([_, ty'] as tr) ->
raise (Unify ((ty, ty') :: tr))
let generalize_global ty = generalize_structure !global_level ty
let generalize_structure ty = generalize_structure !current_level ty
(* Correct the levels of type [ty]. *)
let correct_levels ty =
duplicate_type ty
(* Only generalize the type ty0 in ty *)
let limited_generalize ty0 ty =
let ty0 = repr ty0 in
let graph = Hashtbl.create 17 in
let idx = ref lowest_level in
let roots = ref [] in
let rec inverse pty ty =
let ty = repr ty in
if (ty.level > !current_level) || (ty.level = generic_level) then begin
decr idx;
Hashtbl.add graph !idx (ty, ref pty);
if (ty.level = generic_level) || (ty == ty0) then
roots := ty :: !roots;
set_level ty !idx;
iter_type_expr (inverse [ty]) ty
end else if ty.level < lowest_level then begin
let (_, parents) = Hashtbl.find graph ty.level in
parents := pty @ !parents
end
and generalize_parents ty =
let idx = ty.level in
if idx <> generic_level then begin
set_level ty generic_level;
List.iter generalize_parents !(snd (Hashtbl.find graph idx));
(* Special case for rows: must generalize the row variable *)
match ty.desc with
Tvariant row ->
let more = row_more row in
let lv = more.level in
if (lv < lowest_level || lv > !current_level)
&& lv <> generic_level then set_level more generic_level
| _ -> ()
end
in
inverse [] ty;
if ty0.level < lowest_level then
iter_type_expr (inverse []) ty0;
List.iter generalize_parents !roots;
Hashtbl.iter
(fun _ (ty, _) ->
if ty.level <> generic_level then set_level ty !current_level)
graph
(* Compute statically the free univars of all nodes in a type *)
(* This avoids doing it repeatedly during instantiation *)
type inv_type_expr =
{ inv_type : type_expr;
mutable inv_parents : inv_type_expr list }
let rec inv_type hash pty ty =
let ty = repr ty in
try
let inv = TypeHash.find hash ty in
inv.inv_parents <- pty @ inv.inv_parents
with Not_found ->
let inv = { inv_type = ty; inv_parents = pty } in
TypeHash.add hash ty inv;
iter_type_expr (inv_type hash [inv]) ty
let compute_univars ty =
let inverted = TypeHash.create 17 in
inv_type inverted [] ty;
let node_univars = TypeHash.create 17 in
let rec add_univar univ inv =
match inv.inv_type.desc with
Tpoly (_ty, tl) when List.memq univ (List.map repr tl) -> ()
| _ ->
try
let univs = TypeHash.find node_univars inv.inv_type in
if not (TypeSet.mem univ !univs) then begin
univs := TypeSet.add univ !univs;
List.iter (add_univar univ) inv.inv_parents
end
with Not_found ->
TypeHash.add node_univars inv.inv_type (ref(TypeSet.singleton univ));
List.iter (add_univar univ) inv.inv_parents
in
TypeHash.iter (fun ty inv -> if is_Tunivar ty then add_univar ty inv)
inverted;
fun ty ->
try !(TypeHash.find node_univars ty) with Not_found -> TypeSet.empty
(*******************)
(* Instantiation *)
(*******************)
let rec find_repr p1 =
function
Mnil ->
None
| Mcons (Public, p2, ty, _, _) when Path.same p1 p2 ->
Some ty
| Mcons (_, _, _, _, rem) ->
find_repr p1 rem
| Mlink {contents = rem} ->
find_repr p1 rem
(*
Generic nodes are duplicated, while non-generic nodes are left
as-is.
During instantiation, the description of a generic node is first
replaced by a link to a stub ([Tsubst (newvar ())]). Once the
copy is made, it replaces the stub.
After instantiation, the description of generic node, which was
stored by [save_desc], must be put back, using [cleanup_types].
*)
let abbreviations = ref (ref Mnil)
(* Abbreviation memorized. *)
(* partial: we may not wish to copy the non generic types
before we call type_pat *)
let rec copy ?env ?partial ?keep_names ty =
let copy = copy ?env ?partial ?keep_names in
let ty = repr ty in
match ty.desc with
Tsubst ty -> ty
| _ ->
if ty.level <> generic_level && partial = None then ty else
(* We only forget types that are non generic and do not contain
free univars *)
let forget =
if ty.level = generic_level then generic_level else
match partial with
None -> assert false
| Some (free_univars, keep) ->
if TypeSet.is_empty (free_univars ty) then
if keep then ty.level else !current_level
else generic_level
in
if forget <> generic_level then newty2 forget (Tvar None) else
let desc = ty.desc in
save_desc ty desc;
let t = newvar() in (* Stub *)
begin match env with
Some env when Env.has_local_constraints env ->
begin match Env.gadt_instance_level env ty with
Some lv -> Env.add_gadt_instances env lv [t]
| None -> ()
end
| _ -> ()
end;
ty.desc <- Tsubst t;
t.desc <-
begin match desc with
| Tconstr (p, tl, _) ->
let abbrevs = proper_abbrevs p tl !abbreviations in
begin match find_repr p !abbrevs with
Some ty when repr ty != t ->
Tlink ty
| _ ->
(*
One must allocate a new reference, so that abbrevia-
tions belonging to different branches of a type are
independent.
Moreover, a reference containing a [Mcons] must be
shared, so that the memorized expansion of an abbrevi-
ation can be released by changing the content of just
one reference.
*)
Tconstr (p, List.map copy tl,
ref (match !(!abbreviations) with
Mcons _ -> Mlink !abbreviations
| abbrev -> abbrev))
end
| Tvariant row0 ->
let row = row_repr row0 in
let more = repr row.row_more in
(* We must substitute in a subtle way *)
(* Tsubst takes a tuple containing the row var and the variant *)
begin match more.desc with
Tsubst {desc = Ttuple [_;ty2]} ->
(* This variant type has been already copied *)
ty.desc <- Tsubst ty2; (* avoid Tlink in the new type *)
Tlink ty2
| _ ->
(* If the row variable is not generic, we must keep it *)
let keep = more.level <> generic_level in
let more' =
match more.desc with
Tsubst ty -> ty
| Tconstr _ | Tnil ->
if keep then save_desc more more.desc;
copy more
| Tvar _ | Tunivar _ ->
save_desc more more.desc;
if keep then more else newty more.desc
| _ -> assert false
in
let row =
match repr more' with (* PR#6163 *)
{desc=Tconstr _} when not row.row_fixed ->
{row with row_fixed = true}
| _ -> row
in
(* Open row if partial for pattern and contains Reither *)
let more', row =
match partial with
Some (free_univars, false) ->
let more' =
if more.id != more'.id then more' else
let lv = if keep then more.level else !current_level in
newty2 lv (Tvar None)
in
let not_reither (_, f) =
match row_field_repr f with
Reither _ -> false
| _ -> true
in
if row.row_closed && not row.row_fixed
&& TypeSet.is_empty (free_univars ty)
&& not (List.for_all not_reither row.row_fields) then
(more',
{row_fields = Ext_list.filter row.row_fields not_reither;
row_more = more'; row_bound = ();
row_closed = false; row_fixed = false; row_name = None})
else (more', row)
| _ -> (more', row)
in
(* Register new type first for recursion *)
more.desc <- Tsubst(newgenty(Ttuple[more';t]));
(* Return a new copy *)
Tvariant (copy_row copy true row keep more')
end
| Tfield (_p, k, _ty1, ty2) ->
begin match field_kind_repr k with
Fabsent -> Tlink (copy ty2)
| Fpresent -> copy_type_desc copy desc
| Fvar r ->
dup_kind r;
copy_type_desc copy desc
end
| Tobject (ty1, _) when partial <> None ->
Tobject (copy ty1, ref None)
| _ -> copy_type_desc ?keep_names copy desc
end;
t
let simple_copy t = copy t
(**** Variants of instantiations ****)
let gadt_env env =