diff options
-rw-r--r-- | debugger/loadprinter.ml | 15 | ||||
-rw-r--r-- | testsuite/tests/typing-objects/class_2.ml | 15 | ||||
-rw-r--r-- | toplevel/topdirs.ml | 60 | ||||
-rw-r--r-- | typing/ctype.ml | 59 | ||||
-rw-r--r-- | typing/ctype.mli | 41 | ||||
-rw-r--r-- | typing/typeclass.ml | 225 | ||||
-rw-r--r-- | typing/typecore.ml | 1288 | ||||
-rw-r--r-- | typing/typecore.mli | 1 | ||||
-rw-r--r-- | typing/typedecl.ml | 270 | ||||
-rw-r--r-- | typing/typemod.ml | 28 | ||||
-rw-r--r-- | typing/typetexp.ml | 112 | ||||
-rw-r--r-- | typing/typetexp.mli | 3 |
12 files changed, 1136 insertions, 981 deletions
diff --git a/debugger/loadprinter.ml b/debugger/loadprinter.ml index 5009623a89..ff2eed190b 100644 --- a/debugger/loadprinter.ml +++ b/debugger/loadprinter.ml @@ -90,14 +90,13 @@ let eval_value_path env path = (* Install, remove a printer (as in toplevel/topdirs) *) let match_printer_type desc make_printer_type = - Ctype.begin_def(); - let ty_arg = Ctype.newvar() in - Ctype.unify Env.empty - (make_printer_type ty_arg) - (Ctype.instance desc.val_type); - Ctype.end_def(); - Ctype.generalize ty_arg; - ty_arg + Ctype.wrap_def ~post:Ctype.generalize begin fun () -> + let ty_arg = Ctype.newvar() in + Ctype.unify Env.empty + (make_printer_type ty_arg) + (Ctype.instance desc.val_type); + ty_arg + end let find_printer_type lid = match Env.find_value_by_name lid Env.empty with diff --git a/testsuite/tests/typing-objects/class_2.ml b/testsuite/tests/typing-objects/class_2.ml new file mode 100644 index 0000000000..2d70884cdd --- /dev/null +++ b/testsuite/tests/typing-objects/class_2.ml @@ -0,0 +1,15 @@ +(* TEST + * expect +*) + +(* class expressions may also contain local recursive bindings *) +class test = + let rec f = fun x -> g x + and g = fun x -> f x in +object + method f : 'a 'b. 'a -> 'b = f + method g : 'a 'b. 'a -> 'b = g +end +[%%expect{| +class test : object method f : 'a -> 'b method g : 'a -> 'b end +|}] diff --git a/toplevel/topdirs.ml b/toplevel/topdirs.ml index 1d92cb65dd..4529a1cf00 100644 --- a/toplevel/topdirs.ml +++ b/toplevel/topdirs.ml @@ -231,43 +231,43 @@ let match_simple_printer_type desc ~is_old_style = then Topprinters.printer_type_old else Topprinters.printer_type_new in - Ctype.begin_def(); - let ty_arg = Ctype.newvar() in - match - Ctype.unify !toplevel_env - (make_printer_type ty_arg) - (Ctype.instance desc.val_type); - with - | exception Ctype.Unify _ -> None - | () -> - Ctype.end_def(); - Ctype.generalize ty_arg; - if is_old_style - then Some (Printer.Old ty_arg) - else Some (Printer.Simple ty_arg) + match + Ctype.wrap_def ~post:Ctype.generalize begin fun () -> + let ty_arg = Ctype.newvar() in + Ctype.unify !toplevel_env + (make_printer_type ty_arg) + (Ctype.instance desc.val_type); + ty_arg + end + with + | exception Ctype.Unify _ -> None + | ty_arg -> + if is_old_style + then Some (Printer.Old ty_arg) + else Some (Printer.Simple ty_arg) let match_generic_printer_type desc ty_path args = let make_printer_type = Topprinters.printer_type_new in - Ctype.begin_def(); - let args = List.map (fun _ -> Ctype.newvar ()) args in - let ty_target = Ctype.newty (Tconstr (ty_path, args, ref Mnil)) in - let printer_args_ty = - List.map (fun ty_var -> make_printer_type ty_var) args in - let ty_expected = - List.fold_right Topprinters.type_arrow - printer_args_ty (make_printer_type ty_target) in match - Ctype.unify !toplevel_env + Ctype.wrap_def ~post:generalize begin fun () -> + let args = List.map (fun _ -> Ctype.newvar ()) args in + let ty_target = Ctype.newty (Tconstr (ty_path, args, ref Mnil)) in + let printer_args_ty = + List.map (fun ty_var -> make_printer_type ty_var) args in + let ty_expected = + List.fold_right Topprinters.type_arrow + printer_args_ty (make_printer_type ty_target) in + Ctype.unify !toplevel_env + ty_expected + (Ctype.instance desc.val_type); ty_expected - (Ctype.instance desc.val_type); + end with | exception Ctype.Unify _ -> None - | _ -> - Ctype.end_def(); - Ctype.generalize ty_expected; - if Ctype.all_distinct_vars !toplevel_env args - then Some () - else None + | ty_expected -> + if Ctype.all_distinct_vars !toplevel_env args + then Some () + else None let match_printer_type desc = match match_simple_printer_type desc ~is_old_style:false with diff --git a/typing/ctype.ml b/typing/ctype.ml index 67593ae1d4..de0b0e4e5c 100644 --- a/typing/ctype.ml +++ b/typing/ctype.ml @@ -182,6 +182,52 @@ let end_def () = let create_scope () = init_def (!current_level + 1); !current_level +let wrap_def ?post f = + begin_def (); + let result = f () in + end_def (); + Option.iter (fun g -> g result) post; + result +let wrap_def_process_if cond f ~proc = + if cond then begin_def (); + let result, l = f () in + if cond then begin + end_def (); + List.iter proc l; + end; + result +let wrap_def_process f ~proc = wrap_def_process_if true f ~proc +let wrap_def_if cond f ~post = + if cond then begin_def (); + let result = f () in + if cond then begin + end_def (); + post result; + end; + result +let wrap_def_principal f ~post = wrap_def_if !Clflags.principal f ~post +let wrap_def_process_principal f ~proc = + wrap_def_process_if !Clflags.principal f ~proc +let wrap_init_def_if cond ~level f = + if cond then (begin_def (); init_def level); + let result = f () in + if cond then end_def (); + result +let wrap_init_def ~level f = wrap_init_def_if true ~level f + +let wrap_class_def ?post f = + begin_class_def (); + let result = f () in + end_def (); + Option.iter (fun g -> g result) post; + result + +let wrap_raise_nongen_level f = + raise_nongen_level (); + let result = f () in + end_def (); + result + let reset_global_level () = global_level := !current_level + 1 @@ -1671,16 +1717,13 @@ let full_expand ~may_forget_scope env ty = if may_forget_scope then try expand_head_unif env ty with Unify_trace _ -> (* #10277: forget scopes when printing trace *) - begin_def (); - init_def (get_level ty); - let ty = + wrap_def begin fun () -> + init_def (get_level ty); (* The same as [expand_head], except in the failing case we return the - *original* type, not [correct_levels ty].*) + *original* type, not [correct_levels ty].*) try try_expand_head try_expand_safe env (correct_levels ty) with | Cannot_expand -> ty - in - end_def (); - ty + end else expand_head env ty in match get_desc ty with @@ -3166,6 +3209,8 @@ let unify_pairs env ty1 ty2 pairs = let unify env ty1 ty2 = unify_pairs (ref env) ty1 ty2 [] +(* Lower the level of a type to the current level *) +let enforce_current_level env ty = unify_var env (newvar ()) ty (**** Special cases of unification ****) diff --git a/typing/ctype.mli b/typing/ctype.mli index 86c46d1ee8..ad19acb4c3 100644 --- a/typing/ctype.mli +++ b/typing/ctype.mli @@ -33,14 +33,49 @@ exception Matches_failure of Env.t * Errortrace.unification_error exception Incompatible (* Raised from [mcomp] *) +(* Old API val init_def: int -> unit (* Set the initial variable level *) val begin_def: unit -> unit (* Raise the variable level by one at the beginning of a definition. *) -val end_def: unit -> unit - (* Lower the variable level by one at the end of a definition *) val begin_class_def: unit -> unit + (* Raise the current level not touching the nongen level *) val raise_nongen_level: unit -> unit + (* Raise the nongen level to the current level *) +val end_def: unit -> unit + (* Lower the variable level by one at the end of a definition *) +*) + +val wrap_def: ?post:('a -> unit) -> (unit -> 'a) -> 'a + (* [wrap_def (fun () -> cmd) ~post] evaluates [cmd] at a raised level. + If given, [post] is applied to the result, at the original level. + It is expected to contain only level related post-processing. *) +val wrap_def_if: bool -> (unit -> 'a) -> post:('a -> unit) -> 'a + (* Same as [wrap_init_def], but only raise the level conditionally. + [post] also is only called if the level is raised. *) +val wrap_def_process: (unit -> 'a * 'b list) -> proc:('b -> unit) -> 'a + (* Variant of [wrap_def], where [proc] is iterated on the returned + list. *) +val wrap_def_process_if: + bool -> (unit -> 'a * 'b list) -> proc:('b -> unit) -> 'a + (* Conditional variant of [wrap_def_process] *) +val wrap_init_def: level: int -> (unit -> 'a) -> 'a + (* [wrap_init_def ~level (fun () -> cmd)] evaluates [cmd] with + [current_level] set to [level] *) +val wrap_init_def_if: bool -> level: int -> (unit -> 'a) -> 'a + (* Conditional variant of [wrap_init_def] *) +val wrap_def_principal: (unit -> 'a) -> post:('a -> unit) -> 'a +val wrap_def_process_principal: + (unit -> 'a * 'b list) -> proc:('b -> unit) -> 'a + (* Applications of [wrap_def_if] and [wrap_def_process_if] to + [!Clflags.principal] *) + +val wrap_class_def: ?post:('a -> unit) -> (unit -> 'a) -> 'a + (* Variant of [wrap_def], where the current level is raised but + the nongen level is not touched *) +val wrap_raise_nongen_level: (unit -> 'a) -> 'a + (* Variant of [wrap_def], raises the nongen level to the current level *) + val reset_global_level: unit -> unit (* Reset the global level before typing an expression *) val increase_global_level: unit -> int @@ -115,6 +150,8 @@ val lower_contravariant: Env.t -> type_expr -> unit to be used before generalize for expansive expressions *) val lower_variables_only: Env.t -> int -> type_expr -> unit (* Lower all variables to the given level *) +val enforce_current_level: Env.t -> type_expr -> unit + (* Lower whole type to !current_level *) val generalize_structure: type_expr -> unit (* Generalize the structure of a type, lowering variables to !current_level *) diff --git a/typing/typeclass.ml b/typing/typeclass.ml index 2d0c3d1085..336d09401b 100644 --- a/typing/typeclass.ml +++ b/typing/typeclass.ml @@ -643,15 +643,13 @@ let rec class_field_first_pass self_loc cl_num sign self_scope acc cf = | Pcf_val (label, mut, Cfk_virtual styp) -> with_attrs (fun () -> - if !Clflags.principal then Ctype.begin_def (); - let cty = Typetexp.transl_simple_type val_env false styp in - let ty = cty.ctyp_type in - if !Clflags.principal then begin - Ctype.end_def (); - Ctype.generalize_structure ty - end; + let cty = + Ctype.wrap_def_principal + (fun () -> Typetexp.transl_simple_type val_env false styp) + ~post:(fun cty -> Ctype.generalize_structure cty.ctyp_type) + in add_instance_variable ~strict:true loc val_env - label.txt mut Virtual ty sign; + label.txt mut Virtual cty.ctyp_type sign; let already_declared, val_env, par_env, id, vars = match Vars.find label.txt vars with | id -> true, val_env, par_env, id, vars @@ -684,12 +682,10 @@ let rec class_field_first_pass self_loc cl_num sign self_scope acc cf = raise(Error(loc, val_env, No_overriding ("instance variable", label.txt))) end; - if !Clflags.principal then Ctype.begin_def (); - let definition = type_exp val_env sdefinition in - if !Clflags.principal then begin - Ctype.end_def (); - Ctype.generalize_structure definition.exp_type - end; + let definition = + Ctype.wrap_def_principal ~post:Typecore.generalize_structure_exp + (fun () -> type_exp val_env sdefinition) + in add_instance_variable ~strict:true loc val_env label.txt mut Concrete definition.exp_type sign; let already_declared, val_env, par_env, id, vars = @@ -907,9 +903,9 @@ and class_field_second_pass cl_num sign met_env field = mk_expected (Btype.newgenty (Tarrow(Nolabel, self_type, ty, commu_ok))) in - Ctype.raise_nongen_level (); - let texp = type_expect met_env sdefinition meth_type in - Ctype.end_def (); + let texp = + Ctype.wrap_raise_nongen_level + (fun () -> type_expect met_env sdefinition meth_type) in let kind = Tcfk_concrete (override, texp) in let desc = Tcf_method(label, priv, kind) in met_env, mkcf desc loc attributes) @@ -919,15 +915,15 @@ and class_field_second_pass cl_num sign met_env field = | Initializer { sexpr; warning_state; loc; attributes } -> Warnings.with_state warning_state (fun () -> - Ctype.raise_nongen_level (); let unit_type = Ctype.instance Predef.type_unit in let self_type = sign.Types.csig_self in let meth_type = mk_expected (Ctype.newty (Tarrow (Nolabel, self_type, unit_type, commu_ok))) in - let texp = type_expect met_env sexpr meth_type in - Ctype.end_def (); + let texp = + Ctype.wrap_raise_nongen_level + (fun () -> type_expect met_env sexpr meth_type) in let desc = Tcf_initializer texp in met_env, mkcf desc loc attributes) | Attribute { attribute; loc; attributes; } -> @@ -1142,15 +1138,15 @@ and class_expr_aux cl_num val_env met_env virt self_scope scl = in class_expr cl_num val_env met_env virt self_scope sfun | Pcl_fun (l, None, spat, scl') -> - if !Clflags.principal then Ctype.begin_def (); let (pat, pv, val_env', met_env) = - Typecore.type_class_arg_pattern cl_num val_env met_env l spat + Ctype.wrap_def_principal + (fun () -> + Typecore.type_class_arg_pattern cl_num val_env met_env l spat) + ~post: begin fun (pat, _, _, _) -> + let gen {pat_type = ty} = Ctype.generalize_structure ty in + iter_pattern gen pat + end in - if !Clflags.principal then begin - Ctype.end_def (); - let gen {pat_type = ty} = Ctype.generalize_structure ty in - iter_pattern gen pat - end; let pv = List.map begin fun (id, id', _ty) -> @@ -1177,9 +1173,9 @@ and class_expr_aux cl_num val_env met_env virt self_scope scl = Typecore.check_partial val_env pat.pat_type pat.pat_loc [{c_lhs = pat; c_guard = None; c_rhs = dummy}] in - Ctype.raise_nongen_level (); - let cl = class_expr cl_num val_env' met_env virt self_scope scl' in - Ctype.end_def (); + let cl = + Ctype.wrap_raise_nongen_level + (fun () -> class_expr cl_num val_env' met_env virt self_scope scl') in if Btype.is_optional l && not_nolabel_function cl.cl_type then Location.prerr_warning pat.pat_loc Warnings.Unerasable_optional_argument; @@ -1192,12 +1188,11 @@ and class_expr_aux cl_num val_env met_env virt self_scope scl = } | Pcl_apply (scl', sargs) -> assert (sargs <> []); - if !Clflags.principal then Ctype.begin_def (); - let cl = class_expr cl_num val_env met_env virt self_scope scl' in - if !Clflags.principal then begin - Ctype.end_def (); - Ctype.generalize_class_type_structure cl.cl_type; - end; + let cl = + Ctype.wrap_def_principal + (fun () -> class_expr cl_num val_env met_env virt self_scope scl') + ~post:(fun cl -> Ctype.generalize_class_type_structure cl.cl_type) + in let rec nonopt_labels ls ty_fun = match ty_fun with | Cty_arrow (l, _, ty_res) -> @@ -1306,18 +1301,19 @@ and class_expr_aux cl_num val_env met_env virt self_scope scl = let path = Pident id in (* do not mark the value as used *) let vd = Env.find_value path val_env in - Ctype.begin_def (); let expr = - {exp_desc = - Texp_ident(path, mknoloc(Longident.Lident (Ident.name id)),vd); - exp_loc = Location.none; exp_extra = []; - exp_type = Ctype.instance vd.val_type; - exp_attributes = []; - exp_env = val_env; - } + Ctype.wrap_def begin fun () -> + {exp_desc = + Texp_ident(path, + mknoloc(Longident.Lident (Ident.name id)),vd); + exp_loc = Location.none; exp_extra = []; + exp_type = Ctype.instance vd.val_type; + exp_attributes = []; + exp_env = val_env; + } + end + ~post:(fun exp -> Ctype.generalize exp.exp_type) in - Ctype.end_def (); - Ctype.generalize expr.exp_type; let desc = {val_type = expr.exp_type; val_kind = Val_ivar (Immutable, cl_num); @@ -1344,22 +1340,29 @@ and class_expr_aux cl_num val_env met_env virt self_scope scl = cl_attributes = scl.pcl_attributes; } | Pcl_constraint (scl', scty) -> - Ctype.begin_class_def (); - let context = Typetexp.narrow () in - let cl = class_expr cl_num val_env met_env virt self_scope scl' in - complete_class_type cl.cl_loc val_env virt Class_type cl.cl_type; - Typetexp.widen context; - let context = Typetexp.narrow () in - let clty = class_type val_env virt self_scope scty in - complete_class_type clty.cltyp_loc val_env virt Class clty.cltyp_type; - Typetexp.widen context; - Ctype.end_def (); - - Ctype.limited_generalize_class_type - (Btype.self_type_row cl.cl_type) cl.cl_type; - Ctype.limited_generalize_class_type - (Btype.self_type_row clty.cltyp_type) clty.cltyp_type; - + let cl, clty = + Ctype.wrap_class_def begin fun () -> + let cl = + Typetexp.wrap_type_variable_scope begin fun () -> + let cl = class_expr cl_num val_env met_env virt self_scope scl' in + complete_class_type cl.cl_loc val_env virt Class_type cl.cl_type; + cl + end + and clty = + Typetexp.wrap_type_variable_scope begin fun () -> + let clty = class_type val_env virt self_scope scty in + complete_class_type + clty.cltyp_loc val_env virt Class clty.cltyp_type; + clty + end + in + cl, clty + end + ~post: begin fun ({cl_type=cl}, {cltyp_type=clty}) -> + Ctype.limited_generalize_class_type (Btype.self_type_row cl) cl; + Ctype.limited_generalize_class_type (Btype.self_type_row clty) clty; + end + in begin match Includeclass.class_types val_env cl.cl_type clty.cltyp_type with @@ -1457,12 +1460,10 @@ let initial_env define_class approx let (cl_params, cl_ty, cl_td) = temp_abbrev cl.pci_loc arity uid in (* Temporary type for the class constructor *) - if !Clflags.principal then Ctype.begin_def (); - let constr_type = approx cl.pci_expr in - if !Clflags.principal then begin - Ctype.end_def (); - Ctype.generalize_structure constr_type; - end; + let constr_type = + Ctype.wrap_def_principal (fun () -> approx cl.pci_expr) + ~post:Ctype.generalize_structure + in let dummy_cty = Cty_signature (Ctype.new_class_signature ()) in let dummy_class = {Types.cty_params = []; (* Dummy value *) @@ -1513,42 +1514,43 @@ let class_infos define_class kind (res, env) = reset_type_variables (); - Ctype.begin_class_def (); - - (* Introduce class parameters *) - let ci_params = - let make_param (sty, v) = - try - (transl_type_param env sty, v) - with Already_bound -> - raise(Error(sty.ptyp_loc, env, Repeated_parameter)) - in - List.map make_param cl.pci_params - in - let params = List.map (fun (cty, _) -> cty.ctyp_type) ci_params in - - (* Allow self coercions (only for class declarations) *) - let coercion_locs = ref [] in - - (* Type the class expression *) - let (expr, typ) = - try - Typecore.self_coercion := - (Path.Pident obj_id, coercion_locs) :: !Typecore.self_coercion; - let res = kind env cl.pci_virt cl.pci_expr in - Typecore.self_coercion := List.tl !Typecore.self_coercion; - res - with exn -> - Typecore.self_coercion := []; raise exn + let ci_params, params, coercion_locs, expr, typ, sign = + Ctype.wrap_class_def begin fun () -> + (* Introduce class parameters *) + let ci_params = + let make_param (sty, v) = + try + (transl_type_param env sty, v) + with Already_bound -> + raise(Error(sty.ptyp_loc, env, Repeated_parameter)) + in + List.map make_param cl.pci_params + in + let params = List.map (fun (cty, _) -> cty.ctyp_type) ci_params in + + (* Allow self coercions (only for class declarations) *) + let coercion_locs = ref [] in + + (* Type the class expression *) + let (expr, typ) = + try + Typecore.self_coercion := + (Path.Pident obj_id, coercion_locs) :: !Typecore.self_coercion; + let res = kind env cl.pci_virt cl.pci_expr in + Typecore.self_coercion := List.tl !Typecore.self_coercion; + res + with exn -> + Typecore.self_coercion := []; raise exn + in + let sign = Btype.signature_of_class_type typ in + (ci_params, params, coercion_locs, expr, typ, sign) + end + ~post: begin fun (_, params, _, _, typ, sign) -> + (* Generalize the row variable *) + List.iter (Ctype.limited_generalize sign.csig_self_row) params; + Ctype.limited_generalize_class_type sign.csig_self_row typ; + end in - let sign = Btype.signature_of_class_type typ in - - Ctype.end_def (); - - (* Generalize the row variable *) - List.iter (Ctype.limited_generalize sign.csig_self_row) params; - Ctype.limited_generalize_class_type sign.csig_self_row typ; - (* Check the abbreviation for the object type *) let (obj_params', obj_type) = Ctype.instance_class params typ in let constr = Ctype.newconstr (Path.Pident obj_id) obj_params in @@ -1833,14 +1835,17 @@ let type_classes define_class approx kind env cls = )) cls in - Ctype.begin_class_def (); - let (res, env) = - List.fold_left (initial_env define_class approx) ([], env) cls - in - let (res, env) = - List.fold_right (class_infos define_class kind) res ([], env) + let res, env = + Ctype.wrap_class_def begin fun () -> + let (res, env) = + List.fold_left (initial_env define_class approx) ([], env) cls + in + let (res, env) = + List.fold_right (class_infos define_class kind) res ([], env) + in + res, env + end in - Ctype.end_def (); let res = List.rev_map (final_decl env define_class) res in let decls = List.fold_right extract_type_decls res [] in let decls = diff --git a/typing/typecore.ml b/typing/typecore.ml index 156209491c..d03f47ab09 100644 --- a/typing/typecore.ml +++ b/typing/typecore.ml @@ -544,10 +544,9 @@ let rec build_as_type ~refine (env : Env.t ref) p = here. If we used [generic_instance] we would lose the sharing between [instance ty] and [ty]. *) - begin_def (); - let ty = instance cty.ctyp_type in - end_def (); - generalize_structure ty; + let ty = + wrap_def ~post:generalize_structure (fun () -> instance cty.ctyp_type) + in (* This call to unify can't fail since the pattern is well typed. *) unify_pat_types ~refine p.pat_loc env (instance as_ty) (instance ty); ty @@ -621,19 +620,15 @@ let solve_Ppat_poly_constraint ~refine env loc sty expected_ty = pattern_force := force :: !pattern_force; match get_desc ty with | Tpoly (body, tyl) -> - begin_def (); - init_def generic_level; - let _, ty' = instance_poly ~keep_names:true false tyl body in - end_def (); + let _, ty' = + wrap_init_def ~level:generic_level + (fun () -> instance_poly ~keep_names:true false tyl body) + in (cty, ty, ty') | _ -> assert false let solve_Ppat_alias ~refine env pat = - begin_def (); - let ty_var = build_as_type ~refine env pat in - end_def (); - generalize ty_var; - ty_var + wrap_def ~post:generalize (fun () -> build_as_type ~refine env pat) let solve_Ppat_tuple (type a) ~refine loc env (args : a list) expected_ty = let vars = List.map (fun _ -> newgenvar ()) args in @@ -654,10 +649,10 @@ let solve_constructor_annotation env name_list sty ty_args ty_ex = {name with txt = id}) name_list in - begin_def (); - let cty, ty, force = Typetexp.transl_simple_type_delayed !env sty in - end_def (); - generalize_structure ty; + let cty, ty, force = + wrap_def ~post:(fun (_,ty,_) -> generalize_structure ty) + (fun () -> Typetexp.transl_simple_type_delayed !env sty) + in pattern_force := force :: !pattern_force; let ty_args = let ty1 = instance ty and ty2 = instance ty in @@ -697,10 +692,9 @@ let solve_Ppat_construct ~refine env loc constr no_existentials correct head *) if constr.cstr_generalized then unify_head_only ~refine loc env (instance expected_ty) constr; - begin_def (); - let expected_ty = instance expected_ty in + (* PR#7214: do not use gadt unification for toplevel lets *) - let unify_res ty_res = + let unify_res ty_res expected_ty = let refine = match refine, no_existentials with | None, None when constr.cstr_generalized -> Some false @@ -708,38 +702,43 @@ let solve_Ppat_construct ~refine env loc constr no_existentials in unify_pat_types_return_equated_pairs ~refine loc env ty_res expected_ty in - let expansion_scope = get_gadt_equations_level () in - let ty_args, ty_res, equated_types, existential_ctyp = - match existential_styp with - None -> - let ty_args, ty_res, _ = - instance_constructor - (Make_existentials_abstract { env; scope = expansion_scope }) constr - in - ty_args, ty_res, unify_res ty_res, None - | Some (name_list, sty) -> - let existential_treatment = - if name_list = [] then - Make_existentials_abstract { env; scope = expansion_scope } - else - (* we will unify them (in solve_constructor_annotation) with the - local types provided by the user *) - Keep_existentials_flexible - in - let ty_args, ty_res, ty_ex = - instance_constructor existential_treatment constr - in - let equated_types = unify_res ty_res in - let ty_args, existential_ctyp = - solve_constructor_annotation env name_list sty ty_args ty_ex in - ty_args, ty_res, equated_types, existential_ctyp + + let ty_args, equated_types, existential_ctyp = + wrap_def_process ~proc: generalize_structure begin fun () -> + let expected_ty = instance expected_ty in + let expansion_scope = get_gadt_equations_level () in + let ty_args, ty_res, equated_types, existential_ctyp = + match existential_styp with + None -> + let ty_args, ty_res, _ = + instance_constructor + (Make_existentials_abstract { env; scope = expansion_scope }) + constr + in + ty_args, ty_res, unify_res ty_res expected_ty, None + | Some (name_list, sty) -> + let existential_treatment = + if name_list = [] then + Make_existentials_abstract { env; scope = expansion_scope } + else + (* we will unify them (in solve_constructor_annotation) with the + local types provided by the user *) + Keep_existentials_flexible + in + let ty_args, ty_res, ty_ex = + instance_constructor existential_treatment constr + in + let equated_types = unify_res ty_res expected_ty in + let ty_args, existential_ctyp = + solve_constructor_annotation env name_list sty ty_args ty_ex in + ty_args, ty_res, equated_types, existential_ctyp + in + if constr.cstr_existentials <> [] then + lower_variables_only !env expansion_scope ty_res; + ((ty_args, equated_types, existential_ctyp), + expected_ty :: ty_res :: ty_args) + end in - if constr.cstr_existentials <> [] then - lower_variables_only !env expansion_scope ty_res; - end_def (); - generalize_structure expected_ty; - generalize_structure ty_res; - List.iter generalize_structure ty_args; if !Clflags.principal && refine = None then begin (* Do not warn for counter-examples *) let exception Warn_only_once in @@ -765,18 +764,16 @@ let solve_Ppat_construct ~refine env loc constr no_existentials (ty_args, existential_ctyp) let solve_Ppat_record_field ~refine loc env label label_lid record_ty = - begin_def (); - let (_, ty_arg, ty_res) = instance_label false label in - begin try - unify_pat_types ~refine loc env ty_res (instance record_ty) - with Error(_loc, _env, Pattern_type_clash(err, _)) -> - raise(Error(label_lid.loc, !env, - Label_mismatch(label_lid.txt, err))) - end; - end_def (); - generalize_structure ty_res; - generalize_structure ty_arg; - ty_arg + wrap_def_process ~proc:generalize_structure begin fun () -> + let (_, ty_arg, ty_res) = instance_label false label in + begin try + unify_pat_types ~refine loc env ty_res (instance record_ty) + with Error(_loc, _env, Pattern_type_clash(err, _)) -> + raise(Error(label_lid.loc, !env, + Label_mismatch(label_lid.txt, err))) + end; + (ty_arg, [ty_res; ty_arg]) + end let solve_Ppat_array ~refine loc env expected_ty = let ty_elt = newgenvar() in @@ -792,11 +789,11 @@ let solve_Ppat_lazy ~refine loc env expected_ty = nv let solve_Ppat_constraint ~refine loc env sty expected_ty = - begin_def(); - let cty, ty, force = Typetexp.transl_simple_type_delayed !env sty in - end_def(); + let cty, ty, force = + wrap_def ~post:(fun (_, ty, _) -> generalize_structure ty) + (fun () -> Typetexp.transl_simple_type_delayed !env sty) + in pattern_force := force :: !pattern_force; - generalize_structure ty; let ty, expected_ty' = instance ty, ty in unify_pat_types ~refine loc env ty (instance expected_ty); (cty, ty, expected_ty') @@ -1723,20 +1720,23 @@ and type_pat_aux let initial_module_variables = !module_variables in let equation_level = !gadt_equations_level in let outter_lev = get_current_level () in - (* introduce a new scope *) - begin_def (); - let lev = get_current_level () in - gadt_equations_level := Some lev; - let type_pat_rec env sp = type_pat category sp expected_ty ~env in - let env1 = ref !env in - let p1 = type_pat_rec env1 sp1 in - let p1_variables = !pattern_variables in - let p1_module_variables = !module_variables in - pattern_variables := initial_pattern_variables; - module_variables := initial_module_variables; - let env2 = ref !env in - let p2 = type_pat_rec env2 sp2 in - end_def (); + (* Introduce a new scope; wrap_def without generalizations *) + let env1, p1, p1_variables, p1_module_variables, env2, p2 = + wrap_def begin fun () -> + let lev = get_current_level () in + gadt_equations_level := Some lev; + let type_pat_rec env sp = type_pat category sp expected_ty ~env in + let env1 = ref !env in + let p1 = type_pat_rec env1 sp1 in + let p1_variables = !pattern_variables in + let p1_module_variables = !module_variables in + pattern_variables := initial_pattern_variables; + module_variables := initial_module_variables; + let env2 = ref !env in + let p2 = type_pat_rec env2 sp2 in + (env1, p1, p1_variables, p1_module_variables, env2, p2) + end + in gadt_equations_level := equation_level; let p2_variables = !pattern_variables in (* Make sure no variable with an ambiguous type gets added to the @@ -2517,22 +2517,20 @@ let list_labels env ty = ty_expected should already be generalized. *) let check_univars env kind exp ty_expected vars = let pty = instance ty_expected in - begin_def (); let exp_ty, vars = - match get_desc pty with - Tpoly (body, tl) -> - (* Enforce scoping for type_let: - since body is not generic, instance_poly only makes - copies of nodes that have a Tvar as descendant *) - let _, ty' = instance_poly true tl body in - let vars, exp_ty = instance_parameterized_type vars exp.exp_type in - unify_exp_types exp.exp_loc env exp_ty ty'; - exp_ty, vars - | _ -> assert false + wrap_def_process ~proc:generalize begin fun () -> + match get_desc pty with + Tpoly (body, tl) -> + (* Enforce scoping for type_let: + since body is not generic, instance_poly only makes + copies of nodes that have a Tvar as descendant *) + let _, ty' = instance_poly true tl body in + let vars, exp_ty = instance_parameterized_type vars exp.exp_type in + unify_exp_types exp.exp_loc env exp_ty ty'; + ((exp_ty, vars), exp_ty::vars) + | _ -> assert false + end in - end_def (); - generalize exp_ty; - List.iter generalize vars; let ty, complete = polyfy env exp_ty vars in if not complete then let ty_expected = instance ty_expected in @@ -2848,6 +2846,12 @@ let with_explanation explanation f = let err = Expr_type_clash(err', Some explanation, exp') in raise (Error (loc', env', err)) +(* Generalize expressions *) +let generalize_structure_exp exp = generalize_structure exp.exp_type +let may_lower_contravariant_then_generalize env exp = + if maybe_expansive exp then lower_contravariant env exp.exp_type; + generalize exp.exp_type + let rec type_exp ?recarg env sexp = (* We now delegate everything to type_expect *) type_expect ?recarg env sexp (mk_expected (newvar ())) @@ -2855,7 +2859,8 @@ let rec type_exp ?recarg env sexp = (* Typing of an expression with an expected type. This provide better error messages, and allows controlled propagation of return type information. - In the principal case, [type_expected'] may be at generic_level. + In the principal case, structural nodes of [type_expected_explained] may be + at [generic_level] (but its variables no higher than [!current_level]). *) and type_expect ?in_function ?recarg env sexp ty_expected_explained = @@ -2878,6 +2883,7 @@ and type_expect_ let desc = sexp.pexp_desc in (* Record the expression type before unifying it with the expected type *) let with_explanation = with_explanation explanation in + (* Unify the result with [ty_expected], enforcing the current level *) let rue exp = with_explanation (fun () -> unify_exp ~sdesc_for_hint:desc env (re exp) (instance ty_expected)); @@ -3021,23 +3027,23 @@ and type_expect_ if TypeSet.mem ty seen then () else match get_desc ty with Tarrow (_l, ty_arg, ty_fun, _com) -> - (try unify_var env (newvar()) ty_arg + (try enforce_current_level env ty_arg with Unify _ -> assert false); lower_args (TypeSet.add ty seen) ty_fun | _ -> () in let type_sfunct sfunct = - begin_def (); (* one more level for non-returning functions *) - if !Clflags.principal then begin_def (); - let funct = type_exp env sfunct in - if !Clflags.principal then begin - end_def (); - generalize_structure funct.exp_type - end; - let ty = instance funct.exp_type in - end_def (); - wrap_trace_gadt_instances env (lower_args TypeSet.empty) ty; - funct + (* one more level for warning on non-returning functions *) + wrap_def_process + begin fun () -> + let funct = + wrap_def_principal (fun () -> type_exp env sfunct) + ~post: generalize_structure_exp + in + let ty = instance funct.exp_type in + (funct, [ty]) + end + ~proc:(wrap_trace_gadt_instances env (lower_args TypeSet.empty)) in let funct, sargs = let funct = type_sfunct sfunct in @@ -3056,10 +3062,7 @@ and type_expect_ | _ -> funct, sargs in - begin_def (); let (args, ty_res) = type_application env funct sargs in - end_def (); - unify_var env (newvar()) funct.exp_type; rue { exp_desc = Texp_apply(funct, args); exp_loc = loc; exp_extra = []; @@ -3067,11 +3070,10 @@ and type_expect_ exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_match(sarg, caselist) -> - begin_def (); - let arg = type_exp env sarg in - end_def (); - if maybe_expansive arg then lower_contravariant env arg.exp_type; - generalize arg.exp_type; + let arg = + wrap_def (fun () -> type_exp env sarg) + ~post:(may_lower_contravariant_then_generalize env) + in let cases, partial = type_cases Computation env arg.exp_type ty_expected_explained true loc caselist in @@ -3158,12 +3160,10 @@ and type_expect_ match opt_sexp with None -> None | Some sexp -> - if !Clflags.principal then begin_def (); - let exp = type_exp ~recarg env sexp in - if !Clflags.principal then begin - end_def (); - generalize_structure exp.exp_type - end; + let exp = + wrap_def_principal (fun () -> type_exp ~recarg env sexp) + ~post: generalize_structure_exp + in Some exp in let ty_record, expected_type = @@ -3194,10 +3194,10 @@ and type_expect_ | Some(_, _, true), Some _ -> ty_expected, expected_opath | (None | Some (_, _, false)), Some (_, p', _) -> let decl = Env.find_type p' env in - begin_def (); - let ty = newconstr p' (instance_list decl.type_params) in - end_def (); - generalize_structure ty; + let ty = + wrap_def ~post:generalize_structure + (fun () -> newconstr p' (instance_list decl.type_params)) + in ty, opt_exp_opath in let closed = (opt_sexp = None) in @@ -3411,11 +3411,11 @@ and type_expect_ exp_env = env } | Pexp_constraint (sarg, sty) -> (* Pretend separate = true, 1% slowdown for lablgtk *) - begin_def (); - let cty = Typetexp.transl_simple_type env false sty in + let cty = + wrap_def (fun () -> Typetexp.transl_simple_type env false sty) + ~post:(fun cty -> generalize_structure cty.ctyp_type) + in let ty = cty.ctyp_type in - end_def (); - generalize_structure ty; let (arg, ty') = (type_argument env sarg ty (instance ty), instance ty) in rue { exp_desc = arg.exp_desc; @@ -3436,12 +3436,14 @@ and type_expect_ let (cty', ty', force) = Typetexp.transl_simple_type_delayed env sty' in - begin_def (); - let arg = type_exp env sarg in - end_def (); - let tv = newvar () in - let gen = generalizable (get_level tv) arg.exp_type in - unify_var env tv arg.exp_type; + let arg, gen = + let lv = get_current_level () in + wrap_def begin fun () -> + let arg = type_exp env sarg in + (arg, generalizable lv arg.exp_type) + end + ~post:(fun (arg,_) -> enforce_current_level env arg.exp_type) + in begin match arg.exp_desc, !self_coercion, get_desc ty' with Texp_ident(_, _, {val_kind=Val_self _}), (path,r) :: _, Tconstr(path',_,_) when Path.same path path' -> @@ -3479,15 +3481,17 @@ and type_expect_ end; (arg, ty', None, cty') | Some sty -> - begin_def (); - let (cty, ty, force) = - Typetexp.transl_simple_type_delayed env sty - and (cty', ty', force') = - Typetexp.transl_simple_type_delayed env sty' + let cty, ty, force, cty', ty', force' = + wrap_def_process ~proc:generalize_structure begin fun () -> + let (cty, ty, force) = + Typetexp.transl_simple_type_delayed env sty + and (cty', ty', force') = + Typetexp.transl_simple_type_delayed env sty' + in + ((cty, ty, force, cty', ty', force'), + [ty; ty']) + end in - end_def (); - generalize_structure ty; - generalize_structure ty'; begin try let force'' = subtype env (instance ty) (instance ty') in force (); force' (); force'' () @@ -3507,13 +3511,10 @@ and type_expect_ arg.exp_extra; } | Pexp_send (e, {txt=met}) -> - if !Clflags.principal then begin_def (); - let (obj,meth,typ) = type_send env loc explanation e met + let (obj,meth,typ) = + wrap_def_principal (fun () -> type_send env loc explanation e met) + ~post:(fun (_,_,typ) -> generalize_structure typ) in - if !Clflags.principal then begin - end_def (); - generalize_structure typ; - end; let typ = match get_desc typ with | Tpoly (ty, []) -> @@ -3614,44 +3615,55 @@ and type_expect_ assert false end | Pexp_letmodule(name, smodl, sbody) -> - let ty = newvar() in - (* remember original level *) - begin_def (); - let context = Typetexp.narrow () in - let modl, md_shape = !type_module env smodl in - Mtype.lower_nongen (get_level ty) modl.mod_type; - let pres = - match modl.mod_type with - | Mty_alias _ -> Mp_absent - | _ -> Mp_present - in - let scope = create_scope () in - let md = - { md_type = modl.mod_type; md_attributes = []; md_loc = name.loc; - md_uid = Uid.mk ~current_unit:(Env.get_unit_name ()); } - in - let (id, new_env) = - match name.txt with - | None -> None, env - | Some name -> - let id, env = - Env.enter_module_declaration ~scope ~shape:md_shape name pres md env + let lv = get_current_level () in + let (id, name, pres, modl, _, body) = + wrap_def begin fun () -> + let modl, pres, id, new_env = + Typetexp.wrap_type_variable_scope begin fun () -> + let modl, md_shape = !type_module env smodl in + Mtype.lower_nongen lv modl.mod_type; + let pres = + match modl.mod_type with + | Mty_alias _ -> Mp_absent + | _ -> Mp_present + in + let scope = create_scope () in + let md = + { md_type = modl.mod_type; md_attributes = []; + md_loc = name.loc; + md_uid = Uid.mk ~current_unit:(Env.get_unit_name ()); } + in + let (id, new_env) = + match name.txt with + | None -> None, env + | Some name -> + let id, env = + Env.enter_module_declaration + ~scope ~shape:md_shape name pres md env + in + Some id, env + in + modl, pres, id, new_env + end in - Some id, env + (* Ideally, we should catch Expr_type_clash errors + in type_expect triggered by escaping identifiers + from the local module and refine them into + Scoping_let_module errors + *) + let body = type_expect new_env sbody ty_expected_explained in + (id, name, pres, modl, new_env, body) + end + ~post: begin fun (_,_,_,_,new_env,body) -> + (* Ensure that local definitions do not leak. *) + (* required for implicit unpack *) + enforce_current_level new_env body.exp_type + end in - Typetexp.widen context; - (* ideally, we should catch Expr_type_clash errors - in type_expect triggered by escaping identifiers from the local module - and refine them into Scoping_let_module errors - *) - let body = type_expect new_env sbody ty_expected_explained in - (* go back to original level *) - end_def (); - Ctype.unify_var new_env ty body.exp_type; re { exp_desc = Texp_letmodule(id, name, pres, modl, body); exp_loc = loc; exp_extra = []; - exp_type = ty; + exp_type = body.exp_type; exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_letexception(cd, sbody) -> @@ -3710,18 +3722,16 @@ and type_expect_ exp_env = env; } | Pexp_poly(sbody, sty) -> - if !Clflags.principal then begin_def (); let ty, cty = - match sty with None -> protect_expansion env ty_expected, None - | Some sty -> - let sty = Ast_helper.Typ.force_poly sty in - let cty = Typetexp.transl_simple_type env false sty in - cty.ctyp_type, Some cty + wrap_def_principal ~post:(fun (ty,_) -> generalize_structure ty) + begin fun () -> + match sty with None -> protect_expansion env ty_expected, None + | Some sty -> + let sty = Ast_helper.Typ.force_poly sty in + let cty = Typetexp.transl_simple_type env false sty in + cty.ctyp_type, Some cty + end in - if !Clflags.principal then begin - end_def (); - generalize_structure ty - end; if sty <> None then with_explanation (fun () -> unify_exp_types loc env (instance ty) (instance ty_expected)); @@ -3732,16 +3742,19 @@ and type_expect_ { exp with exp_type = instance ty } | Tpoly (ty', tl) -> (* One more level to generalize locally *) - begin_def (); - if !Clflags.principal then begin_def (); - let vars, ty'' = instance_poly true tl ty' in - if !Clflags.principal then begin - end_def (); - generalize_structure ty'' - end; - let exp = type_expect env sbody (mk_expected ty'') in - end_def (); - generalize_and_check_univars env "method" exp ty_expected vars; + let (exp,_) = + wrap_def begin fun () -> + let vars, ty'' = + wrap_def_principal (fun () -> instance_poly true tl ty') + ~post:(fun (_,ty'') -> generalize_structure ty'') + in + let exp = type_expect env sbody (mk_expected ty'') in + (exp, vars) + end + ~post: begin fun (exp,vars) -> + generalize_and_check_univars env "method" exp ty_expected vars + end + in { exp with exp_type = instance ty } | Tvar _ -> let exp = type_exp env sbody in @@ -3759,33 +3772,31 @@ and type_expect_ else newvar () in - (* remember original level *) - begin_def (); - (* Create a fake abstract type declaration for name. *) - let decl = new_local_type ~loc () in - let scope = create_scope () in - let (id, new_env) = Env.enter_type ~scope name decl env in - - let body = type_exp new_env sbody in - (* Replace every instance of this type constructor in the resulting - type. *) - let seen = Hashtbl.create 8 in - let rec replace t = - if Hashtbl.mem seen (get_id t) then () - else begin - Hashtbl.add seen (get_id t) (); - match get_desc t with - | Tconstr (Path.Pident id', _, _) when id == id' -> link_type t ty - | _ -> Btype.iter_type_expr replace t - end + (* Use [wrap_def] just for scoping *) + let body, ety = wrap_def begin fun () -> + (* Create a fake abstract type declaration for [name]. *) + let decl = new_local_type ~loc () in + let scope = create_scope () in + let (id, new_env) = Env.enter_type ~scope name decl env in + + let body = type_exp new_env sbody in + (* Replace every instance of this type constructor in the resulting + type. *) + let seen = Hashtbl.create 8 in + let rec replace t = + if Hashtbl.mem seen (get_id t) then () + else begin + Hashtbl.add seen (get_id t) (); + match get_desc t with + | Tconstr (Path.Pident id', _, _) when id == id' -> link_type t ty + | _ -> Btype.iter_type_expr replace t + end + in + let ety = Subst.type_expr Subst.identity body.exp_type in + replace ety; + (body, ety) + end in - let ety = Subst.type_expr Subst.identity body.exp_type in - replace ety; - (* back to original level *) - end_def (); - (* lower the levels of the result type *) - (* unify_var env ty ety; *) - (* non-expansive if the body is non-expansive, so we don't introduce any new extra node in the typed AST. *) rue { body with exp_loc = loc; exp_type = ety; @@ -3841,32 +3852,32 @@ and type_expect_ let ty_acc = newty (Ttuple [ty_acc; ty]) in loop spat_acc ty_acc rest in - if !Clflags.principal then begin_def (); - let let_loc = slet.pbop_op.loc in - let op_path, op_desc = type_binding_op_ident env slet.pbop_op in - let op_type = instance op_desc.val_type in - let spat_params, ty_params = loop slet.pbop_pat (newvar ()) sands in - let ty_func_result = newvar () in - let ty_func = - newty (Tarrow(Nolabel, ty_params, ty_func_result, commu_ok)) in - let ty_result = newvar () in - let ty_andops = newvar () in - let ty_op = - newty (Tarrow(Nolabel, ty_andops, - newty (Tarrow(Nolabel, ty_func, ty_result, commu_ok)), commu_ok)) + let op_path, op_desc, op_type, spat_params, ty_params, + ty_func_result, ty_result, ty_andops = + wrap_def_process_principal ~proc:generalize_structure begin fun () -> + let let_loc = slet.pbop_op.loc in + let op_path, op_desc = type_binding_op_ident env slet.pbop_op in + let op_type = instance op_desc.val_type in + let spat_params, ty_params = loop slet.pbop_pat (newvar ()) sands in + let ty_func_result = newvar () in + let ty_func = + newty (Tarrow(Nolabel, ty_params, ty_func_result, commu_ok)) in + let ty_result = newvar () in + let ty_andops = newvar () in + let ty_op = + newty (Tarrow(Nolabel, ty_andops, + newty (Tarrow(Nolabel, ty_func, ty_result, commu_ok)), commu_ok)) + in + begin try + unify env op_type ty_op + with Unify err -> + raise(Error(let_loc, env, Letop_type_clash(slet.pbop_op.txt, err))) + end; + ((op_path, op_desc, op_type, spat_params, ty_params, + ty_func_result, ty_result, ty_andops), + [ty_andops; ty_params; ty_func_result; ty_result]) + end in - begin try - unify env op_type ty_op - with Unify err -> - raise(Error(let_loc, env, Letop_type_clash(slet.pbop_op.txt, err))) - end; - if !Clflags.principal then begin - end_def (); - generalize_structure ty_andops; - generalize_structure ty_params; - generalize_structure ty_func_result; - generalize_structure ty_result - end; let exp, ands = type_andops env slet.pbop_exp sands ty_andops in let scase = Ast_helper.Exp.case spat_params sbody in let cases, partial = @@ -3974,38 +3985,37 @@ and type_function ?(in_function : (Location.t * type_expr) option) | None -> (loc, instance ty_expected) in let separate = !Clflags.principal || Env.has_local_constraints env in - if separate then begin_def (); - let (ty_arg, ty_res) = - try filter_arrow env (instance ty_expected) arg_label - with Filter_arrow_failed err -> - let err = match err with - | Unification_error unif_err -> - Expr_type_clash(unif_err, explanation, None) - | Label_mismatch { got; expected; expected_type} -> - Abstract_wrong_label { got; expected; expected_type; explanation } - | Not_a_function -> begin - match in_function with - | Some _ -> Too_many_arguments(ty_fun, explanation) - | None -> Not_a_function(ty_fun, explanation) + let ty_arg, ty_res = + wrap_def_process_if separate ~proc:generalize_structure begin fun () -> + let (ty_arg, ty_res) = + try filter_arrow env (instance ty_expected) arg_label + with Filter_arrow_failed err -> + let err = match err with + | Unification_error unif_err -> + Expr_type_clash(unif_err, explanation, None) + | Label_mismatch { got; expected; expected_type} -> + Abstract_wrong_label { got; expected; expected_type; explanation } + | Not_a_function -> begin + match in_function with + | Some _ -> Too_many_arguments(ty_fun, explanation) + | None -> Not_a_function(ty_fun, explanation) end + in + raise (Error(loc_fun, env, err)) in - raise (Error(loc_fun, env, err)) - in - let ty_arg = - if is_optional arg_label then - let tv = newvar() in - begin - try unify env ty_arg (type_option tv) - with Unify _ -> assert false - end; - type_option tv - else ty_arg + let ty_arg = + if is_optional arg_label then + let tv = newvar() in + begin + try unify env ty_arg (type_option tv) + with Unify _ -> assert false + end; + type_option tv + else ty_arg + in + ((ty_arg, ty_res), [ty_arg; ty_res]) + end in - if separate then begin - end_def (); - generalize_structure ty_arg; - generalize_structure ty_res - end; let cases, partial = type_cases Value ~in_function:(loc_fun,ty_fun) env ty_arg (mk_expected ty_res) true loc caselist in @@ -4027,12 +4037,10 @@ and type_function ?(in_function : (Location.t * type_expr) option) and type_label_access env srecord usage lid = - if !Clflags.principal then begin_def (); - let record = type_exp ~recarg:Allowed env srecord in - if !Clflags.principal then begin - end_def (); - generalize_structure record.exp_type - end; + let record = + wrap_def_principal ~post:generalize_structure_exp + (fun () -> type_exp ~recarg:Allowed env srecord) + in let ty_exp = record.exp_type in let expected_type = match extract_concrete_record env ty_exp with @@ -4298,37 +4306,40 @@ and type_format loc str env = and type_label_exp create env loc ty_expected (lid, label, sarg) = (* Here also ty_expected may be at generic_level *) - begin_def (); let separate = !Clflags.principal || Env.has_local_constraints env in - if separate then (begin_def (); begin_def ()); - let (vars, ty_arg, ty_res) = instance_label true label in - if separate then begin - end_def (); - (* Generalize label information *) - generalize_structure ty_arg; - generalize_structure ty_res - end; - begin try - unify env (instance ty_res) (instance ty_expected) - with Unify err -> - raise (Error(lid.loc, env, Label_mismatch(lid.txt, err))) - end; - (* Instantiate so that we can generalize internal nodes *) - let ty_arg = instance ty_arg in - if separate then begin - end_def (); - (* Generalize information merged from ty_expected *) - generalize_structure ty_arg - end; - if label.lbl_private = Private then - if create then - raise (Error(loc, env, Private_type ty_expected)) - else - raise (Error(lid.loc, env, Private_label(lid.txt, ty_expected))); + let (vars, ty_arg, snap, arg) = + wrap_def begin fun () -> + let (vars, ty_arg) = + wrap_def_process_if separate ~proc:generalize_structure begin fun () -> + let (vars, ty_arg, ty_res) = + wrap_def_process_if separate ~proc:generalize_structure + begin fun () -> + let ((_, ty_arg, ty_res) as r) = instance_label true label in + (r, [ty_arg; ty_res]) + end + in + begin try + unify env (instance ty_res) (instance ty_expected) + with Unify err -> + raise (Error(lid.loc, env, Label_mismatch(lid.txt, err))) + end; + (* Instantiate so that we can generalize internal nodes *) + let ty_arg = instance ty_arg in + ((vars, ty_arg), [ty_arg]) + end + in + + if label.lbl_private = Private then + if create then + raise (Error(loc, env, Private_type ty_expected)) + else + raise (Error(lid.loc, env, Private_label(lid.txt, ty_expected))); + let snap = if vars = [] then None else Some (Btype.snapshot ()) in + let arg = type_argument env sarg ty_arg (instance ty_arg) in + (vars, ty_arg, snap, arg) + end + in let arg = - let snap = if vars = [] then None else Some (Btype.snapshot ()) in - let arg = type_argument env sarg ty_arg (instance ty_arg) in - end_def (); try if (vars = []) then arg else begin @@ -4340,15 +4351,19 @@ and type_label_exp create env loc ty_expected with exn when maybe_expansive arg -> try (* Try to retype without propagating ty_arg, cf PR#4862 *) Option.iter Btype.backtrack snap; - begin_def (); - let arg = type_exp env sarg in - end_def (); - lower_contravariant env arg.exp_type; - begin_def (); - let arg = {arg with exp_type = instance arg.exp_type} in - unify_exp env arg (instance ty_arg); - end_def (); - generalize_and_check_univars env "field value" arg label.lbl_arg vars; + let arg = wrap_def (fun () -> type_exp env sarg) + ~post:(fun arg -> lower_contravariant env arg.exp_type) + in + let arg = + wrap_def begin fun () -> + let arg = {arg with exp_type = instance arg.exp_type} in + unify_exp env arg (instance ty_arg); + arg + end + ~post: begin fun arg -> + generalize_and_check_univars env "field value" arg label.lbl_arg vars + end + in {arg with exp_type = instance arg.exp_type} with Error (_, _, Less_general _) as e -> raise e | _ -> raise exn (* In case of failure return the first error *) @@ -4380,12 +4395,10 @@ and type_argument ?explanation ?recarg env sarg ty_expected' ty_expected = Some (safe_expect, lv) -> (* apply optional arguments when expected type is "" *) (* we must be very careful about not breaking the semantics *) - if !Clflags.principal then begin_def (); - let texp = type_exp env sarg in - if !Clflags.principal then begin - end_def (); - generalize_structure texp.exp_type - end; + let texp = + wrap_def_principal ~post:generalize_structure_exp + (fun () -> type_exp env sarg) + in let rec make_args args ty_fun = match get_desc (expand_head env ty_fun) with | Tarrow (l,ty_arg,ty_fun,_) when is_optional l -> @@ -4646,16 +4659,20 @@ and type_application env funct sargs = (try ignore (filter_arrow env (instance funct.exp_type) Nolabel); true with Filter_arrow_failed _ -> false) in - match sargs with - | (* Special case for ignore: avoid discarding warning *) - [Nolabel, sarg] when is_ignore funct -> - let ty_arg, ty_res = filter_arrow env (instance funct.exp_type) Nolabel in - let exp = type_expect env sarg (mk_expected ty_arg) in - check_partial_application ~statement:false exp; - ([Nolabel, Some exp], ty_res) - | _ -> - let ty = funct.exp_type in - type_args [] ty (instance ty) sargs + (* Extra scope to check for non-returning functions *) + wrap_def begin fun () -> + match sargs with + | (* Special case for ignore: avoid discarding warning *) + [Nolabel, sarg] when is_ignore funct -> + let ty_arg, ty_res = + filter_arrow env (instance funct.exp_type) Nolabel in + let exp = type_expect env sarg (mk_expected ty_arg) in + check_partial_application ~statement:false exp; + ([Nolabel, Some exp], ty_res) + | _ -> + let ty = funct.exp_type in + type_args [] ty (instance ty) sargs + end and type_construct env loc lid sarg ty_expected_explained attrs = let { ty = ty_expected; explanation } = ty_expected_explained in @@ -4689,27 +4706,32 @@ and type_construct env loc lid sarg ty_expected_explained attrs = raise(Error(loc, env, Constructor_arity_mismatch (lid.txt, constr.cstr_arity, List.length sargs))); let separate = !Clflags.principal || Env.has_local_constraints env in - if separate then (begin_def (); begin_def ()); - let (ty_args, ty_res, _) = - instance_constructor Keep_existentials_flexible constr + let ty_args, ty_res, texp = + wrap_def_process_if separate ~proc:generalize_structure begin fun () -> + let ty_args, ty_res, texp = + wrap_def_if separate begin fun () -> + let (ty_args, ty_res, _) = + instance_constructor Keep_existentials_flexible constr + in + let texp = + re { + exp_desc = Texp_construct(lid, constr, []); + exp_loc = loc; exp_extra = []; + exp_type = ty_res; + exp_attributes = attrs; + exp_env = env } in + (ty_args, ty_res, texp) + end + ~post: begin fun (_, ty_res, texp) -> + generalize_structure ty_res; + with_explanation explanation (fun () -> + unify_exp env {texp with exp_type = instance ty_res} + (instance ty_expected)); + end + in + ((ty_args, ty_res, texp), ty_res::ty_args) + end in - let texp = - re { - exp_desc = Texp_construct(lid, constr, []); - exp_loc = loc; exp_extra = []; - exp_type = ty_res; - exp_attributes = attrs; - exp_env = env } in - if separate then begin - end_def (); - generalize_structure ty_res; - with_explanation explanation (fun () -> - unify_exp env {texp with exp_type = instance ty_res} - (instance ty_expected)); - end_def (); - List.iter generalize_structure ty_args; - generalize_structure ty_res; - end; let ty_args0, ty_res = match instance_list (ty_res :: ty_args) with t :: tl -> tl, t @@ -4747,11 +4769,10 @@ and type_construct env loc lid sarg ty_expected_explained attrs = (* Typing of statements (expressions whose values are discarded) *) and type_statement ?explanation env sexp = - begin_def(); - let exp = type_exp env sexp in - end_def(); - let ty = expand_head env exp.exp_type and tv = newvar() in - if is_Tvar ty && get_level ty > get_level tv then + (* Raise the current level to detect non-returning functions *) + let exp = wrap_def (fun () -> type_exp env sexp) in + let ty = expand_head env exp.exp_type in + if is_Tvar ty && get_level ty > get_current_level () then Location.prerr_warning (final_subexpression exp).exp_loc Warnings.Nonreturning_statement; @@ -4762,7 +4783,7 @@ and type_statement ?explanation env sexp = exp else begin check_partial_application ~statement:true exp; - unify_var env tv ty; + enforce_current_level env ty; exp end @@ -4780,45 +4801,47 @@ and type_unpacks ?(in_function : (Location.t * type_expr) option) *) type_expect ?in_function env sbody expected_ty | unpack :: rem -> - begin_def (); - let context = Typetexp.narrow () in - let name = unpack.tu_name in - let modl, md_shape = - !type_module env - Ast_helper.( - Mod.unpack ~loc:unpack.tu_loc - (Exp.ident ~loc:name.loc - (mkloc (Longident.Lident name.txt) name.loc))) - in - Mtype.lower_nongen (get_level ty) modl.mod_type; - let pres = - match modl.mod_type with - | Mty_alias _ -> Mp_absent - | _ -> Mp_present - in - let scope = create_scope () in - let md = - { md_type = modl.mod_type; md_attributes = []; - md_loc = name.loc; - md_uid = unpack.tu_uid; } - in - let (id, extended_env) = - Env.enter_module_declaration ~scope ~shape:md_shape - name.txt pres md env - in - Typetexp.widen context; - let body = fold_unpacks extended_env rem in - (* go back to parent level *) - end_def (); - Ctype.unify_var extended_env ty body.exp_type; - re { - exp_desc = Texp_letmodule(Some id, { name with txt = Some name.txt }, - pres, modl, body); - exp_loc; - exp_attributes; - exp_extra = []; - exp_type = ty; - exp_env = env } + wrap_def begin fun () -> + let name, modl, pres, id, extended_env = + Typetexp.wrap_type_variable_scope begin fun () -> + let name = unpack.tu_name in + let modl, md_shape = + !type_module env + Ast_helper.( + Mod.unpack ~loc:unpack.tu_loc + (Exp.ident ~loc:name.loc + (mkloc (Longident.Lident name.txt) name.loc))) + in + Mtype.lower_nongen (get_level ty) modl.mod_type; + let pres = + match modl.mod_type with + | Mty_alias _ -> Mp_absent + | _ -> Mp_present + in + let scope = create_scope () in + let md = + { md_type = modl.mod_type; md_attributes = []; + md_loc = name.loc; + md_uid = unpack.tu_uid; } + in + let (id, extended_env) = + Env.enter_module_declaration ~scope ~shape:md_shape + name.txt pres md env + in + name, modl, pres, id, extended_env + end + in + let body = fold_unpacks extended_env rem in + Ctype.unify_var extended_env ty body.exp_type; + re { + exp_desc = Texp_letmodule(Some id, { name with txt = Some name.txt }, + pres, modl, body); + exp_loc; + exp_attributes; + exp_extra = []; + exp_type = ty; + exp_env = env } + end in fold_unpacks env unpacks @@ -4851,87 +4874,97 @@ and type_cases | _ -> true in let outer_level = get_current_level () in - let lev = - if may_contain_gadts then begin_def (); - get_current_level () - in + wrap_def_process_if may_contain_gadts begin fun () -> + let lev = get_current_level () in let take_partial_instance = if erase_either then Some false else None in - begin_def (); (* propagation of the argument *) - let pattern_force = ref [] in -(* Format.printf "@[%i %i@ %a@]@." lev (get_current_level()) - Printtyp.raw_type_expr ty_arg; *) - let half_typed_cases = - List.map - (fun ({pc_lhs; pc_guard = _; pc_rhs = _} as case) -> - if !Clflags.principal then begin_def (); (* propagation of pattern *) - begin_def (); - let ty_arg = instance ?partial:take_partial_instance ty_arg in - end_def (); - generalize_structure ty_arg; - let (pat, ext_env, force, pvs, unpacks) = - type_pattern category ~lev env pc_lhs ty_arg - in - pattern_force := force @ !pattern_force; - let pat = - if !Clflags.principal then begin - end_def (); - iter_pattern_variables_type generalize_structure pvs; - { pat with pat_type = instance pat.pat_type } - end else pat - in - (* Ensure that no ambivalent pattern type escapes its branch *) - check_scope_escape pat.pat_loc env outer_level ty_arg; - { typed_pat = pat; - pat_type_for_unif = ty_arg; - untyped_case = case; - branch_env = ext_env; - pat_vars = pvs; - unpacks; - contains_gadt = contains_gadt (as_comp_pattern category pat); } + let half_typed_cases, ty_res, do_copy_types, ty_arg' = + (* propagation of the argument *) + wrap_def begin fun () -> + let pattern_force = ref [] in + (* Format.printf "@[%i %i@ %a@]@." lev (get_current_level()) + Printtyp.raw_type_expr ty_arg; *) + let half_typed_cases = + List.map + (fun ({pc_lhs; pc_guard = _; pc_rhs = _} as case) -> + let htc = + wrap_def_principal begin fun () -> + let ty_arg = + (* propagation of pattern *) + wrap_def ~post:generalize_structure + (fun () -> instance ?partial:take_partial_instance ty_arg) + in + let (pat, ext_env, force, pvs, unpacks) = + type_pattern category ~lev env pc_lhs ty_arg + in + pattern_force := force @ !pattern_force; + { typed_pat = pat; + pat_type_for_unif = ty_arg; + untyped_case = case; + branch_env = ext_env; + pat_vars = pvs; + unpacks; + contains_gadt = contains_gadt (as_comp_pattern category pat); } + end + ~post: begin fun htc -> + iter_pattern_variables_type generalize_structure htc.pat_vars; + end + in + (* Ensure that no ambivalent pattern type escapes its branch *) + check_scope_escape htc.typed_pat.pat_loc env outer_level + htc.pat_type_for_unif; + if !Clflags.principal then (* XXX find a bettery way? *) + let pat = htc.typed_pat in + {htc with typed_pat = { pat with pat_type = instance pat.pat_type }} + else htc ) - caselist in - let patl = List.map (fun { typed_pat; _ } -> typed_pat) half_typed_cases in - let does_contain_gadt = - List.exists (fun { contains_gadt; _ } -> contains_gadt) half_typed_cases - in - let ty_res, do_copy_types = - if does_contain_gadt && not !Clflags.principal then - correct_levels ty_res, Env.make_copy_of_types env - else ty_res, (fun env -> env) - in - (* Unify all cases (delayed to keep it order-free) *) - let ty_arg' = newvar () in - let unify_pats ty = - List.iter (fun { typed_pat = pat; pat_type_for_unif = pat_ty; _ } -> - unify_pat_types pat.pat_loc (ref env) pat_ty ty - ) half_typed_cases + caselist in + let patl = + List.map (fun { typed_pat; _ } -> typed_pat) half_typed_cases in + let does_contain_gadt = + List.exists (fun { contains_gadt; _ } -> contains_gadt) half_typed_cases + in + let ty_res, do_copy_types = + if does_contain_gadt && not !Clflags.principal then + correct_levels ty_res, Env.make_copy_of_types env + else ty_res, (fun env -> env) + in + (* Unify all cases (delayed to keep it order-free) *) + let ty_arg' = newvar () in + let unify_pats ty = + List.iter (fun { typed_pat = pat; pat_type_for_unif = pat_ty; _ } -> + unify_pat_types pat.pat_loc (ref env) pat_ty ty + ) half_typed_cases + in + unify_pats ty_arg'; + (* Check for polymorphic variants to close *) + if List.exists has_variants patl then begin + Parmatch.pressure_variants_in_computation_pattern env + (List.map (as_comp_pattern category) patl); + List.iter finalize_variants patl + end; + (* `Contaminating' unifications start here *) + List.iter (fun f -> f()) !pattern_force; + (* Post-processing and generalization *) + if take_partial_instance <> None then unify_pats (instance ty_arg); + List.iter (fun { pat_vars; _ } -> + iter_pattern_variables_type + (fun t -> unify_var env (newvar()) t) pat_vars + ) half_typed_cases; + (half_typed_cases, ty_res, do_copy_types, ty_arg') + end + ~post: begin fun (half_typed_cases, _, _, ty_arg') -> + generalize ty_arg'; + List.iter (fun { pat_vars; _ } -> + iter_pattern_variables_type generalize pat_vars + ) half_typed_cases + end in - unify_pats ty_arg'; - (* Check for polymorphic variants to close *) - if List.exists has_variants patl then begin - Parmatch.pressure_variants_in_computation_pattern env - (List.map (as_comp_pattern category) patl); - List.iter finalize_variants patl - end; - (* `Contaminating' unifications start here *) - List.iter (fun f -> f()) !pattern_force; - (* Post-processing and generalization *) - if take_partial_instance <> None then unify_pats (instance ty_arg); - List.iter (fun { pat_vars; _ } -> - iter_pattern_variables_type (fun t -> unify_var env (newvar()) t) pat_vars - ) half_typed_cases; - end_def (); - generalize ty_arg'; - List.iter (fun { pat_vars; _ } -> - iter_pattern_variables_type generalize pat_vars - ) half_typed_cases; (* type bodies *) let in_function = if List.length caselist = 1 then in_function else None in let ty_res' = instance ty_res in - if !Clflags.principal then begin_def (); let cases = List.map (fun { typed_pat = pat; branch_env = ext_env; pat_vars = pvs; unpacks; @@ -4956,7 +4989,8 @@ and type_cases in let ty_expected = if contains_gadt && not !Clflags.principal then - (* allow propagation from preceding branches *) + (* Take a generic copy of [ty_res] again to allow propagation of + type information from preceding branches *) correct_levels ty_res else ty_res in let guard = @@ -4979,7 +5013,6 @@ and type_cases ) half_typed_cases in - if !Clflags.principal then end_def (); let do_init = may_contain_gadts || needs_exhaust_check in let ty_arg_check = if do_init then @@ -5003,10 +5036,10 @@ and type_cases List.iter (fun { typed_pat; branch_env; _ } -> check_absent_variant branch_env (as_comp_pattern category typed_pat) ) half_typed_cases; - if delayed then (begin_def (); init_def lev); - check_unused ~lev env ty_arg_check val_cases ; - check_unused ~lev env Predef.type_exn exn_cases ; - if delayed then end_def (); + wrap_init_def_if delayed ~level:lev begin fun () -> + check_unused ~lev env ty_arg_check val_cases ; + check_unused ~lev env Predef.type_exn exn_cases ; + end; Parmatch.check_ambiguous_bindings val_cases ; Parmatch.check_ambiguous_bindings exn_cases in @@ -5015,12 +5048,10 @@ and type_cases else (* Check for unused cases, do not delay because of gadts *) unused_check false; - if may_contain_gadts then begin - end_def (); - (* Ensure that existential types do not escape *) - unify_exp_types loc env ty_res' (newvar ()) ; - end; - cases, partial + ((cases, partial), [ty_res']) + end + (* Ensure that existential types do not escape *) + ~proc:(fun ty_res' -> unify_exp_types loc env ty_res' (newvar ())) (* Typing of let bindings *) @@ -5042,118 +5073,126 @@ and type_let ?check ?check_strict sty | _ -> spat) spat_sexp_list in - - begin_def(); - if !Clflags.principal then begin_def (); - let nvs = List.map (fun _ -> newvar ()) spatl in - let (pat_list, new_env, force, pvs, unpacks) = - type_pattern_list Value existential_context env spatl nvs allow in let attrs_list = List.map fst spatl in let is_recursive = (rec_flag = Recursive) in - (* If recursive, first unify with an approximation of the expression *) - if is_recursive then - List.iter2 - (fun pat binding -> - let pat = - match get_desc pat.pat_type with - | Tpoly (ty, tl) -> - {pat with pat_type = - snd (instance_poly ~keep_names:true false tl ty)} - | _ -> pat - in unify_pat (ref env) pat (type_approx env binding.pvb_expr)) - pat_list spat_sexp_list; - (* Polymorphic variant processing *) - List.iter - (fun pat -> - if has_variants pat then begin - Parmatch.pressure_variants env [pat]; - finalize_variants pat - end) - pat_list; - (* Generalize the structure *) - let pat_list = - if !Clflags.principal then begin - end_def (); - iter_pattern_variables_type generalize_structure pvs; - List.map (fun pat -> - generalize_structure pat.pat_type; - {pat with pat_type = instance pat.pat_type} - ) pat_list - end else - pat_list - in - (* Only bind pattern variables after generalizing *) - List.iter (fun f -> f()) force; - let exp_list = - let exp_env = if is_recursive then new_env else env in - type_let_def_wrap_warnings ?check ?check_strict ~is_recursive - ~exp_env ~new_env ~spat_sexp_list ~attrs_list ~pat_list ~pvs - (fun exp_env {pvb_expr=sexp; pvb_attributes; _} pat -> - match get_desc pat.pat_type with - | Tpoly (ty, tl) -> - if !Clflags.principal then begin_def (); - let vars, ty' = instance_poly ~keep_names:true true tl ty in - if !Clflags.principal then begin - end_def (); - generalize_structure ty' - end; - let exp = - Builtin_attributes.warning_scope pvb_attributes (fun () -> - if rec_flag = Recursive then - type_unpacks exp_env unpacks sexp (mk_expected ty') - else - type_expect exp_env sexp (mk_expected ty') - ) - in - exp, Some vars - | _ -> - let exp = - Builtin_attributes.warning_scope pvb_attributes (fun () -> - if rec_flag = Recursive then - type_unpacks exp_env unpacks sexp (mk_expected pat.pat_type) - else - type_expect exp_env sexp (mk_expected pat.pat_type)) - in - exp, None) + let (pat_list, exp_list, new_env, unpacks, _pvs) = + wrap_def begin fun () -> + let (pat_list, new_env, force, pvs, unpacks) = + wrap_def_principal begin fun () -> + let nvs = List.map (fun _ -> newvar ()) spatl in + let (pat_list, _new_env, _force, _pvs, _unpacks as res) = + type_pattern_list Value existential_context env spatl nvs allow in + (* If recursive, first unify with an approximation of the + expression *) + if is_recursive then + List.iter2 + (fun pat binding -> + let pat = + match get_desc pat.pat_type with + | Tpoly (ty, tl) -> + {pat with pat_type = + snd (instance_poly ~keep_names:true false tl ty)} + | _ -> pat + in unify_pat (ref env) pat (type_approx env binding.pvb_expr)) + pat_list spat_sexp_list; + (* Polymorphic variant processing *) + List.iter + (fun pat -> + if has_variants pat then begin + Parmatch.pressure_variants env [pat]; + finalize_variants pat + end) + pat_list; + res + end + ~post: begin fun (pat_list, _, _, pvs, _) -> + (* Generalize the structure *) + iter_pattern_variables_type generalize_structure pvs; + List.iter (fun pat -> generalize_structure pat.pat_type) pat_list + end + in + let pat_list = + List.map + (fun pat -> {pat with pat_type = instance pat.pat_type}) + pat_list + in + (* Only bind pattern variables after generalizing *) + List.iter (fun f -> f()) force; + + let exp_list = + let exp_env = if is_recursive then new_env else env in + type_let_def_wrap_warnings ?check ?check_strict ~is_recursive + ~exp_env ~new_env ~spat_sexp_list ~attrs_list ~pat_list ~pvs + (fun exp_env {pvb_expr=sexp; pvb_attributes; _} pat -> + match get_desc pat.pat_type with + | Tpoly (ty, tl) -> + let vars, ty' = + wrap_def_principal + ~post:(fun (_,ty') -> generalize_structure ty') + (fun () -> instance_poly ~keep_names:true true tl ty) + in + let exp = + Builtin_attributes.warning_scope pvb_attributes (fun () -> + if rec_flag = Recursive then + type_unpacks exp_env unpacks sexp (mk_expected ty') + else + type_expect exp_env sexp (mk_expected ty') + ) + in + exp, Some vars + | _ -> + let exp = + Builtin_attributes.warning_scope pvb_attributes (fun () -> + if rec_flag = Recursive then + type_unpacks exp_env unpacks sexp + (mk_expected pat.pat_type) + else + type_expect exp_env sexp (mk_expected pat.pat_type)) + in + exp, None) + in + List.iter2 + (fun pat (attrs, exp) -> + Builtin_attributes.warning_scope ~ppwarning:false attrs + (fun () -> + ignore(check_partial env pat.pat_type pat.pat_loc + [case pat exp]) + ) + ) + pat_list + (List.map2 (fun (attrs, _) (e, _) -> attrs, e) spatl exp_list); + (pat_list, exp_list, new_env, unpacks, + List.map (fun pv -> { pv with pv_type = instance pv.pv_type}) pvs) + end + ~post: begin fun (pat_list, exp_list, _, _, pvs) -> + List.iter2 + (fun pat (exp, _) -> + if maybe_expansive exp then lower_contravariant env pat.pat_type) + pat_list exp_list; + iter_pattern_variables_type generalize pvs; + List.iter2 + (fun pat (exp, vars) -> + match vars with + | None -> + (* We generalize expressions even if they are not bound to a variable + and do not have an expliclit polymorphic type annotation. This is + not needed in general, however those types may be shown by the + interactive toplevel, for example: + {[ + let _ = Array.get;; + - : 'a array -> int -> 'a = <fun> + ]} + so we do it anyway. *) + generalize exp.exp_type + | Some vars -> + if maybe_expansive exp then + lower_contravariant env exp.exp_type; + generalize_and_check_univars env "definition" + exp pat.pat_type vars) + pat_list exp_list + end in - List.iter2 - (fun pat (attrs, exp) -> - Builtin_attributes.warning_scope ~ppwarning:false attrs - (fun () -> - ignore(check_partial env pat.pat_type pat.pat_loc - [case pat exp]) - ) - ) - pat_list - (List.map2 (fun (attrs, _) (e, _) -> attrs, e) spatl exp_list); - let pvs = List.map (fun pv -> { pv with pv_type = instance pv.pv_type}) pvs in - end_def(); - List.iter2 - (fun pat (exp, _) -> - if maybe_expansive exp then - lower_contravariant env pat.pat_type) - pat_list exp_list; - iter_pattern_variables_type generalize pvs; - List.iter2 - (fun pat (exp, vars) -> - match vars with - | None -> - (* We generalize expressions even if they are not bound to a variable - and do not have an expliclit polymorphic type annotation. This is - not needed in general, however those types may be shown by the - interactive toplevel, for example: - {[ - let _ = Array.get;; - - : 'a array -> int -> 'a = <fun> - ]} - so we do it anyway. *) - generalize exp.exp_type - | Some vars -> - if maybe_expansive exp then - lower_contravariant env exp.exp_type; - generalize_and_check_univars env "definition" exp pat.pat_type vars) - pat_list exp_list; let l = List.combine pat_list exp_list in let l = List.map2 @@ -5306,26 +5345,26 @@ and type_andops env sarg sands expected_ty = match rev_sands with | [] -> type_expect env let_sarg (mk_expected expected_ty), [] | { pbop_op = sop; pbop_exp = sexp; pbop_loc = loc; _ } :: rest -> - if !Clflags.principal then begin_def (); - let op_path, op_desc = type_binding_op_ident env sop in - let op_type = instance op_desc.val_type in - let ty_arg = newvar () in - let ty_rest = newvar () in - let ty_result = newvar() in - let ty_rest_fun = - newty (Tarrow(Nolabel, ty_arg, ty_result, commu_ok)) in - let ty_op = newty (Tarrow(Nolabel, ty_rest, ty_rest_fun, commu_ok)) in - begin try - unify env op_type ty_op - with Unify err -> - raise(Error(sop.loc, env, Andop_type_clash(sop.txt, err))) - end; - if !Clflags.principal then begin - end_def (); - generalize_structure ty_rest; - generalize_structure ty_arg; - generalize_structure ty_result - end; + let op_path, op_desc, op_type, ty_arg, ty_rest, ty_result = + wrap_def_process_principal ~proc:generalize_structure begin fun () -> + let op_path, op_desc = type_binding_op_ident env sop in + let op_type = instance op_desc.val_type in + let ty_arg = newvar () in + let ty_rest = newvar () in + let ty_result = newvar() in + let ty_rest_fun = + newty (Tarrow(Nolabel, ty_arg, ty_result, commu_ok)) in + let ty_op = + newty (Tarrow(Nolabel, ty_rest, ty_rest_fun, commu_ok)) in + begin try + unify env op_type ty_op + with Unify err -> + raise(Error(sop.loc, env, Andop_type_clash(sop.txt, err))) + end; + ((op_path, op_desc, op_type, ty_arg, ty_rest, ty_result), + [ty_rest; ty_arg; ty_result]) + end + in let let_arg, rest = loop env let_sarg rest ty_rest in let exp = type_expect env sexp (mk_expected ty_arg) in begin try @@ -5451,11 +5490,10 @@ let type_let existential_ctx env rec_flag spat_sexp_list = let type_expression env sexp = Typetexp.reset_type_variables(); - begin_def(); - let exp = type_exp env sexp in - end_def(); - if maybe_expansive exp then lower_contravariant env exp.exp_type; - generalize exp.exp_type; + let exp = + wrap_def (fun () -> type_exp env sexp) + ~post:(may_lower_contravariant_then_generalize env) + in match sexp.pexp_desc with Pexp_ident lid -> let loc = sexp.pexp_loc in diff --git a/typing/typecore.mli b/typing/typecore.mli index c1da384df1..2095d3b3e5 100644 --- a/typing/typecore.mli +++ b/typing/typecore.mli @@ -134,6 +134,7 @@ val option_some: Env.t -> Typedtree.expression -> Typedtree.expression val option_none: Env.t -> type_expr -> Location.t -> Typedtree.expression val extract_option_type: Env.t -> type_expr -> type_expr val generalizable: int -> type_expr -> bool +val generalize_structure_exp: Typedtree.expression -> unit val reset_delayed_checks: unit -> unit val force_delayed_checks: unit -> unit diff --git a/typing/typedecl.ml b/typing/typedecl.ml index 5d5bebd917..7d87c0fb5b 100644 --- a/typing/typedecl.ml +++ b/typing/typedecl.ml @@ -263,54 +263,54 @@ let make_constructor env loc type_path type_params svars sargs sret_type = | Some sret_type -> (* if it's a generalized constructor we must first narrow and then widen so as to not introduce any new constraints *) - let z = narrow () in + (* narrow and widen are now invoked through wrap_type_variable_scope *) + wrap_type_variable_scope begin fun () -> reset_type_variables (); - let univars, closed = - match svars with - | [] -> None, false - | vs -> - Ctype.begin_def(); - Some (make_poly_univars (List.map (fun v -> v.txt) vs)), true - in - let args, targs = - transl_constructor_arguments env univars closed sargs - in - let tret_type = transl_simple_type env ?univars closed sret_type in - let ret_type = tret_type.ctyp_type in - (* TODO add back type_path as a parameter ? *) - begin match get_desc ret_type with - | Tconstr (p', _, _) when Path.same type_path p' -> () - | _ -> - let trace = - (* Expansion is not helpful here -- the restriction on GADT return - types is purely syntactic. (In the worst case, expansion - produces gibberish.) *) - [Ctype.unexpanded_diff - ~got:ret_type - ~expected:(Ctype.newconstr type_path type_params)] + let closed = svars <> [] in + let targs, tret_type, args, ret_type, _univars = + Ctype.wrap_def_if closed begin fun () -> + let univar_list = + make_poly_univars (List.map (fun v -> v.txt) svars) in + let univars = if closed then Some univar_list else None in + let args, targs = + transl_constructor_arguments env univars closed sargs in - raise (Error(sret_type.ptyp_loc, - Constraint_failed(env, - Errortrace.unification_error ~trace))) - end; - begin match univars with - | None -> () - | Some univars -> - Ctype.end_def(); - Btype.iter_type_expr_cstr_args Ctype.generalize args; - Ctype.generalize ret_type; - let _vars = instance_poly_univars env loc univars in - let set_level t = Ctype.unify_var env (Ctype.newvar()) t in - Btype.iter_type_expr_cstr_args set_level args; - set_level ret_type; - end; - widen z; + let tret_type = transl_simple_type env ?univars closed sret_type in + let ret_type = tret_type.ctyp_type in + (* TODO add back type_path as a parameter ? *) + begin match get_desc ret_type with + | Tconstr (p', _, _) when Path.same type_path p' -> () + | _ -> + let trace = + (* Expansion is not helpful here -- the restriction on GADT + return types is purely syntactic. (In the worst case, + expansion produces gibberish.) *) + [Ctype.unexpanded_diff + ~got:ret_type + ~expected:(Ctype.newconstr type_path type_params)] + in + raise (Error(sret_type.ptyp_loc, + Constraint_failed( + env, Errortrace.unification_error ~trace))) + end; + (targs, tret_type, args, ret_type, univar_list) + end + ~post: begin fun (_, _, args, ret_type, univars) -> + Btype.iter_type_expr_cstr_args Ctype.generalize args; + Ctype.generalize ret_type; + let _vars = instance_poly_univars env loc univars in + let set_level t = Ctype.enforce_current_level env t in + Btype.iter_type_expr_cstr_args set_level args; + set_level ret_type; + end + in targs, Some tret_type, args, Some ret_type + end let transl_declaration env sdecl (id, uid) = (* Bind type parameters *) reset_type_variables(); - Ctype.begin_def (); + Ctype.wrap_def begin fun () -> let tparams = make_params env sdecl.ptype_params in let params = List.map (fun (cty, _) -> cty.ctyp_type) tparams in let cstrs = List.map @@ -460,7 +460,6 @@ let transl_declaration env sdecl (id, uid) = try Ctype.unify env ty ty' with Ctype.Unify err -> raise(Error(loc, Inconsistent_constraint (env, err)))) cstrs; - Ctype.end_def (); (* Add abstract row *) if is_fixed_type sdecl then begin let p, _ = @@ -482,6 +481,7 @@ let transl_declaration env sdecl (id, uid) = typ_private = sdecl.ptype_private; typ_attributes = sdecl.ptype_attributes; } + end (* Generalize a type declaration *) @@ -886,59 +886,62 @@ let transl_type_decl env rec_flag sdecl_list = Uid.mk ~current_unit:(Env.get_unit_name ()) ) sdecl_list in - Ctype.begin_def(); - (* Enter types. *) - let temp_env = - List.fold_left2 (enter_type rec_flag) env sdecl_list ids_list in - (* Translate each declaration. *) - let current_slot = ref None in - let warn_unused = Warnings.is_active (Warnings.Unused_type_declaration "") in - let ids_slots (id, _uid as ids) = - match rec_flag with - | Asttypes.Recursive when warn_unused -> - (* See typecore.ml for a description of the algorithm used - to detect unused declarations in a set of recursive definitions. *) - let slot = ref [] in - let td = Env.find_type (Path.Pident id) temp_env in - Env.set_type_used_callback - td - (fun old_callback -> - match !current_slot with - | Some slot -> slot := td.type_uid :: !slot - | None -> - List.iter Env.mark_type_used (get_ref slot); - old_callback () - ); - ids, Some slot - | Asttypes.Recursive | Asttypes.Nonrecursive -> - ids, None - in - let transl_declaration name_sdecl (id, slot) = - current_slot := slot; - Builtin_attributes.warning_scope - name_sdecl.ptype_attributes - (fun () -> transl_declaration temp_env name_sdecl id) + let tdecls, decls, new_env = + Ctype.wrap_def_process ~proc:generalize_decl begin fun () -> + (* Enter types. *) + let temp_env = + List.fold_left2 (enter_type rec_flag) env sdecl_list ids_list in + (* Translate each declaration. *) + let current_slot = ref None in + let warn_unused = + Warnings.is_active (Warnings.Unused_type_declaration "") in + let ids_slots (id, _uid as ids) = + match rec_flag with + | Asttypes.Recursive when warn_unused -> + (* See typecore.ml for a description of the algorithm used to + detect unused declarations in a set of recursive definitions. *) + let slot = ref [] in + let td = Env.find_type (Path.Pident id) temp_env in + Env.set_type_used_callback + td + (fun old_callback -> + match !current_slot with + | Some slot -> slot := td.type_uid :: !slot + | None -> + List.iter Env.mark_type_used (get_ref slot); + old_callback () + ); + ids, Some slot + | Asttypes.Recursive | Asttypes.Nonrecursive -> + ids, None + in + let transl_declaration name_sdecl (id, slot) = + current_slot := slot; + Builtin_attributes.warning_scope + name_sdecl.ptype_attributes + (fun () -> transl_declaration temp_env name_sdecl id) + in + let tdecls = + List.map2 transl_declaration sdecl_list (List.map ids_slots ids_list) in + let decls = + List.map (fun tdecl -> (tdecl.typ_id, tdecl.typ_type)) tdecls in + current_slot := None; + (* Check for duplicates *) + check_duplicates sdecl_list; + (* Build the final env. *) + let new_env = add_types_to_env decls env in + (* Update stubs *) + begin match rec_flag with + | Asttypes.Nonrecursive -> () + | Asttypes.Recursive -> + List.iter2 + (fun (id, _) sdecl -> + update_type temp_env new_env id sdecl.ptype_loc) + ids_list sdecl_list + end; + ((tdecls, decls, new_env), List.map snd decls) + end in - let tdecls = - List.map2 transl_declaration sdecl_list (List.map ids_slots ids_list) in - let decls = - List.map (fun tdecl -> (tdecl.typ_id, tdecl.typ_type)) tdecls in - current_slot := None; - (* Check for duplicates *) - check_duplicates sdecl_list; - (* Build the final env. *) - let new_env = add_types_to_env decls env in - (* Update stubs *) - begin match rec_flag with - | Asttypes.Nonrecursive -> () - | Asttypes.Recursive -> - List.iter2 - (fun (id, _) sdecl -> update_type temp_env new_env id sdecl.ptype_loc) - ids_list sdecl_list - end; - (* Generalize type declarations. *) - Ctype.end_def(); - List.iter (fun (_, decl) -> generalize_decl decl) decls; (* Check for ill-formed abbrevs *) let id_loc_list = List.map2 (fun (id, _) sdecl -> (id, sdecl.ptype_loc)) @@ -1124,11 +1127,6 @@ let is_rebind ext = | Text_decl _ -> false let transl_type_extension extend env loc styext = - (* Note: it would be incorrect to call [create_scope] *after* - [reset_type_variables] or after [begin_def] (see #10010). *) - let scope = Ctype.create_scope () in - reset_type_variables(); - Ctype.begin_def(); let type_path, type_decl = let lid = styext.ptyext_path in Env.lookup_type ~loc:lid.loc lid.txt env @@ -1173,24 +1171,34 @@ let transl_type_extension extend env loc styext = | None -> () | Some err -> raise (Error(loc, Extension_mismatch (type_path, env, err))) end; - let ttype_params = make_params env styext.ptyext_params in - let type_params = List.map (fun (cty, _) -> cty.ctyp_type) ttype_params in - List.iter2 (Ctype.unify_var env) - (Ctype.instance_list type_decl.type_params) - type_params; - let constructors = - List.map (transl_extension_constructor ~scope env type_path - type_decl.type_params type_params styext.ptyext_private) - styext.ptyext_constructors + (* Note: it would be incorrect to call [create_scope] *after* + [reset_type_variables] or after [wrap_def] (see #10010). *) + let scope = Ctype.create_scope () in + reset_type_variables(); + let ttype_params, _type_params, constructors = + Ctype.wrap_def begin fun () -> + let ttype_params = make_params env styext.ptyext_params in + let type_params = List.map (fun (cty, _) -> cty.ctyp_type) ttype_params in + List.iter2 (Ctype.unify_var env) + (Ctype.instance_list type_decl.type_params) + type_params; + let constructors = + List.map (transl_extension_constructor ~scope env type_path + type_decl.type_params type_params styext.ptyext_private) + styext.ptyext_constructors + in + (ttype_params, type_params, constructors) + end + ~post: begin fun (_, type_params, constructors) -> + (* Generalize types *) + List.iter Ctype.generalize type_params; + List.iter + (fun ext -> + Btype.iter_type_expr_cstr_args Ctype.generalize ext.ext_type.ext_args; + Option.iter Ctype.generalize ext.ext_type.ext_ret_type) + constructors; + end in - Ctype.end_def(); - (* Generalize types *) - List.iter Ctype.generalize type_params; - List.iter - (fun ext -> - Btype.iter_type_expr_cstr_args Ctype.generalize ext.ext_type.ext_args; - Option.iter Ctype.generalize ext.ext_type.ext_ret_type) - constructors; (* Check that all type variables are closed *) List.iter (fun ext -> @@ -1237,15 +1245,16 @@ let transl_type_extension extend env loc styext = let transl_exception env sext = let scope = Ctype.create_scope () in reset_type_variables(); - Ctype.begin_def(); let ext = - transl_extension_constructor ~scope env - Predef.path_exn [] [] Asttypes.Public sext + Ctype.wrap_def + (fun () -> + transl_extension_constructor ~scope env + Predef.path_exn [] [] Asttypes.Public sext) + ~post: begin fun ext -> + Btype.iter_type_expr_cstr_args Ctype.generalize ext.ext_type.ext_args; + Option.iter Ctype.generalize ext.ext_type.ext_ret_type; + end in - Ctype.end_def(); - (* Generalize types *) - Btype.iter_type_expr_cstr_args Ctype.generalize ext.ext_type.ext_args; - Option.iter Ctype.generalize ext.ext_type.ext_ret_type; (* Check that all type variables are closed *) begin match Ctype.closed_extension_constructor ext.ext_type with Some ty -> @@ -1452,7 +1461,7 @@ let transl_with_constraint id ?fixed_row_path ~sig_env ~sig_decl ~outer_env sdecl = Env.mark_type_used sig_decl.type_uid; reset_type_variables(); - Ctype.begin_def(); + Ctype.wrap_def begin fun () -> (* In the first part of this function, we typecheck the syntactic declaration [sdecl] in the outer environment [outer_env]. *) let env = outer_env in @@ -1572,8 +1581,6 @@ let transl_with_constraint id ?fixed_row_path ~sig_env ~sig_decl ~outer_env type_immediate = new_type_immediate; type_separability = new_type_separability; } in - Ctype.end_def(); - generalize_decl new_sig_decl; { typ_id = id; typ_name = sdecl.ptype_name; @@ -1586,14 +1593,15 @@ let transl_with_constraint id ?fixed_row_path ~sig_env ~sig_decl ~outer_env typ_private = sdecl.ptype_private; typ_attributes = sdecl.ptype_attributes; } + end + ~post:(fun ttyp -> generalize_decl ttyp.typ_type) (* Approximate a type declaration: just make all types abstract *) let abstract_type_decl ~injective arity = let rec make_params n = if n <= 0 then [] else Ctype.newvar() :: make_params (n-1) in - Ctype.begin_def(); - let decl = + Ctype.wrap_def ~post:generalize_decl begin fun () -> { type_params = make_params arity; type_arity = arity; type_kind = Type_abstract; @@ -1608,10 +1616,8 @@ let abstract_type_decl ~injective arity = type_immediate = Unknown; type_unboxed_default = false; type_uid = Uid.internal_not_actually_unique; - } in - Ctype.end_def(); - generalize_decl decl; - decl + } + end let approx_type_decl sdecl_list = let scope = Ctype.create_scope () in diff --git a/typing/typemod.ml b/typing/typemod.ml index ebdeb97bbe..2037f30059 100644 --- a/typing/typemod.ml +++ b/typing/typemod.ml @@ -2223,12 +2223,10 @@ and type_module_aux ~alias sttn funct_body anchor env smod = }, final_shape | Pmod_unpack sexp -> - if !Clflags.principal then Ctype.begin_def (); - let exp = Typecore.type_exp env sexp in - if !Clflags.principal then begin - Ctype.end_def (); - Ctype.generalize_structure exp.exp_type - end; + let exp = + Ctype.wrap_def_principal (fun () -> Typecore.type_exp env sexp) + ~post:Typecore.generalize_structure_exp + in let mty = match get_desc (Ctype.expand_head env exp.exp_type) with Tpackage (p, fl) -> @@ -2886,12 +2884,16 @@ let lookup_type_in_sig sg = let type_package env m p fl = (* Same as Pexp_letmodule *) - (* remember original level *) - Ctype.begin_def (); - let context = Typetexp.narrow () in - let modl, _mod_shape = type_module env m in - let scope = Ctype.create_scope () in - Typetexp.widen context; + let modl, scope = + Typetexp.wrap_type_variable_scope begin fun () -> + (* type the module and create a scope in a raised level *) + Ctype.wrap_def begin fun () -> + let modl, _mod_shape = type_module env m in + let scope = Ctype.create_scope () in + modl, scope + end + end + in let fl', env = match fl with | [] -> [], env @@ -2932,8 +2934,6 @@ let type_package env m p fl = in fl', env in - (* go back to original level *) - Ctype.end_def (); let mty = if fl = [] then (Mty_ident p) else modtype_of_package env modl.mod_loc p fl' diff --git a/typing/typetexp.ml b/typing/typetexp.ml index f70c0645bf..2f474a388d 100644 --- a/typing/typetexp.ml +++ b/typing/typetexp.ml @@ -105,6 +105,14 @@ let widen (gl, tv) = restore_global_level gl; type_variables := tv +let wrap_type_variable_scope f = + let context = narrow () in + let r = f () in + widen context; + r + +let generalize_ctyp typ = generalize typ.ctyp_type + let strict_ident c = (c = '_' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') let validate_name = function @@ -316,19 +324,20 @@ and transl_type_aux env policy styp = end; ty with Not_found -> - if !Clflags.principal then begin_def (); - let t = newvar () in - used_variables := - TyVarMap.add alias (t, styp.ptyp_loc) !used_variables; - let ty = transl_type env policy st in - begin try unify_var env t ty.ctyp_type with Unify err -> - let err = Errortrace.swap_unification_error err in - raise(Error(styp.ptyp_loc, env, Alias_type_mismatch err)) - end; - if !Clflags.principal then begin - end_def (); - generalize_structure t; - end; + let t, ty = + wrap_def_principal begin fun () -> + let t = newvar () in + used_variables := + TyVarMap.add alias (t, styp.ptyp_loc) !used_variables; + let ty = transl_type env policy st in + begin try unify_var env t ty.ctyp_type with Unify err -> + let err = Errortrace.swap_unification_error err in + raise(Error(styp.ptyp_loc, env, Alias_type_mismatch err)) + end; + (t, ty) + end + ~post: (fun (t, _) -> generalize_structure t) + in let t = instance t in let px = Btype.proxy t in begin match get_desc px with @@ -436,15 +445,18 @@ and transl_type_aux env policy styp = ctyp (Ttyp_variant (tfields, closed, present)) ty | Ptyp_poly(vars, st) -> let vars = List.map (fun v -> v.txt) vars in - begin_def(); - let new_univars = make_poly_univars vars in - let old_univars = !univars in - univars := new_univars @ !univars; - let cty = transl_type env policy st in + let new_univars, cty = + wrap_def begin fun () -> + let new_univars = make_poly_univars vars in + let old_univars = !univars in + univars := new_univars @ !univars; + let cty = transl_type env policy st in + univars := old_univars; + (new_univars, cty) + end + ~post:(fun (_,cty) -> generalize_ctyp cty) + in let ty = cty.ctyp_type in - univars := old_univars; - end_def(); - generalize ty; let ty_list = check_poly_univars env styp.ptyp_loc new_univars in let ty_list = List.filter (fun v -> deep_occur v ty) ty_list in let ty' = Btype.newgenty (Tpoly(ty, ty_list)) in @@ -452,9 +464,7 @@ and transl_type_aux env policy styp = ctyp (Ttyp_poly (vars, cty)) ty' | Ptyp_package (p, l) -> let l, mty = create_package_mty true styp.ptyp_loc env (p, l) in - let z = narrow () in - let mty = !transl_modtype env mty in - widen z; + let mty = wrap_type_variable_scope (fun () -> !transl_modtype env mty) in let ptys = List.map (fun (s, pty) -> s, transl_type env policy pty ) l in @@ -600,19 +610,21 @@ let transl_simple_type env ?univars:(uvs=[]) fixed styp = let transl_simple_type_univars env styp = univars := []; used_variables := TyVarMap.empty; pre_univars := []; - begin_def (); - let typ = transl_type env Univars styp in - (* Only keep already global variables in used_variables *) - let new_variables = !used_variables in - used_variables := TyVarMap.empty; - TyVarMap.iter - (fun name p -> - if TyVarMap.mem name !type_variables then - used_variables := TyVarMap.add name p !used_variables) - new_variables; - globalize_used_variables env false (); - end_def (); - generalize typ.ctyp_type; + let typ = + wrap_def ~post:generalize_ctyp begin fun () -> + let typ = transl_type env Univars styp in + (* Only keep already global variables in used_variables *) + let new_variables = !used_variables in + used_variables := TyVarMap.empty; + TyVarMap.iter + (fun name p -> + if TyVarMap.mem name !type_variables then + used_variables := TyVarMap.add name p !used_variables) + new_variables; + globalize_used_variables env false (); + typ + end + in let univs = List.fold_left (fun acc v -> @@ -628,28 +640,29 @@ let transl_simple_type_univars env styp = let transl_simple_type_delayed env styp = univars := []; used_variables := TyVarMap.empty; - begin_def (); - let typ = transl_type env Extensible styp in - end_def (); + let typ = wrap_def (fun () -> transl_type env Extensible styp) in make_fixed_univars typ.ctyp_type; (* This brings the used variables to the global level, but doesn't link them to their other occurrences just yet. This will be done when [force] is called. *) let force = globalize_used_variables env false in (* Generalizes everything except the variables that were just globalized. *) - generalize typ.ctyp_type; + generalize_ctyp typ; (* XXX: should be post-processed by [wrap_def] *) (typ, instance typ.ctyp_type, force) let transl_type_scheme env styp = reset_type_variables(); match styp.ptyp_desc with | Ptyp_poly (vars, st) -> - begin_def(); let vars = List.map (fun v -> v.txt) vars in - let univars = make_poly_univars vars in - let typ = transl_simple_type env ~univars true st in - end_def(); - generalize typ.ctyp_type; + let univars, typ = + wrap_def begin fun () -> + let univars = make_poly_univars vars in + let typ = transl_simple_type env ~univars true st in + (univars, typ) + end + ~post:(fun (_,typ) -> generalize_ctyp typ) + in let _ = instance_poly_univars env styp.ptyp_loc univars in { ctyp_desc = Ttyp_poly (vars, typ); ctyp_type = typ.ctyp_type; @@ -657,11 +670,8 @@ let transl_type_scheme env styp = ctyp_loc = styp.ptyp_loc; ctyp_attributes = styp.ptyp_attributes } | _ -> - begin_def(); - let typ = transl_simple_type env false styp in - end_def(); - generalize typ.ctyp_type; - typ + wrap_def (fun () -> transl_simple_type env false styp) + ~post:generalize_ctyp (* Error report *) diff --git a/typing/typetexp.mli b/typing/typetexp.mli index c264ab599a..786cf503e7 100644 --- a/typing/typetexp.mli +++ b/typing/typetexp.mli @@ -52,8 +52,7 @@ val transl_type_param: Env.t -> Parsetree.core_type -> Typedtree.core_type type variable_context -val narrow: unit -> variable_context -val widen: variable_context -> unit +val wrap_type_variable_scope: (unit -> 'a) -> 'a exception Already_bound |