Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add regression tests for instanceof #4525

Merged
merged 3 commits into from Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 31 additions & 8 deletions src/ast/nodes/BinaryExpression.ts
Expand Up @@ -16,8 +16,32 @@ import type * as NodeType from './NodeType';
import { type LiteralValueOrUnknown, UnknownValue } from './shared/Expression';
import { type ExpressionNode, NodeBase } from './shared/Node';

type Operator =
| '!='
| '!=='
| '%'
| '&'
| '*'
| '**'
| '+'
| '-'
| '/'
| '<'
| '<<'
| '<='
| '=='
| '==='
| '>'
| '>='
| '>>'
| '>>>'
| '^'
| '|'
| 'in'
| 'instanceof';

const binaryOperators: {
[operator: string]: (left: LiteralValue, right: LiteralValue) => LiteralValueOrUnknown;
[operator in Operator]?: (left: LiteralValue, right: LiteralValue) => LiteralValueOrUnknown;
} = {
'!=': (left, right) => left != right,
'!==': (left, right) => left !== right,
Expand All @@ -29,15 +53,13 @@ const binaryOperators: {
'+': (left: any, right: any) => left + right,
'-': (left: any, right: any) => left - right,
'/': (left: any, right: any) => left / right,
'<': (left, right) => (left as NonNullable<LiteralValue>) < (right as NonNullable<LiteralValue>),
'<': (left, right) => left! < right!,
'<<': (left: any, right: any) => left << right,
'<=': (left, right) =>
(left as NonNullable<LiteralValue>) <= (right as NonNullable<LiteralValue>),
'<=': (left, right) => left! <= right!,
'==': (left, right) => left == right,
'===': (left, right) => left === right,
'>': (left, right) => (left as NonNullable<LiteralValue>) > (right as NonNullable<LiteralValue>),
'>=': (left, right) =>
(left as NonNullable<LiteralValue>) >= (right as NonNullable<LiteralValue>),
'>': (left, right) => left! > right!,
'>=': (left, right) => left! >= right!,
'>>': (left: any, right: any) => left >> right,
'>>>': (left: any, right: any) => left >>> right,
'^': (left: any, right: any) => left ^ right,
Expand Down Expand Up @@ -79,8 +101,9 @@ export default class BinaryExpression extends NodeBase implements DeoptimizableE
this.operator === '+' &&
this.parent instanceof ExpressionStatement &&
this.left.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this) === ''
)
) {
return true;
}
return super.hasEffects(context);
}

Expand Down
3 changes: 2 additions & 1 deletion src/ast/nodes/NewExpression.ts
Expand Up @@ -28,8 +28,9 @@ export default class NewExpression extends NodeBase {
if (
(this.context.options.treeshake as NormalizedTreeshakingOptions).annotations &&
this.annotations
)
) {
return false;
}
return (
this.callee.hasEffects(context) ||
this.callee.hasEffectsOnInteractionAtPath(EMPTY_PATH, this.interaction, context)
Expand Down
3 changes: 3 additions & 0 deletions test/function/samples/instanceof/left-hand-effect/_config.js
@@ -0,0 +1,3 @@
module.exports = {
description: 'retains side effects in the left hand side of instanceof'
};
14 changes: 14 additions & 0 deletions test/function/samples/instanceof/left-hand-effect/main.js
@@ -0,0 +1,14 @@
let effect = false;

class Bar {}
class Foo {
constructor() {
effect = true;
}
}

if (new Foo() instanceof Bar) {
assert.fail('Wrong instance relation');
}

assert.ok(effect);
3 changes: 3 additions & 0 deletions test/function/samples/instanceof/right-hand-effect/_config.js
@@ -0,0 +1,3 @@
module.exports = {
description: 'retains side effects in the right hand side of instanceof'
};
14 changes: 14 additions & 0 deletions test/function/samples/instanceof/right-hand-effect/main.js
@@ -0,0 +1,14 @@
let effect = false;

class Foo {}

if (
new Foo() instanceof
class {
[(effect = true)]() {}
}
) {
assert.fail('Wrong instance relation');
}

assert.ok(effect);
3 changes: 3 additions & 0 deletions test/function/samples/instanceof/used-parameter/_config.js
@@ -0,0 +1,3 @@
module.exports = {
description: 'retains instanceof for function parameters'
};
12 changes: 12 additions & 0 deletions test/function/samples/instanceof/used-parameter/main.js
@@ -0,0 +1,12 @@
let effect = false;

class Foo {}

function checkInstance(instance) {
if (instance instanceof Foo) {
effect = true;
}
}

checkInstance(new Foo());
assert.ok(effect);
3 changes: 3 additions & 0 deletions test/function/samples/instanceof/used/_config.js
@@ -0,0 +1,3 @@
module.exports = {
description: 'retains instanceof if it is true'
};
5 changes: 5 additions & 0 deletions test/function/samples/instanceof/used/main.js
@@ -0,0 +1,5 @@
class Foo {}

if (!(new Foo() instanceof Foo)) {
assert.fail('instanceof not resolved correctly');
}