(**************************************************************************) (* *) (* OCaml *) (* *) (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 1996 Institut National de Recherche en Informatique et *) (* en Automatique. *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) (* special exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (* typetexp.ml,v 1.34.4.9 2002/01/07 08:39:16 garrigue Exp *) (* Typechecking of type expressions for the core language *) open Asttypes open Misc open Parsetree open Typedtree open Types open Ctype exception Already_bound type error = Unbound_type_variable of string | Undefined_type_constructor of Path.t | Type_arity_mismatch of Longident.t * int * int | Bound_type_variable of string | Recursive_type | Unbound_row_variable of Longident.t | Type_mismatch of Ctype.Unification_trace.t | Alias_type_mismatch of Ctype.Unification_trace.t | Present_has_conjunction of string | Present_has_no_type of string | Constructor_mismatch of type_expr * type_expr | Not_a_variant of type_expr | Variant_tags of string * string | Invalid_variable_name of string | Cannot_quantify of string * type_expr | Multiple_constraints_on_type of Longident.t | Method_mismatch of string * type_expr * type_expr | Opened_object of Path.t option | Not_an_object of type_expr exception Error of Location.t * Env.t * error exception Error_forward of Location.error (** Map indexed by type variable names. *) module TyVarMap = Misc.Stdlib.String.Map type variable_context = int * type_expr TyVarMap.t (* Support for first-class modules. *) let transl_modtype_longident = ref (fun _ -> assert false) let transl_modtype = ref (fun _ -> assert false) let create_package_mty fake loc env (p, l) = let l = List.sort (fun (s1, _t1) (s2, _t2) -> if s1.txt = s2.txt then raise (Error (loc, env, Multiple_constraints_on_type s1.txt)); compare s1.txt s2.txt) l in l, List.fold_left (fun mty (s, t) -> let d = {ptype_name = mkloc (Longident.last s.txt) s.loc; ptype_params = []; ptype_cstrs = []; ptype_kind = Ptype_abstract; ptype_private = Asttypes.Public; ptype_manifest = if fake then None else Some t; ptype_attributes = []; ptype_loc = loc} in Ast_helper.Mty.mk ~loc (Pmty_with (mty, [ Pwith_type ({ txt = s.txt; loc }, d) ])) ) (Ast_helper.Mty.mk ~loc (Pmty_ident p)) l (* Translation of type expressions *) let type_variables = ref (TyVarMap.empty : type_expr TyVarMap.t) let univars = ref ([] : (string * type_expr) list) let pre_univars = ref ([] : type_expr list) let used_variables = ref (TyVarMap.empty : (type_expr * Location.t) TyVarMap.t) let reset_type_variables () = reset_global_level (); Ctype.reset_reified_var_counter (); type_variables := TyVarMap.empty let narrow () = (increase_global_level (), !type_variables) let widen (gl, tv) = restore_global_level gl; type_variables := tv let strict_ident c = (c = '_' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') let validate_name = function None -> None | Some name as s -> if name <> "" && strict_ident name.[0] then s else None let new_global_var ?name () = new_global_var ?name:(validate_name name) () let newvar ?name () = newvar ?name:(validate_name name) () let type_variable loc name = try TyVarMap.find name !type_variables with Not_found -> raise(Error(loc, Env.empty, Unbound_type_variable ("'" ^ name))) let valid_tyvar_name name = name <> "" && name.[0] <> '_' let transl_type_param env styp = let loc = styp.ptyp_loc in match styp.ptyp_desc with Ptyp_any -> let ty = new_global_var ~name:"_" () in { ctyp_desc = Ttyp_any; ctyp_type = ty; ctyp_env = env; ctyp_loc = loc; ctyp_attributes = styp.ptyp_attributes; } | Ptyp_var name -> let ty = try if not (valid_tyvar_name name) then raise (Error (loc, Env.empty, Invalid_variable_name ("'" ^ name))); ignore (TyVarMap.find name !type_variables); raise Already_bound with Not_found -> let v = new_global_var ~name () in type_variables := TyVarMap.add name v !type_variables; v in { ctyp_desc = Ttyp_var name; ctyp_type = ty; ctyp_env = env; ctyp_loc = loc; ctyp_attributes = styp.ptyp_attributes; } | _ -> assert false let transl_type_param env styp = (* Currently useless, since type parameters cannot hold attributes (but this could easily be lifted in the future). *) Builtin_attributes.warning_scope styp.ptyp_attributes (fun () -> transl_type_param env styp) let new_pre_univar ?name () = let v = newvar ?name () in pre_univars := v :: !pre_univars; v type policy = Fixed | Extensible | Univars let rec transl_type env policy styp = Builtin_attributes.warning_scope styp.ptyp_attributes (fun () -> transl_type_aux env policy styp) and transl_type_aux env policy styp = let loc = styp.ptyp_loc in let ctyp ctyp_desc ctyp_type = { ctyp_desc; ctyp_type; ctyp_env = env; ctyp_loc = loc; ctyp_attributes = styp.ptyp_attributes } in match styp.ptyp_desc with Ptyp_any -> let ty = if policy = Univars then new_pre_univar () else if policy = Fixed then raise (Error (styp.ptyp_loc, env, Unbound_type_variable "_")) else newvar () in ctyp Ttyp_any ty | Ptyp_var name -> let ty = if not (valid_tyvar_name name) then raise (Error (styp.ptyp_loc, env, Invalid_variable_name ("'" ^ name))); begin try instance (List.assoc name !univars) with Not_found -> try instance (fst (TyVarMap.find name !used_variables)) with Not_found -> let v = if policy = Univars then new_pre_univar ~name () else newvar ~name () in used_variables := TyVarMap.add name (v, styp.ptyp_loc) !used_variables; v end in ctyp (Ttyp_var name) ty | Ptyp_arrow(l, st1, st2) -> let cty1 = transl_type env policy st1 in let cty2 = transl_type env policy st2 in let ty1 = cty1.ctyp_type in let ty1 = if Btype.is_optional l then newty (Tconstr(Predef.path_option,[ty1], ref Mnil)) else ty1 in let ty = newty (Tarrow(l, ty1, cty2.ctyp_type, Cok)) in ctyp (Ttyp_arrow (l, cty1, cty2)) ty | Ptyp_tuple stl -> assert (List.length stl >= 2); let ctys = List.map (transl_type env policy) stl in let ty = newty (Ttuple (List.map (fun ctyp -> ctyp.ctyp_type) ctys)) in ctyp (Ttyp_tuple ctys) ty | Ptyp_constr(lid, stl) -> let (path, decl) = Env.lookup_type ~loc:lid.loc lid.txt env in let stl = match stl with | [ {ptyp_desc=Ptyp_any} as t ] when decl.type_arity > 1 -> List.map (fun _ -> t) decl.type_params | _ -> stl in if List.length stl <> decl.type_arity then raise(Error(styp.ptyp_loc, env, Type_arity_mismatch(lid.txt, decl.type_arity, List.length stl))); let args = List.map (transl_type env policy) stl in let params = instance_list decl.type_params in let unify_param = match decl.type_manifest with None -> unify_var | Some ty -> if (repr ty).level = Btype.generic_level then unify_var else unify in List.iter2 (fun (sty, cty) ty' -> try unify_param env ty' cty.ctyp_type with Unify trace -> let trace = Unification_trace.swap trace in raise (Error(sty.ptyp_loc, env, Type_mismatch trace)) ) (List.combine stl args) params; let constr = newconstr path (List.map (fun ctyp -> ctyp.ctyp_type) args) in begin try Ctype.enforce_constraints env constr with Unify trace -> raise (Error(styp.ptyp_loc, env, Type_mismatch trace)) end; ctyp (Ttyp_constr (path, lid, args)) constr | Ptyp_object (fields, o) -> let ty, fields = transl_fields env policy o fields in ctyp (Ttyp_object (fields, o)) (newobj ty) | Ptyp_class(lid, stl) -> let (path, decl, _is_variant) = try let path, decl = Env.find_type_by_name lid.txt env in let rec check decl = match decl.type_manifest with None -> raise Not_found | Some ty -> match (repr ty).desc with Tvariant row when Btype.static_row row -> () | Tconstr (path, _, _) -> check (Env.find_type path env) | _ -> raise Not_found in check decl; Location.deprecated styp.ptyp_loc "old syntax for polymorphic variant type"; ignore(Env.lookup_type ~loc:lid.loc lid.txt env); (path, decl,true) with Not_found -> try let lid2 = match lid.txt with Longident.Lident s -> Longident.Lident ("#" ^ s) | Longident.Ldot(r, s) -> Longident.Ldot (r, "#" ^ s) | Longident.Lapply(_, _) -> fatal_error "Typetexp.transl_type" in let path, decl = Env.find_type_by_name lid2 env in ignore(Env.lookup_cltype ~loc:lid.loc lid.txt env); (path, decl, false) with Not_found -> ignore (Env.lookup_cltype ~loc:lid.loc lid.txt env); assert false in if List.length stl <> decl.type_arity then raise(Error(styp.ptyp_loc, env, Type_arity_mismatch(lid.txt, decl.type_arity, List.length stl))); let args = List.map (transl_type env policy) stl in let params = instance_list decl.type_params in List.iter2 (fun (sty, cty) ty' -> try unify_var env ty' cty.ctyp_type with Unify trace -> let trace = Unification_trace.swap trace in raise (Error(sty.ptyp_loc, env, Type_mismatch trace)) ) (List.combine stl args) params; let ty_args = List.map (fun ctyp -> ctyp.ctyp_type) args in let ty = try Ctype.expand_head env (newconstr path ty_args) with Unify trace -> raise (Error(styp.ptyp_loc, env, Type_mismatch trace)) in let ty = match ty.desc with Tvariant row -> let row = Btype.row_repr row in let fields = List.map (fun (l,f) -> l, match Btype.row_field_repr f with | Rpresent (Some ty) -> Reither(false, [ty], false, ref None) | Rpresent None -> Reither (true, [], false, ref None) | _ -> f) row.row_fields in let row = { row_closed = true; row_fields = fields; row_bound = (); row_name = Some (path, ty_args); row_fixed = None; row_more = newvar () } in let static = Btype.static_row row in let row = if static then { row with row_more = newty Tnil } else if policy <> Univars then row else { row with row_more = new_pre_univar () } in newty (Tvariant row) | Tobject (fi, _) -> let _, tv = flatten_fields fi in if policy = Univars then pre_univars := tv :: !pre_univars; ty | _ -> assert false in ctyp (Ttyp_class (path, lid, args)) ty | Ptyp_alias(st, alias) -> let cty = try let t = try List.assoc alias !univars with Not_found -> instance (fst(TyVarMap.find alias !used_variables)) in let ty = transl_type env policy st in begin try unify_var env t ty.ctyp_type with Unify trace -> let trace = Unification_trace.swap trace in raise(Error(styp.ptyp_loc, env, Alias_type_mismatch trace)) 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 trace -> let trace = Unification_trace.swap trace in raise(Error(styp.ptyp_loc, env, Alias_type_mismatch trace)) end; if !Clflags.principal then begin end_def (); generalize_structure t; end; let t = instance t in let px = Btype.proxy t in begin match px.desc with | Tvar None -> Btype.set_type_desc px (Tvar (Some alias)) | Tunivar None -> Btype.set_type_desc px (Tunivar (Some alias)) | _ -> () end; { ty with ctyp_type = t } in ctyp (Ttyp_alias (cty, alias)) cty.ctyp_type | Ptyp_variant(fields, closed, present) -> let name = ref None in let mkfield l f = newty (Tvariant {row_fields=[l,f]; row_more=newvar(); row_bound=(); row_closed=true; row_fixed=None; row_name=None}) in let hfields = Hashtbl.create 17 in let add_typed_field loc l f = let h = Btype.hash_variant l in try let (l',f') = Hashtbl.find hfields h in (* Check for tag conflicts *) if l <> l' then raise(Error(styp.ptyp_loc, env, Variant_tags(l, l'))); let ty = mkfield l f and ty' = mkfield l f' in if equal env false [ty] [ty'] then () else try unify env ty ty' with Unify _trace -> raise(Error(loc, env, Constructor_mismatch (ty,ty'))) with Not_found -> Hashtbl.add hfields h (l,f) in let add_field field = let rf_loc = field.prf_loc in let rf_attributes = field.prf_attributes in let rf_desc = match field.prf_desc with | Rtag (l, c, stl) -> name := None; let tl = Builtin_attributes.warning_scope rf_attributes (fun () -> List.map (transl_type env policy) stl) in let f = match present with Some present when not (List.mem l.txt present) -> let ty_tl = List.map (fun cty -> cty.ctyp_type) tl in Reither(c, ty_tl, false, ref None) | _ -> if List.length stl > 1 || c && stl <> [] then raise(Error(styp.ptyp_loc, env, Present_has_conjunction l.txt)); match tl with [] -> Rpresent None | st :: _ -> Rpresent (Some st.ctyp_type) in add_typed_field styp.ptyp_loc l.txt f; Ttag (l,c,tl) | Rinherit sty -> let cty = transl_type env policy sty in let ty = cty.ctyp_type in let nm = match repr cty.ctyp_type with {desc=Tconstr(p, tl, _)} -> Some(p, tl) | _ -> None in name := if Hashtbl.length hfields <> 0 then None else nm; let fl = match expand_head env cty.ctyp_type, nm with {desc=Tvariant row}, _ when Btype.static_row row -> let row = Btype.row_repr row in row.row_fields | {desc=Tvar _}, Some(p, _) -> raise(Error(sty.ptyp_loc, env, Undefined_type_constructor p)) | _ -> raise(Error(sty.ptyp_loc, env, Not_a_variant ty)) in List.iter (fun (l, f) -> let f = match present with Some present when not (List.mem l present) -> begin match f with Rpresent(Some ty) -> Reither(false, [ty], false, ref None) | Rpresent None -> Reither(true, [], false, ref None) | _ -> assert false end | _ -> f in add_typed_field sty.ptyp_loc l f) fl; Tinherit cty in { rf_desc; rf_loc; rf_attributes; } in let tfields = List.map add_field fields in let fields = Hashtbl.fold (fun _ p l -> p :: l) hfields [] in begin match present with None -> () | Some present -> List.iter (fun l -> if not (List.mem_assoc l fields) then raise(Error(styp.ptyp_loc, env, Present_has_no_type l))) present end; let row = { row_fields = List.rev fields; row_more = newvar (); row_bound = (); row_closed = (closed = Closed); row_fixed = None; row_name = !name } in let static = Btype.static_row row in let row = if static then { row with row_more = newty Tnil } else if policy <> Univars then row else { row with row_more = new_pre_univar () } in let ty = newty (Tvariant row) in 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 = List.map (fun name -> name, newvar ~name ()) vars in let old_univars = !univars in univars := new_univars @ !univars; let cty = transl_type env policy st in let ty = cty.ctyp_type in univars := old_univars; end_def(); generalize ty; let ty_list = List.fold_left (fun tyl (name, ty1) -> let v = Btype.proxy ty1 in if deep_occur v ty then begin match v.desc with Tvar name when v.level = Btype.generic_level -> v.desc <- Tunivar name; v :: tyl | _ -> raise (Error (styp.ptyp_loc, env, Cannot_quantify (name, v))) end else tyl) [] new_univars in let ty' = Btype.newgenty (Tpoly(ty, List.rev ty_list)) in unify_var env (newvar()) ty'; 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 ptys = List.map (fun (s, pty) -> s, transl_type env policy pty ) l in let path = !transl_modtype_longident styp.ptyp_loc env p.txt in let ty = newty (Tpackage (path, List.map (fun (s, _pty) -> s.txt) l, List.map (fun (_,cty) -> cty.ctyp_type) ptys)) in ctyp (Ttyp_package { pack_path = path; pack_type = mty.mty_type; pack_fields = ptys; pack_txt = p; }) ty | Ptyp_extension ext -> raise (Error_forward (Builtin_attributes.error_of_extension ext)) and transl_poly_type env policy t = transl_type env policy (Ast_helper.Typ.force_poly t) and transl_fields env policy o fields = let hfields = Hashtbl.create 17 in let add_typed_field loc l ty = try let ty' = Hashtbl.find hfields l in if equal env false [ty] [ty'] then () else try unify env ty ty' with Unify _trace -> raise(Error(loc, env, Method_mismatch (l, ty, ty'))) with Not_found -> Hashtbl.add hfields l ty in let add_field {pof_desc; pof_loc; pof_attributes;} = let of_loc = pof_loc in let of_attributes = pof_attributes in let of_desc = match pof_desc with | Otag (s, ty1) -> begin let ty1 = Builtin_attributes.warning_scope of_attributes (fun () -> transl_poly_type env policy ty1) in let field = OTtag (s, ty1) in add_typed_field ty1.ctyp_loc s.txt ty1.ctyp_type; field end | Oinherit sty -> begin let cty = transl_type env policy sty in let nm = match repr cty.ctyp_type with {desc=Tconstr(p, _, _)} -> Some p | _ -> None in let t = expand_head env cty.ctyp_type in match t, nm with {desc=Tobject ({desc=(Tfield _ | Tnil) as tf}, _)}, _ -> begin if opened_object t then raise (Error (sty.ptyp_loc, env, Opened_object nm)); let rec iter_add = function | Tfield (s, _k, ty1, ty2) -> begin add_typed_field sty.ptyp_loc s ty1; iter_add ty2.desc end | Tnil -> () | _ -> assert false in iter_add tf; OTinherit cty end | {desc=Tvar _}, Some p -> raise (Error (sty.ptyp_loc, env, Undefined_type_constructor p)) | _ -> raise (Error (sty.ptyp_loc, env, Not_an_object t)) end in { of_desc; of_loc; of_attributes; } in let object_fields = List.map add_field fields in let fields = Hashtbl.fold (fun s ty l -> (s, ty) :: l) hfields [] in let ty_init = match o, policy with | Closed, _ -> newty Tnil | Open, Univars -> new_pre_univar () | Open, _ -> newvar () in let ty = List.fold_left (fun ty (s, ty') -> newty (Tfield (s, Fpresent, ty', ty))) ty_init fields in ty, object_fields (* Make the rows "fixed" in this type, to make universal check easier *) let rec make_fixed_univars ty = let ty = repr ty in if ty.level >= Btype.lowest_level then begin Btype.mark_type_node ty; match ty.desc with | Tvariant row -> let row = Btype.row_repr row in let more = Btype.row_more row in if Btype.is_Tunivar more then ty.desc <- Tvariant {row with row_fixed=Some(Univar more); row_fields = List.map (fun (s,f as p) -> match Btype.row_field_repr f with Reither (c, tl, _m, r) -> s, Reither (c, tl, true, r) | _ -> p) row.row_fields}; Btype.iter_row make_fixed_univars row | _ -> Btype.iter_type_expr make_fixed_univars ty end let make_fixed_univars ty = make_fixed_univars ty; Btype.unmark_type ty let create_package_mty = create_package_mty false let globalize_used_variables env fixed = let r = ref [] in TyVarMap.iter (fun name (ty, loc) -> let v = new_global_var () in let snap = Btype.snapshot () in if try unify env v ty; true with _ -> Btype.backtrack snap; false then try r := (loc, v, TyVarMap.find name !type_variables) :: !r with Not_found -> if fixed && Btype.is_Tvar (repr ty) then raise(Error(loc, env, Unbound_type_variable ("'"^name))); let v2 = new_global_var () in r := (loc, v, v2) :: !r; type_variables := TyVarMap.add name v2 !type_variables) !used_variables; used_variables := TyVarMap.empty; fun () -> List.iter (function (loc, t1, t2) -> try unify env t1 t2 with Unify trace -> raise (Error(loc, env, Type_mismatch trace))) !r let transl_simple_type env fixed styp = univars := []; used_variables := TyVarMap.empty; let typ = transl_type env (if fixed then Fixed else Extensible) styp in globalize_used_variables env fixed (); make_fixed_univars typ.ctyp_type; typ 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 univs = List.fold_left (fun acc v -> let v = repr v in match v.desc with Tvar name when v.level = Btype.generic_level -> v.desc <- Tunivar name; v :: acc | _ -> acc) [] !pre_univars in make_fixed_univars typ.ctyp_type; { typ with ctyp_type = instance (Btype.newgenty (Tpoly (typ.ctyp_type, univs))) } let transl_simple_type_delayed env styp = univars := []; used_variables := TyVarMap.empty; begin_def (); let typ = transl_type env Extensible styp in end_def (); 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; (typ, instance typ.ctyp_type, force) let transl_type_scheme env styp = reset_type_variables(); begin_def(); let typ = transl_simple_type env false styp in end_def(); generalize typ.ctyp_type; typ (* Error report *) open Format open Printtyp let report_error env ppf = function | Unbound_type_variable name -> let add_name name _ l = if name = "_" then l else ("'" ^ name) :: l in let names = TyVarMap.fold add_name !type_variables [] in fprintf ppf "The type variable %s is unbound in this type declaration.@ %a" name did_you_mean (fun () -> Misc.spellcheck names name ) | Undefined_type_constructor p -> fprintf ppf "The type constructor@ %a@ is not yet completely defined" path p | Type_arity_mismatch(lid, expected, provided) -> fprintf ppf "@[The type constructor %a@ expects %i argument(s),@ \ but is here applied to %i argument(s)@]" longident lid expected provided | Bound_type_variable name -> fprintf ppf "Already bound type parameter %a" Pprintast.tyvar name | Recursive_type -> fprintf ppf "This type is recursive" | Unbound_row_variable lid -> (* we don't use "spellcheck" here: this error is not raised anywhere so it's unclear how it should be handled *) fprintf ppf "Unbound row variable in #%a" longident lid | Type_mismatch trace -> Printtyp.report_unification_error ppf Env.empty trace (function ppf -> fprintf ppf "This type") (function ppf -> fprintf ppf "should be an instance of type") | Alias_type_mismatch trace -> Printtyp.report_unification_error ppf Env.empty trace (function ppf -> fprintf ppf "This alias is bound to type") (function ppf -> fprintf ppf "but is used as an instance of type") | Present_has_conjunction l -> fprintf ppf "The present constructor %s has a conjunctive type" l | Present_has_no_type l -> fprintf ppf "@[@[The constructor %s is missing from the upper bound@ \ (between '<'@ and '>')@ of this polymorphic variant@ \ but is present in@ its lower bound (after '>').@]@,\ @[Hint: Either add `%s in the upper bound,@ \ or remove it@ from the lower bound.@]@]" l l | Constructor_mismatch (ty, ty') -> wrap_printing_env ~error:true env (fun () -> Printtyp.reset_and_mark_loops_list [ty; ty']; fprintf ppf "@[%s %a@ %s@ %a@]" "This variant type contains a constructor" !Oprint.out_type (tree_of_typexp false ty) "which should be" !Oprint.out_type (tree_of_typexp false ty')) | Not_a_variant ty -> fprintf ppf "@[The type %a@ does not expand to a polymorphic variant type@]" Printtyp.type_expr ty; begin match ty.desc with | Tvar (Some s) -> (* PR#7012: help the user that wrote 'Foo instead of `Foo *) Misc.did_you_mean ppf (fun () -> ["`" ^ s]) | _ -> () end | Variant_tags (lab1, lab2) -> fprintf ppf "@[Variant tags `%s@ and `%s have the same hash value.@ %s@]" lab1 lab2 "Change one of them." | Invalid_variable_name name -> fprintf ppf "The type variable name %s is not allowed in programs" name | Cannot_quantify (name, v) -> fprintf ppf "@[The universal type variable %a cannot be generalized:@ " Pprintast.tyvar name; if Btype.is_Tvar v then fprintf ppf "it escapes its scope" else if Btype.is_Tunivar v then fprintf ppf "it is already bound to another variable" else fprintf ppf "it is bound to@ %a" Printtyp.type_expr v; fprintf ppf ".@]"; | Multiple_constraints_on_type s -> fprintf ppf "Multiple constraints for type %a" longident s | Method_mismatch (l, ty, ty') -> wrap_printing_env ~error:true env (fun () -> fprintf ppf "@[Method '%s' has type %a,@ which should be %a@]" l Printtyp.type_expr ty Printtyp.type_expr ty') | Opened_object nm -> fprintf ppf "Illegal open object type%a" (fun ppf -> function Some p -> fprintf ppf "@ %a" path p | None -> fprintf ppf "") nm | Not_an_object ty -> fprintf ppf "@[The type %a@ is not an object type@]" Printtyp.type_expr ty let () = Location.register_error_of_exn (function | Error (loc, env, err) -> Some (Location.error_of_printer ~loc (report_error env) err) | Error_forward err -> Some err | _ -> None )