Skip to content

Commit 0743b86

Browse files
committed
coerce variants to string/int
1 parent 508e2b3 commit 0743b86

13 files changed

+140
-1
lines changed
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_int.res:5:10-17
4+
5+
3 │ let x = One(true)
6+
4 │
7+
5 │ let y = (x :> int)
8+
6 │
9+
10+
Type x is not a subtype of int
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_int_as.res:5:10-17
4+
5+
3 │ let x = One
6+
4 │
7+
5 │ let y = (x :> int)
8+
6 │
9+
10+
Type x is not a subtype of int
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.res:5:10-20
4+
5+
3 │ let x = One(true)
6+
4 │
7+
5 │ let y = (x :> string)
8+
6 │
9+
10+
Type x is not a subtype of string
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_as.res:5:10-20
4+
5+
3 │ let x = One
6+
4 │
7+
5 │ let y = (x :> string)
8+
6 │
9+
10+
Type x is not a subtype of string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type x = | @as(1) One(bool) | @as(2) Two
2+
3+
let x = One(true)
4+
5+
let y = (x :> int)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type x = | @as(1) One | Two
2+
3+
let x = One
4+
5+
let y = (x :> int)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type x = One(bool) | Two
2+
3+
let x = One(true)
4+
5+
let y = (x :> string)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type x = One | @as(2) Two
2+
3+
let x = One
4+
5+
let y = (x :> string)

Diff for: jscomp/ml/ctype.ml

+16
Original file line numberDiff line numberDiff line change
@@ -3951,6 +3951,22 @@ 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(_, [], _), Tconstr(p, [], _)) when Path.same p Predef.path_string -> (* type coercion for variants represented by strings *)
3955+
(match extract_concrete_typedecl env t1 with
3956+
| (_, _, {type_kind=Type_variant (constructors)}) ->
3957+
if Variant_coercion.can_coerce_to_string constructors then
3958+
cstrs
3959+
else
3960+
(trace, t1, t2, !univar_pairs)::cstrs
3961+
| _ -> (trace, t1, t2, !univar_pairs)::cstrs)
3962+
| (Tconstr(_, [], _), Tconstr(p, [], _)) when Path.same p Predef.path_int -> (* type coercion for variants represented by ints *)
3963+
(match extract_concrete_typedecl env t1 with
3964+
| (_, _, {type_kind=Type_variant (constructors)}) ->
3965+
if Variant_coercion.can_coerce_to_int constructors then
3966+
cstrs
3967+
else
3968+
(trace, t1, t2, !univar_pairs)::cstrs
3969+
| _ -> (trace, t1, t2, !univar_pairs)::cstrs)
39543970
| (Tconstr(_, [], _), Tconstr(_, [], _)) -> (* type coercion for records *)
39553971
(match extract_concrete_typedecl env t1, extract_concrete_typedecl env t2 with
39563972
| (_, _, {type_kind=Type_record (fields1, repr1)}), (_, _, {type_kind=Type_record (fields2, repr2)}) ->

Diff for: jscomp/ml/variant_coercion.ml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
type variant_representation = String | Int | Other
3+
4+
let find_as_attribute_payload (attributes : Parsetree.attribute list) =
5+
attributes
6+
|> List.find_map (fun (({txt = name}, payload) : Parsetree.attribute) ->
7+
match (name, payload) with
8+
| ( "as",
9+
PStr
10+
[
11+
{
12+
pstr_desc =
13+
Pstr_eval ({pexp_desc = Pexp_constant constant}, _);
14+
};
15+
] ) ->
16+
Some constant
17+
| _ -> None)
18+
19+
let constructors_representations
20+
(constructors : Types.constructor_declaration list) =
21+
constructors
22+
|> List.map (fun (c : Types.constructor_declaration) ->
23+
match (c.cd_args, c.cd_attributes |> find_as_attribute_payload) with
24+
| Cstr_tuple [], (Some (Pconst_string _) | None) -> String
25+
| Cstr_tuple [], Some (Pconst_integer _) -> Int
26+
| _ -> Other)
27+
28+
(* TODO: Improve error messages? Say why we can't coerce. *)
29+
30+
let can_coerce_to_string (constructors : Types.constructor_declaration list) =
31+
constructors |> constructors_representations |> List.for_all (( = ) String)
32+
33+
let can_coerce_to_int (constructors : Types.constructor_declaration list) =
34+
constructors |> constructors_representations |> List.for_all (( = ) Int)

Diff for: jscomp/test/VariantCoercion.js

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

Diff for: jscomp/test/VariantCoercion.res

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type a = One | @as("two") Two | Three
2+
3+
let a: a = Three
4+
5+
let b = (a :> string)
6+
7+
type onlyInts = | @as(1) One1 | @as(2) Two2 | @as(3) Three3
8+
9+
let i = One1
10+
11+
let d = (i :> int)

Diff for: jscomp/test/build.ninja

+2-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)