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-0dff7051ff02master
parent
8bd234ffab
commit
ebbf345d29
3
Changes
3
Changes
|
@ -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)
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 *)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue