Skip to content

Commit 1792cdf

Browse files
authored
Add regression tests for instanceof (#4525)
* Treeshake instanceof * Fix side effect and self-reference handling * Remove feature and add regression test
1 parent 30735b4 commit 1792cdf

10 files changed

Lines changed: 90 additions & 9 deletions

File tree

src/ast/nodes/BinaryExpression.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,32 @@ import type * as NodeType from './NodeType';
1616
import { type LiteralValueOrUnknown, UnknownValue } from './shared/Expression';
1717
import { type ExpressionNode, NodeBase } from './shared/Node';
1818

19+
type Operator =
20+
| '!='
21+
| '!=='
22+
| '%'
23+
| '&'
24+
| '*'
25+
| '**'
26+
| '+'
27+
| '-'
28+
| '/'
29+
| '<'
30+
| '<<'
31+
| '<='
32+
| '=='
33+
| '==='
34+
| '>'
35+
| '>='
36+
| '>>'
37+
| '>>>'
38+
| '^'
39+
| '|'
40+
| 'in'
41+
| 'instanceof';
42+
1943
const binaryOperators: {
20-
[operator: string]: (left: LiteralValue, right: LiteralValue) => LiteralValueOrUnknown;
44+
[operator in Operator]?: (left: LiteralValue, right: LiteralValue) => LiteralValueOrUnknown;
2145
} = {
2246
'!=': (left, right) => left != right,
2347
'!==': (left, right) => left !== right,
@@ -29,15 +53,13 @@ const binaryOperators: {
2953
'+': (left: any, right: any) => left + right,
3054
'-': (left: any, right: any) => left - right,
3155
'/': (left: any, right: any) => left / right,
32-
'<': (left, right) => (left as NonNullable<LiteralValue>) < (right as NonNullable<LiteralValue>),
56+
'<': (left, right) => left! < right!,
3357
'<<': (left: any, right: any) => left << right,
34-
'<=': (left, right) =>
35-
(left as NonNullable<LiteralValue>) <= (right as NonNullable<LiteralValue>),
58+
'<=': (left, right) => left! <= right!,
3659
'==': (left, right) => left == right,
3760
'===': (left, right) => left === right,
38-
'>': (left, right) => (left as NonNullable<LiteralValue>) > (right as NonNullable<LiteralValue>),
39-
'>=': (left, right) =>
40-
(left as NonNullable<LiteralValue>) >= (right as NonNullable<LiteralValue>),
61+
'>': (left, right) => left! > right!,
62+
'>=': (left, right) => left! >= right!,
4163
'>>': (left: any, right: any) => left >> right,
4264
'>>>': (left: any, right: any) => left >>> right,
4365
'^': (left: any, right: any) => left ^ right,
@@ -79,8 +101,9 @@ export default class BinaryExpression extends NodeBase implements DeoptimizableE
79101
this.operator === '+' &&
80102
this.parent instanceof ExpressionStatement &&
81103
this.left.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this) === ''
82-
)
104+
) {
83105
return true;
106+
}
84107
return super.hasEffects(context);
85108
}
86109

src/ast/nodes/NewExpression.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ export default class NewExpression extends NodeBase {
2828
if (
2929
(this.context.options.treeshake as NormalizedTreeshakingOptions).annotations &&
3030
this.annotations
31-
)
31+
) {
3232
return false;
33+
}
3334
return (
3435
this.callee.hasEffects(context) ||
3536
this.callee.hasEffectsOnInteractionAtPath(EMPTY_PATH, this.interaction, context)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
description: 'retains side effects in the left hand side of instanceof'
3+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
let effect = false;
2+
3+
class Bar {}
4+
class Foo {
5+
constructor() {
6+
effect = true;
7+
}
8+
}
9+
10+
if (new Foo() instanceof Bar) {
11+
assert.fail('Wrong instance relation');
12+
}
13+
14+
assert.ok(effect);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
description: 'retains side effects in the right hand side of instanceof'
3+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
let effect = false;
2+
3+
class Foo {}
4+
5+
if (
6+
new Foo() instanceof
7+
class {
8+
[(effect = true)]() {}
9+
}
10+
) {
11+
assert.fail('Wrong instance relation');
12+
}
13+
14+
assert.ok(effect);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
description: 'retains instanceof for function parameters'
3+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
let effect = false;
2+
3+
class Foo {}
4+
5+
function checkInstance(instance) {
6+
if (instance instanceof Foo) {
7+
effect = true;
8+
}
9+
}
10+
11+
checkInstance(new Foo());
12+
assert.ok(effect);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
description: 'retains instanceof if it is true'
3+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class Foo {}
2+
3+
if (!(new Foo() instanceof Foo)) {
4+
assert.fail('instanceof not resolved correctly');
5+
}

0 commit comments

Comments
 (0)