Continue to dig-in codept

main
Romain Calascibetta 9 months ago
parent e027cfbaf2
commit e2a2a84a1f

@ -1 +1,2 @@
version=0.24.1
break-before-in=auto

@ -12,8 +12,7 @@ let print delta =
List.fold_left
(fun acc (fpath, _) ->
max (String.length (Fmt.to_to_string Fpath.pp fpath)) acc)
0 bindings
in
0 bindings in
List.iter (print_binding ~max:max_length) bindings;
Fiber.return (Ok 0)
@ -57,8 +56,7 @@ let root =
| Ok v when Sys.file_exists str && Sys.is_directory str ->
Ok (Fpath.to_dir_path v)
| Ok v -> R.error_msgf "%a does not exist or is not a directory" Fpath.pp v
| Error _ as err -> err
in
| Error _ as err -> err in
let existing_directory = Arg.conv (existing_directory, Fpath.pp) in
Arg.(
required & opt (some existing_directory) None & info [ "r"; "root" ] ~doc)
@ -82,8 +80,7 @@ let path =
let hash =
let parser str =
try Ok (Digest.from_hex str)
with _exn -> R.error_msgf "Invalid hash: %S" str
in
with _exn -> R.error_msgf "Invalid hash: %S" str in
let pp = Fmt.using Digest.to_hex Fmt.string in
let hash = Arg.conv (parser, pp) in
let doc = "Specifies the search with a hash of the interface." in
@ -94,16 +91,14 @@ let term_print = Term.(ret (const run_print $ Envs.term_delta))
let cmd_print =
let doc =
"Show all implementations with their interfaces available into the given \
root directory."
in
root directory." in
let man =
[
`S Manpage.s_description;
`P
"$(tname) shows all implementations with their interfaces from the \
given $(b,root) directory.";
]
in
] in
Cmd.v (Cmd.info "print" ~version ~doc ~man) term_print
let term_search_intf =
@ -115,8 +110,7 @@ let cmd_search =
[
`S Manpage.s_description;
`P "$(tname) tries to search implementations of a given interface.";
]
in
] in
Cmd.v (Cmd.info "search-intf" ~version ~doc ~man) term_search_intf
let cmd =

