summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--typing/ctype.ml72
-rw-r--r--typing/ctype.mli5
-rw-r--r--typing/typedecl.ml40
3 files changed, 83 insertions, 34 deletions
diff --git a/typing/ctype.ml b/typing/ctype.ml
index a9d7cace2..756abff91 100644
--- a/typing/ctype.ml
+++ b/typing/ctype.ml
@@ -1203,38 +1203,40 @@ let rec occur_rec env visited ty0 ty =
Tconstr(p, tl, abbrev) ->
begin try
if List.memq ty visited then raise Occur;
- iter_type_expr (occur_rec env (ty::visited) ty0) ty
- with Occur -> try
- let ty' = try_expand_head env ty in
+ if not !Clflags.recursive_types then
+ iter_type_expr (occur_rec env (ty::visited) ty0) ty
+ with Occur ->
+ if not (generic_abbrev env p) then raise Occur else
+ let ty' = repr (expand_abbrev env ty) in
(* Maybe we could simply make a recursive call here,
but it seems it could make the occur check loop
(see change in rev. 1.58) *)
if ty' == ty0 || List.memq ty' visited then raise Occur;
match ty'.desc with
Tobject _ | Tvariant _ -> ()
- | _ -> iter_type_expr (occur_rec env (ty'::visited) ty0) ty'
- with Cannot_expand ->
- raise Occur
+ | _ ->
+ if not !Clflags.recursive_types then
+ iter_type_expr (occur_rec env (ty'::visited) ty0) ty'
end
| Tobject _ | Tvariant _ ->
()
| _ ->
- iter_type_expr (occur_rec env visited ty0) ty
+ if not !Clflags.recursive_types then
+ iter_type_expr (occur_rec env visited ty0) ty
let type_changed = ref false (* trace possible changes to the studied type *)
let merge r b = if b then r := true
let occur env ty0 ty =
- if not !Clflags.recursive_types then
- let old = !type_changed in
- try
- while type_changed := false; occur_rec env [] ty0 ty; !type_changed
- do () (* prerr_endline "changed" *) done;
- merge type_changed old
- with exn ->
- merge type_changed old;
- raise (match exn with Occur -> Unify [] | _ -> exn)
+ let old = !type_changed in
+ try
+ while type_changed := false; occur_rec env [] ty0 ty; !type_changed
+ do () (* prerr_endline "changed" *) done;
+ merge type_changed old
+ with exn ->
+ merge type_changed old;
+ raise (match exn with Occur -> Unify [] | _ -> exn)
(*****************************)
@@ -2063,6 +2065,44 @@ let moregeneral env inst_nongen pat_sch subj_sch =
res
+(* Alternative approach: "rigidify" a type scheme,
+ and check validity after unification *)
+(* Simpler, no? *)
+
+let rec rigidify_rec vars ty =
+ let ty = repr ty in
+ if ty.level >= lowest_level then begin
+ ty.level <- pivot_level - ty.level;
+ begin match ty.desc with
+ | Tvar ->
+ if not (List.memq ty !vars) then vars := ty :: !vars
+ | Tvariant row ->
+ let row = row_repr row in
+ let more = repr row.row_more in
+ if more.desc = Tvar && not row.row_fixed then
+ let more' = newty2 more.level Tvar in
+ let row' = {row with row_fixed=true; row_fields=[]; row_more=more'}
+ in link_type more (newty2 ty.level (Tvariant row'))
+ | _ -> ()
+ end;
+ iter_type_expr (rigidify_rec vars) ty
+ end
+
+let rigidify ty =
+ let vars = ref [] in
+ rigidify_rec vars ty;
+ unmark_type ty;
+ !vars
+
+let all_distinct_vars vars =
+ let tyl = ref [] in
+ List.for_all
+ (fun ty ->
+ let ty = repr ty in
+ if List.memq ty !tyl then false else
+ (tyl := ty :: !tyl; ty.desc = Tvar))
+ vars
+
(*********************************************)
(* Equivalence between parameterized types *)
(*********************************************)
diff --git a/typing/ctype.mli b/typing/ctype.mli
index c7c93e109..158dd2498 100644
--- a/typing/ctype.mli
+++ b/typing/ctype.mli
@@ -150,6 +150,11 @@ val filter_self_method:
type_expr -> Ident.t * type_expr
val moregeneral: Env.t -> bool -> type_expr -> type_expr -> bool
(* Check if the first type scheme is more general than the second. *)
+val rigidify: type_expr -> type_expr list
+ (* "Rigidify" a type and return its type variable *)
+val all_distinct_vars: type_expr list -> bool
+ (* Check those type are all distinct type variables *)
+
type class_match_failure =
CM_Virtual_class
| CM_Parameter_arity_mismatch of int * int
diff --git a/typing/typedecl.ml b/typing/typedecl.ml
index f7278ea4a..4e9081d99 100644
--- a/typing/typedecl.ml
+++ b/typing/typedecl.ml
@@ -193,32 +193,36 @@ module TypeSet =
let compare t1 t2 = t1.id - t2.id
end)
-let rec check_constraints_rec env newenv loc visited ty =
+let rec check_constraints_rec env loc visited ty =
let ty = Ctype.repr ty in
if TypeSet.mem ty !visited then () else begin
visited := TypeSet.add ty !visited;
match ty.desc with
| Tconstr (path, args, _) ->
- Ctype.begin_def ();
let args' = List.map (fun _ -> Ctype.newvar ()) args in
let ty' = Ctype.newconstr path args' in
- begin try Ctype.enforce_constraints newenv ty'
+ begin try Ctype.enforce_constraints env ty'
with Ctype.Unify _ -> assert false
| Not_found -> raise (Error(loc, Unavailable_type_constructor path))
end;
- Ctype.end_def ();
- Ctype.generalize ty';
- if not (List.for_all2 (Ctype.moregeneral env false) args' args) then
- raise (Error(loc, Constraint_failed (ty, ty')));
- List.iter (check_constraints_rec env newenv loc visited) args
+ let snap = Btype.snapshot () in
+ let vars = Ctype.rigidify ty in
+ begin try
+ Ctype.unify env ty ty';
+ if not (Ctype.all_distinct_vars vars) then raise (Ctype.Unify[])
+ with Ctype.Unify _ ->
+ raise (Error(loc, Constraint_failed (ty, ty')))
+ end;
+ Btype.backtrack snap;
+ List.iter (check_constraints_rec env loc visited) args
| Tpoly (ty, tl) ->
let _, ty = Ctype.instance_poly false tl ty in
- check_constraints_rec env newenv loc visited ty
+ check_constraints_rec env loc visited ty
| _ ->
- Btype.iter_type_expr (check_constraints_rec env newenv loc visited) ty
+ Btype.iter_type_expr (check_constraints_rec env loc visited) ty
end
-let check_constraints env newenv (_, sdecl) (_, decl) =
+let check_constraints env (_, sdecl) (_, decl) =
let visited = ref TypeSet.empty in
let rec check = function
| Type_abstract -> ()
@@ -234,7 +238,7 @@ let check_constraints env newenv (_, sdecl) (_, decl) =
let styl = try List.assoc name pl with Not_found -> assert false in
List.iter2
(fun sty ty ->
- check_constraints_rec env newenv sty.ptyp_loc visited ty)
+ check_constraints_rec env sty.ptyp_loc visited ty)
styl tyl)
l
| Type_record (l, _) ->
@@ -251,7 +255,7 @@ let check_constraints env newenv (_, sdecl) (_, decl) =
in
List.iter
(fun (name, _, ty) ->
- check_constraints_rec env newenv (get_loc name pl) visited ty)
+ check_constraints_rec env (get_loc name pl) visited ty)
l
| Type_private tkind -> check tkind in
check decl.type_kind;
@@ -261,7 +265,7 @@ let check_constraints env newenv (_, sdecl) (_, decl) =
let sty =
match sdecl.ptype_manifest with Some sty -> sty | _ -> assert false
in
- check_constraints_rec env newenv sty.ptyp_loc visited ty
+ check_constraints_rec env sty.ptyp_loc visited ty
end
(*
@@ -309,8 +313,8 @@ let check_recursive_abbrev env (name, sdecl) (id, decl) =
let rec check_expansion_rec env id args loc id_check_list visited ty =
let ty = Ctype.repr ty in
if List.memq ty visited then () else
- let check_rec =
- check_expansion_rec env id args loc id_check_list (ty :: visited) in
+ let visited = ty :: visited in
+ let check_rec = check_expansion_rec env id args loc id_check_list visited in
match ty.desc with
| Tconstr(Path.Pident id' as path, args', _) ->
if Ident.same id id' then begin
@@ -328,7 +332,7 @@ let rec check_expansion_rec env id args loc id_check_list visited ty =
try List.iter2 (Ctype.unify env) params args'
with Ctype.Unify _ -> assert false
end;
- check_rec body
+ check_expansion_rec env id args loc id_check_list visited body
end
with Not_found -> ()
end;
@@ -527,7 +531,7 @@ let transl_type_decl env name_sdecl_list =
(* Check re-exportation *)
List.iter2 (check_abbrev newenv) name_sdecl_list decls;
(* Check that constraints are enforced *)
- List.iter2 (check_constraints temp_env newenv) name_sdecl_list decls;
+ List.iter2 (check_constraints newenv) name_sdecl_list decls;
(* Check that abbreviations have same parameters *)
let id_loc_list =
List.map2