Skip to content

Commit 78b3172

Browse files
authored
Support coercing string to elgible untagged variants (#6443)
* support coercing string to elgible untagged variants * changelog * fix * all constructors in variant does not need to be coercable to string as long as there is a catch all case * adapt changelog to changed constraints
1 parent 761adc2 commit 78b3172

7 files changed

+71
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#### :rocket: New Feature
1616
- Allow coercing unboxed variants with only strings (now including with a single payload of string) to the primitive string. https://github.com/rescript-lang/rescript-compiler/pull/6441
17+
- Allow coercing strings to unboxed variants that has a catch-all unboxed string case. https://github.com/rescript-lang/rescript-compiler/pull/6443
1718

1819
#### :bug: Bug Fix
1920

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/variant_coercion_string_to_variant_no_payload.res:6:10-15
4+
5+
4 │ let x = "one"
6+
5 │
7+
6 │ let y = (x :> x)
8+
7 │
9+
10+
Type string is not a subtype of x
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@unboxed
2+
type x = One | Two
3+
4+
let x = "one"
5+
6+
let y = (x :> x)

jscomp/ml/ctype.ml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3951,6 +3951,19 @@ let rec subtype_rec env trace t1 t2 cstrs =
39513951
end
39523952
| (Tconstr(p1, _, _), _) when generic_private_abbrev env p1 ->
39533953
subtype_rec env trace (expand_abbrev_opt env t1) t2 cstrs
3954+
| (Tconstr(path, [], _), Tconstr(_, [], _)) when Path.same path Predef.path_string &&
3955+
extract_concrete_typedecl env t2 |> Variant_coercion.can_try_coerce_variant_to_primitive |> Option.is_some
3956+
->
3957+
(* type coercion for strings to elgible unboxed variants:
3958+
- must be unboxed
3959+
- must have a constructor case with a string payload *)
3960+
(match Variant_coercion.can_try_coerce_variant_to_primitive (extract_concrete_typedecl env t2) with
3961+
| Some (constructors, true) ->
3962+
if constructors |> Variant_coercion.variant_has_catch_all_string_case then
3963+
cstrs
3964+
else
3965+
(trace, t1, t2, !univar_pairs)::cstrs
3966+
| _ -> (trace, t1, t2, !univar_pairs)::cstrs)
39543967
| (Tconstr(_, [], _), Tconstr(path, [], _)) when Variant_coercion.can_coerce_path path &&
39553968
extract_concrete_typedecl env t1 |> Variant_coercion.can_try_coerce_variant_to_primitive |> Option.is_some
39563969
->

jscomp/ml/variant_coercion.ml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ let can_coerce_path (path : Path.t) =
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) =
13+
let has_catch_all_string_case (c : Types.constructor_declaration) =
14+
let args = c.cd_args in
15+
match args with
16+
| Cstr_tuple [{desc = Tconstr (p, [], _)}] ->
17+
Path.same p Predef.path_string
18+
| _ -> false
19+
in
20+
21+
constructors |> List.exists has_catch_all_string_case
22+
1223
(* Checks if every case of the variant has the same runtime representation as the target type. *)
1324
let variant_has_same_runtime_representation_as_target ~(targetPath : Path.t)
1425
~unboxed (constructors : Types.constructor_declaration list) =

jscomp/test/VariantCoercion.js

Lines changed: 18 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jscomp/test/VariantCoercion.res

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,15 @@ module CoerceWithPayload = {
4444
let d: float = (c :> float)
4545
let dd: float = (cc :> float)
4646
}
47+
48+
module CoerceFromStringToVariant = {
49+
@unboxed type strings = String(string) | First | Second | Third
50+
let a = "hello"
51+
let aa = "First"
52+
let b: strings = (a :> strings)
53+
let bb: strings = (aa :> strings)
54+
55+
@unboxed type mixed = String(string) | @as(1) One | @as(null) Null | Two
56+
let c = "Hi"
57+
let cc: mixed = (c :> mixed)
58+
}

0 commit comments

Comments
 (0)