-
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
Fix wrong calls to Env.normalize_path on non-module paths #2131
Conversation
It seems that this change requires a bootstrap. This is a bit surprising at first, but this may just be a problem of loss of sharing before the change (supposing you end up copying less now). This looks like a good idea. Indeed, calling As for the repeated calls to |
There was at least one real bug; when passing the following to the compiler: module X = struct
module B = List
exception B of {x:int}
end
let _ = X.B {x=2} It used to fail with an assertion failure (LocalExt case in find_type_full). I will add a test for that. |
;; | ||
[%%expect{| | ||
+module X : sig module B = List exception B of { x : int; } end | ||
+- : exn = X.B {x = 2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On trunk, the output is:
module X : sig module B = List exception B of { x : int; } end
Uncaught exception: File "typing/env.ml", line 942, characters 26-32: Assertion failed
Honestly, unify2 is a bit mysterious to me, but do you agree that if the first pair:
does nothing, then the second pair is also necessarily a no-op:
? |
Note that checking whether they've changed using |
05f5121
to
9753b8d
Compare
This fixes both an actual bug, and a performance bug as well, so I think it's worth looking at for 4.08. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fine to me.
I added just a request for comment, and a possible change of function name, to make the code more readable.
else normalize_module_path0 lax env (Papply(p1', p2')) | ||
| Pident _ as path -> | ||
normalize_module_path0 lax env path | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about calling this function expand_module_path
rather normalize_module_path0
?
typing/env.ml
Outdated
| _ -> false | ||
|
||
let normalize_type_path oloc env path = | ||
(* Inlined version of Path.constructor_typath *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, you're inlining is_constructor_typath
.
It would be good to add a comment about the structure of those paths: a regular type path is followed by a capitalized constructor name, hence the choice based on the capitalization.
9753b8d
to
5b18159
Compare
Thanks for the review! Comments taken into account and branch rebased. Waiting for a green light for CI before merging. |
(* Inlined version of Path.is_constructor_typath: | ||
constructor type paths (i.e. path pointing to an inline | ||
record argument of a constructpr) are built as a regular | ||
type path followed by a capitalized constructor name. *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about Ext
paths?
According to Subst.type_path
, it seems that if p
is a module path, it should be normalized as such.
Or is there some invariant that ensures that this cannot happen?
OK, if I understand correctly, it seems that in the following example, your code would fail to normalize module M = struct exception E of {x:int; y:int} end
module N = M |
To be on the safe side, I added explicit support for paths of inline records under extension constructor. |
Ok. I let you merge it. |
2eaa454
to
225817c
Compare
Env.normalize_path
is supposed to be applied on module paths; in particular, it may callfind_module
, which of course does not make sense on other kinds of paths, and is not completely cheap. This PR renames this function tonormalize_module_path
to make its intended use more explicit, addsnormalize_type_path
(which takes care of the encoding in paths introduced by inline records), and fixes several wrong calls tonormalize_path
to use eithernormalize_type_path
ornormalize_path_prefix
(all other kinds of paths). There is also a new fast shortcut for persistent modules (i.e. compilation units) which cannot be aliases. (@lpw25 already confirmed to me that some of these calls were indeed wrong).This results in a noticeable speedup of the typechecker (about 10% when compiling typing/typecore.ml with ocamlc).
I suspect that normalize_path still accounts for a non-negligible fraction of type-checking time and would be worth looking at more closely.
(Another source of improvement would be to avoid always calling twice expand_head_unif in Ctype.unify2 on each type. This is by tracking initially this one that I realized that normalize_path and find_module were called on "wrong" paths.)