summaryrefslogtreecommitdiff
path: root/typing/ctype.ml
diff options
context:
space:
mode:
Diffstat (limited to 'typing/ctype.ml')
-rw-r--r--typing/ctype.ml221
1 files changed, 137 insertions, 84 deletions
diff --git a/typing/ctype.ml b/typing/ctype.ml
index 645f9890c7..69061e5f1c 100644
--- a/typing/ctype.ml
+++ b/typing/ctype.ml
@@ -101,7 +101,6 @@ let current_level = ref 0
let nongen_level = ref 0
let global_level = ref 1
let saved_level = ref []
-let saved_global_level = ref []
let init_def level = current_level := level; nongen_level := level
let begin_def () =
@@ -119,8 +118,7 @@ let end_def () =
current_level := cl; nongen_level := nl
let reset_global_level () =
- global_level := !current_level + 1;
- saved_global_level := []
+ global_level := !current_level + 1
let increase_global_level () =
let gl = !global_level in
global_level := !current_level;
@@ -322,17 +320,21 @@ let rec class_type_arity =
let sort_row_fields = Sort.list (fun (p,_) (q,_) -> p < q)
+let rec merge_rf r1 r2 pairs fi1 fi2 =
+ 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 fi2 =
- let rec merge r1 r2 pairs fi1 fi2 =
- match fi1, fi2 with
- (l1,f1 as p1)::fi1', (l2,f2 as p2)::fi2' ->
- if l1 = l2 then merge r1 r2 ((l1,f1,f2)::pairs) fi1' fi2' else
- if l1 < l2 then merge (p1::r1) r2 pairs fi1' fi2 else
- merge r1 (p2::r2) pairs fi1 fi2'
- | [], _ -> (List.rev r1, List.rev_append r2 fi2, pairs)
- | _, [] -> (List.rev_append r1 fi1, List.rev r2, pairs)
- in
- merge [] [] [] (sort_row_fields fi1) (sort_row_fields fi2)
+ 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
[] -> []
@@ -364,7 +366,7 @@ let rec closed_schema_rec ty =
closed_schema_rec t2
| Tvariant row ->
let row = row_repr row in
- iter_row closed_schema_rec {row with row_bound = []};
+ iter_row closed_schema_rec row;
if not (static_row row) then closed_schema_rec row.row_more
| _ ->
iter_type_expr closed_schema_rec ty
@@ -401,7 +403,7 @@ let rec free_vars_rec real ty =
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 with row_bound = []};
+ 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
@@ -439,9 +441,9 @@ let closed_type_decl decl =
begin match decl.type_kind with
Type_abstract ->
()
- | Type_variant(v, priv) ->
+ | Type_variant v ->
List.iter (fun (_, tyl) -> List.iter closed_type tyl) v
- | Type_record(r, rep, priv) ->
+ | Type_record(r, rep) ->
List.iter (fun (_, _, ty) -> closed_type ty) r
end;
begin match decl.type_manifest with
@@ -575,7 +577,7 @@ let rec generalize_spine ty =
generalize_spine ty'
| _ -> ()
-let try_expand_once' = (* Forward declaration *)
+let forward_try_expand_once = (* Forward declaration *)
ref (fun env ty -> raise Cannot_expand)
(*
@@ -597,7 +599,7 @@ let rec update_level env level ty =
Tconstr(p, tl, abbrev) when level < Path.binding_time p ->
(* Try first to replace an abbreviation by its expansion. *)
begin try
- link_type ty (!try_expand_once' env ty);
+ link_type ty (!forward_try_expand_once env ty);
update_level env level ty
with Cannot_expand ->
(* +++ Levels should be restored... *)
@@ -733,9 +735,9 @@ let rec find_repr p1 =
function
Mnil ->
None
- | Mcons (p2, ty, _, _) when Path.same p1 p2 ->
+ | Mcons (Public, p2, ty, _, _) when Path.same p1 p2 ->
Some ty
- | Mcons (_, _, _, rem) ->
+ | Mcons (_, _, _, _, rem) ->
find_repr p1 rem
| Mlink {contents = rem} ->
find_repr p1 rem
@@ -1007,7 +1009,7 @@ let instance_label fixed lbl =
let unify' = (* Forward declaration *)
ref (fun env ty1 ty2 -> raise (Unify []))
-let rec subst env level abbrev ty params args body =
+let rec subst env level priv abbrev ty params args body =
if List.length params <> List.length args then raise (Unify []);
let old_level = !current_level in
current_level := level;
@@ -1017,7 +1019,7 @@ let rec subst env level abbrev ty params args body =
None -> ()
| Some ({desc = Tconstr (path, tl, _)} as ty) ->
let abbrev = proper_abbrevs path tl abbrev in
- memorize_abbrev abbrev path ty body0
+ memorize_abbrev abbrev priv path ty body0
| _ ->
assert false
end;
@@ -1040,7 +1042,7 @@ let rec subst env level abbrev ty params args body =
*)
let apply env params body args =
try
- subst env generic_level (ref Mnil) None params args body
+ subst env generic_level Public (ref Mnil) None params args body
with
Unify _ -> raise Cannot_apply
@@ -1056,8 +1058,10 @@ let apply env params body args =
type or module definition is overriden in the environnement.
*)
let previous_env = ref Env.empty
+let string_of_kind = function Public -> "public" | Private -> "private"
let check_abbrev_env env =
if env != !previous_env then begin
+ (* prerr_endline "cleanup expansion cache"; *)
cleanup_abbrev ();
previous_env := env
end
@@ -1080,13 +1084,15 @@ let check_abbrev_env env =
4. The expansion requires the expansion of another abbreviation,
and this other expansion fails.
*)
-let expand_abbrev env ty =
+let expand_abbrev_gen kind find_type_expansion env ty =
check_abbrev_env env;
match ty with
{desc = Tconstr (path, args, abbrev); level = level} ->
let lookup_abbrev = proper_abbrevs path args abbrev in
- begin match find_expans path !lookup_abbrev with
+ begin match find_expans kind path !lookup_abbrev with
Some ty ->
+ (* prerr_endline
+ ("found a "^string_of_kind kind^" expansion for "^Path.name path);*)
if level <> generic_level then
begin try
update_level env level ty
@@ -1099,10 +1105,12 @@ let expand_abbrev env ty =
ty
| None ->
let (params, body) =
- try Env.find_type_expansion path env with Not_found ->
+ try find_type_expansion path env with Not_found ->
raise Cannot_expand
in
- let ty' = subst env level abbrev (Some ty) params args body in
+ (* prerr_endline
+ ("add a "^string_of_kind kind^" expansion for "^Path.name path);*)
+ let ty' = subst env level kind abbrev (Some ty) params args body in
(* Hack to name the variant type *)
begin match repr ty' with
{desc=Tvariant row} as ty when static_row row ->
@@ -1114,6 +1122,8 @@ let expand_abbrev env ty =
| _ ->
assert false
+let expand_abbrev = expand_abbrev_gen Public Env.find_type_expansion
+
let safe_abbrev env ty =
let snap = Btype.snapshot () in
try ignore (expand_abbrev env ty); true
@@ -1127,7 +1137,7 @@ let try_expand_once env ty =
Tconstr _ -> repr (expand_abbrev env ty)
| _ -> raise Cannot_expand
-let _ = try_expand_once' := try_expand_once
+let _ = forward_try_expand_once := try_expand_once
(* Fully expand the head of a type.
Raise Cannot_expand if the type cannot be expanded.
@@ -1155,6 +1165,36 @@ let expand_head env ty =
Btype.backtrack snap;
repr ty
+(* Implementing function [expand_head_opt], the compiler's own version of
+ [expand_head] used for type-based optimisations.
+ [expand_head_opt] uses [Env.find_type_expansion_opt] to access the
+ manifest type information of private abstract data types which is
+ normally hidden to the type-checker out of the implementation module of
+ the private abbreviation. *)
+
+let expand_abbrev_opt = expand_abbrev_gen Private Env.find_type_expansion_opt
+
+let try_expand_once_opt env ty =
+ let ty = repr ty in
+ match ty.desc with
+ Tconstr _ -> repr (expand_abbrev_opt env ty)
+ | _ -> raise Cannot_expand
+
+let rec try_expand_head_opt env ty =
+ let ty' = try_expand_once_opt env ty in
+ begin try
+ try_expand_head_opt env ty'
+ with Cannot_expand ->
+ ty'
+ end
+
+let expand_head_opt env ty =
+ let snap = Btype.snapshot () in
+ try try_expand_head_opt env ty
+ with Cannot_expand | Unify _ -> (* expand_head shall never fail *)
+ Btype.backtrack snap;
+ repr ty
+
(* Make sure that the type parameters of the type constructor [ty]
respect the type constraints *)
let enforce_constraints env ty =
@@ -1162,7 +1202,8 @@ let enforce_constraints env ty =
{desc = Tconstr (path, args, abbrev); level = level} ->
let decl = Env.find_type path env in
ignore
- (subst env level (ref Mnil) None decl.type_params args (newvar2 level))
+ (subst env level Public (ref Mnil) None decl.type_params args
+ (newvar2 level))
| _ ->
assert false
@@ -1208,7 +1249,7 @@ let rec non_recursive_abbrev env ty0 ty =
match ty.desc with
Tconstr(p, args, abbrev) ->
begin try
- non_recursive_abbrev env ty0 (try_expand_head env ty)
+ non_recursive_abbrev env ty0 (try_expand_once env ty)
with Cannot_expand ->
if !Clflags.recursive_types then () else
iter_type_expr (non_recursive_abbrev env ty0) ty
@@ -1224,11 +1265,11 @@ let correct_abbrev env path params ty =
check_abbrev_env env;
let ty0 = newgenvar () in
visited := [];
- let abbrev = Mcons (path, ty0, ty0, Mnil) in
+ let abbrev = Mcons (Public, path, ty0, ty0, Mnil) in
simple_abbrevs := abbrev;
try
non_recursive_abbrev env ty0
- (subst env generic_level (ref abbrev) None [] [] ty);
+ (subst env generic_level Public (ref abbrev) None [] [] ty);
simple_abbrevs := Mnil;
visited := []
with exn ->
@@ -1424,7 +1465,7 @@ let univar_pairs = ref []
let rec has_cached_expansion p abbrev =
match abbrev with
Mnil -> false
- | Mcons(p', _, _, rem) -> Path.same p p' || has_cached_expansion p rem
+ | Mcons(_, p', _, _, rem) -> Path.same p p' || has_cached_expansion p rem
| Mlink rem -> has_cached_expansion p !rem
(**** Transform error trace ****)
@@ -1441,7 +1482,7 @@ let mkvariant fields closed =
newgenty
(Tvariant
{row_fields = fields; row_closed = closed; row_more = newvar();
- row_bound = []; row_fixed = false; row_name = None })
+ row_bound = (); row_fixed = false; row_name = None })
(**** Unification ****)
@@ -1745,8 +1786,7 @@ and unify_row env row1 row2 =
then row2.row_name
else None
in
- let bound = row1.row_bound @ row2.row_bound in
- let row0 = {row_fields = []; row_more = more; row_bound = bound;
+ let row0 = {row_fields = []; row_more = more; row_bound = ();
row_closed = closed; row_fixed = fixed; row_name = name} in
let set_more row rest =
let rest =
@@ -1999,6 +2039,10 @@ let moregen_occur env level ty =
occur_univar env ty;
update_level env level ty
+let may_instantiate inst_nongen t1 =
+ if inst_nongen then t1.level <> generic_level - 1
+ else t1.level = generic_level
+
let rec moregen inst_nongen type_pairs env t1 t2 =
if t1 == t2 then () else
let t1 = repr t1 in
@@ -2009,8 +2053,7 @@ let rec moregen inst_nongen type_pairs env t1 t2 =
match (t1.desc, t2.desc) with
(Tunivar, Tunivar) ->
unify_univar t1 t2 !univar_pairs
- | (Tvar, _) when if inst_nongen then t1.level <> generic_level - 1
- else t1.level = generic_level ->
+ | (Tvar, _) when may_instantiate inst_nongen t1 ->
moregen_occur env t1.level t2;
occur env t1 t2;
link_type t1 t2
@@ -2027,8 +2070,7 @@ let rec moregen inst_nongen type_pairs env t1 t2 =
with Not_found ->
TypePairs.add type_pairs (t1', t2') ();
match (t1'.desc, t2'.desc) with
- (Tvar, _) when if inst_nongen then t1'.level <> generic_level - 1
- else t1'.level = generic_level ->
+ (Tvar, _) when may_instantiate inst_nongen t1 ->
moregen_occur env t1'.level t2;
link_type t1' t2
| (Tarrow (l1, t1, u1, _), Tarrow (l2, t2, u2, _)) when l1 = l2
@@ -2090,33 +2132,36 @@ and moregen_kind k1 k2 =
and moregen_row inst_nongen type_pairs env row1 row2 =
let row1 = row_repr row1 and row2 = row_repr row2 in
+ let rm1 = repr row1.row_more and rm2 = repr row2.row_more in
+ if rm1 == rm2 then () else
+ let may_inst = rm1.desc = Tvar && may_instantiate inst_nongen rm1 in
let r1, r2, pairs = merge_row_fields row1.row_fields row2.row_fields in
let r1, r2 =
if row2.row_closed then
- filter_row_fields true r1, filter_row_fields false r2
+ filter_row_fields may_inst r1, filter_row_fields false r2
else r1, r2
in
if r1 <> [] || row1.row_closed && (not row2.row_closed || r2 <> [])
then raise (Unify []);
- let rm1 = repr row1.row_more and rm2 = repr row2.row_more in
- let univ =
- match rm1.desc, rm2.desc with
- Tunivar, Tunivar ->
- unify_univar rm1 rm2 !univar_pairs;
- true
- | Tunivar, _ | _, Tunivar ->
- raise (Unify [])
- | _ ->
- if not (static_row row2) then moregen_occur env rm1.level rm2;
- let ext =
- if r2 = [] then rm2 else
- let row_ext = {row2 with row_fields = r2} in
- iter_row (moregen_occur env rm1.level) row_ext;
- newty2 rm1.level (Tvariant row_ext)
- in
- if ext != rm1 then link_type rm1 ext;
- false
- in
+ begin match rm1.desc, rm2.desc with
+ Tunivar, Tunivar ->
+ unify_univar rm1 rm2 !univar_pairs
+ | Tunivar, _ | _, Tunivar ->
+ raise (Unify [])
+ | _ when static_row row1 -> ()
+ | _ when may_inst ->
+ if not (static_row row2) then moregen_occur env rm1.level rm2;
+ let ext =
+ if r2 = [] then rm2 else
+ let row_ext = {row2 with row_fields = r2} in
+ iter_row (moregen_occur env rm1.level) row_ext;
+ newty2 rm1.level (Tvariant row_ext)
+ in
+ link_type rm1 ext
+ | Tconstr _, Tconstr _ ->
+ moregen inst_nongen type_pairs env rm1 rm2
+ | _ -> raise (Unify [])
+ end;
List.iter
(fun (l,f1,f2) ->
let f1 = row_field_repr f1 and f2 = row_field_repr f2 in
@@ -2125,7 +2170,7 @@ and moregen_row inst_nongen type_pairs env row1 row2 =
Rpresent(Some t1), Rpresent(Some t2) ->
moregen inst_nongen type_pairs env t1 t2
| Rpresent None, Rpresent None -> ()
- | Reither(false, tl1, _, e1), Rpresent(Some t2) when not univ ->
+ | Reither(false, tl1, _, e1), Rpresent(Some t2) when may_inst ->
set_row_field e1 f2;
List.iter (fun t1 -> moregen inst_nongen type_pairs env t1 t2) tl1
| Reither(c1, tl1, _, e1), Reither(c2, tl2, m2, e2) ->
@@ -2141,9 +2186,9 @@ and moregen_row inst_nongen type_pairs env row1 row2 =
| [] ->
if tl1 <> [] then raise (Unify [])
end
- | Reither(true, [], _, e1), Rpresent None when not univ ->
+ | Reither(true, [], _, e1), Rpresent None when may_inst ->
set_row_field e1 f2
- | Reither(_, _, _, e1), Rabsent when not univ ->
+ | Reither(_, _, _, e1), Rabsent when may_inst ->
set_row_field e1 f2
| Rabsent, Rabsent -> ()
| _ -> raise (Unify []))
@@ -2780,7 +2825,8 @@ let rec build_subtype env visited loops posi level t =
Tobject _ when posi && not (opened_object t') ->
let cl_abbr, body = find_cltype_for_path env p in
let ty =
- subst env !current_level abbrev None cl_abbr.type_params tl body in
+ subst env !current_level Public abbrev None
+ cl_abbr.type_params tl body in
let ty = repr ty in
let ty1, tl1 =
match ty.desc with
@@ -2839,7 +2885,6 @@ let rec build_subtype env visited loops posi level t =
let level' = pred_enlarge level in
let visited =
t :: if level' < level then [] else filter_visited visited in
- let bound = ref row.row_bound in
let fields = filter_row_fields false row.row_fields in
let fields =
List.map
@@ -2851,18 +2896,18 @@ let rec build_subtype env visited loops posi level t =
orig, Unchanged
| Rpresent(Some t) ->
let (t', c) = build_subtype env visited loops posi level' t in
- if posi && level > 0 then begin
- bound := t' :: !bound;
- (l, Reither(false, [t'], false, ref None)), c
- end else
- (l, Rpresent(Some t')), c
+ let f =
+ if posi && level > 0
+ then Reither(false, [t'], false, ref None)
+ else Rpresent(Some t')
+ in (l, f), c
| _ -> assert false)
fields
in
let c = collect fields in
let row =
{ row_fields = List.map fst fields; row_more = newvar();
- row_bound = !bound; row_closed = posi; row_fixed = false;
+ row_bound = (); row_closed = posi; row_fixed = false;
row_name = if c > Unchanged then None else row.row_name }
in
(newty (Tvariant row), Changed)
@@ -2925,6 +2970,12 @@ let subtypes = TypePairs.create 17
let subtype_error env trace =
raise (Subtype (expand_trace env (List.rev trace), []))
+let private_abbrev env path =
+ try
+ let decl = Env.find_type path env in
+ decl.type_private = Private && decl.type_manifest <> None
+ with Not_found -> false
+
let rec subtype_rec env trace t1 t2 cstrs =
let t1 = repr t1 in
let t2 = repr t2 in
@@ -2969,6 +3020,8 @@ let rec subtype_rec env trace t1 t2 cstrs =
with Not_found ->
(trace, t1, t2, !univar_pairs)::cstrs
end
+ | (Tconstr(p1, tl1, _), _) when private_abbrev env p1 ->
+ subtype_rec env trace (expand_abbrev_opt env t1) t2 cstrs
| (Tobject (f1, _), Tobject (f2, _))
when (object_row f1).desc = Tvar && (object_row f2).desc = Tvar ->
(* Same row variable implies same object. *)
@@ -2983,6 +3036,9 @@ let rec subtype_rec env trace t1 t2 cstrs =
end
| (Tpoly (u1, []), Tpoly (u2, [])) ->
subtype_rec env trace u1 u2 cstrs
+ | (Tpoly (u1, tl1), Tpoly (u2, [])) ->
+ let _, u1' = instance_poly false tl1 u1 in
+ subtype_rec env trace u1' u2 cstrs
| (Tpoly (u1, tl1), Tpoly (u2,tl2)) ->
begin try
enter_poly env univar_pairs u1 tl1 u2 tl2
@@ -3176,13 +3232,9 @@ let rec normalize_type_rec env ty =
row.row_fields in
let fields =
List.sort (fun (p,_) (q,_) -> compare p q)
- (List.filter (fun (_,fi) -> fi <> Rabsent) fields)
- and bound = List.fold_left
- (fun tyl ty -> if List.memq ty tyl then tyl else ty :: tyl)
- [] (List.map repr row.row_bound)
- in
+ (List.filter (fun (_,fi) -> fi <> Rabsent) fields) in
log_type ty;
- ty.desc <- Tvariant {row with row_fields = fields; row_bound = bound}
+ ty.desc <- Tvariant {row with row_fields = fields}
| Tobject (fi, nm) ->
begin match !nm with
| None -> ()
@@ -3312,16 +3364,16 @@ let nondep_type_decl env mid id is_covariant decl =
match decl.type_kind with
Type_abstract ->
Type_abstract
- | Type_variant(cstrs, priv) ->
+ | Type_variant cstrs ->
Type_variant(List.map
(fun (c, tl) -> (c, List.map (nondep_type_rec env mid) tl))
- cstrs, priv)
- | Type_record(lbls, rep, priv) ->
+ cstrs)
+ | Type_record(lbls, rep) ->
Type_record(
List.map
(fun (c, mut, t) -> (c, mut, nondep_type_rec env mid t))
lbls,
- rep, priv)
+ rep)
with Not_found when is_covariant ->
Type_abstract
end;
@@ -3334,6 +3386,7 @@ let nondep_type_decl env mid id is_covariant decl =
with Not_found when is_covariant ->
None
end;
+ type_private = decl.type_private;
type_variance = decl.type_variance;
}
in
@@ -3341,9 +3394,9 @@ let nondep_type_decl env mid id is_covariant decl =
List.iter unmark_type decl.type_params;
begin match decl.type_kind with
Type_abstract -> ()
- | Type_variant(cstrs, priv) ->
+ | Type_variant cstrs ->
List.iter (fun (c, tl) -> List.iter unmark_type tl) cstrs
- | Type_record(lbls, rep, priv) ->
+ | Type_record(lbls, rep) ->
List.iter (fun (c, mut, t) -> unmark_type t) lbls
end;
begin match decl.type_manifest with