Skip to content

Commit 938db06

Browse files
authored
Allow free vars in types for coercion. (rescript-lang#6828)
* Test: allow free vars in types for coercion. See rescript-lang#6821 Free variables are not allowed in coercion, and if that happens, simple unification is performed without ever attempting coercion. This seems to go back a very long time. There's probably a good reason why free vars were not allowed. At the same time, there are no objects/classes supported in the language anymore, so it's not clear how those reasons would adapt. This just marks the place where one could investigate. * Add tests of type coercion with free vars. * Clean up code for coercion and free variables. * Update CHANGELOG.md * Remove unused code for self coercion. * Remove unused error that suggests double coercion.
1 parent 4d9456f commit 938db06

File tree

6 files changed

+128
-49
lines changed

6 files changed

+128
-49
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- Allow `@directive` on functions for emitting function level directive code (`let serverAction = @directive("'use server'") (~name) => {...}`). https://github.com/rescript-lang/rescript-compiler/pull/6756
1818
- Add `rewatch` to the npm package as an alternative build tool. https://github.com/rescript-lang/rescript-compiler/pull/6762
1919
- Throws an instance of JavaScript's `new Error()` and adds the extension payload for `cause` option. https://github.com/rescript-lang/rescript-compiler/pull/6611
20+
- Allow free vars in types for type coercion `e :> t`. https://github.com/rescript-lang/rescript-compiler/pull/6828
2021

2122
#### :boom: Breaking Change
2223

jscomp/ml/typecore.ml

+14-44
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ type error =
4646
| Private_label of Longident.t * type_expr
4747

4848
| Not_subtype of (type_expr * type_expr) list * (type_expr * type_expr) list
49-
| Coercion_failure of
50-
type_expr * type_expr * (type_expr * type_expr) list * bool
5149
| Too_many_arguments of bool * type_expr
5250
| Abstract_wrong_label of arg_label * type_expr
5351
| Scoping_let_module of string * type_expr
@@ -1783,9 +1781,6 @@ let generalizable level ty =
17831781
try check ty; unmark_type ty; true
17841782
with Exit -> unmark_type ty; false
17851783

1786-
(* Hack to allow coercion of self. Will clean-up later. *)
1787-
let self_coercion = ref ([] : (Path.t * Location.t list ref) list)
1788-
17891784
(* Helpers for packaged modules. *)
17901785
let create_package_type loc env (p, l) =
17911786
let s = !Typetexp.transl_modtype_longident loc env p in
@@ -2592,31 +2587,20 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
25922587
gen
25932588
end else true
25942589
in
2595-
begin match arg.exp_desc, !self_coercion, (repr ty').desc with
2596-
| _ when free_variables ~env arg.exp_type = []
2597-
&& free_variables ~env ty' = [] ->
2598-
if not gen && (* first try a single coercion *)
2599-
let snap = snapshot () in
2600-
let ty, _b = enlarge_type env ty' in
2601-
try
2602-
force (); Ctype.unify env arg.exp_type ty; true
2603-
with Unify _ ->
2604-
backtrack snap; false
2605-
then ()
2606-
else begin try
2607-
let force' = subtype env arg.exp_type ty' in
2608-
force (); force' ();
2609-
with Subtype (tr1, tr2) ->
2610-
(* prerr_endline "coercion failed"; *)
2611-
raise(Error(loc, env, Not_subtype(tr1, tr2)))
2612-
end;
2613-
| _ ->
2614-
let ty, b = enlarge_type env ty' in
2615-
force ();
2616-
begin try Ctype.unify env arg.exp_type ty with Unify trace ->
2617-
raise(Error(sarg.pexp_loc, env,
2618-
Coercion_failure(ty', full_expand env ty', trace, b)))
2619-
end
2590+
if not gen && (* first try a single coercion *)
2591+
let snap = snapshot () in
2592+
let ty, _b = enlarge_type env ty' in
2593+
try
2594+
force (); Ctype.unify env arg.exp_type ty; true
2595+
with Unify _ ->
2596+
backtrack snap; false
2597+
then ()
2598+
else begin try
2599+
let force' = subtype env arg.exp_type ty' in
2600+
force (); force' ();
2601+
with Subtype (tr1, tr2) ->
2602+
(* prerr_endline "coercion failed"; *)
2603+
raise(Error(loc, env, Not_subtype(tr1, tr2)))
26202604
end;
26212605
(arg, ty', cty')
26222606
in
@@ -3925,20 +3909,6 @@ let report_error env ppf = function
39253909
end
39263910
| Not_subtype(tr1, tr2) ->
39273911
report_subtyping_error ppf env tr1 "is not a subtype of" tr2
3928-
| Coercion_failure (ty, ty', trace, b) ->
3929-
(* modified *)
3930-
super_report_unification_error ppf env trace
3931-
(function ppf ->
3932-
let ty, ty' = Printtyp.prepare_expansion (ty, ty') in
3933-
fprintf ppf
3934-
"This expression cannot be coerced to type@;<1 2>%a;@ it has type"
3935-
(Printtyp.type_expansion ty) ty')
3936-
(function ppf ->
3937-
fprintf ppf "but is here used with type");
3938-
if b then
3939-
fprintf ppf ".@.@[<hov>%s@ %s@]"
3940-
"This simple coercion was not fully general."
3941-
"Consider using a double coercion."
39423912
| Too_many_arguments (in_function, ty) ->
39433913
(* modified *)
39443914
reset_and_mark_loops ty;

jscomp/ml/typecore.mli

-4
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ val generalizable: int -> type_expr -> bool
5858
val id_of_pattern : Typedtree.pattern -> Ident.t option
5959
val name_pattern : string -> Typedtree.case list -> Ident.t
6060

61-
val self_coercion : (Path.t * Location.t list ref) list ref
62-
6361
type error =
6462
Polymorphic_label of Longident.t
6563
| Constructor_arity_mismatch of Longident.t * int * int
@@ -81,8 +79,6 @@ type error =
8179
| Private_type of type_expr
8280
| Private_label of Longident.t * type_expr
8381
| Not_subtype of (type_expr * type_expr) list * (type_expr * type_expr) list
84-
| Coercion_failure of
85-
type_expr * type_expr * (type_expr * type_expr) list * bool
8682
| Too_many_arguments of bool * type_expr
8783
| Abstract_wrong_label of arg_label * type_expr
8884
| Scoping_let_module of string * type_expr

jscomp/test/build.ninja

+2-1
Large diffs are not rendered by default.
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module NoFreeVars = {
2+
type t = private int
3+
4+
let f = (x: t) => (x :> int)
5+
6+
let g = (y: t) => ()
7+
8+
let h = x => (g(x), (x :> int))
9+
10+
// let h2 = x => ((x :> int), g(x))
11+
}
12+
13+
module WithTypeArg = {
14+
type t<'a> = private int
15+
16+
let f = (x: t<_>) => (x :> int)
17+
}
18+
19+
module FunctionType = {
20+
type t = private int
21+
let f = _ => (Obj.magic(3) : t)
22+
let _ = f :> (_ => int)
23+
}
24+
25+
module Contravariant = {
26+
type t = private int
27+
let f1 = (_:int) => ()
28+
let _ = f1 :> (t => unit)
29+
let f2 = (_:int, _) => ()
30+
let _ = f2 :> ((t, _) => unit)
31+
}
32+
33+
34+
module Totallypoly = {
35+
let f = x => (x :> int)
36+
let idint = (x:int) => x
37+
let _ = f === idint
38+
}

jscomp/test/type-coercion-free.js

+73
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)