ocaml/typing/btype.ml

177 lines
5.2 KiB
OCaml

(***********************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* Xavier Leroy and Jerome Vouillon, projet Cristal, INRIA Rocquencourt*)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
(***********************************************************************)
(* $Id$ *)
(* Basic operations on core types *)
open Types
(**** Type level management ****)
let generic_level = 100000000
(* Used to mark a type during a traversal. *)
let lowest_level = 0
let pivot_level = 2 * lowest_level - 1
(* pivot_level - lowest_level < lowest_level *)
(**** Some type creators ****)
let new_id = ref (-1)
let newty2 level desc =
incr new_id; { desc = desc; level = level; id = !new_id }
let newgenty desc = newty2 generic_level desc
let newgenvar () = newgenty Tvar
let newmarkedvar level =
incr new_id; { desc = Tvar; level = pivot_level - level; id = !new_id }
let newmarkedgenvar () =
incr new_id;
{ desc = Tvar; level = pivot_level - generic_level; id = !new_id }
(**** Representative of a type ****)
let rec field_kind_repr =
function
Fvar {contents = Some kind} -> field_kind_repr kind
| kind -> kind
let rec repr =
function
{desc = Tlink t'} ->
(*
We do no path compression. Path compression does not seem to
improve notably efficiency, and it prevents from changing a
[Tlink] into another type (for instance, for undoing a
unification).
*)
repr t'
| {desc = Tfield (_, k, _, t')} when field_kind_repr k = Fabsent ->
repr t'
| t -> t
(**********************************)
(* Utilities for type traversal *)
(**********************************)
let iter_type_expr f ty =
match ty.desc with
Tvar -> ()
| Tarrow (ty1, ty2) -> f ty1; f ty2
| Ttuple l -> List.iter f l
| Tconstr (_, l, _) -> List.iter f l
| Tobject(ty, {contents = Some (_, p)})
-> f ty; List.iter f p
| Tobject (ty, _) -> f ty
| Tfield (_, _, ty1, ty2) -> f ty1; f ty2
| Tnil -> ()
| Tlink ty -> f ty
let saved_desc = ref []
(* Saved association of generic nodes with their description. *)
let save_desc ty desc =
saved_desc := (ty, desc)::!saved_desc
(* Restored type descriptions. *)
let cleanup_types () =
List.iter (fun (ty, desc) -> ty.desc <- desc) !saved_desc;
saved_desc := []
(* Mark a type. *)
let rec mark_type ty =
let ty = repr ty in
if ty.level >= lowest_level then begin
ty.level <- pivot_level - ty.level;
iter_type_expr mark_type ty
end
let mark_type_node ty =
let ty = repr ty in
if ty.level >= lowest_level then begin
ty.level <- pivot_level - ty.level;
end
let mark_type_params ty =
iter_type_expr mark_type ty
(* Remove marks from a type. *)
let rec unmark_type ty =
let ty = repr ty in
if ty.level < lowest_level then begin
ty.level <- pivot_level - ty.level;
iter_type_expr unmark_type ty
end
let unmark_type_decl decl =
List.iter unmark_type decl.type_params;
begin match decl.type_kind with
Type_abstract -> ()
| Type_variant cstrs ->
List.iter (fun (c, tl) -> List.iter unmark_type tl) cstrs
| Type_record lbls ->
List.iter (fun (c, mut, t) -> unmark_type t) lbls
end;
begin match decl.type_manifest with
None -> ()
| Some ty -> unmark_type ty
end
let unmark_class_signature sign =
unmark_type sign.cty_self;
Vars.iter (fun l (m, t) -> unmark_type t) sign.cty_vars
let rec unmark_class_type =
function
Tcty_constr (p, tyl, cty) ->
List.iter unmark_type tyl; unmark_class_type cty
| Tcty_signature sign ->
unmark_class_signature sign
| Tcty_fun (ty, cty) ->
unmark_type ty; unmark_class_type cty
(*******************************************)
(* Memorization of abbreviation expansion *)
(*******************************************)
let memo = ref []
(* Contains the list of saved abbreviation expansions. *)
let cleanup_abbrev () =
(* Remove all memorized abbreviation expansions. *)
List.iter (fun abbr -> abbr := Mnil) !memo;
memo := []
let memorize_abbrev mem path v v' =
(* Memorize the expansion of an abbreviation. *)
mem := Mcons (path, v, v', !mem);
memo := mem :: !memo
let rec forget_abbrev_rec mem path =
match mem with
Mnil ->
assert false
| Mcons (path', _, _, rem) when Path.same path path' ->
rem
| Mcons (path, v, v', rem) ->
Mcons (path, v, v', forget_abbrev_rec rem path)
| Mlink mem' ->
mem' := forget_abbrev_rec !mem' path;
raise Exit
let forget_abbrev mem path =
try mem := forget_abbrev_rec !mem path with Exit -> ()