-
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
Spellchecker hints and type-directed disambiguation for extensible variants: bis #1706
Conversation
At a first glance, I like that version a lot better. The code is much more straightforward and is a simplification over the existing implementation. I'll take time to review more carefully later. |
@Drup, would you by any chance be able to review it now? |
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.
I had a look at the new implementation. It's much simpler than the previous version, and I believe it is correct. The test file is very comprehensive, so I'm fairly confident about it. I'll let @Octachron decide what he wants to do for the empty type case, but it's very minor.
typing/typecore.ml
Outdated
if cstrs = [] then (* extension constructor path *) | ||
let env = extend t env in | ||
List.map fst ( Env.lookup_all_constructors (Longident.Lident s) env ) | ||
else cstrs |
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.
Since we have empty sum type now, cstrs = []
doesn't necessarily mean it's an extension constructor. That being said, this simply means doing extra work in a very uncommon cases, and doesn't compromise soundness, so I guess it's fine.
You could make this a bit better with the (unexposed) Env.find_type_full
function I suppose.
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.
I think I will start by extending the comment, I believe that optimization for empty sum types can come later.
Side note: when you rebase, do not forget to rewrite your tests using Armael's new error message syntax. |
Sorry for not commenting on this proposal earlier, but IIUC what you are doing I'm not sure that the disambiguation feature is a good idea. It looks like you're planning to allow: module M = struct
type Foo.t += Bar
end
let x : Foo.t = Bar but this will break as soon as Supporting things like: module M = struct
type Foo.t += Bar
end
open M
type Other.t += Bar
let x : Foo.t = Bar on the other hand would be absolutely fine. It shouldn't be too hard to restrict the disambiguation to cases such as these where the constructor is already available at the given path -- these are the cases that do not raise warning 40. Note that this criticism does not apply to spell-checking hints -- it is fine for them to change when a module is lifted out to its own module. |
Your first example still fails with this PR since the constructor is not in the environment, whereas the second one compiles fine. The extension of the environment in module M = struct
module N = struct
type t = ..
type t += A
end
end
let x : M.N.t = A by making sure that, at least, extension constructors defined in It is still posible to get a warning 40, with module M = struct type t = .. type t+=A end
let f (x:M.t) = x = A but this the same behavior as the one for classical variants. Should those case be disallowed for extension constructors? |
This feels ad hoc. Some constructors in the type M.N.t would be "favored", only because they are defined in the same module as their type. If one wants to create such "favored" constructors, this should be explicit in the syntax, e.g. by defining the constructors together with their type (not just in the same module, but with a single definition). But this should perhaps be discussed independently from a more basic kind of disambiguation, that only restricts the set of candidates, both for qualified references (when different constructors with the same name but different types are defined in a single module) and for unqualified ones (when different constructors are available in the current scope, for instance following an |
This part could be clearly split to a separate PR. Nevertheless, I see it as merely using all information provided by the user for the disambiguation, by acknowledging that the extension constructors defined along the type are easier to find. |
Ok, so that is nowhere near as bad as I thought, but I agree with Alain that this is too ad-hoc for my taste. I'm also suspicious of how it works with type aliases like: module M = struct
type t = ..
type t += A
end
module N = struct
type t = M.t = ..
type t += A
end
let x : N.t = A |
3fe4ce8
to
feddfe5
Compare
Ok, I have removed this ad-hoc open. |
Ensuring that the constructors in scope of the type are visible for the disambiguation seemed fairly reasonable to me, since it's just more disambiguation and doesn't impact correctness, but I'm fine either ways. |
This should address https://caml.inria.fr/mantis/view.php?id=6514, right? |
This PR is not enough in its current state: the error for multiple definitions would need to be removed, the shadowing in include would need to be refined to handle type t = ..
type s = ..
module M = struct type t += A end
module N = struct type s += A end
module A = struct include M include N end without hiding M.A or N.A, and the typing of extension rebinding in |
What's the status of this PR? I got the impression that people were happy with the final design and the code had been reviewed, but it seems to have got blocked anyway. |
I am planning to rebase it after the refactoring of the disambiguation code in #9182. The rebased version will need to re-expose a function to go through all constructors in scope, so your opinion would be welcome. |
317d7c7
to
24e98c0
Compare
I have rebased the PR, and removed some of the logic that was not needed anymore. The PR is now simply removing the logic for removing shadowed extension construction from the lookup; and adding an escape hatch for searching constructors with the right type in the whole environment in the misspelling hint. |
After further discussion with @gasche, I have written an alternative implementation that restrict the special handling for extension constructors to the This seemed to be a sensible compromise in term of future compatibility (if we add a notion of extension constructors in scope at a type in the environment) and present complexity. |
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.
The new implementation is very simple and clear, thanks. I made some nitpick comments, you should decide whether to take them into account or not.
(This is good to merge when the CI is ready; you should either merge or give me the bit of information on whether you want to work more or not.)
Let me fix these minor points and squash everything. |
This commit exposes all extension constructors when looking up for a construction with a given type in the environment. This makes constructor disambiguation work for extension constructors. Going one step further, when the name of an extension constructors is misspelled, we cannot rely on the type to find all possible names. However, since we are in an error path, we have some path at hand. Thus, this commit alters the "lookup_from_type" function in the Constructor module to make it scan the whole environment for extension constructors with the right type. This commit should not change anything for labels and standard constructors.
d0011e6
to
4f9f41e
Compare
This PR is an alternative implementation of #1154. Rather than tracking the list of extension constructors associated to a type in
Env.t
, this implementation splits the list of candidates used inTypescore.NameChoice
into a list of spellchecking candidates list and a list of disambiguation candidates. Since the list of spellchecking candidates is only used in a user-facing error path; it can afford to be relatively slow contrarily to the disambiguation candidates list.This patch keeps the same candidate lists as before for both labels and standard constructors. Contrarily, for extension constructors, the disambiguation candidates are generated with a call to
lookup_all_constructors
and the computation of the list of all extension constructors associated to a specific type is relegated to the spellchecking path.