Skip to content

Commit 230269b

Browse files
committed
Make variant pattern matching not rely on tags being int
There are several ways in which the compilation of variants relies on tags being integers: - Sometimes it uses booleans `if x` to mean `x !=0` to mean: not the first variant (i.e. tag 0) - Sometimes it uses intervals `if (x > 3 || x < 1)` Care is required not to change the compilation of variants with special compilation: - true and false - lists have constructors "[]" and "::" - options have a specific definition for "Some" and "None" See #6077
1 parent a5c7568 commit 230269b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+9131
-8791
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ These are only breaking changes for unformatted code.
7474
- New internal representation for uncurried functions using built-in type `function$<fun_type, arity>` this avoids having to declare all the possible arities ahead of time https://github.com/rescript-lang/rescript-compiler/pull/5870
7575
- PPX V3: allow uncurried `make` function and treat it like a curried one https://github.com/rescript-lang/rescript-compiler/pull/6081
7676
- Add support for `|>` in uncurried mode by desugaring it https://github.com/rescript-lang/rescript-compiler/pull/6083
77+
- Change the compilation of pattern matching for variants so it does not depends on variats being integers https://github.com/rescript-lang/rescript-compiler/pull/6085
7778

7879
# 10.1.4
7980

jscomp/core/js_exp_make.ml

+3
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,9 @@ let string_equal ?comment (e0 : t) (e1 : t) : t =
760760
let is_type_number ?comment (e : t) : t =
761761
string_equal ?comment (typeof e) (str "number")
762762

763+
let is_tag (e : t) : t =
764+
string_equal ~comment:"tag" (typeof e) (str "number")
765+
763766
let is_type_string ?comment (e : t) : t =
764767
string_equal ?comment (typeof e) (str "string")
765768

jscomp/core/js_exp_make.mli

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ val eq_null_undefined_boolean : ?comment:string -> t -> t -> t
199199
val neq_null_undefined_boolean : ?comment:string -> t -> t -> t
200200

201201
val is_type_number : ?comment:string -> t -> t
202+
val is_tag : t -> t
202203

203204
val is_type_string : ?comment:string -> t -> t
204205

jscomp/core/lam_compile.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ and compile_switch (switch_arg : Lam.t) (sw : Lam.lambda_switch)
616616
else
617617
(* [e] will be used twice *)
618618
let dispatch e =
619-
S.if_ (E.is_type_number e)
619+
S.if_ (E.is_tag e)
620620
(compile_cases cxt e sw_consts sw_num_default get_const_name)
621621
(* default still needed, could simplified*)
622622
~else_:

jscomp/ml/matching.ml

