Skip to content

Commit 6f73c0a

Browse files
authored
Untagged variants: fix pm with overlap. (#6125)
* Untagged variants: fix pm with string overlap. TODO: There should be something similar with int. Fixes: #6123 * Other case of overlap: int and float. * Add test for number overlap. * Add case of object overlap. * Handle object overlap. * Unrelated: leftover instanceof. * Logic more readable. * Simplify object overlap. * rename
1 parent b929991 commit 6f73c0a

File tree

3 files changed

+139
-14
lines changed

3 files changed

+139
-14
lines changed

jscomp/core/js_exp_make.ml

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -776,13 +776,39 @@ let is_type_number ?comment (e : t) : t =
776776
string_equal ?comment (typeof e) (str "number")
777777

778778
let rec is_a_literal_case ~(literal_cases : Lambda.literal list) ~block_cases (e:t) : t =
779-
let is_literal_case (l:Lambda.literal) : t = bin EqEqEq e (literal l) in
780-
let is_block_case (c:Lambda.block_type) : t = match c with
781-
| StringType -> bin NotEqEq (typeof e) (str "string")
782-
| IntType -> bin NotEqEq (typeof e) (str "number")
783-
| FloatType -> bin NotEqEq (typeof e) (str "number")
784-
| Array -> not (bin InstanceOf e (str "Array" ~delim:DNoQuotes))
785-
| Object -> { expression_desc = Bin (NotEqEq, typeof e, str "object"); comment=None }
779+
let literals_overlaps_with_string () =
780+
Ext_list.exists literal_cases (function
781+
| String _ -> true
782+
| l -> false ) in
783+
let literals_overlaps_with_number () =
784+
Ext_list.exists literal_cases (function
785+
| Int _ | Float _ -> true
786+
| l -> false ) in
787+
let literals_overlaps_with_object () =
788+
Ext_list.exists literal_cases (function
789+
| Null -> true
790+
| l -> false ) in
791+
let (==) x y = bin EqEqEq x y in
792+
let (!=) x y = bin NotEqEq x y in
793+
let (||) x y = bin Or x y in
794+
let (&&) x y = bin And x y in
795+
let is_literal_case (l:Lambda.literal) : t = e == (literal l) in
796+
let is_not_block_case (c:Lambda.block_type) : t = match c with
797+
| StringType when literals_overlaps_with_string () = false (* No overlap *) ->
798+
(typeof e) != (str "string")
799+
| IntType when literals_overlaps_with_number () = false ->
800+
(typeof e) != (str "number")
801+
| FloatType when literals_overlaps_with_number () = false ->
802+
(typeof e) != (str "number")
803+
| Array ->
804+
not (is_array e)
805+
| Object when literals_overlaps_with_object () = false ->
806+
(typeof e) != (str "object")
807+
| Object (* overlap *) ->
808+
e == nil || (typeof e) != (str "object")
809+
| StringType (* overlap *)
810+
| IntType (* overlap *)
811+
| FloatType (* overlap *)
786812
| Unknown ->
787813
(* We don't know the type of unknown, so we need to express:
788814
this is not one of the literals *)
@@ -793,14 +819,14 @@ let rec is_a_literal_case ~(literal_cases : Lambda.literal list) ~block_cases (e
793819
| l1 :: others ->
794820
let is_literal_1 = is_literal_case l1 in
795821
Ext_list.fold_right others is_literal_1 (fun literal_n acc ->
796-
bin Or (is_literal_case literal_n) acc
822+
(is_literal_case literal_n) || acc
797823
)
798824
)
799825
in
800826
match block_cases with
801-
| [c] -> is_block_case c
827+
| [c] -> is_not_block_case c
802828
| c1 :: (_::_ as rest) ->
803-
bin And (is_block_case c1) (is_a_literal_case ~literal_cases ~block_cases:rest e)
829+
(is_not_block_case c1) && (is_a_literal_case ~literal_cases ~block_cases:rest e)
804830
| [] -> assert false
805831

806832
let is_int_tag ?(has_null_undefined_other=(false, false, false)) (e : t) : t =

jscomp/test/UntaggedVariants.js

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
function classify(x) {
5-
if (typeof x !== "string" && typeof x !== "number") {
5+
if (x === "A" && typeof x !== "number") {
66
return "A";
77
} else if (typeof x === "number") {
88
return "An integer";
@@ -76,7 +76,7 @@ var Truthy = {
7676
};
7777

7878
function classify$1(x) {
79-
if (typeof x !== "object") {
79+
if (x === null || typeof x !== "object") {
8080
if (x === null) {
8181
return "null";
8282
} else {
@@ -108,7 +108,7 @@ var Unknown = {
108108
};
109109

110110
function classify$3(x) {
111-
if (typeof x !== "object" && typeof x !== "number" && typeof x !== "string") {
111+
if (typeof x !== "object" && typeof x !== "number" && (x === "C" || x === "B" || x === "A" || x === "D")) {
112112
switch (x) {
113113
case "A" :
114114
return "a";
@@ -173,7 +173,7 @@ var WithArray = {
173173
};
174174

175175
function classify$6(x) {
176-
if (!(x instanceof Array) && typeof x !== "object" && typeof x !== "number" && typeof x !== "string") {
176+
if (!Array.isArray(x) && (x === null || typeof x !== "object") && typeof x !== "number" && typeof x !== "string") {
177177
switch (x) {
178178
case false :
179179
return "JSONFalse";
@@ -235,6 +235,63 @@ var TrickyNested = {
235235
check: check
236236
};
237237

238+
function checkEnum(e) {
239+
if (!(e === "Two" || e === "One" || e === "Three")) {
240+
return "Something else..." + e;
241+
}
242+
switch (e) {
243+
case "One" :
244+
return "One!";
245+
case "Two" :
246+
return "Two";
247+
case "Three" :
248+
return "Threeeee";
249+
250+
}
251+
}
252+
253+
var OverlapString = {
254+
checkEnum: checkEnum
255+
};
256+
257+
function checkEnum$1(e) {
258+
if (!(e === "Two" || e === 1.0 || e === "Three")) {
259+
return "Something else...";
260+
}
261+
switch (e) {
262+
case 1.0 :
263+
return "One!";
264+
case "Two" :
265+
return "Two";
266+
case "Three" :
267+
return "Threeeee";
268+
269+
}
270+
}
271+
272+
var OverlapNumber = {
273+
checkEnum: checkEnum$1
274+
};
275+
276+
function checkEnum$2(e) {
277+
if (!(e === null || typeof e !== "object")) {
278+
return "Object...";
279+
}
280+
switch (e) {
281+
case null :
282+
return "One!";
283+
case "Two" :
284+
return "Two";
285+
case "Three" :
286+
return "Threeeee";
287+
288+
}
289+
}
290+
291+
var OverlapObject = {
292+
checkEnum: checkEnum$2
293+
};
294+
238295
var i = 42;
239296

240297
var i2 = 42.5;
@@ -269,4 +326,7 @@ exports.OnlyBlocks = OnlyBlocks;
269326
exports.WithArray = WithArray;
270327
exports.Json = Json;
271328
exports.TrickyNested = TrickyNested;
329+
exports.OverlapString = OverlapString;
330+
exports.OverlapNumber = OverlapNumber;
331+
exports.OverlapObject = OverlapObject;
272332
/* l2 Not a pure module */

jscomp/test/UntaggedVariants.res

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,42 @@ module TrickyNested = {
196196
| _ => 42
197197
}
198198
}
199+
200+
module OverlapString = {
201+
@unboxed
202+
type enum = One | Two | Three | FutureAddedValue(string)
203+
204+
let checkEnum = e =>
205+
switch e {
206+
| One => "One!"
207+
| Two => "Two"
208+
| Three => "Threeeee"
209+
| FutureAddedValue(s) => "Something else..." ++ s
210+
}
211+
}
212+
213+
module OverlapNumber = {
214+
@unboxed
215+
type enum = | @as(1.0) One | Two | Three | FutureAddedValue(float)
216+
217+
let checkEnum = e =>
218+
switch e {
219+
| One => "One!"
220+
| Two => "Two"
221+
| Three => "Threeeee"
222+
| FutureAddedValue(_) => "Something else..."
223+
}
224+
}
225+
226+
module OverlapObject = {
227+
@unboxed
228+
type enum = | @as(null) One | Two | Three | Object({x: int})
229+
230+
let checkEnum = e =>
231+
switch e {
232+
| One => "One!"
233+
| Two => "Two"
234+
| Three => "Threeeee"
235+
| Object(_) => "Object..."
236+
}
237+
}

0 commit comments

Comments
 (0)