summaryrefslogtreecommitdiff
path: root/typing/env.ml
diff options
context:
space:
mode:
Diffstat (limited to 'typing/env.ml')
-rw-r--r--typing/env.ml321
1 files changed, 231 insertions, 90 deletions
diff --git a/typing/env.ml b/typing/env.ml
index beee7a17d2..938d438ec8 100644
--- a/typing/env.ml
+++ b/typing/env.ml
@@ -57,6 +57,7 @@ type error =
| Illegal_renaming of string * string * string
| Inconsistent_import of string * string * string
| Need_recursive_types of string * string
+ | Missing_module of Location.t * Path.t * Path.t
exception Error of error
@@ -111,6 +112,7 @@ type summary =
| Env_class of summary * Ident.t * class_declaration
| Env_cltype of summary * Ident.t * class_type_declaration
| Env_open of summary * Path.t
+ | Env_functor_arg of summary * Ident.t
module EnvTbl =
struct
@@ -172,6 +174,7 @@ type t = {
components: (Path.t * module_components) EnvTbl.t;
classes: (Path.t * class_declaration) EnvTbl.t;
cltypes: (Path.t * class_type_declaration) EnvTbl.t;
+ functor_args: unit Ident.tbl;
summary: summary;
local_constraints: bool;
gadt_instances: (int * TypeSet.t ref) list;
@@ -201,11 +204,12 @@ and structure_components = {
and functor_components = {
fcomp_param: Ident.t; (* Formal parameter *)
- fcomp_arg: module_type; (* Argument signature *)
+ fcomp_arg: module_type option; (* Argument signature *)
fcomp_res: module_type; (* Result signature *)
fcomp_env: t; (* Environment in which the result signature makes sense *)
fcomp_subst: Subst.t; (* Prefixing substitution for the result signature *)
- fcomp_cache: (Path.t, module_components) Hashtbl.t (* For memoization *)
+ fcomp_cache: (Path.t, module_components) Hashtbl.t; (* For memoization *)
+ fcomp_subst_cache: (Path.t, module_type) Hashtbl.t
}
let subst_modtype_maker (subst, mty) = Subst.modtype subst mty
@@ -218,6 +222,7 @@ let empty = {
cltypes = EnvTbl.empty;
summary = Env_empty; local_constraints = false; gadt_instances = [];
in_signature = false;
+ functor_args = Ident.empty;
}
let in_signature env = {env with in_signature = true}
@@ -262,9 +267,13 @@ let check_modtype_inclusion =
(* to be filled with Includemod.check_modtype_inclusion *)
ref ((fun env mty1 path1 mty2 -> assert false) :
t -> module_type -> Path.t -> module_type -> unit)
+let strengthen =
+ (* to be filled with Mtype.strengthen *)
+ ref ((fun env mty path -> assert false) :
+ t -> module_type -> Path.t -> module_type)
let md md_type =
- {md_type; md_attributes=[]}
+ {md_type; md_attributes=[]; md_loc=Location.none}
(* The name of the compilation unit currently compiled.
"" if outside a compilation unit. *)
@@ -279,7 +288,8 @@ type pers_struct =
ps_comps: module_components;
ps_crcs: (string * Digest.t) list;
ps_filename: string;
- ps_flags: pers_flags list }
+ ps_flags: pers_flags list;
+ mutable ps_crcs_checked: bool }
let persistent_structures =
(Hashtbl.create 17 : (string, pers_struct option) Hashtbl.t)
@@ -288,17 +298,19 @@ let persistent_structures =
let crc_units = Consistbl.create()
-let check_consistency filename crcs =
+let check_consistency ps =
+ if ps.ps_crcs_checked then () else
try
List.iter
- (fun (name, crc) -> Consistbl.check crc_units name crc filename)
- crcs
+ (fun (name, crc) -> Consistbl.check crc_units name crc ps.ps_filename)
+ ps.ps_crcs;
+ ps.ps_crcs_checked <- true
with Consistbl.Inconsistency(name, source, auth) ->
error (Inconsistent_import(name, auth, source))
(* Reading persistent structures from .cmi files *)
-let read_pers_struct modname filename = (
+let read_pers_struct modname filename =
let cmi = read_cmi filename in
let name = cmi.cmi_name in
let sign = cmi.cmi_sign in
@@ -307,35 +319,37 @@ let read_pers_struct modname filename = (
let comps =
!components_of_module' empty Subst.identity
(Pident(Ident.create_persistent name))
- (Mty_signature sign) in
- let ps = { ps_name = name;
- ps_sig = sign;
- ps_comps = comps;
- ps_crcs = crcs;
- ps_filename = filename;
- ps_flags = flags } in
- if ps.ps_name <> modname then
- error (Illegal_renaming(modname, ps.ps_name, filename));
- check_consistency filename ps.ps_crcs;
- List.iter
- (function Rectypes ->
- if not !Clflags.recursive_types then
- error (Need_recursive_types(ps.ps_name, !current_unit)))
- ps.ps_flags;
- Hashtbl.add persistent_structures modname (Some ps);
- ps
-)
-
-let find_pers_struct name =
+ (Mty_signature sign)
+ in
+ let ps = { ps_name = name;
+ ps_sig = sign;
+ ps_comps = comps;
+ ps_crcs = crcs;
+ ps_crcs_checked = false;
+ ps_filename = filename;
+ ps_flags = flags } in
+ if ps.ps_name <> modname then
+ error (Illegal_renaming(modname, ps.ps_name, filename));
+ if not !Clflags.transparent_modules then check_consistency ps;
+ List.iter
+ (function Rectypes ->
+ if not !Clflags.recursive_types then
+ error (Need_recursive_types(ps.ps_name, !current_unit)))
+ ps.ps_flags;
+ Hashtbl.add persistent_structures modname (Some ps);
+ ps
+
+let find_pers_struct ?(check=true) name =
if name = "*predef*" then raise Not_found;
let r =
try Some (Hashtbl.find persistent_structures name)
with Not_found -> None
in
- match r with
- | Some None -> raise Not_found
- | Some (Some sg) -> sg
- | None ->
+ let ps =
+ match r with
+ | Some None -> raise Not_found
+ | Some (Some sg) -> sg
+ | None ->
let filename =
try find_in_path_uncap !load_path (name ^ ".cmi")
with Not_found ->
@@ -343,6 +357,9 @@ let find_pers_struct name =
raise Not_found
in
read_pers_struct name filename
+ in
+ if check then check_consistency ps;
+ ps
let reset_cache () =
current_unit := "";
@@ -436,10 +453,94 @@ let find_type p env =
let find_type_descrs p env =
snd (find_type_full p env)
+let find_module ~alias path env =
+ match path with
+ Pident id ->
+ begin try
+ let (p, data) = EnvTbl.find_same id env.modules
+ in data
+ with Not_found ->
+ if Ident.persistent id then
+ let ps = find_pers_struct (Ident.name id) in
+ md (Mty_signature(ps.ps_sig))
+ else raise Not_found
+ end
+ | Pdot(p, s, pos) ->
+ begin match
+ EnvLazy.force !components_of_module_maker' (find_module_descr p env)
+ with
+ Structure_comps c ->
+ let (data, pos) = Tbl.find s c.comp_modules in
+ md (EnvLazy.force subst_modtype_maker data)
+ | Functor_comps f ->
+ raise Not_found
+ end
+ | Papply(p1, p2) ->
+ let desc1 = find_module_descr p1 env in
+ begin match EnvLazy.force !components_of_module_maker' desc1 with
+ Functor_comps f ->
+ md begin match f.fcomp_res with
+ | Mty_alias p ->
+ Mty_alias (Subst.module_path f.fcomp_subst p)
+ | mty ->
+ if alias then mty else
+ try
+ Hashtbl.find f.fcomp_subst_cache p2
+ with Not_found ->
+ let mty =
+ Subst.modtype
+ (Subst.add_module f.fcomp_param p2 f.fcomp_subst)
+ f.fcomp_res in
+ Hashtbl.add f.fcomp_subst_cache p2 mty;
+ mty
+ end
+ | Structure_comps c ->
+ raise Not_found
+ end
+
+let required_globals = ref []
+let reset_required_globals () = required_globals := []
+let get_required_globals () = !required_globals
+let add_required_global id =
+ if Ident.global id && not !Clflags.transparent_modules
+ && not (List.exists (Ident.same id) !required_globals)
+ then required_globals := id :: !required_globals
+
+let rec normalize_path lax env path =
+ let path =
+ match path with
+ Pdot(p, s, pos) ->
+ Pdot(normalize_path lax env p, s, pos)
+ | Papply(p1, p2) ->
+ Papply(normalize_path lax env p1, normalize_path true env p2)
+ | _ -> path
+ in
+ try match find_module ~alias:true path env with
+ {md_type=Mty_alias path1} ->
+ let path' = normalize_path lax env path1 in
+ if lax || !Clflags.transparent_modules then path' else
+ let id = Path.head path in
+ if Ident.global id && not (Ident.same id (Path.head path'))
+ then add_required_global id;
+ path'
+ | _ -> path
+ with Not_found when lax
+ || (match path with Pident id -> not (Ident.persistent id) | _ -> true) ->
+ path
+
+let normalize_path oloc env path =
+ try normalize_path (oloc = None) env path
+ with Not_found ->
+ match oloc with None -> assert false
+ | Some loc ->
+ raise (Error(Missing_module(loc, path, normalize_path true env path)))
+
+let find_module = find_module ~alias:false
+
(* Find the manifest type associated to a type when appropriate:
- the type should be public or should have a private row,
- the type should have an associated manifest type. *)
-let find_type_expansion ?level path env =
+let find_type_expansion path env =
let decl = find_type path env in
match decl.type_manifest with
| Some body when decl.type_private = Public
@@ -450,7 +551,13 @@ let find_type_expansion ?level path env =
private row are still considered unknown to the type system.
Hence, this case is caught by the following clause that also handles
purely abstract data types without manifest type definition. *)
- | _ -> raise Not_found
+ | _ ->
+ (* another way to expand is to normalize the path itself *)
+ let path' = normalize_path None env path in
+ if Path.same path path' then raise Not_found else
+ (decl.type_params,
+ newgenty (Tconstr (path', decl.type_params, ref Mnil)),
+ may_map snd decl.type_newtype_level)
(* Find the manifest type information associated to a type, i.e.
the necessary information for the compiler's type-based optimisations.
@@ -462,37 +569,26 @@ let find_type_expansion_opt path env =
(* The manifest type of Private abstract data types can still get
an approximation using their manifest type. *)
| Some body -> (decl.type_params, body, may_map snd decl.type_newtype_level)
- | _ -> raise Not_found
+ | _ ->
+ let path' = normalize_path None env path in
+ if Path.same path path' then raise Not_found else
+ (decl.type_params,
+ newgenty (Tconstr (path', decl.type_params, ref Mnil)),
+ may_map snd decl.type_newtype_level)
let find_modtype_expansion path env =
match (find_modtype path env).mtd_type with
| None -> raise Not_found
| Some mty -> mty
-let find_module path env =
+let rec is_functor_arg path env =
match path with
Pident id ->
- begin try
- let (p, data) = EnvTbl.find_same id env.modules
- in data
- with Not_found ->
- if Ident.persistent id then
- let ps = find_pers_struct (Ident.name id) in
- md (Mty_signature(ps.ps_sig))
- else raise Not_found
- end
- | Pdot(p, s, pos) ->
- begin match
- EnvLazy.force !components_of_module_maker' (find_module_descr p env)
- with
- Structure_comps c ->
- let (data, pos) = Tbl.find s c.comp_modules in
- md (EnvLazy.force subst_modtype_maker data)
- | Functor_comps f ->
- raise Not_found
+ begin try Ident.find_same id env.functor_args; true
+ with Not_found -> false
end
- | Papply(p1, p2) ->
- raise Not_found (* not right *)
+ | Pdot (p, s, _) -> is_functor_arg p env
+ | Papply _ -> true
(* Lookup by name *)
@@ -519,54 +615,51 @@ let rec lookup_module_descr lid env =
end
| Lapply(l1, l2) ->
let (p1, desc1) = lookup_module_descr l1 env in
- let (p2, {md_type=mty2}) = lookup_module l2 env in
+ let p2 = lookup_module l2 env in
+ let {md_type=mty2} = find_module p2 env in
begin match EnvLazy.force !components_of_module_maker' desc1 with
Functor_comps f ->
- !check_modtype_inclusion env mty2 p2 f.fcomp_arg;
+ Misc.may (!check_modtype_inclusion env mty2 p2) f.fcomp_arg;
(Papply(p1, p2), !components_of_functor_appl' f p1 p2)
| Structure_comps c ->
raise Not_found
end
-and lookup_module lid env : Path.t * module_declaration =
+and lookup_module lid env : Path.t =
match lid with
Lident s ->
begin try
- let (_, {md_type}) as r = EnvTbl.find_name s env.modules in
+ let (p, {md_type}) as r = EnvTbl.find_name s env.modules in
begin match md_type with
| Mty_ident (Path.Pident id) when Ident.name id = "#recmod#" ->
(* see #5965 *)
raise Recmodule
| _ -> ()
end;
- r
+ p
with Not_found ->
if s = !current_unit then raise Not_found;
- let ps = find_pers_struct s in
- (Pident(Ident.create_persistent s),
- md (Mty_signature ps.ps_sig)
- )
+ ignore (find_pers_struct ~check:false s);
+ Pident(Ident.create_persistent s)
end
| Ldot(l, s) ->
let (p, descr) = lookup_module_descr l env in
begin match EnvLazy.force !components_of_module_maker' descr with
Structure_comps c ->
let (data, pos) = Tbl.find s c.comp_modules in
- (Pdot(p, s, pos), md (EnvLazy.force subst_modtype_maker data))
+ Pdot(p, s, pos)
| Functor_comps f ->
raise Not_found
end
| Lapply(l1, l2) ->
let (p1, desc1) = lookup_module_descr l1 env in
- let (p2, {md_type=mty2}) = lookup_module l2 env in
+ let p2 = lookup_module l2 env in
+ let {md_type=mty2} = find_module p2 env in
let p = Papply(p1, p2) in
begin match EnvLazy.force !components_of_module_maker' desc1 with
Functor_comps f ->
- !check_modtype_inclusion env mty2 p2 f.fcomp_arg;
- let mty =
- Subst.modtype (Subst.add_module f.fcomp_param p2 f.fcomp_subst)
- f.fcomp_res in
- (p, md mty)
+ Misc.may (!check_modtype_inclusion env mty2 p2) f.fcomp_arg;
+ p
| Structure_comps c ->
raise Not_found
end
@@ -915,16 +1008,29 @@ let add_gadt_instance_chain env lv t =
(* Expand manifest module type names at the top of the given module type *)
-let rec scrape_modtype mty env =
- match mty with
- Mty_ident path ->
+let rec scrape_alias env ?path mty =
+ match mty, path with
+ Mty_ident p, _ ->
begin try
- scrape_modtype (find_modtype_expansion path env) env
+ scrape_alias env (find_modtype_expansion p env) ?path
with Not_found ->
mty
end
+ | Mty_alias path, _ ->
+ begin try
+ scrape_alias env (find_module path env).md_type ~path
+ with Not_found ->
+ Location.prerr_warning Location.none
+ (Warnings.Deprecated
+ ("module " ^ Path.name path ^ " cannot be accessed"));
+ mty
+ end
+ | mty, Some path ->
+ !strengthen env mty path
| _ -> mty
+let scrape_alias env mty = scrape_alias env mty
+
(* Compute constructor descriptions *)
let constructors_of_type ty_path decl =
@@ -1042,7 +1148,7 @@ let rec components_of_module env sub path mty =
EnvLazy.create (env, sub, path, mty)
and components_of_module_maker (env, sub, path, mty) =
- (match scrape_modtype mty env with
+ (match scrape_alias env mty with
Mty_signature sg ->
let c =
{ comp_values = Tbl.empty;
@@ -1120,13 +1226,15 @@ and components_of_module_maker (env, sub, path, mty) =
fcomp_param = param;
(* fcomp_arg must be prefixed eagerly, because it is interpreted
in the outer environment, not in env *)
- fcomp_arg = Subst.modtype sub ty_arg;
+ fcomp_arg = may_map (Subst.modtype sub) ty_arg;
(* fcomp_res is prefixed lazily, because it is interpreted in env *)
fcomp_res = ty_res;
fcomp_env = env;
fcomp_subst = sub;
- fcomp_cache = Hashtbl.create 17 }
- | Mty_ident p ->
+ fcomp_cache = Hashtbl.create 17;
+ fcomp_subst_cache = Hashtbl.create 17 }
+ | Mty_ident _
+ | Mty_alias _ ->
Structure_comps {
comp_values = Tbl.empty;
comp_constrs = Tbl.empty;
@@ -1290,6 +1398,12 @@ let _ =
(* Insertion of bindings by identifier *)
+let add_functor_arg ?(arg=false) id env =
+ if not arg then env else
+ {env with
+ functor_args = Ident.add id () env.functor_args;
+ summary = Env_functor_arg (env.summary, id)}
+
let add_value ?check id desc env =
store_value None ?check id (Pident id) desc env env
@@ -1299,8 +1413,14 @@ let add_type ~check id info env =
and add_exception ~check id decl env =
store_exception ~check None id (Pident id) decl env env
-and add_module_declaration id md env =
- store_module None id (Pident id) md env env
+and add_module_declaration ?arg id md env =
+ let path =
+ (*match md.md_type with
+ Mty_alias path -> normalize_path env path
+ | _ ->*) Pident id
+ in
+ let env = store_module None id path md env env in
+ add_functor_arg ?arg id env
and add_modtype id info env =
store_modtype None id (Pident id) info env env
@@ -1311,8 +1431,8 @@ and add_class id ty env =
and add_cltype id ty env =
store_cltype None id (Pident id) ty env env
-let add_module id mty env =
- add_module_declaration id (md mty) env
+let add_module ?arg id mty env =
+ add_module_declaration ?arg id (md mty) env
let add_local_constraint id info elv env =
match info with
@@ -1332,13 +1452,17 @@ let enter store_fun name data env =
let enter_value ?check = enter (store_value ?check)
and enter_type = enter (store_type ~check:true)
and enter_exception = enter (store_exception ~check:true)
-and enter_module_declaration = enter store_module
+and enter_module_declaration ?arg name md env =
+ let id = Ident.create name in
+ (id, add_module_declaration ?arg id md env)
+ (* let (id, env) = enter store_module name md env in
+ (id, add_functor_arg ?arg id env) *)
and enter_modtype = enter store_modtype
and enter_class = enter store_class
and enter_cltype = enter store_cltype
-let enter_module s mty env =
- enter_module_declaration s (md mty) env
+let enter_module ?arg s mty env =
+ enter_module_declaration ?arg s (md mty) env
(* Insertion of all components of a signature *)
@@ -1427,12 +1551,14 @@ let open_signature ?(loc = Location.none) ?(toplevel = false) ovf root sg env =
(* Read a signature from a file *)
let read_signature modname filename =
- let ps = read_pers_struct modname filename in ps.ps_sig
+ let ps = read_pers_struct modname filename in
+ check_consistency ps;
+ ps.ps_sig
(* Return the CRC of the interface of the given compilation unit *)
let crc_of_unit name =
- let ps = find_pers_struct name in
+ let ps = find_pers_struct ~check:false name in
try
List.assoc name ps.ps_crcs
with Not_found ->
@@ -1446,6 +1572,8 @@ let imported_units() =
(* Save a signature to a file *)
let save_signature_with_imports sg modname filename imports =
+ (*prerr_endline filename;
+ List.iter (fun (name, crc) -> prerr_endline name) imports;*)
Btype.cleanup_abbrev ();
Subst.reset_for_saving ();
let sg = Subst.signature (Subst.for_saving Subst.identity) sg in
@@ -1470,7 +1598,8 @@ let save_signature_with_imports sg modname filename imports =
ps_comps = comps;
ps_crcs = (cmi.cmi_name, crc) :: imports;
ps_filename = filename;
- ps_flags = cmi.cmi_flags } in
+ ps_flags = cmi.cmi_flags;
+ ps_crcs_checked = true } in
Hashtbl.add persistent_structures modname (Some ps);
Consistbl.set crc_units modname crc filename;
sg
@@ -1625,10 +1754,22 @@ let report_error ppf = function
fprintf ppf
"@[<hov>Unit %s imports from %s, which uses recursive types.@ %s@]"
export import "The compilation flag -rectypes is required"
+ | Missing_module(_, path1, path2) ->
+ fprintf ppf "@[@[<hov>";
+ if Path.same path1 path2 then
+ fprintf ppf "Internal path@ %s@ is dangling." (Path.name path1)
+ else
+ fprintf ppf "Internal path@ %s@ expands to@ %s@ which is dangling."
+ (Path.name path1) (Path.name path2);
+ fprintf ppf "@]@ @[%s@ %s@ %s.@]@]"
+ "The compiled interface for module" (Ident.name (Path.head path2))
+ "was not found"
let () =
Location.register_error_of_exn
(function
+ | Error (Missing_module (loc, _, _) as err) when loc <> Location.none ->
+ Some (Location.error_of_printer loc report_error err)
| Error err -> Some (Location.error_of_printer_file report_error err)
| _ -> None
)