+14-8
Original file line numberDiff line numberDiff line change
@@ -2348,19 +2348,25 @@ let combine_constructor sw_names loc arg ex_pat cstr partial ctx def
23482348
match
23492349
(cstr.cstr_consts, cstr.cstr_nonconsts, consts, nonconsts)
23502350
with
2351-
| (1, 1, [0, act1], [0, act2]) ->
2352-
(* Typically, match on lists, will avoid isint primitive in that
2353-
case *)
2351+
| (1, 1, [0, act1], [0, act2])
2352+
when cstr.cstr_name = "::" || cstr.cstr_name = "[]" || Datarepr.constructor_has_optional_shape cstr
2353+
->
2354+
(* Typically, match on lists, will avoid isint primitive in that
2355+
case *)
23542356
let arg =
23552357
if !Config.bs_only && Datarepr.constructor_has_optional_shape cstr then
23562358
Lprim(is_not_none_bs_primitve , [arg], loc)
23572359
else arg
23582360
in
23592361
Lifthenelse(arg, act2, act1)
23602362
| (2,0, [(i1,act1); (_,act2)],[]) ->
2361-
if i1 = 0 then Lifthenelse(arg, act2, act1)
2362-
else Lifthenelse (arg,act1,act2)
2363-
| (n,0,_,[]) -> (* The type defines constant constructors only *)
2363+
let arg = match act1 with
2364+
| Lconst (Const_pointer (_, Pt_constructor _ )) ->
2365+
Lprim (Pintcomp(Ceq), [arg; act1], loc)
2366+
| _ -> arg in
2367+
if i1 = 0 then Lifthenelse(arg, act2, act1)
2368+
else Lifthenelse (arg, act1, act2)
2369+
| (n,0,_,[]) when false (* relies on tag being an int *) -> (* The type defines constant constructors only *)
23642370
call_switcher loc fail_opt arg 0 (n-1) consts sw_names
23652371
| (n, _, _, _) ->
23662372
let act0 =
@@ -2373,15 +2379,15 @@ let combine_constructor sw_names loc arg ex_pat cstr partial ctx def
23732379
else None
23742380
| None,_ -> same_actions nonconsts in
23752381
match act0 with
2376-
| Some act ->
2382+
| Some act when false (* relies on tag being an int *) ->
23772383
Lifthenelse
23782384
(Lprim (Pisint, [arg], loc),
23792385
call_switcher loc
23802386
fail_opt arg
23812387
0 (n-1) consts sw_names,
23822388
act)
23832389
(* Emit a switch, as bytecode implements this sophisticated instruction *)
2384-
| None ->
2390+
| _ ->
23852391
let sw =
23862392
{sw_numconsts = cstr.cstr_consts; sw_consts = consts;
23872393
sw_numblocks = cstr.cstr_nonconsts; sw_blocks = nonconsts;

jscomp/test/adt_optimize_test.js

+15-13
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function f4(param) {
2626
}
2727

2828
function f5(param) {
29-
if (typeof param === "number") {
29+
if (/* tag */typeof param === "number") {
3030
switch (param) {
3131
case /* A */0 :
3232
return 1;
@@ -49,19 +49,21 @@ function f5(param) {
4949
}
5050

5151
function f6(param) {
52-
if (typeof param === "number") {
53-
if (param >= 2) {
54-
return 2;
55-
} else {
56-
return 0;
57-
}
58-
} else {
52+
if (/* tag */typeof param !== "number") {
5953
return 1;
6054
}
55+
switch (param) {
56+
case /* A */0 :
57+
case /* B */1 :
58+
return 0;
59+
case /* F */2 :
60+
return 2;
61+
62+
}
6163
}
6264

6365
function f7(param) {
64-
if (typeof param === "number") {
66+
if (/* tag */typeof param === "number") {
6567
switch (param) {
6668
case /* A */0 :
6769
return 1;
@@ -85,7 +87,7 @@ function f7(param) {
8587
}
8688

8789
function f8(param) {
88-
if (typeof param === "number") {
90+
if (/* tag */typeof param === "number") {
8991
switch (param) {
9092
case /* T60 */0 :
9193
case /* T61 */1 :
@@ -105,7 +107,7 @@ function f8(param) {
105107
}
106108

107109
function f9(param) {
108-
if (typeof param === "number") {
110+
if (/* tag */typeof param === "number") {
109111
if (param === /* T63 */3) {
110112
return 3;
111113
} else {
@@ -124,7 +126,7 @@ function f9(param) {
124126
}
125127

126128
function f10(param) {
127-
if (typeof param === "number") {
129+
if (/* tag */typeof param === "number") {
128130
switch (param) {
129131
case /* T60 */0 :
130132
return 0;
@@ -150,7 +152,7 @@ function f10(param) {
150152
}
151153

152154
function f11(x) {
153-
if (typeof x === "number") {
155+
if (/* tag */typeof x === "number") {
154156
return 2;
155157
}
156158
if (x.TAG === /* D */0) {

jscomp/test/bal_set_mini.js

+22-22
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33

44
function height(param) {
5-
if (param) {
6-
return param._3;
7-
} else {
5+
if (/* tag */typeof param === "number") {
86
return 0;
7+
} else {
8+
return param._3;
99
}
1010
}
1111

@@ -24,18 +24,18 @@ function bal(l, v, r) {
2424
var hl = height(l);
2525
var hr = height(r);
2626
if (hl > (hr + 2 | 0)) {
27-
if (!l) {
27+
if (/* tag */typeof l === "number") {
2828
return /* Empty */0;
2929
}
3030
var lr = l._2;
3131
var lv = l._1;
3232
var ll = l._0;
3333
if (height(ll) >= height(lr)) {
3434
return create(ll, lv, create(lr, v, r));
35-
} else if (lr) {
36-
return create(create(ll, lv, lr._0), lr._1, create(lr._2, v, r));
37-
} else {
35+
} else if (/* tag */typeof lr === "number") {
3836
return /* Empty */0;
37+
} else {
38+
return create(create(ll, lv, lr._0), lr._1, create(lr._2, v, r));
3939
}
4040
}
4141
if (hr <= (hl + 2 | 0)) {
@@ -46,18 +46,18 @@ function bal(l, v, r) {
4646
_3: hl >= hr ? hl + 1 | 0 : hr + 1 | 0
4747
};
4848
}
49-
if (!r) {
49+
if (/* tag */typeof r === "number") {
5050
return /* Empty */0;
5151
}
5252
var rr = r._2;
5353
var rv = r._1;
5454
var rl = r._0;
5555
if (height(rr) >= height(rl)) {
5656
return create(create(l, v, rl), rv, rr);
57-
} else if (rl) {
58-
return create(create(l, v, rl._0), rl._1, create(rl._2, rv, rr));
59-
} else {
57+
} else if (/* tag */typeof rl === "number") {
6058
return /* Empty */0;
59+
} else {
60+
return create(create(l, v, rl._0), rl._1, create(rl._2, rv, rr));
6161
}
6262
}
6363

@@ -72,7 +72,7 @@ function compare_int(x, y) {
7272
}
7373

7474
function add(x, t) {
75-
if (!t) {
75+
if (/* tag */typeof t === "number") {
7676
return /* Node */{
7777
_0: /* Empty */0,
7878
_1: x,
@@ -97,11 +97,11 @@ function min_elt(_def, _param) {
9797
while(true) {
9898
var param = _param;
9999
var def = _def;
100-
if (!param) {
100+
if (/* tag */typeof param === "number") {
101101
return def;
102102
}
103103
var l = param._0;
104-
if (!l) {
104+
if (/* tag */typeof l === "number") {
105105
return param._1;
106106
}
107107
_param = l;
@@ -111,26 +111,26 @@ function min_elt(_def, _param) {
111111
}
112112

113113
function remove_min_elt(l, v, r) {
114-
if (l) {
115-
return bal(remove_min_elt(l._0, l._1, l._2), v, r);
116-
} else {
114+
if (/* tag */typeof l === "number") {
117115
return r;
116+
} else {
117+
return bal(remove_min_elt(l._0, l._1, l._2), v, r);
118118
}
119119
}
120120

121121
function internal_merge(l, r) {
122-
if (!l) {
122+
if (/* tag */typeof l === "number") {
123123
return r;
124124
}
125-
if (!r) {
125+
if (/* tag */typeof r === "number") {
126126
return l;
127127
}
128128
var rv = r._1;
129129
return bal(l, min_elt(rv, r), remove_min_elt(r._0, rv, r._2));
130130
}
131131

132132
function remove(x, tree) {
133-
if (!tree) {
133+
if (/* tag */typeof tree === "number") {
134134
return /* Empty */0;
135135
}
136136
var r = tree._2;
@@ -149,7 +149,7 @@ function remove(x, tree) {
149149
function mem(x, _param) {
150150
while(true) {
151151
var param = _param;
152-
if (!param) {
152+
if (/* tag */typeof param === "number") {
153153
return false;
154154
}
155155
var c = compare_int(x, param._1);
@@ -180,7 +180,7 @@ for(var i$2 = 0; i$2 <= 100000; ++i$2){
180180

181181
var match = v;
182182

183-
if (match) {
183+
if (/* tag */typeof match !== "number") {
184184
console.log("impossible");
185185
}
186186

0 commit comments

Comments
 (0)