-
Notifications
You must be signed in to change notification settings - Fork 463
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 issue with typing application and polymorphic types. #7338
Conversation
Fixes #7323 When typing application there's a special treatment for polymorphic types, where the arity and kinds of arguments are inferred. For example: `f => f(~lbl1, ~lbl2)` assigns a polymorphic type `'a` to `f` initially which is then instantated to `(~lbl1:t1, ~lbl2:t2) => t3`. That same mechanism currently applies when a function is annotated to return a polymorphic type such as `(string, ~wrongLabelName: int=?) => 'a`, where the `'a` is further instantiated to extend the function type with additional arguments. This mechanism is OK for curried function, but incorrect for uncurried functions: while e.g. `'a => 'b` with curried function designates any function where the first argument is unlabeled, with uncurried function it only designates functions of arity 1. So when processing application, `'b` should not be expanded further. Two examples of problematic code that now gives type error: ```res let r: (string, ~wrongLabelName: int=?) => 'a = (_s, ~wrongLabelName=3) => { let _ = wrongLabelName assert(false) } let tst1 = r("", ~initialValue=2) let tst2 = r("")(~initialValue=2) ``` and ```res let f = (_, ~def=3) => assert(false) let g1 = f(1,2) let g2 = f(1)(2) ```
Here's a tentative fix for the issue of functions that should not pass the type checker but do. |
compiler/ml/typecore.ml
Outdated
let ty1, ty2 = | ||
let ty_fun = expand_head env ty_fun in | ||
let arity_ok = List.length args < max_arity in | ||
match ty_fun.desc with | ||
| Tvar _ -> | ||
| Tvar _ when (* l1 = Nolabel || *) force_tvar -> |
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 is the only change.
Obviously there's some cleanup to do -- but interested in checking that the behaviour is solid for now (and might need to re-introduce debugging code in case issues are found).
Thanks a lot! Will test it now. |
Ok I can confirm that
What about let f = (_, ~def=3) => assert(false)
let g1 = f(1,2) // Error
let g2 = f(1)(2) // OK |
To see why let f : (int, ~def:int=?) => (int => unit) = (_, ~def=3) => assert(false) where |
Can't think of any issues right now. Cleaned up the code and added some tests for the expected error messages. |
Ah, yes, I somehow thought it had return type like In let f = (_, ~def=3) => ignore(def) There let g2 = f(1)(2) correctly gives an error, too. |
Fixes #7323
When typing application there's a special treatment for polymorphic types, where the arity and kinds of arguments are inferred. For example:
f => f(~lbl1, ~lbl2)
assigns a polymorphic type'a
tof
initially which is then instantated to(~lbl1:t1, ~lbl2:t2) => t3
.That same mechanism currently applies when a function is annotated to return a polymorphic type such as
(string, ~wrongLabelName: int=?) => 'a
, where the'a
is further instantiated to extend the function type with additional arguments. This mechanism is OK for curried function, but incorrect for uncurried functions: while e.g.'a => 'b
with curried function designates any function where the first argument is unlabeled, with uncurried function it only designates functions of arity 1. So when processing application,'b
should not be expanded further.Two examples of problematic code that now gives type error:
and