Skip to content

Commit e25d32b

Browse files
cristianocfhammerschmidt
authored andcommitted
Fix issue with typing application and polymorphic types. (#7338)
* Fix issue with typing application and polymorphic types. 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) ``` * Cleanup and type errot tests.
1 parent 4e29c7e commit e25d32b

File tree

6 files changed

+62
-1
lines changed

6 files changed

+62
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#### :bug: Bug fix
3939

4040
- Fix recursive untagged variant type checking by delaying well-formedness checks until environment construction completes. [#7320](https://github.com/rescript-lang/rescript/pull/7320)
41+
- Fix incorrect expansion of polymorphic return types in uncurried function applications. https://github.com/rescript-lang/rescript/pull/7338
4142

4243
# 12.0.0-alpha.9
4344

compiler/ml/typecore.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3554,7 +3554,9 @@ and type_application ?type_clash_context total_app env funct (sargs : sargs) :
35543554
let ty_fun = expand_head env ty_fun in
35553555
let arity_ok = List.length args < max_arity in
35563556
match ty_fun.desc with
3557-
| Tvar _ ->
3557+
| Tvar _ when force_tvar ->
3558+
(* This is a total application when the toplevel type is a polymorphic variable,
3559+
so the function type including arity can be inferred. *)
35583560
let t1 = newvar () and t2 = newvar () in
35593561
if ty_fun.level >= t1.level && not_identity funct.exp_desc then
35603562
Location.prerr_warning sarg1.pexp_loc Warnings.Unused_argument;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
Warning number 20
3+
/.../fixtures/fun_return_poly1.res:3:15
4+
5+
1 │ let f = (_, ~def=3) => assert(false)
6+
2 │
7+
3 │ let ok = f(1)(2)
8+
4 │ let err = f(1, 2)
9+
5 │
10+
11+
this argument will not be used by the function.
12+
13+
14+
We've found a bug for you!
15+
/.../fixtures/fun_return_poly1.res:4:16
16+
17+
2 │
18+
3 │ let ok = f(1)(2)
19+
4 │ let err = f(1, 2)
20+
5 │
21+
22+
The function applied to this argument has type ('a, ~def: int=?) => 'b
23+
This argument cannot be applied without label
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
Warning number 20
3+
/.../fixtures/fun_return_poly2.res:6:30
4+
5+
4 │ }
6+
5 │
7+
6 │ let ok = r("")(~initialValue=2)
8+
7 │ let err = r("", ~initialValue=2)
9+
8 │
10+
11+
this argument will not be used by the function.
12+
13+
14+
We've found a bug for you!
15+
/.../fixtures/fun_return_poly2.res:7:31
16+
17+
5 │
18+
6 │ let ok = r("")(~initialValue=2)
19+
7 │ let err = r("", ~initialValue=2)
20+
8 │
21+
22+
The function applied to this argument has type
23+
(string, ~wrongLabelName: int=?) => 'a
24+
This argument cannot be applied with label ~initialValue
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
let f = (_, ~def=3) => assert(false)
2+
3+
let ok = f(1)(2)
4+
let err = f(1, 2)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
let r: (string, ~wrongLabelName: int=?) => 'a = (_s, ~wrongLabelName=3) => {
2+
let _ = wrongLabelName
3+
assert(false)
4+
}
5+
6+
let ok = r("")(~initialValue=2)
7+
let err = r("", ~initialValue=2)

0 commit comments

Comments
 (0)