Fix PR#5663: program rejected due to nongeneralizable type variable that appears nowhere

git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@16029 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
master
Jacques Garrigue 2015-04-22 07:12:49 +00:00
parent 8bd234ffab
commit ebbf345d29
5 changed files with 59 additions and 47 deletions

View File

@ -76,6 +76,9 @@ Bug fixes:
(Nicolas Braud-Santoni, report by Eric Cooper)
- PR#4832: Filling bigarrays may block out runtime
(Markus Mottl)
- PR#5663: program rejected due to nongeneralizable type variable that
appears nowhere
(Jacques Garrigue, report by Stephen Weeks)
- PR#5887: move the byterun/*.h headers to byterun/caml/*.h to avoid header
name clashes
(Jérôme Vouillon and Adrien Nader and Peter Zotov)

View File

@ -454,38 +454,6 @@ let rec filter_row_fields erase = function
(**************************************)
exception Non_closed0
let rec closed_schema_rec ty =
let ty = repr ty in
if ty.level >= lowest_level then begin
let level = ty.level in
ty.level <- pivot_level - level;
match ty.desc with
Tvar _ when level <> generic_level ->
raise Non_closed0
| Tfield(_, kind, t1, t2) ->
if field_kind_repr kind = Fpresent then
closed_schema_rec t1;
closed_schema_rec t2
| Tvariant row ->
let row = row_repr row in
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
end
(* Return whether all variables of type [ty] are generic. *)
let closed_schema ty =
try
closed_schema_rec ty;
unmark_type ty;
true
with Non_closed0 ->
unmark_type ty;
false
exception Non_closed of type_expr * bool
let free_variables = ref []
@ -4205,6 +4173,40 @@ let cyclic_abbrev env id ty =
false
in check_cycle [] ty
(* Check for non-generalizable type variables *)
exception Non_closed0
let visited = ref TypeSet.empty
let rec closed_schema_rec env ty =
let ty = expand_head env ty in
if TypeSet.mem ty !visited then () else begin
visited := TypeSet.add ty !visited;
match ty.desc with
Tvar _ when ty.level <> generic_level ->
raise Non_closed0
| Tfield(_, kind, t1, t2) ->
if field_kind_repr kind = Fpresent then
closed_schema_rec env t1;
closed_schema_rec env t2
| Tvariant row ->
let row = row_repr row in
iter_row (closed_schema_rec env) row;
if not (static_row row) then closed_schema_rec env row.row_more
| _ ->
iter_type_expr (closed_schema_rec env) ty
end
(* Return whether all variables of type [ty] are generic. *)
let closed_schema env ty =
visited := TypeSet.empty;
try
closed_schema_rec env ty;
visited := TypeSet.empty;
true
with Non_closed0 ->
visited := TypeSet.empty;
false
(* Normalize a type before printing, saving... *)
(* Cannot use mark_type because deep_occur uses it too *)
let rec normalize_type_rec env visited ty =

View File

@ -245,7 +245,7 @@ val cyclic_abbrev: Env.t -> Ident.t -> type_expr -> bool
val is_contractive: Env.t -> type_expr -> bool
val normalize_type: Env.t -> type_expr -> unit
val closed_schema: type_expr -> bool
val closed_schema: Env.t -> type_expr -> bool
(* Check whether the given type scheme contains no non-generic
type variables *)

View File

@ -153,23 +153,26 @@ let rec abbreviate_class_type path params cty =
| Cty_arrow (l, ty, cty) ->
Cty_arrow (l, ty, abbreviate_class_type path params cty)
(* Check that all type variables are generalizable *)
(* Use Env.empty to prevent expansion of recursively defined object types;
cf. typing-poly/poly.ml *)
let rec closed_class_type =
function
Cty_constr (_, params, _) ->
List.for_all Ctype.closed_schema params
List.for_all (Ctype.closed_schema Env.empty) params
| Cty_signature sign ->
Ctype.closed_schema sign.csig_self
Ctype.closed_schema Env.empty sign.csig_self
&&
Vars.fold (fun _ (_, _, ty) cc -> Ctype.closed_schema ty && cc)
Vars.fold (fun _ (_, _, ty) cc -> Ctype.closed_schema Env.empty ty && cc)
sign.csig_vars
true
| Cty_arrow (_, ty, cty) ->
Ctype.closed_schema ty
Ctype.closed_schema Env.empty ty
&&
closed_class_type cty
let closed_class cty =
List.for_all Ctype.closed_schema cty.cty_params
List.for_all (Ctype.closed_schema Env.empty) cty.cty_params
&&
closed_class_type cty.cty_type

View File

@ -845,15 +845,19 @@ let rec path_of_module mexp =
(* Check that all core type schemes in a structure are closed *)
let rec closed_modtype = function
let rec closed_modtype env = function
Mty_ident p -> true
| Mty_alias p -> true
| Mty_signature sg -> List.for_all closed_signature_item sg
| Mty_functor(id, param, body) -> closed_modtype body
| Mty_signature sg ->
let env = Env.add_signature sg env in
List.for_all (closed_signature_item env) sg
| Mty_functor(id, param, body) ->
let env = Env.add_module ~arg:true id (Btype.default_mty param) env in
closed_modtype env body
and closed_signature_item = function
Sig_value(id, desc) -> Ctype.closed_schema desc.val_type
| Sig_module(id, md, _) -> closed_modtype md.md_type
and closed_signature_item env = function
Sig_value(id, desc) -> Ctype.closed_schema env desc.val_type
| Sig_module(id, md, _) -> closed_modtype env md.md_type
| _ -> true
let check_nongen_scheme env str =
@ -861,11 +865,11 @@ let check_nongen_scheme env str =
Tstr_value(rec_flag, pat_exp_list) ->
List.iter
(fun {vb_expr=exp} ->
if not (Ctype.closed_schema exp.exp_type) then
if not (Ctype.closed_schema env exp.exp_type) then
raise(Error(exp.exp_loc, env, Non_generalizable exp.exp_type)))
pat_exp_list
| Tstr_module {mb_expr=md;_} ->
if not (closed_modtype md.mod_type) then
if not (closed_modtype env md.mod_type) then
raise(Error(md.mod_loc, env, Non_generalizable_module md.mod_type))
| _ -> ()
@ -1489,7 +1493,7 @@ let type_module_type_of env smod =
(* PR#6307: expand aliases at root and submodules *)
let mty = Mtype.remove_aliases env mty in
(* PR#5036: must not contain non-generalized type variables *)
if not (closed_modtype mty) then
if not (closed_modtype env mty) then
raise(Error(smod.pmod_loc, env, Non_generalizable_module mty));
tmty, mty