Alternative implementation of type-checking for open#828
Alternative implementation of type-checking for open#828alainfrisch wants to merge 7 commits intoocaml:trunkfrom
open#828Conversation
…creating them from the signature.
|
(ocamldoc is failing, will investigate that...) |
|
FYI, the only failures I see in the testsuite are: So this seems to be a problem with how ocamldoc is using compilerlibs, rather than something wrong with |
|
The problem with ocamldoc: odoc_analyse calls |
|
This seems like a reasonable change, but I'm quite concerned that it affects the behavior of inline records at all. It seems that inline record types are created on the fly in |
|
Many different techniques were tried when implementing inline records. One of them involved representing these types explicitly in signatures, but it leads to a lot of complications. In the current implementation, the inline record does have a proper name, of the form M.t.X; it's only that the representation of this type is computed on demand. |
But there is no element |
|
It might also be a good idea to clean up how private row types are handled at the same time. Currently they are siblings of the main |
|
I thought you were suggesting to use a trick similar to row_type, which is precisely what I tried and reverted in favor of the current approach, which is more robust and simpler. So what you're suggesting is to create and keep the type_declaration corresponding to the inline record as part of the constructor_declaration / extension_constructor (that would be an extra argument to Cstr_record, I guess; or perhaps a replacement for the current label_description list). This inner type_declaration would simply be copied over (instanciated) to produce the cstr_inlined field of constructor_description. Is that right? I don't see any big issue with that, but I'm not sure it would simplify/robustify a lot compared to the current solution. One would still need a way to refer to the inner type, with a path such as M.t.X |
Basically, although it is a little more involved than that. These inner types should be treated essentially the same as any other type definition within the signature. For example, they should be appropriately handled by substitutions and strengthening. Grouping them inside of the |
Another alternative to these two parts would be to take the |
That would not really work because equalities are not mutually recursive, but they should in order to support types such as
I'm concerned that this would precisely create a problem with the lack of canonical ordering between free type variables for the inner inline record. Remember that |
Yes I was just about to post a correction on this. You really can't think of I need to give this some more thought. Both the way these types are handled and the way row types are handled are pretty dubious. I'm convinced there is a cleaner way to represent what is going on, but it requires some more thought. |
|
(and whilst I'm at it the way classes and class types are made up of three/four different components with the same name is also pretty questionable -- I'd love to have a cleaner solution to that as well). |
Indeed, it's an implementation trick (which leaks into error messages in reasonably user-friendly way). I believe the only real concern for making the path a first-class citizen (and allow inline records to escape) is the choice of parameters for the inline record definition. You're more than welcome to propose an alternative implementation! It would be great if it would allow using paths to inline records and letting them escape. |
openopen
|
Would anyone like to review that? |
|
I started reviewing the patch. I am not done but it looks good to me. I wonder if the |
|
Are you sure about prefixed_sg? It is used in components_of_module_maker as soon as the substitution is the identity. It's not clear to me that this becomes completely useless, even though it is much less frequently used than before. For instance, compiling hashtbl.mli has two "hits" in the cache (for "H"), caused by the "with type" constraints on functors. And the code below has one "hit" for "X": module X : sig
type 'a t
end
module Y : sig
val x: 'a X.t
end |
|
I agree it is still used, but not by Since it was introduced to speed-up opens, I was just questioning whether it benefits other use cases enough to justify the increased complexity. |
|
I agree that removing some of the cruft when it is not needed anymore would be good, as Env seems to be full of caches that tried to solve some efficiency problem at some point, but may have been subsumed by something else. Of course we need sufficient testing. |
|
@alainfrisch This is too big to get into 4.04.0 at this point, so you have to decide between merging #824 or leaving the bug in 4.04.0 and trying to get this one in the next release. |
|
This seems too risky for a last minute change; I prefer to leave the bug in 4.04. |
|
I finally looked at it again, it seems fine to me. |
|
Superseded by #834. |
initialise extern_flags to 0 on extern stat init
initialise extern_flags to 0 on extern stat init
…erations (ocaml#828) * Fix stack operand bug (when registers are spilled duting different loop iterations). * format * review
* make documentation link more obvious * minor style improvement Co-authored-by: Sabine Schmaltz <[email protected]>
* make package documentation link more obvious (ocaml#828) * make documentation link more obvious * minor style improvement Co-Authored-By: Sabine Schmaltz <[email protected]> * improve authors/maintainers display on package overview (ocaml#1001) * refactor package urls, routes, and handlers (ocaml#999) * refactor package urls, routes, and handlers * move package redirects to redirection.ml * Unify package overview and documentation layout (ocaml#1015) * unified package overview/docs layout Rearranges package overview and documentation such that: * package_layout.eml defines the two sidebars and the content area * there is a navigation element to switch between Overview (About) and Documentation (Docs) * there is a placeholder element for the upcoming in-package search (to remind us how important this feature is and to show users that we have a plan where it goes) Consequences: * package overview page now has a collapsing sidebar with a button to slide it in on small screens * package documentation now has a tablet (md) layout that shows the sidebar on-screen, instead of collapsed * add text-sm which was lost during unification * "Overview" instead of "About" since we have the space * Add support for sitemap.xml * Generate sitemap.xml by dream * Apply suggestions from @cuihtlauac code review Co-authored-by: Cuihtlauac Alvarado <[email protected]> * Convert lists of urls to sequences and change names of functions * Apply suggestions from @cuihtlauac code review 2 Co-authored-by: Cuihtlauac Alvarado <[email protected]> * Delete subdomains URLs and URLs returning status code other than 200 * Apply suggestions from @cuihtlauac code review 3 Co-authored-by: Cuihtlauac Alvarado <[email protected]> * Update PR * formating * do not touch playground asset * Apply suggestions from @cuihtlauac code review 4 * Apply suggestions from @cuihtlauac code review 5 * Apply suggestions from @cuihtlauac code review 6 * Apply suggestions from @cuihtlauac code review 7 * Apply suggestions from @cuihtlauac code review 8 --------- Co-authored-by: Sabine Schmaltz <[email protected]> Co-authored-by: sabine <[email protected]> Co-authored-by: Cuihtlauac Alvarado <[email protected]>
Currently,
openis type-checked by extracting the signature of the opened module, rewriting its paths to add the opened path prefix, and then inserting each element of the signature (as if type-checking that signature). With this approach, components of the opened module are recomputed on every open. For instance, labels and constructors are processed by Datarepr for each data type declaration (to produce label_descriptions/constructor_descriptions).This PR proposes an alternative implementation technique for type-checking an open statement: extracting the components of the opened module and re-inserting them in the environment with a local name.
This guarantees for instance that if a name X refers to a component in module Foo after an
open Foo, then this lookup forXreturns exactly the same component as a lookup forFoo.X. This is not the case with the current implementation, which is one way to explain http://caml.inria.fr/mantis/view.php?id=7372 (fixed by this PR).Also, this alternative technique can be much faster in some cases (see below) and it simplifies a bit some code by removing from many functions the need to support open-related warnings (shadowing and unused open).
Concerning performance, consider for instance:
type-checking this modules goes from 10s to 1.6s on my machine. (Similar speedup if the opened module contains instead "type t1 = A of {x:'a}, etc", and the ratio grows with larger type declarations.)
Note that with local opens (esp. with their short form), it is not uncommon for the same module (potentially large) to be opened many times in a given compilation unit.
[edit: also relevant to the discussion is http://caml.inria.fr/mantis/view.php?id=6826]