@ -24,8 +24,7 @@ let signature_of ~sat root =
Fiber.run_thread (fun () -> Merkle.of_path fpath (Bytes.create 0x1000))
>>= function
| Ok hash' -> Fiber.return (Ok Merkle.(hash <.> hash'))
| Error _ as err -> Fiber.return err)
in
| Error _ as err -> Fiber.return err) in
match
OS.Path.fold ~dotfiles:false ~elements:(`Sat sat) ~traverse:`Any fold
(Fiber.return (Ok (Digestif.SHA256.digest_string "")))
@ -61,8 +60,7 @@ let run_database :
| Some serialized ->
let fpath = Fpath.to_string serialized in
Sys.file_exists fpath && not (Sys.is_directory fpath)
| None -> false
in
| None -> false in
match serialized with
| Some serialized when upgrade && exists ->
signature_of ~sat:Database.sat root >>? fun signature ->
@ -136,8 +134,7 @@ let root =
| Ok v when Sys.file_exists str && Sys.is_directory str ->
Ok (Fpath.to_dir_path v)
| Ok v -> R.error_msgf "%a does not exist or is not a directory" Fpath.pp v
| Error _ as err -> err
in
| Error _ as err -> err in
let existing_directory = Arg.conv (existing_directory, Fpath.pp) in
Arg.(
required

@ -1,7 +1,6 @@
let print_intf g ~max (intf : Gamma.interface) =
let modtype, fpath, digest =
(intf :> Mod.Path.t * Fpath.t * Digest.t option)
in
(intf :> Mod.Path.t * Fpath.t * Digest.t option) in
let surround s0 s1 pp ppf v = Fmt.pf ppf "%s%a%s" s0 pp v s1 in
Fmt.pr "%a %*s %a%a\n%!"
Fmt.(
@ -23,8 +22,7 @@ let print gamma =
(fun acc (intf : Gamma.interface) ->
let modtype, _, _ = (intf :> Mod.Path.t * Fpath.t * Digest.t option) in
max (String.length (Mod.Path.to_string modtype)) acc)
0 interfaces
in
0 interfaces in
List.iter (print_intf g ~max:max_length) interfaces;
Fiber.return (Ok 0)
@ -58,8 +56,7 @@ let print_interfaces g ~only_dirs interfaces =
(fun acc (intf : Gamma.interface) ->
let path, _, _ = (intf :> Mod.Path.t * Fpath.t * Digest.t option) in
max (String.length (Mod.Path.to_string path)) acc)
0 interfaces
in
0 interfaces in
if only_dirs then
List.iter (Fmt.pr "%a\n%!" Fpath.pp) (Gamma.to_dirs interfaces)
else List.iter (print_intf g ~max:max_length) interfaces
@ -81,8 +78,7 @@ let resolve gamma only_dirs hash = function
let intfs =
List.map
(fun (modtype, hash) -> (Mod.Path.singleton modtype, hash))
intfs
in
intfs in
Gamma.resolve_multiple_paths ?opens:None g intfs |> Fiber.return
>>? fun interfaces ->
print_interfaces g ~only_dirs interfaces;
@ -132,16 +128,14 @@ let cmd_print =
`P
"$(tname) shows all interfaces (with their hashes and their locations) \
from the given $(b,root) directory.";
]
in
] in
Cmd.v (Cmd.info "print" ~version ~doc ~man) term_print
let hash =
let parser str =
match Digest.from_hex str with
| hash -> Ok hash
| exception _ -> R.error_msgf "Invalid hash: %S" str
in
| exception _ -> R.error_msgf "Invalid hash: %S" str in
let pp = Fmt.using Digest.to_hex Fmt.string in
let hash = Arg.conv (parser, pp) in
let doc = "The hash of the interface." in
@ -164,8 +158,7 @@ let cmd_search =
`P
"$(tname) searches the given module name and returns which OCaml \
object describes it from the given $(b,root) directory.";
]
in
] in
Cmd.v (Cmd.info "search" ~version ~doc ~man) term_search
let only_dirs =
@ -177,12 +170,10 @@ let ocaml_object_or_path =
match Fpath.of_string str with
| Ok v when Sys.file_exists str && not (Sys.is_directory str) ->
Ok (`Object v)
| _ -> Mod.Path.of_string str >>| fun v -> `Interface v
in
| _ -> Mod.Path.of_string str >>| fun v -> `Interface v in
let pp ppf = function
| `Object v -> Fpath.pp ppf v
| `Interface v -> Mod.Path.pp ppf v
in
| `Interface v -> Mod.Path.pp ppf v in
Arg.conv (parser, pp)
let ocaml_object_or_path =
@ -203,8 +194,7 @@ let cmd_resolve =
`P
"$(tname) resolves all dependencies needed to compile the given\n\
\ $(i,*.cmi).";
]
in
] in
Cmd.v (Cmd.info "resolve" ~version ~doc ~man) term_resolve
let modtype =
@ -234,8 +224,7 @@ let cmd_hash_of_intf =
$(i,certain) name (given by the user or equal to the name of the \
requested interface) and lets OCaml to compile it and get the hash. \
Note that the name has an implication into the resulted hash.";
]
in
] in
Cmd.v (Cmd.info "hash" ~version ~doc ~man) term_hash_of_intf
let cmd =

@ -52,8 +52,7 @@ let provided_intfs fpath =
option
~none:(const string (String.make 32 '-'))
(using Digest.to_hex string))
digest Mod.Path.pp path
in
digest Mod.Path.pp path in
List.iter print_intf intfs;
Ok 0
@ -72,8 +71,7 @@ let provided_implementations fpath =
(fun (sub_modname, sub_modtype) ->
( Mod.Path.join modname sub_modname,
Option.map (Mod.Path.join modtype) sub_modtype ))
sub_impls
in
sub_impls in
let impls =
(Mod.Path.singleton modname, Some (Mod.Path.singleton modtype)) :: sub_impls
in
@ -81,14 +79,12 @@ let provided_implementations fpath =
List.fold_left
(fun acc (modname, _) ->
max acc (String.length (Mod.Path.to_string modname)))
0 impls
in
0 impls in
let print_impl ~max (modname, modtype) =
Fmt.pr "module %*s%a\n%!" max
(Mod.Path.to_string modname)
Fmt.(option (const string " : " ++ Mod.Path.pp))
modtype
in
modtype in
List.iter (print_impl ~max:max_length) impls;
Ok 0
@ -115,18 +111,15 @@ let filter =
Logs.warn (fun m ->
m "%S is an invalid module name, ignore it." v);
a)
[] ms
in
[] ms in
Ok (Some ms)
| [] ->
Logs.warn (fun m ->
m "There are no filters, we will display everything.");
Ok None
in
Ok None in
let pp ppf = function
| Some filter -> Fmt.(list ~sep:(any ",") Mod.pp) ppf filter
| None -> Fmt.nop ppf filter
in
| None -> Fmt.nop ppf filter in
let filter = Arg.conv (filter, pp) in
Arg.(value & opt filter None & info [ "filter" ] ~doc)
@ -136,8 +129,7 @@ let artifact =
match Fpath.of_string str with
| Ok v when Sys.file_exists str && not (Sys.is_directory str) -> Ok v
| Ok v -> R.error_msgf "%a does not exist" Fpath.pp v
| Error _ as err -> err
in
| Error _ as err -> err in
let existing_file = Arg.conv (existing_file, Fpath.pp) in
Arg.(required & pos 0 (some existing_file) None & info [] ~doc)
@ -152,8 +144,7 @@ let cmd_required_intfs =
`P
"$(tname) is a simple program which tries to infer required interfaces \
from a given OCaml object.";
]
in
] in
Cmd.v (Cmd.info "req-intfs" ~version ~doc ~man) term_required_intfs
let term_implements = Term.(ret (const run_implements $ Jobs.term $ artifact))
@ -166,8 +157,7 @@ let cmd_implements =
`P
"$(tname) is a simple program which shows interfaces implemented by \
the given OCaml object.";
]
in
] in
Cmd.v (Cmd.info "implements" ~version ~doc ~man) term_implements
let term_provided_intfs =
@ -175,16 +165,14 @@ let term_provided_intfs =
let cmd_provided_intfs =
let doc =
"A tool which returns provided interfaces from an $(i,*.cmi) object."
in
"A tool which returns provided interfaces from an $(i,*.cmi) object." in
let man =
[
`S Manpage.s_description;
`P
"$(tname) is a simple program which shows provided interfaces from a \
$(i,*.cmi) object.";
]
in
] in
Cmd.v (Cmd.info "provided-intfs" ~version ~doc ~man) term_provided_intfs
let term_provided_impls =
@ -200,8 +188,7 @@ let cmd_provided_impls =
`P
"$(tname) is a simple program which shows provided implementations \
from a $(i,*.cmi) object.";
]
in
] in
Cmd.v (Cmd.info "provided-impls" ~version ~doc ~man) term_provided_impls
let cmd =
@ -212,8 +199,7 @@ let cmd =
`P
"$(tname) is a simple tool to introspect and show informations from \
given OCaml objects.";
]
in
] in
Cmd.group
(Cmd.info "intro" ~version ~doc ~man)
[

@ -34,8 +34,7 @@ let jobs =
try
let n = int_of_string str in
if n < 1 then R.error_msgf "The number of jobs must be positive" else Ok n
with _exn -> Rresult.R.error_msgf "It's an invalid number: %S" str
in
with _exn -> Rresult.R.error_msgf "It's an invalid number: %S" str in
Arg.(
value
& opt (conv (parser, Fmt.int)) (get_concurrency ())

@ -45,17 +45,14 @@ let reporter ppf =
let report src level ~over k msgf =
let k _ =
over ();
k ()
in
k () in
let with_metadata header _tags k ppf fmt =
Fmt.kpf k ppf
("[%6d]%a[%a]: " ^^ fmt ^^ "\n%!")
pid pp_header (level, header)
Fmt.(styled `Magenta (fmt "%20s"))
(Logs.Src.name src)
in
msgf @@ fun ?header ?tags fmt -> with_metadata header tags k ppf fmt
in
(Logs.Src.name src) in
msgf @@ fun ?header ?tags fmt -> with_metadata header tags k ppf fmt in
{ Logs.report }
let setup_logs utf_8 style_renderer level =

