Skip to content

Commit c65f360

Browse files
authored
Coercing int and float unboxed variant catch all cases (#6540)
* allow coercing int and float in addition to strings with unboxed variants with catch all cases * changelog
1 parent 00cb645 commit c65f360

File tree

5 files changed

+56
-8
lines changed

5 files changed

+56
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#### :rocket: New Feature
1616

1717
- GenType: support `@deriving(accessors)` outputs. https://github.com/rescript-lang/rescript-compiler/pull/6537
18+
- Allow coercing ints and floats to unboxed variants that have a catch-all unboxed int or float case. https://github.com/rescript-lang/rescript-compiler/pull/6540
1819

1920
# 11.0.0-rc.8
2021

jscomp/ml/ctype.ml

+5-5
Original file line numberDiff line numberDiff line change
@@ -3959,20 +3959,20 @@ let rec subtype_rec env trace t1 t2 cstrs =
39593959
subtype_rec env trace (expand_abbrev_opt env t1) t2 cstrs
39603960
| (Tconstr(p1, [], _), Tconstr(p2, [], _)) when Path.same p1 Predef.path_int && Path.same p2 Predef.path_float ->
39613961
cstrs
3962-
| (Tconstr(path, [], _), Tconstr(_, [], _)) when Path.same path Predef.path_string &&
3962+
| (Tconstr(path, [], _), Tconstr(_, [], _)) when Variant_coercion.can_coerce_primitive path &&
39633963
extract_concrete_typedecl env t2 |> Variant_coercion.can_try_coerce_variant_to_primitive |> Option.is_some
39643964
->
3965-
(* type coercion for strings to elgible unboxed variants:
3965+
(* type coercion for primitives (int/float/string) to elgible unboxed variants:
39663966
- must be unboxed
3967-
- must have a constructor case with a string payload *)
3967+
- must have a constructor case with a supported and matching primitive payload *)
39683968
(match Variant_coercion.can_try_coerce_variant_to_primitive (extract_concrete_typedecl env t2) with
39693969
| Some (constructors, true) ->
3970-
if constructors |> Variant_coercion.variant_has_catch_all_string_case then
3970+
if Variant_coercion.variant_has_catch_all_case constructors (fun p -> Path.same p path) then
39713971
cstrs
39723972
else
39733973
(trace, t1, t2, !univar_pairs)::cstrs
39743974
| _ -> (trace, t1, t2, !univar_pairs)::cstrs)
3975-
| (Tconstr(_, [], _), Tconstr(path, [], _)) when Variant_coercion.can_coerce_path path &&
3975+
| (Tconstr(_, [], _), Tconstr(path, [], _)) when Variant_coercion.can_coerce_primitive path &&
39763976
extract_concrete_typedecl env t1 |> Variant_coercion.can_try_coerce_variant_to_primitive |> Option.is_some
39773977
->
39783978
(* type coercion for variants to primitives *)

jscomp/ml/variant_coercion.ml

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
(* TODO: Improve error messages? Say why we can't coerce. *)
22

33
(* Right now we only allow coercing to primitives string/int/float *)
4-
let can_coerce_path (path : Path.t) =
4+
let can_coerce_primitive (path : Path.t) =
55
Path.same path Predef.path_string
66
|| Path.same path Predef.path_int
77
|| Path.same path Predef.path_float
88

99
let check_paths_same p1 p2 target_path =
1010
Path.same p1 target_path && Path.same p2 target_path
1111

12-
let variant_has_catch_all_string_case (constructors : Types.constructor_declaration list) =
12+
let variant_has_catch_all_case (constructors : Types.constructor_declaration list) path_is_same =
1313
let has_catch_all_string_case (c : Types.constructor_declaration) =
1414
let args = c.cd_args in
1515
match args with
1616
| Cstr_tuple [{desc = Tconstr (p, [], _)}] ->
17-
Path.same p Predef.path_string
17+
path_is_same p
1818
| _ -> false
1919
in
2020

2121
constructors |> List.exists has_catch_all_string_case
2222

23+
let variant_has_relevant_primitive_catch_all (constructors : Types.constructor_declaration list) =
24+
variant_has_catch_all_case constructors can_coerce_primitive
25+
2326
(* Checks if every case of the variant has the same runtime representation as the target type. *)
2427
let variant_has_same_runtime_representation_as_target ~(targetPath : Path.t)
2528
~unboxed (constructors : Types.constructor_declaration list) =

jscomp/test/VariantCoercion.js

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

jscomp/test/VariantCoercion.res

+24
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,27 @@ module CoerceFromStringToVariant = {
5656
let c = "Hi"
5757
let cc: mixed = (c :> mixed)
5858
}
59+
60+
module CoerceFromIntToVariant = {
61+
@unboxed type ints = Int(int) | @as(1) First | @as(2) Second | @as(3) Third
62+
let a = 100
63+
let aa = 1
64+
let b: ints = (a :> ints)
65+
let bb: ints = (aa :> ints)
66+
67+
@unboxed type mixed = Int(int) | @as(1) One | @as(null) Null | Two
68+
let c = 120
69+
let cc: mixed = (c :> mixed)
70+
}
71+
72+
module CoerceFromFloatToVariant = {
73+
@unboxed type floats = Float(float) | @as(1.) First | @as(2.) Second | @as(3.) Third
74+
let a = 100.
75+
let aa = 1.
76+
let b: floats = (a :> floats)
77+
let bb: floats = (aa :> floats)
78+
79+
@unboxed type mixed = Float(float) | @as(1.) One | @as(null) Null | Two
80+
let c = 120.
81+
let cc: mixed = (c :> mixed)
82+
}

0 commit comments

Comments
 (0)