-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Add hidden directory (proposed in RFC 31) #11989
Conversation
but consider it like -I for now
I worked a bit with @bobot on this prototype implementation of the RFC (the There is a testsuite by François that checks that the various "obvious" cases work as intended. This is very reassuring. The general idea of the implementation is as follows:
Subtlety: which lookups to check?I thought at first that we should instrument all (* A.ml : imported hidden *)
type t = Toto
(* B.mli: imported visible *)
val f : A.t -> unit
(* C.ml: being type-checked *)
let () = B.f Toto It depends on the specification that we want for hidden compilation units:
Subtlety:
|
let find_name_module ~mark name tbl = | |
match IdTbl.find_name wrap_module ~mark name tbl with | |
| x -> x | |
| exception Not_found when not (Current_unit_name.is name) -> | |
let path = Pident(Ident.create_persistent name) in | |
path, Mod_persistent |
For those compilation units, we don't know whether they should be treated as visible or hidden (there is no information in the environment).
One might naively think that this logic only fires in the case of "missing .cmi files", compilation units that are missing and are treated as black boxes. (Black boxes instead of failing because: dune currently implements its own poor man's -Ihidden
by ensuring that certain compilation units are not in the load path.) But in fact this is wrong, some compilation units that are in the load path are intentionally not inserted in the environment:
Lines 853 to 861 in 79fffac
let modules = | |
(* With [-no-alias-deps], non-material additions should not | |
affect the environment at all. We should only observe the | |
existence of a cmi when accessing components of the module. | |
(See #9991). *) | |
if material || not !Clflags.transparent_modules then | |
IdTbl.add id Mod_persistent env.modules | |
else | |
env.modules |
@bobot and myself believe that the PR is currently incorrect in this case of "phantom" compilation units, but we are not sure how to fix it. There are two approaches:
- One would be to try another approach to issue Fix reproducibility for
-no-alias-deps
#9991, as mentioned by @bobot, to provide the guarantee that the only case of phantom compilation units are those that correspond to missing.cmi
files, never those that have a.cmi
in the load path. (Our idea is, because Fix reproducibility for-no-alias-deps
#9991 was about observed differences of sharing in certain cases, to add a memo-table toIdent.create_persistent
to hashcons all instances of each compilation-unit name in the environment summary.) I am not sure that this work, but if it does it would provide a nice conceptual simplification compared to the current hard-to-understand logic for Fix reproducibility for-no-alias-deps
#9991: I like the guarantee that only missing cmis create phantom compilation units. - Another would be to store the "hidden or visible?" information for compilation units separately in the typing environment (not in the
Mod_persistent
metadatata). This side-steps the problem, and does not simplify the existing code.
I don't love the idea of fix #9991 a different way. The advantage of the current approach is that it makes sure that the existence or not of unused immaterial cmi files can't possibly affect the result of compilation. Fixing one particular case with hash-consing might not have that property if there turn out to be other ways it can affect things. I think there is a much easier solution here:
Then there is no need to record which modules are hidden or not. It is just that |
I forgot that we only put the material ones in the environment now, so that's not quite right. It should be:
|
Yes, we tried your earlier suggestion of "When looking up using a lookup_foo function you only use modules in the environment.', and it did not work. We should try your revised suggestion. If I understand correctly, we need to send the "are we accessing from |
Yeah, that sounds right. |
For conciseness, I'll use @gasche was saying it's debatable whether this should be a type error or not: type X.t = C
val I.f : X.t -> unit
let () = I.f C I think this should be accepted, for two reasons. First, even if I'll also mention that the client code can manipulate module X = struct type t = C end
module I = struct let f (_ : X.t) = () end
(* no mention of X from here *)
module type T = sig type t end
let type_of_arg (type a) (_ : a -> unit) : (module T with type t = a) =
(module struct type t = a end)
module Type_of_f_arg = (val type_of_arg I.f)
let _ : Type_of_f_arg.t = C Second, it's probably useful to think about the purpose of this change: we want to force the client code to state it uses |
Thank you @ccasin for taking the ball I dropped. |
It is a POC for RFC 31:
- In the initial environment the hidden modules are added as
Mod_persistent { hidden = true }
instead ofMod_persistent
.- In the
lookup_ident_module
, those modules raise an error. I think this function is used only for the user provided identifiers, since modules that are not found raises an error which is not the case if it is a name that comes from a signature.-I
and-H
are gathered in the same list of path in order to handle the priorities in a consistent way. That change the type ofClflags.include_dirs
. The first commit propages this change.-H
does not work yet with-no-alias-deps
because in this case initial modules are not always added to the environment. So I will change that separately with different fix for Fix reproducibility for-no-alias-deps
#9991.