Source

ocaml / typing / typedecl.ml

Full commit
(* Typing of type definitions *)

open Parsetree
open Typedtree
open Typetexp


type error =
    Repeated_parameter
  | Duplicate_constructor of string
  | Too_many_constructors
  | Duplicate_label of string
  | Recursive_abbrev of string

exception Error of Location.t * error

(* Enter all declared types in the environment as abstract types *)

let rec enter_types env = function
    [] ->
      ([], env)
  | (name, sdecl) :: srem ->
      let decl =
        { type_params = []; (*this field is unused when kind = Type_abstract*)
          type_arity = List.length sdecl.ptype_params;
          type_kind = Type_abstract } in
      let (id, extenv) = Env.enter_type name decl env in
      let (rem_id, final_env) = enter_types extenv srem in
      (id :: rem_id, final_env)

(* Translate one type declaration *)

module StringSet =
  Set.Make(struct
    type t = string
    let compare = compare
  end)

let transl_declaration env (name, sdecl) id =
  Ctype.begin_def();
  reset_type_variables();
  let params =
    try
      List.map enter_type_variable sdecl.ptype_params
    with Already_bound ->
      raise(Error(sdecl.ptype_loc, Repeated_parameter)) in
  let kind =
    match sdecl.ptype_kind with
      Ptype_abstract ->
        Type_abstract
    | Ptype_manifest sty ->
        Type_manifest(transl_simple_type env true sty)
    | Ptype_variant cstrs ->
        let all_constrs = ref StringSet.empty in
        List.iter
          (fun (name, args) ->
            if StringSet.mem name !all_constrs then
              raise(Error(sdecl.ptype_loc, Duplicate_constructor name));
            all_constrs := StringSet.add name !all_constrs)
          cstrs;
        if List.length cstrs > Config.max_tag then
          raise(Error(sdecl.ptype_loc, Too_many_constructors));
        Type_variant(List.map
          (fun (name, args) ->
                  (name, List.map (transl_simple_type env true) args))
          cstrs)
    | Ptype_record lbls ->
        let all_labels = ref StringSet.empty in
        List.iter
          (fun (name, mut, arg) ->
            if StringSet.mem name !all_labels then
              raise(Error(sdecl.ptype_loc, Duplicate_label name));
            all_labels := StringSet.add name !all_labels)
          lbls;
        Type_record(List.map
          (fun (name, mut, arg) ->
                  (name, mut, transl_simple_type env true arg))
          lbls) in
  Ctype.end_def();
  List.iter Ctype.generalize params;
  (id,
   {type_params = params; type_arity = List.length params; type_kind = kind})

(* Check for recursive abbrevs *)

let check_recursive_abbrev env (name, sdecl) (id, decl) =
  match decl.type_kind with
    Type_manifest ty ->
      if Ctype.free_type_ident env id ty
      then raise(Error(sdecl.ptype_loc, Recursive_abbrev name))
  | _ -> ()

(* Translate a set of mutually recursive type declarations *)

let transl_type_decl env name_sdecl_list =
  (* Enter the types as abstract *)
  let (id_list, temp_env) = enter_types env name_sdecl_list in
  (* Translate each declaration *)
  let decls = List.map2 (transl_declaration temp_env) name_sdecl_list id_list in
  (* Build the final env *)
  let newenv =
    List.fold_right (fun (id, decl) env -> Env.add_type id decl env) decls env in
  (* Check for recursive abbrevs *)
  List.iter2 (check_recursive_abbrev newenv) name_sdecl_list decls;
  (* Done *)
  (decls, newenv)

(* Translate an exception declaration *)

let transl_exception env excdecl =
  reset_type_variables();
  List.map (transl_simple_type env true) excdecl

(* Error report *)

open Format

let report_error = function
    Repeated_parameter ->
      print_string "A type parameter occurs several times"
  | Duplicate_constructor s ->
      print_string "Two constructors are named "; print_string s
  | Too_many_constructors ->
      print_string "Too many constructors -- maximum is ";
      print_int Config.max_tag; print_string " constructors"
  | Duplicate_label s ->
      print_string "Two labels are named "; print_string s
  | Recursive_abbrev s ->
      print_string "The type abbreviation "; print_string s;
      print_string " is cyclic"