@ -6,8 +6,7 @@ let run fpath output =
| None -> (stdout, ignore)
| Some fpath ->
let oc = open_out (Fpath.to_string fpath) in
(oc, fun () -> close_out oc)
in
(oc, fun () -> close_out oc) in
let mml =
match Fpath.get_ext fpath with
| ".ml" -> Converter.of_ml fpath
@ -33,8 +32,7 @@ let artifact =
match Fpath.of_string str with
| Ok v when Sys.file_exists str && not (Sys.is_directory str) -> Ok v
| Ok v -> R.error_msgf "%a does not exist" Fpath.pp v
| Error _ as err -> err
in
| Error _ as err -> err in
let existing_file = Arg.conv (existing_file, Fpath.pp) in
Arg.(required & pos 0 (some existing_file) None & info [] ~doc)
@ -53,8 +51,7 @@ let cmd =
`P
"$(tname) converts a *.ml, a *.mli or a *.cmi file to the MML language \
to be able to track dependencies.";
]
in
] in
Cmd.v (Cmd.info "mml" ~version ~doc ~man) term
let () = exit @@ Cmd.eval' cmd

@ -25,10 +25,8 @@ let access { Location.txt = v; loc } =
let res =
match longident with
| Longident.Lident _ | Lapply _ -> None
| Ldot (t, v) -> Some (t, v)
in
Option.map (fun (t, v) -> (With_apply.of_longident t, v)) res
in
| Ldot (t, v) -> Some (t, v) in
Option.map (fun (t, v) -> (With_apply.of_longident t, v)) res in
match access_to_path v with
| None -> Mml.Annot.empty
| Some (path, name) ->
@ -80,10 +78,8 @@ module Pattern = struct
let bind_fmod p inner =
let binded x =
let binder inner b =
[ Mml.Local_bind (b.Mml.Loc.location, b.Mml.Loc.v, inner) ]
in
List.fold_left binder x p.binds
in
[ Mml.Local_bind (b.Mml.Loc.location, b.Mml.Loc.v, inner) ] in
List.fold_left binder x p.binds in
Mml.Annot.merge p.annot (Mml.Loc.fmap binded inner)
let extension ext = of_annot (Mml.Annot.extension ext)
@ -135,8 +131,7 @@ let rec signature_item (item : Parsetree.signature_item) =
Mml.Expr_ident
With_apply.(
concrete (of_longident msub.pms_manifest.Location.txt));
}
in
} in
do_open msub.pms_loc (Mml.Struct [ Mml.Loc.v ~location ghost ])
| Psig_modtypesubst mtsub ->
let name, expr = module_type_declaration mtsub in
@ -254,8 +249,7 @@ and module_type (mt : Parsetree.module_type) =
{
Mml.arg_name = Option.map Mod.v name.Location.txt;
signature = module_type s;
}
in
} in
Mml.Type_functor { type_arg; type_body = module_type res }
| Pmty_with (mt, with_constraints) (* X with ... *) ->
With
@ -440,16 +434,14 @@ and structure_item item =
and rec_modules mbs =
let location =
List.fold_left Mml.Loc.choose Mml.Loc.nowhere
(List.map (fun mb -> Mml.Loc.of_location mb.pmb_loc) mbs)
in
(List.map (fun mb -> Mml.Loc.of_location mb.pmb_loc) mbs) in
[ Mml.Loc.v ~location (Mml.Bind_rec (List.map module_binding_raw mbs)) ]
and module_type_declaration mdec =
let name = Mod.v mdec.pmtd_name.Location.txt in
let expr =
let ( >>| ) x f = Option.map f x in
Option.value ~default:Type_abstract (mdec.pmtd_type >>| module_type)
in
Option.value ~default:Type_abstract (mdec.pmtd_type >>| module_type) in
(Some name, expr)
and expr e =
@ -577,10 +569,8 @@ and val_bindings : 'a. ('a -> pattern * Parsetree.expression) -> 'a list -> _ =
let p = Pattern.union_map (val_binding <.> proj) vbs in
let v =
let binder inner b =
[ Mml.Local_bind (b.Mml.Loc.location, b.Mml.Loc.v, inner) ]
in
List.fold_left binder expr.Mml.Loc.v p.binds
in
[ Mml.Local_bind (b.Mml.Loc.location, b.Mml.Loc.v, inner) ] in
List.fold_left binder expr.Mml.Loc.v p.binds in
Pattern.to_annot p ++ Mml.Loc.v ~location:expr.Mml.Loc.location v
and vb_pair x = (x.pvb_pat, x.pvb_expr)
@ -649,8 +639,7 @@ and class_expr ce =
(Mml.Loc.v ~location:(Mml.Loc.of_location loc) (extension_core ext))
| Pcl_open (m, cl) ->
let path =
With_apply.(concrete (of_longident m.popen_expr.Location.txt))
in
With_apply.(concrete (of_longident m.popen_expr.Location.txt)) in
Mml.Annot.local_open
(Mml.Loc.of_location m.popen_loc)
(Mml.Expr_ident path) (class_expr cl)
@ -675,8 +664,7 @@ and class_type ct =
(extension_core ext))
| Pcty_open (m, cty) ->
let path =
With_apply.(concrete (of_longident m.popen_expr.Location.txt))
in
With_apply.(concrete (of_longident m.popen_expr.Location.txt)) in
Mml.Annot.local_open
(Mml.Loc.of_location m.popen_loc)
(Mml.Expr_ident path) (class_type cty)
@ -741,8 +729,7 @@ let module_type_declaration module_type id mtd =
let name = Some (Mod.v (Ident.name id)) in
let expr =
let ( >>| ) x f = Option.map f x in
Option.value ~default:Mml.Type_abstract (mtd.mtd_type >>| module_type)
in
Option.value ~default:Mml.Type_abstract (mtd.mtd_type >>| module_type) in
Mml.Bind_sig { name; expr }
let rec cmi x = mmap signature_item x
@ -768,8 +755,7 @@ and module_type = function
Mml.arg_name = Option.map (Mod.v <.> Ident.name) name;
signature = module_type mt;
}
| Unit -> None
in
| Unit -> None in
Mml.Type_functor { type_arg; type_body = module_type mt }
| Mty_alias p -> Mml.Alias With_apply.(concrete (of_path p))

@ -33,27 +33,23 @@ let include_sub_modules ~root ?hash impl (intf : Gamma.interface) a =
match (hash, hash') with
| Some hash, Some hash' when Digest.equal hash hash' ->
let[@warning "-8"] (Ok sub_impls) =
Objinfo.provided_implementations_of_cmi Fpath.(root // fpath)
in
Objinfo.provided_implementations_of_cmi Fpath.(root // fpath) in
let sub_impls =
List.map
(fun (sub_impl, sub_intf) ->
( Mod.Path.concat impl sub_impl,
Option.map (Mod.Path.concat intf) sub_intf ))
sub_impls
in
sub_impls in
let sub_intfs =
List.fold_left
(fun acc -> function
| modname, Some modtype -> (modname, (modtype, fpath, None)) :: acc
| _ -> acc)
[] sub_impls
in
[] sub_impls in
let sub_intfs =
List.map
(fun (modname, intf) -> (modname, Gamma.unsafe_interface intf))
sub_intfs
in
sub_intfs in
(* XXX(dinosaure): the hash of the implementation is equal to the hash
of the interface. That mostly means that the implementation **implements**
everything exported by the interface (included sub-modules) *)
@ -83,13 +79,11 @@ let make ?(count = ignore) gamma =
| Some intf ->
(impl, intf) :: include_sub_modules ~root ?hash impl intf a
| None -> a)
[] impls
in
[] impls in
List.iter
(fun (impl, (intf : Gamma.interface)) ->
let intf, _, hash =
(intf :> Mod.Path.t * Fpath.t * Digest.t option)
in
(intf :> Mod.Path.t * Fpath.t * Digest.t option) in
multi_add art intf (impl, fpath, hash))
intfs;
let[@warning "-8"] (Some fpath) = Fpath.relativize ~root fpath in
@ -98,8 +92,7 @@ let make ?(count = ignore) gamma =
| Error (`Msg err) ->
Log.warn (fun m ->
m "Error obtained for the file %a: %s" Fpath.pp fpath err);
Fiber.return (hash, map)
in
Fiber.return (hash, map) in
match
OS.Path.fold ~dotfiles:false ~elements:(`Sat is_an_implementation)
~traverse:`Any fold
@ -174,15 +167,13 @@ let search_from_intf { interfaces; _ } ?(target = `All) ?hash intf =
match target with
| `All -> Fun.const true
| `Bytecode -> select_bytecode
| `Native -> select_native
in
| `Native -> select_native in
let fpaths = List.filter filter fpaths in
let filter (_, hash', _) =
match (hash, hash') with
| None, _ -> true
| Some _, None -> false
| Some hash, Some hash' -> Digest.equal hash hash'
in
| Some hash, Some hash' -> Digest.equal hash hash' in
let fpaths = List.filter filter fpaths in
if fpaths <> [] then Some fpaths else None
| None -> None

@ -0,0 +1,33 @@
type elt = {
what : [ `Val of string | `Module ];
from : [ `Local | `Unknown | `Path of Fpath.t | `Special of Mod.t ];
aliases : Mod.Path.Set.t;
}
type t = elt Mod.Map.t
let merge =
Mod.Map.union (fun _k x y ->
let aliases = Mod.Path.Set.union x.aliases y.aliases in
let what =
match (x.what, y.what) with `Module, _ -> `Module | _, what -> what
in
Some { y with what; aliases })
let empty = Mod.Map.empty
let phantom ?(aliases = Mod.Path.Set.empty) name =
let elt = { what = `Module; from = `Unknown; aliases } in
Mod.Map.singleton name elt
let update ?(aliases = Mod.Path.Set.empty) ~what from name deps =
let elt =
match Mod.Map.find_opt name deps with
| None -> { what; from; aliases }
| Some ({ aliases = aliases'; what = what'; _ } as x) ->
let aliases = Mod.Path.Set.union aliases aliases' in
let what = match what with `Module -> `Module | _ -> what' in
{ x with aliases; what } in
Mod.Map.add name elt deps
let v ?aliases ~what from name = update ?aliases ~what from name empty

@ -8,9 +8,13 @@
(name mml)
(public_name uniq.mml)
(modules mml loc)
(preprocess
(pps ppx_import visitors.ppx))
(libraries fmt uniq.mod uniq.mod.with_apply))
(libraries fmt fpath uniq.mod uniq.mod.with_apply))
(library
(name solver)
(public_name uniq.solver)
(modules solver module id env deps message summary)
(libraries logs fpath uniq.mml))
(library
(name converter)

@ -0,0 +1,200 @@
let src = Logs.Src.create "uniq.env"
module Log = (val Logs.src_log src : Logs.LOG)
open Rresult
type context =
| Signature of Module.signature
(** A simple module with module type definitions & module expressions. *)
| In_pack of Module.dictionary
(** A pack which contains multiple modules with their
module type definitions & module expressions. *)
(* The [Query] module lets us to keep [Deps.t] and [Message.t list]
along our process. The ( >>? ) operator takes care for us to:
1) merge dependencies
2) append messages
*)
module Query = struct
type 'a elt = { v : 'a; deps : Deps.t; msgs : Message.t list }
type 'a t = 'a elt option
let ( >>? ) x f =
match x with
| None -> None
| Some x ->
Option.map
(fun { v; deps; msgs } ->
{ v; deps = Deps.merge deps x.deps; msgs = msgs @ x.msgs })
(f x.v)
let ( >> ) x y = x >>? fun () -> y
let return v : _ t = Some { v; deps = Deps.empty; msgs = [] }
let return_with msg v = Some { v; deps = Deps.empty; msgs = [ msg ] }
let deps deps = Some { v = (); deps; msgs = [] }
let record ~location:_ what ?aliases root name = function
| Module.Origin.Unit src ->
let src, modname =
(src :> [ `Local | `Unknown | `Path of Fpath.t | `Special ] * Mod.t)
in
let src =
match src with
| `Special -> `Special modname
| `Local -> `Local
| `Path path -> `Path path
| `Unknown -> `Unknown in
deps (Deps.v ?aliases ~what src name)
| Module.Origin.Phantom (root', _p) when root && not root' ->
deps (Deps.v ?aliases ~what:`Module `Unknown name)
| _ -> return ()
let injection = function
| None -> None
| Some v -> Some { v; deps = Deps.empty; msgs = [] }
end
type t = { top : Module.dictionary; context : context }
let top env =
{ env with context = Signature (Module.Signature.with_modules env.top) }
let restrict_as_a_pack t modules = { t with context = In_pack modules }
let restrict env context = { env with context }
let v ~impls:me ~intfs:mt =
{ top = me; context = Module.(Signature (Exact { me; mt })) }
type option = {
approximation : bool;
location : Fpath.t * Mml.Loc.t;
what : [ `Module | `Val of string ];
level : [ `Impl | `Intf ];
}
let rec find_name ~location phantom level name = function
| Signature Module.Unknown -> Query.return (Module.unknown name)
| In_pack modules ->
(* XXX(dinosaure): a packed object contains only implementations. *)
if level = `Intf then None
else
Query.injection
(Mod.Path.Map.find_opt (Mod.Path.singleton name) modules)
| Signature (Module.Exact { me; mt }) ->
let m = if level = `Impl then me else mt in
Query.injection (Mod.Path.Map.find_opt (Mod.Path.singleton name) m)
| Signature (Module.Divergence p) -> (
let projection = if level = `Impl then fst else snd in
(* If we have a divergent signature, we first look at the signature
after the divergence. *)
match
Mod.Path.Map.find_opt (Mod.Path.singleton name) (projection p.pst)
with
| Some v -> Query.return v
| None -> (
let
(* We then try to find the searched name in the signature
before the divergence. *)
open
Query in
let default =
lazy
(if level = `Intf then
Query.return_with
(Message.unknown ~location `Intf name)
(Module.unknown name)
else None) in
match
find_name ~location true level name (Signature p.pre) >>? fun r ->
(* If we found the expected name before the divergence,
we add a new ambiguity message and return the found
module, after marking it as a phantom module. *)
let m = Module.spirit_away p.point r in
if phantom then return m
else
Query.return_with
(Message.ambiguous ~location ~point:p.point name)
m
with
| Some _ as v -> v
| None -> Lazy.force default))
let find_name ~location level path t = find_name ~location false level path t
(* What we are looking for? *)
type what =
| Any (* Look for alias too *)
| Concrete (* We are looking for a concrete unit *)
| Sub_module
let is_top = function Any | Concrete -> true | Sub_module -> false
let rec find opt aliases what where env path =
let[@warning "-8"] (root :: rest) = Mod.Path.to_list path in
let open Query in
let level =
match rest with
| [] ->
opt.level (* XXX(dinosaure): can be an [module] or a [module type]. *)
| _ :: _ -> `Impl (* XXX(dinosaure): must be a [module]. *) in
let q =
match find_name ~location:opt.location level root env.context with
| None when opt.approximation && (what = Sub_module || opt.level = `Intf) ->
let name = List.hd (List.rev (root :: rest)) in
Query.return (* with no_sub_module *) (Module.unknown name)
| None -> None (* TODO *)
| Some _ as v -> v in
q >>? find_elt opt aliases what (root :: where) env root rest
and find_elt opt aliases what where env name rest = function
| Module.Alias { path; phantom } ->
Log.debug (fun m -> m "Alias to %a" Mod.Path.pp path);
let[@warning "-8"] (Ok elt) = Mod.Path.of_list_of_names (List.rev where) in
let aliases = Mod.Path.Set.add elt aliases in
let m =
match phantom with
| Some _ when what = Any || what = Concrete ->
Query.deps (* with ambiguity *) (Deps.phantom name)
| None | Some _ -> Query.return () in
let open Query in
(* XXX(dinosaure): currently, we manipulate an alias [name] which
can be concretize by [path]. We must bring dependencies from
it. [name] is /suffixed/ by [rest], so we will try to resolve
dependencies from [path.rest]. *)
let path = List.fold_left Mod.Path.( <.> ) path rest in
m >> find opt aliases Any [] (top env) path
| Module.Link _ when what = Concrete -> None
| Module.Link name ->
find opt aliases Concrete [] (top env) (Mod.Path.singleton name)
| Module.Sig { origin; signature } -> (
let open Query in
Query.record ~location:opt.location opt.what ~aliases (is_top what) name
origin
>>
match rest with
| [] -> return (name, `Module (Module.Sig { origin; signature }))
| rest ->
let[@warning "-8"] (Ok path) = Mod.Path.of_list_of_names rest in
find opt aliases Sub_module where
(restrict env (Signature signature))
path)
| (Module.Abstract _ | Module.Functor _) as kind -> (
match rest with
| [] -> Query.return (name, `Module (Module.Partial.of_extended kind))
| _ :: _ ->
let name = List.hd (List.rev rest) in
let m = Module.unknown name in
Query.return (name, `Module m))
| Module.Pack ms -> (
match rest with
| [] -> Query.return (name, `Pack ms)
| _ :: _ ->
let[@warning "-8"] (Ok path) = Mod.Path.of_list_of_names rest in
find opt aliases what where (restrict_as_a_pack env ms) path)
let find ~location ?(what = `Module) level path env =
let opt = { approximation = true; location; what; level } in
Mod.Path.verify level path >>= fun path ->
match find opt Mod.Path.Set.empty Any [] env path with
| Some { Query.v = name, v; deps; msgs = _ } -> Ok (deps, name, v)
| None -> Error `Not_found

@ -0,0 +1,16 @@
type t
val v : impls:Module.dictionary -> intfs:Module.dictionary -> t
val restrict_as_a_pack : t -> Module.dictionary -> t
val find :
location:Mml.Loc.p ->
?what:[ `Val of string | `Module ] ->
[ `Impl | `Intf ] ->
Mod.Path.t ->
t ->
( Deps.t
* Mod.t
* [ `Pack of Module.dictionary | `Module of Module.simple Module.t ],
[> `Not_found | `Msg of string ] )
result

@ -34,8 +34,7 @@ module LList = struct
let add seq thread =
let node =
{ node_prev = seq.prev; node_next = seq; thread; active = true }
in
{ node_prev = seq.prev; node_next = seq; thread; active = true } in
seq.prev.next <- seq_of_node node;
seq.prev <- seq_of_node node
@ -140,13 +139,10 @@ let create_process ?file prgn =
| Some filename ->
Log.debug (fun m -> m "Save result of children into %s." filename);
let ic =
Unix.openfile filename Unix.[ O_RDONLY; O_CREAT; O_TRUNC ] 0o644
in
Unix.openfile filename Unix.[ O_RDONLY; O_CREAT; O_TRUNC ] 0o644 in
let oc =
Unix.openfile filename Unix.[ O_WRONLY; O_CREAT; O_TRUNC ] 0o644
in
(ic, oc)
in
Unix.openfile filename Unix.[ O_WRONLY; O_CREAT; O_TRUNC ] 0o644 in
(ic, oc) in
match Unix.fork () with
| 0 -> (
pool := None;
@ -204,8 +200,7 @@ let succ_threads () =
let t =
match !pool with
| Some pool -> pool
| None -> failwith "Impossible to thread() into a fork()!"
in
| None -> failwith "Impossible to thread() into a fork()!" in
Mutex.lock t.threads_mutex;
t.threads_alive <- t.threads_alive + 1;
let _ = Thread.create worker t in
@ -217,8 +212,7 @@ let wait_threads t =
let rec loop () =
if t.threads_working > 0 then (
Condition.wait t.pending_condition t.threads_mutex;
loop ())
in
loop ()) in
loop ();
Mutex.unlock t.threads_mutex
@ -291,8 +285,7 @@ let run_process ?file prgn =
let t =
match !pool with
| Some pool -> pool
| None -> Fmt.invalid_arg "Impossible to fork() into a fork()!"
in
| None -> Fmt.invalid_arg "Impossible to fork() into a fork()!" in
let close fd = try Unix.close fd with _exn -> () in
forks_throttle t >>= fun () ->
let fd, pid = create_process ?file prgn in
@ -320,16 +313,14 @@ let run_thread job =
let t =
match !pool with
| Some pool -> pool
| None -> Fmt.invalid_arg "Impossible to thread() into a fork()!"
in
| None -> Fmt.invalid_arg "Impossible to thread() into a fork()!" in
let ivar = Ivar.create () in
let thread =
LList.Thread
( (fun ivar ->
let res = job () in
Ivar.fill ivar res),
ivar )
in
ivar ) in
Mutex.lock t.threads_mutex;
LList.add t.jobs_pending thread;
Condition.broadcast t.working_condition;
@ -340,8 +331,7 @@ let run fiber =
let t =
match !pool with
| Some pool -> pool
| None -> Fmt.invalid_arg "Impossible to run() into a fork()!"
in
| None -> Fmt.invalid_arg "Impossible to run() into a fork()!" in
let result = ref None in
t.resolved <- false;
fiber (fun x ->
@ -354,8 +344,7 @@ let run fiber =
wait_forks t;
wait_threads t;
Condition.broadcast t.pending_condition;
if !result = None then (loop [@tailcall]) t
in
if !result = None then (loop [@tailcall]) t in
loop t;
match !result with
| Some v -> v

@ -51,8 +51,7 @@ let make ?(count = ignore) root =
Fiber.return (hash, intfs)
| Some (fpath', Some digest') when Digest.equal digest digest' ->
let vs =
Option.value (Hashtbl.find_opt duplicate fpath') ~default:[]
in
Option.value (Hashtbl.find_opt duplicate fpath') ~default:[] in
Hashtbl.replace duplicate fpath' (fpath :: vs);
Fiber.return (hash, intfs)
| _ ->
@ -63,16 +62,14 @@ let make ?(count = ignore) root =
Mod.Path.Map.add
(Mod.Path.concat intf symbol)
(fpath, None) map)
intfs symbols
in
intfs symbols in
count ();
Fiber.return (hash, Mod.Path.Map.add intf (fpath, Some digest) intfs)
)
| Error (`Msg err), _ | _, Error (`Msg err) ->
Log.warn (fun m ->
m "Error obtained for the file %a: %s" Fpath.pp fpath err);
Fiber.return (hash, intfs)
in
Fiber.return (hash, intfs) in
match
OS.Path.fold ~dotfiles:false ~elements:(`Sat is_an_interface) ~traverse:`Any
fold
@ -132,8 +129,7 @@ let hash_of_intf { root = gamma; intfs; _ } ?modtype path =
let _qualified, unqualified =
List.partition
(function _, Some _ -> true | _, None -> false)
req_intfs
in
req_intfs in
(* XXX(dinosaure): we just want to find unqualified (no hash) interfaces. *)
Log.debug (fun m ->
m "Unqualified interfaces required: %a."
@ -160,8 +156,7 @@ let hash_of_intf { root = gamma; intfs; _ } ?modtype path =
% p Fpath.((sandbox / name) + ".mli"))
|> OS.Cmd.out_string
>>= fun _ ->
Objinfo.provided_intf_of_cmi Fpath.((sandbox / name) + ".cmi")
in
Objinfo.provided_intf_of_cmi Fpath.((sandbox / name) + ".cmi") in
R.ok Fiber.(run_process command >>| Result.join)
let resolve_multiple_paths ?opens:(_ = []) t =
@ -174,8 +169,7 @@ let resolve_multiple_paths ?opens:(_ = []) t =
let result =
Hashtbl.fold
(fun fpath (intf, hash) acc -> (intf, fpath, Some hash) :: acc)
objects []
in
objects [] in
Ok result
| (intf, hash) :: rest -> (
find t ?hash intf |> function
@ -204,8 +198,7 @@ let resolve_multiple_paths ?opens:(_ = []) t =
->
raise (Conflict intf)
| Some _, _ -> true)
req_intfs
in
req_intfs in
Ok req_intfs
with Conflict intf ->
R.error_msgf "Conflicts on %a" Mod.Path.pp intf)
@ -225,8 +218,7 @@ let resolve_multiple_paths ?opens:(_ = []) t =
if Digest.equal hash hash' then Ok a
else R.error_msgf "Conflicts on %a." Mod.Path.pp intf))
(Ok rest) req_intfs
>>= go solved)
in
>>= go solved) in
go Map.empty
let resolve ?opens t ?hash intf =
@ -253,6 +245,5 @@ let find_first_meta t fpath =
let fpath = Fpath.parent fpath in
(* XXX(dinosaure): don't try to go further than [t.root]. *)
if Fpath.(is_root (normalize (v "/" // fpath))) then R.error `Not_found
else search fpath
in
else search fpath in
search fpath

@ -0,0 +1,12 @@
type t = int
type generator = unit -> t
let pp ppf v = Fmt.pf ppf "$%d" v
let v () =
let v = ref (-1) in
fun () ->
incr v;
!v
let gen = v ()

@ -0,0 +1,6 @@
type t = private int
type generator = unit -> t
val gen : generator
val pp : t Fmt.t
val v : unit -> generator

@ -1,47 +0,0 @@
module Source = struct
type t = {
source : [ `Local | `Unknown | `Pack of Ns.t | `Special of Mod.t ];
file : Ns.t;
}
end
module Arg = struct
type 'a t = { name : Mod.t; signature : 'a }
end
module Divergence = struct
type origin = First_class_module | External
type t = { root : Mod.t option; origin : origin; location : Source.t * Loc.t }
end
module Origin = struct
type t =
| Unit of { source : Source.t; path : Ns.t } (** Toplevel module. *)
| Sub_module
| Namespace (** Temporary module from namespace *)
| First_class_module (* Not resolved first-class module *)
| Arg (** Functor argument *)
| Phantom of bool * Divergence.t
(** Ambiguous module, that could be an external module *)
end
type 'a t =
| Sig : { origin : Origin.t; signature : signature } -> 'a t
| Alias : { path : Ns.t; phantom : Divergence.t option } -> extended t
| Abstract : Id.t -> 'a t
| Functor : 'a t Arg.t option * 'a t -> 'a t
| Link : Ns.t -> extended t
| Namepace : dictionary -> extended t
and extended = |
and simple = |
and dictionary = extended t Mod.Map.t
and signature =
| Unknown
| Exact of { me : extended t Mod.Map.t; mt : extended t Mod.Map.t }
| Divergence of {
point : Divergence.t;
before : signature;
after : signature;
}

@ -4,6 +4,7 @@ type t =
| Line of { line : int; start : int; stop : int }
type 'a t' = { location : t; v : 'a }
type p = Fpath.t * t
let v ~location v = { location; v }
let projection { v; _ } = v
@ -56,10 +57,12 @@ let of_location location =
let open Location in
let extract v =
let open Lexing in
(v.pos_lnum, v.pos_cnum - v.pos_bol)
in
(v.pos_lnum, v.pos_cnum - v.pos_bol) in
let ((l0, c0) as v) = extract location.loc_start in
let ((l1, c1) as w) = extract location.loc_end in
if dummy location then nowhere
else if l0 = l1 then line ~line:l0 c0 c1
else multiline v w
let of_path ~path t = (path, t)
let pp_with_path ppf (path, t) = Fmt.pf ppf "%a.%a" Fpath.pp path pp t

@ -1,5 +1,6 @@
type t
type 'a t' = private { location : t; v : 'a }
type p = Fpath.t * t
val pp : t Fmt.t
val compress : t -> t
@ -12,3 +13,5 @@ val line : line:int -> int -> int -> t
val multiline : int * int -> int * int -> t
val of_location : Location.t -> t
val projection : 'a t' -> 'a
val of_path : path:Fpath.t -> t -> p
val pp_with_path : p Fmt.t

@ -0,0 +1,16 @@
type t =
| Ambiguous of {
where : Fpath.t * Mml.Loc.t;
name : Mod.t;
point : Module.Divergence.t;
}
| Unknown of {
where : Fpath.t * Mml.Loc.t;
name : Mod.t;
level : [ `Impl | `Intf ];
}
let ambiguous ~location ~point name =
Ambiguous { where = location; name; point }
let unknown ~location level name = Unknown { where = location; name; level }

@ -0,0 +1,6 @@
type t
val ambiguous :
location:Fpath.t * Mml.Loc.t -> point:Module.Divergence.t -> Mod.t -> t
val unknown : location:Fpath.t * Mml.Loc.t -> [ `Intf | `Impl ] -> Mod.t -> t

@ -47,13 +47,13 @@ and minor =
and access =
((Loc.t * [ `Val of string | `Module ]) With_apply.Map.t[@visitors.opaque])
(** [M.N.L.x] corresponds to [M.N.L => `Val "x"], and [type t = A.t]
corresponds to [A => `Module]. In both cases, the Mod.Path.t is an
implementation. You can not compile:
corresponds to [A => `Module]. In both cases, the Mod.Path.t is an
implementation. You can not compile:
{[
module type S = sig type t = int end
type t = S.t
]} *)
{[
module type S = sig type t = int end
type t = S.t
]} *)
and module_expr =
| Expr_ident of Mod.Path.t (** [A.B...] *)
@ -365,8 +365,7 @@ let pp =
method! iter_Local_bind ppf ~loc bind x =
let iter_name ppf = function
| None -> Fmt.string ppf "_"
| Some name -> Mod.pp ppf name
in
| Some name -> Mod.pp ppf name in
Fmt.pf ppf "@[<2>(%a)%a=%a in@ (%a)@]" Loc.pp loc iter_name bind.name
self#iter_module_expr bind.with_expr self#iter_annot x
@ -427,8 +426,7 @@ let pp =
| path, (loc, `Val name) ->
Fmt.pf ppf "%a.%s(%a)" With_apply.pp path name Loc.pp loc
| path, (loc, `Module) ->
Fmt.pf ppf "type ? = %a.?(%a)" With_apply.pp path Loc.pp loc
in
Fmt.pf ppf "%a(%a)" With_apply.pp path Loc.pp loc in
Fmt.pf ppf "@[<2>access: {%a}@]@,"
Fmt.(list ~sep:(any "; @,") iter_elt)
(With_apply.Map.bindings v)
@ -508,6 +506,5 @@ let pp =
| Ext_module v -> self#iter ppf v | Ext_val ms -> self#iter_annot ppf ms
method iter_externals = Fmt.(list ~sep:(any "@ ") string)
end
in
end in
visitor#iter

@ -45,7 +45,9 @@ let pp = Fmt.string
let to_string = Fmt.to_to_string pp