220 lines
7.6 KiB
OCaml
220 lines
7.6 KiB
OCaml
(***********************************************************************)
|
|
(* *)
|
|
(* 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 Q Public License version 1.0. *)
|
|
(* *)
|
|
(***********************************************************************)
|
|
|
|
(* Operations on module types *)
|
|
|
|
open Asttypes
|
|
open Path
|
|
open Types
|
|
|
|
|
|
let rec scrape env mty =
|
|
match mty with
|
|
Mty_ident p ->
|
|
begin try
|
|
scrape env (Env.find_modtype_expansion p env)
|
|
with Not_found ->
|
|
mty
|
|
end
|
|
| _ -> mty
|
|
|
|
let freshen mty =
|
|
Subst.modtype Subst.identity mty
|
|
|
|
let rec strengthen env mty p =
|
|
match scrape env mty with
|
|
Mty_signature sg ->
|
|
Mty_signature(strengthen_sig env sg p)
|
|
| Mty_functor(param, arg, res) when !Clflags.applicative_functors ->
|
|
Mty_functor(param, arg, strengthen env res (Papply(p, Pident param)))
|
|
| mty ->
|
|
mty
|
|
|
|
and strengthen_sig env sg p =
|
|
match sg with
|
|
[] -> []
|
|
| (Sig_value(id, desc) as sigelt) :: rem ->
|
|
sigelt :: strengthen_sig env rem p
|
|
| Sig_type(id, decl, rs) :: rem ->
|
|
let newdecl =
|
|
match decl.type_manifest, decl.type_private, decl.type_kind with
|
|
Some _, Public, _ -> decl
|
|
| Some _, Private, (Type_record _ | Type_variant _) -> decl
|
|
| _ ->
|
|
let manif =
|
|
Some(Btype.newgenty(Tconstr(Pdot(p, Ident.name id, nopos),
|
|
decl.type_params, ref Mnil))) in
|
|
if decl.type_kind = Type_abstract then
|
|
{ decl with type_private = Public; type_manifest = manif }
|
|
else
|
|
{ decl with type_manifest = manif }
|
|
in
|
|
Sig_type(id, newdecl, rs) :: strengthen_sig env rem p
|
|
| (Sig_exception(id, d) as sigelt) :: rem ->
|
|
sigelt :: strengthen_sig env rem p
|
|
| Sig_module(id, mty, rs) :: rem ->
|
|
Sig_module(id, strengthen env mty (Pdot(p, Ident.name id, nopos)), rs)
|
|
:: strengthen_sig (Env.add_module id mty env) rem p
|
|
(* Need to add the module in case it defines manifest module types *)
|
|
| Sig_modtype(id, decl) :: rem ->
|
|
let newdecl =
|
|
match decl with
|
|
Modtype_abstract ->
|
|
Modtype_manifest(Mty_ident(Pdot(p, Ident.name id, nopos)))
|
|
| Modtype_manifest _ ->
|
|
decl in
|
|
Sig_modtype(id, newdecl) ::
|
|
strengthen_sig (Env.add_modtype id decl env) rem p
|
|
(* Need to add the module type in case it is manifest *)
|
|
| (Sig_class(id, decl, rs) as sigelt) :: rem ->
|
|
sigelt :: strengthen_sig env rem p
|
|
| (Sig_class_type(id, decl, rs) as sigelt) :: rem ->
|
|
sigelt :: strengthen_sig env rem p
|
|
|
|
(* 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 env va mty =
|
|
match mty with
|
|
Mty_ident p ->
|
|
if Path.isfree mid p then
|
|
nondep_mty env va (Env.find_modtype_expansion p env)
|
|
else mty
|
|
| Mty_signature sg ->
|
|
Mty_signature(nondep_sig env va sg)
|
|
| Mty_functor(param, arg, res) ->
|
|
let var_inv =
|
|
match va with Co -> Contra | Contra -> Co | Strict -> Strict in
|
|
Mty_functor(param, nondep_mty env var_inv arg,
|
|
nondep_mty (Env.add_module param arg env) va res)
|
|
|
|
and nondep_sig env va = function
|
|
[] -> []
|
|
| item :: rem ->
|
|
let rem' = nondep_sig env va rem in
|
|
match item with
|
|
Sig_value(id, d) ->
|
|
Sig_value(id, {val_type = Ctype.nondep_type env mid d.val_type;
|
|
val_kind = d.val_kind;
|
|
val_loc = d.val_loc;
|
|
}) :: rem'
|
|
| Sig_type(id, d, rs) ->
|
|
Sig_type(id, Ctype.nondep_type_decl env mid id (va = Co) d, rs)
|
|
:: rem'
|
|
| Sig_exception(id, d) ->
|
|
let d = {exn_args = List.map (Ctype.nondep_type env mid) d.exn_args;
|
|
exn_loc = d.exn_loc} in
|
|
Sig_exception(id, d) :: rem'
|
|
| Sig_module(id, mty, rs) ->
|
|
Sig_module(id, nondep_mty env va mty, rs) :: rem'
|
|
| Sig_modtype(id, d) ->
|
|
begin try
|
|
Sig_modtype(id, nondep_modtype_decl env d) :: rem'
|
|
with Not_found ->
|
|
match va with
|
|
Co -> Sig_modtype(id, Modtype_abstract) :: rem'
|
|
| _ -> raise Not_found
|
|
end
|
|
| Sig_class(id, d, rs) ->
|
|
Sig_class(id, Ctype.nondep_class_declaration env mid d, rs)
|
|
:: rem'
|
|
| Sig_class_type(id, d, rs) ->
|
|
Sig_class_type(id, Ctype.nondep_cltype_declaration env mid d, rs)
|
|
:: rem'
|
|
|
|
and nondep_modtype_decl env = function
|
|
Modtype_abstract -> Modtype_abstract
|
|
| Modtype_manifest mty -> Modtype_manifest(nondep_mty env Strict mty)
|
|
|
|
in
|
|
nondep_mty env Co mty
|
|
|
|
let enrich_typedecl env p decl =
|
|
match decl.type_manifest with
|
|
Some ty -> decl
|
|
| None ->
|
|
try
|
|
let orig_decl = Env.find_type p env in
|
|
if orig_decl.type_arity <> decl.type_arity
|
|
then decl
|
|
else {decl with type_manifest =
|
|
Some(Btype.newgenty(Tconstr(p, decl.type_params, ref Mnil)))}
|
|
with Not_found ->
|
|
decl
|
|
|
|
let rec enrich_modtype env p mty =
|
|
match mty with
|
|
Mty_signature sg ->
|
|
Mty_signature(List.map (enrich_item env p) sg)
|
|
| _ ->
|
|
mty
|
|
|
|
and enrich_item env p = function
|
|
Sig_type(id, decl, rs) ->
|
|
Sig_type(id,
|
|
enrich_typedecl env (Pdot(p, Ident.name id, nopos)) decl, rs)
|
|
| Sig_module(id, mty, rs) ->
|
|
Sig_module(id,
|
|
enrich_modtype env (Pdot(p, Ident.name id, nopos)) mty, rs)
|
|
| item -> item
|
|
|
|
let rec type_paths env p mty =
|
|
match scrape env mty with
|
|
Mty_ident p -> []
|
|
| Mty_signature sg -> type_paths_sig env p 0 sg
|
|
| Mty_functor(param, arg, res) -> []
|
|
|
|
and type_paths_sig env p pos sg =
|
|
match sg with
|
|
[] -> []
|
|
| Sig_value(id, decl) :: rem ->
|
|
let pos' = match decl.val_kind with Val_prim _ -> pos | _ -> pos + 1 in
|
|
type_paths_sig env p pos' rem
|
|
| Sig_type(id, decl, _) :: rem ->
|
|
Pdot(p, Ident.name id, nopos) :: type_paths_sig env p pos rem
|
|
| Sig_module(id, mty, _) :: rem ->
|
|
type_paths env (Pdot(p, Ident.name id, pos)) mty @
|
|
type_paths_sig (Env.add_module id mty env) p (pos+1) rem
|
|
| Sig_modtype(id, decl) :: rem ->
|
|
type_paths_sig (Env.add_modtype id decl env) p pos rem
|
|
| (Sig_exception _ | Sig_class _) :: rem ->
|
|
type_paths_sig env p (pos+1) rem
|
|
| (Sig_class_type _) :: rem ->
|
|
type_paths_sig env p pos rem
|
|
|
|
let rec no_code_needed env mty =
|
|
match scrape env mty with
|
|
Mty_ident p -> false
|
|
| Mty_signature sg -> no_code_needed_sig env sg
|
|
| Mty_functor(_, _, _) -> false
|
|
|
|
and no_code_needed_sig env sg =
|
|
match sg with
|
|
[] -> true
|
|
| Sig_value(id, decl) :: rem ->
|
|
begin match decl.val_kind with
|
|
| Val_prim _ -> no_code_needed_sig env rem
|
|
| _ -> false
|
|
end
|
|
| Sig_module(id, mty, _) :: rem ->
|
|
no_code_needed env mty &&
|
|
no_code_needed_sig (Env.add_module id mty env) rem
|
|
| (Sig_type _ | Sig_modtype _ | Sig_class_type _) :: rem ->
|
|
no_code_needed_sig env rem
|
|
| (Sig_exception _ | Sig_class _) :: rem ->
|
|
false
|