-
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
Erroneous "Constraints are not satisfied in this type" with mutually recursive abbreviations #12334
Comments
The use of This said, the error message is really bad. I don't know who added this logic, I suppose it needs to be tuned to recognize that |
Thanks for that explanation. It definitely looked like the |
I don't know about you, but I'm definitely not expecting the typechecker to deduce
as the only solution of
As much as I like type inference and constraint resolution, for type declarations I'd prefer the typechecker to just check them but not transform them that much. |
I've found it odd that this is accepted: type 'a t1 = 'a constraint 'a = int
type 'a t2 = 'a t1 which is inferred to have signature type 'a t1 = 'a constraint 'a = int
type 'a t2 = 'a t1 constraint 'a = int Inferring the constraint on |
@goldfirere I don't quite recall the motivating example, but you can have polymorphic recursion by using distinct instances of the same abbreviation in the same mutually recursive definition. type 'a located = 'a * string * int
and pattern = pattern_desc located
and pattern_desc = ...
and expression = expression_desc located
and expression_desc = ... Of course, in this case you can easily break the recursion, but with more contrived examples this becomes difficult. |
Naive questions arising from following this discussion. And what would go wrong if we checked constraints in a mutually-recursive nest with the definitions in scope? I suppose that the problem would be non-termination due to non-well-founded definitions. This gives two questions:
|
In response to @garrigue: I think the issue here is really the definition of "polymorphic recursion". Moving to the more familiar territory of terms, I consider polymorphic recursion to have happened when you have a recursive function whose recursive uses are inferred to have different type instantiation. To me, there are three essential aspects of polymorphic recursion (at least as it affects inference -- or the lack thereof): (1) the instantiation is inferred, and (2) the instantiated parameter is dependent, and (3) the instantiated parameter is different than it was at the definition site. In the mutually-recursive types example above, we have (3) but neither (1) nor (2) (though maybe (2) is a bit squishy in the case of abbreviations). In any case, GHC needs to worry about polymorphic recursion only in the presence of its kind inference. The closest GHC equivalent to the check we're worrying about here is its abbreviation cyclicity check, which is just a fairly straightforward look for cycles, stopping whenever a non-abbreviation is hit. So maybe a better question to aid my understanding is: why do we need to check for regularity in this way? Or, if it's more helpful and implementation-oriented: couldn't we just do a cyclicity check without unification first, and then check the constraints later? |
We have to be careful because constraints can introduce cycles: type 'a t = 'a -> 'a constraint 'a = 'a t I looked at the typedecl.ml code again and here are some extra remarks mostly for myself:
|
Due to the presence of equi-recursive types and constraints on type parameters, the cyclicity check in ocaml is much more complex than in GHC. |
Aha -- so OCaml does not allow propagation of constraints within a mutually recursive group of type definitions. I did not know that. But it nicely explains why my original program is rejected. Is this design decision documented anywhere? It would be great for it to appear in the manual, but maybe is too detailed (given that there are other aspects of the type system not accurately described there)? If we're happy with "do not propagate constraints within a mutually recursive group" (I am), then this bug is just a request for a better error message (and something I perhaps could take on myself). However, this conversation then opens a question for me: I've been thinking about Jane Street's layout system as closely analogous to constraints. Whenever there has been a design question, we look at constraints to see what happens there to get an intuition. But I had not understood about the lack of constraint propagation, and so layouts do propagate within mutually recursive definitions. For example: type 'a t = 'a t2
and 'b t2 = { x : int; y : ('b : float64); z : 'b t option } This would infer that |
For the first point, this was indeed a bad interaction between a not-so-legit use of an original environment and improved error messages reporting the absence of actual definition. This is fixed in #12368, which you're welcome to review if you are willing to delve into this part of the code. Fortunately the change is relatively trivial, once you understand that undefined types already behaved as abstract types for the type checker. I also fixed a wrong parameter order. For your second question, the problem is just whether you can separate your propagation phase from the wellformedness check. If you can check the wellformedness of types, and then propagate, I believe this should be fine. We also do this kind of propagation for variance for instance. |
Build an explicit abstract environment for check_regularity (fix #12334)
When I say
ocaml says
But this program should be accepted, I think, with something like this signature:
I think the problem is that
Typedecl.check_regularity
uses theorig_env
when checking arguments -- but theorig_env
doesn't know that'a foo
is an abbreviation forint
when checking the manifest oft
. I don't know enough of what's going on here to suggest a fix. But even if a proper fix is out of reach, the error message definitely has room for improvement:int
is an instance of'a foo
(because they're equal) and there is no missing cmi file involved.The text was updated successfully, but these errors were encountered: