Conversation
|
If you read PRs through email and you were, like me, confused by the absence of an type t =
Pident of Ident.t
| Pdot of t * string * int
| Papply of t * twhile the PR changes it to just (only type t =
Pident of Ident.t
| Pdot of t * string
| Papply of t * t |
|
Thanks, @gasche !
I do read PRs by e-mail and never think about checking the GitHub page
to see whether something has changed. I realise I should but still can't
remember doing so.
|
|
Yeah, sorry about that. I should remember to make a comment when correcting particularly confusing typos. |
|
Leo White (2018/02/14 10:23 +0000):
Yeah, sorry about that. I should remember to make a comment when
correcting particularly confusing typos.
No, no problem. I think the real issue is the interface. Perhaps it
would help to have a parameter to receive mails also when a PR or a
comment gets modified. With a diff of the modification. :)
|
|
|
|
Exposing the position in the path itself always seemed particularly dubious to me, so I'm happy to see that go away. Before I really dive into the code, can you give some indications on what this |
|
To make the addresses a little easier to calculate I moved the presence information for module aliases from the module type (i.e. |
|
From a first review, to me it looks like a clear improvement (I remember doing sometime wrong things with path positions when playing with modular implicits) and the patch seems correct but I don't understand all the parts. |
|
Maybe you want to point at the parts you don't understand, and they could benefit from a comment :-) |
2b7194f to
c377d2b
Compare
Drup
left a comment
There was a problem hiding this comment.
The main commit is quite difficult to review (mostly trivial or loosely related changes spread out over 50+ files, and the occasional subtle thing). I would have preferred to have the the purely trivial parts split out from the subtle ones, and then squash before merge. That would have made it much easier to review.
But apart from that, I think this is a clear improvement. The handling of address is much more obvious than before, and this removes some weird invariants from the typedtree. The code is also a tiny bit cleaner.
I mostly looked at the typechecking-related parts, as I'm not an expert in bytecomp/, but it all looks pretty good to me.
| | Record_unboxed of bool (* Unboxed single-field record, inlined or not *) | ||
| | Record_inlined of int (* Inlined record *) | ||
| | Record_extension (* Inlined record under extension *) | ||
| | Record_extension of Path.t (* Inlined record under extension *) |
There was a problem hiding this comment.
I'm not very familiar with compilation of inlined record. Why is the path now needed here?
There was a problem hiding this comment.
My guess would be: to avoid doing things like this.
That is: unless I missunderstood, it is a cleanup unrelated to the rest of this PR.
There was a problem hiding this comment.
Ah, I missed that piece of code. That's a very valid reason, although if it is, it really should be in a different commit.
| let name = Ident.name param in | ||
| let exp = | ||
| { exp with exp_loc = loc; exp_desc = | ||
| { exp with exp_loc = loc; exp_env = env; exp_desc = |
There was a problem hiding this comment.
On various occasion where a typechecking function synthesized a new desc, you now add it to the environment before returning it, where previously it was just returned. I suppose it is to make sure it has an address, but I'm not really sure why it is ok to add new things to the env that were not added previously.
Also, in that specific case, it's added only to the expression part, not the pattern one.
There was a problem hiding this comment.
On various occasion where a typechecking function synthesized a new desc, you now add it to the environment before returning it, where previously it was just returned. I suppose it is to make sure it has an address, but I'm not really sure why it is ok to add new things to the env that were not added previously.
Was "typechecking" a typo here?
Also, regardless of why it is now added in the environment (though I think I agree with the reason you propose), I think it's more correct (in this particular instance, i.e. in push_defaults) to add it to the environment than not.
Also, in that specific case, it's added only to the expression part, not the pattern one.
This is similar to what happens in the typechecker, if you look at Typecore.type_cases you'll see that the pattern variables (i.e. the bindings produced by the pattern) only get added to the environment of the body, not of the pattern.
typing/env.ml
Outdated
| if Ident.global id && not (Ident.same id (Path.head path')) | ||
| then add_required_global id; | ||
| path' | ||
| end |
There was a problem hiding this comment.
When normalizing, you consider modules that are aliases but have an address. I failed to find where you introduce aliases that have an address different than None. Where does that happen?
There was a problem hiding this comment.
So if a module is present (i.e. it's presence is Mta_present in a module type) then it will be given an address (see store_module and components_of_module_maker). This can happen for aliases than are produced via strengthening (see strengthen_decl which can produce aliases, and strengthen_sig which then attaches these aliases to a presence that can be Mta_present).
toplevel/toploop.ml
Outdated
| match Env.find_class_address Location.none path env with | ||
| | addr -> eval_address addr | ||
| | exception Not_found -> | ||
| fatal_error ("Cannot find address for: " ^ (Path.name path)) |
There was a problem hiding this comment.
Maybe factorize that code a little bit? :)
c377d2b to
68abbe2
Compare
|
Sorry for the slow response. I've finally found time to look at this again. I've rebased the code and addressed @Drup's comments. |
|
My small concerns have been addressed. I think we need a review from someone familiar with bytecomp now. |
7dfe6f8 to
5a74793
Compare
|
Since this fixes a soundness bug, I would like it to see it move forward. |
|
Could we hold off for a week or so? I've got an improved version implemented as part of my transparent ascription patch, and I'm planning to extract it into this PR. |
5a74793 to
cd31809
Compare
|
Ok I've pushed the improved version and rebased it up to trunk. Should now be ready for review. |
|
I'm having a look. |
trefis
left a comment
There was a problem hiding this comment.
This overall looks good (and correct) modulo the few comments I left here and there.
|
|
||
| let enter_module ~scope ?arg s mty env = | ||
| let enter_value ?check name desc env = | ||
| let id = Ident.create_local name in |
There was a problem hiding this comment.
To be clear:
scope (create_scoped ~scope:0 "foo") == 0
scope (create_local "foo") == highest_scope (== 100_000_000)
So that's an actual change, somewhat unrelated to this PR.
But I believe it is fine: we only check the scope of type constructors, we should never check the scope of value paths.
typing/types.mli
Outdated
| and alias_presence = | ||
| and module_presence = | ||
| | Mta_present | ||
| | Mta_absent |
There was a problem hiding this comment.
Should we rename these to Mp_present | Mp_absent?
bytecomp/translmod.ml
Outdated
| pc1, | ||
| (fun pc -> | ||
| match pc with | ||
| | _, (Tcoerce_primitive _ | Tcoerce_alias _) -> pc |
There was a problem hiding this comment.
I think this deserves a comment.
Apparently p1 in these cases would be -1, because it's not a runtime component (cf. includemod.ml), so we can't really go have a look in v2.
bytecomp/translmod.ml
Outdated
| cont) | ||
|
|
||
| in | ||
| let aliases = List.fold_right store_alias aliases lambda_unit in |
There was a problem hiding this comment.
You could drop the cont parameter of store_alias, have it return the Lprim and simplify this last line to: make_sequence store_alias aliases.
bytecomp/matching.ml
Outdated
|
|
||
| let partial_function loc () = | ||
| let slot = | ||
| transl_extension_path Location.none |
There was a problem hiding this comment.
Is there a reason to use Location.none over loc here?
typing/env.ml
Outdated
| (fun id -> | ||
| is_local (find_same id tbl2) && | ||
| let descr, _ = find_same id tbl2 in | ||
| is_local descr && |
There was a problem hiding this comment.
That feels wrong: it "works", but it's weird.
Here is the type of the function after this change:
val diff_keys: ('a -> bool) -> 'b t -> ('a * 'c) t -> Ident.t listBefore that it was:
val diff_keys: ('a -> bool) -> 'b t -> 'a t -> Ident.t listwhich seems more natural.
I think it's the caller of this function that should be changed, while this function should remain untouched. (And the function appears to be called only once, so it shouldn't be too tedious to update)
| let (desc, _) = NameMap.find name components in | ||
| (Pdot (root, name), desc) :: find_all name next | ||
| with Not_found -> | ||
| find_all name next |
There was a problem hiding this comment.
Like for TycompTbl.diff_keys the changes to this function are weird, and inconsistent with the other changes in this module: this function is making the assumption that the 'a in current : Ident.tbl (* in [t] *) and in components: 'a list NameMap.t (* in [opened] *) is a tuple:
val find_all: string -> ('a * 'b) t -> (Path.t * 'a) listBut there's no reason to. And, for example, I believe you wouldn't be able to call find_all on the modtypes field of the environment with this implementation.
It's the callers that should change.
|
Ok, I've addressed the review comments and fixed the failing tests. |
|
I forgot to say it during my review: but you updated toploop,topdirs,etc. But not the opt versions. And you'll need to :) |
|
I've updated ocamlnat and addressed @let-def's comments. |
604c4a4 to
e47cb6a
Compare
|
Rebased. Merging once CI passes. |
e47cb6a to
68f2b7c
Compare
Currrently, paths contain the integer position of a module field within the runtime representation of the module:
Since
Path.ts appear within types, module types etc. they must remain valid through the various manipulations of the type system. Unfortunately, the positions do not remain valid under module substitution -- which leads to various soundness bugs:Rather than trying to change module substitution to take account of path indices, which appears quite difficult and will become even more difficult as the module system evolves, this PR removes the positions from paths. Instead we add an
addresstype to theEnvmodule:along with functions for finding the "address" of a given path:
These functions are used in
bytecompto translate paths to lambda code. Since we previously had to callnormalize_pathat that point anyway, this is a pretty simple change to make.