Source

ocaml / typing / mtype.ml

Full commit
(* Operations on module types *)

open Path
open Typedtree


let rec scrape env mty =
  match mty with
    Tmty_ident p ->
      begin match Env.find_modtype p env with
        Tmodtype_abstract -> mty
      | Tmodtype_manifest mty' -> scrape env mty'
      end
  | _ -> mty

let rec strengthen env mty p =
  match scrape env mty with
    Tmty_signature sg ->
      Tmty_signature(strengthen_sig env sg p)
  | mty ->
      mty

and strengthen_sig env sg p =
  match sg with
    [] -> []
  | (Tsig_value(id, desc) as sigelt) :: rem ->
      sigelt :: strengthen_sig env rem p
  | Tsig_type(id, decl) :: rem ->
      let newdecl =
        match decl.type_kind with
          Type_abstract ->
            { type_params = decl.type_params;
              type_arity = decl.type_arity;
              type_kind = Type_manifest(Tconstr(Pdot(p, Ident.name id, nopos),
                                                decl.type_params)) }
        | _ -> decl in
      Tsig_type(id, newdecl) :: strengthen_sig env rem p
  | (Tsig_exception(id, d) as sigelt) :: rem ->
      sigelt :: strengthen_sig env rem p
  | Tsig_module(id, mty) :: rem ->
      Tsig_module(id, strengthen env mty (Pdot(p, Ident.name id, nopos))) ::
      strengthen_sig (Env.add_module id mty env) rem p
      (* Need to add the module in case it defines manifest module types *)
  | Tsig_modtype(id, decl) :: rem ->
      let newdecl =
        match decl with
          Tmodtype_abstract ->
            Tmodtype_manifest(Tmty_ident(Pdot(p, Ident.name id, nopos)))
        | Tmodtype_manifest _ ->
            decl in
      Tsig_modtype(id, newdecl) ::
      strengthen_sig (Env.add_modtype id decl env) rem p
      (* Need to add the module type in case it is manifest *)

(* In nondep_supertype, env is only used for the type it assigns to id.
   Hence there is no need to keep env up-to-date by adding the bindings
   traversed. *)

type variance = Co | Contra | Strict

let nondep_supertype env mid mty =

  let rec nondep_mty var mty =
    match mty with
      Tmty_ident p ->
        if Path.isfree mid p then begin
          match Env.find_modtype p env with
            Tmodtype_abstract -> raise Not_found
          | Tmodtype_manifest mty -> nondep_mty var mty      
        end else mty
    | Tmty_signature sg ->
        Tmty_signature(nondep_sig var sg)
    | Tmty_functor(param, arg, res) ->
        let var_inv =
          match var with Co -> Contra | Contra -> Co | Strict -> Strict in
        Tmty_functor(param, nondep_mty var_inv arg, nondep_mty var res)

  and nondep_sig var = function
    [] -> []
  | item :: rem ->
      let rem' = nondep_sig var rem in
      match item with
        Tsig_value(id, d) ->
          begin try
            Tsig_value(id, {val_type = Ctype.nondep_type env mid d.val_type;
                            val_prim = d.val_prim}) :: rem'
          with Not_found ->
            match var with Co -> rem' | _ -> raise Not_found
          end
      | Tsig_type(id, d) ->
          begin try
            Tsig_type(id, nondep_type_decl d) :: rem'
          with Not_found ->
            match var with
              Co -> Tsig_type(id, abstract_type_decl d) :: rem'
            | _  -> raise Not_found
          end
      | Tsig_exception(id, d) ->
          begin try
            Tsig_exception(id, List.map (Ctype.nondep_type env mid) d) :: rem'
          with Not_found ->
            match var with Co -> rem' | _ -> raise Not_found
          end
      | Tsig_module(id, mty) ->
          begin try
            Tsig_module(id, nondep_mty var mty) :: rem'
          with Not_found ->
            match var with Co -> rem' | _ -> raise Not_found
          end
      | Tsig_modtype(id, d) ->
          begin try
            Tsig_modtype(id, nondep_modtype_decl d) :: rem'
          with Not_found ->
            match var with
              Co -> Tsig_modtype(id, Tmodtype_abstract) :: rem'
            | _  -> raise Not_found
          end

  and nondep_type_decl d =
    {type_params = d.type_params;
     type_arity = d.type_arity;
     type_kind =
       match d.type_kind with
         Type_abstract ->
           Type_abstract
       | Type_manifest ty ->
           Type_manifest(Ctype.nondep_type env mid ty)
       | Type_variant cstrs ->
           Type_variant(List.map
             (fun (c, tl) -> (c, List.map (Ctype.nondep_type env mid) tl))
             cstrs)
       | Type_record lbls ->
           Type_record(List.map
             (fun (c, mut, t) -> (c, mut, Ctype.nondep_type env mid t))
             lbls)}

  and abstract_type_decl d =
    {type_params = d.type_params;
     type_arity = d.type_arity;
     type_kind = Type_abstract}

  and nondep_modtype_decl = function
      Tmodtype_abstract -> Tmodtype_abstract
    | Tmodtype_manifest mty -> Tmodtype_manifest(nondep_mty Strict mty)

  in
    nondep_mty Co mty