aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2020-08-26 13:41:11 +0100
committerGitHub <noreply@github.com>2020-08-26 20:41:11 +0800
commitb1cc15e85bf57042fc390c58f2b513304f8543c6 (patch)
treeeada050a29449a9d50569b418542e511e56ff81d /lib
parent3aa765e4296c4caf2f3b2b3e6b43b65caf05a28f (diff)
downloadtracifyjs-b1cc15e85bf57042fc390c58f2b513304f8543c6.tar.gz
tracifyjs-b1cc15e85bf57042fc390c58f2b513304f8543c6.zip
fix corner case in `sequences` (#4080)
fixes #4079
Diffstat (limited to 'lib')
-rw-r--r--lib/compress.js93
1 files changed, 47 insertions, 46 deletions
diff --git a/lib/compress.js b/lib/compress.js
index cd790db3..90dd0f27 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1094,11 +1094,14 @@ merge(Compressor.prototype, {
// func(something) because that changes the meaning of
// the func (becomes lexical instead of global).
function maintain_this_binding(compressor, parent, orig, val) {
- if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
- || parent.TYPE == "Call" && parent.expression === orig && needs_unbinding(compressor, val)) {
- return make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]);
- }
- return val;
+ var wrap = false;
+ if (parent.TYPE == "Call") {
+ wrap = parent.expression === orig && needs_unbinding(compressor, val);
+ } else if (parent instanceof AST_UnaryPrefix) {
+ wrap = parent.operator == "delete"
+ || parent.operator == "typeof" && is_undeclared_ref(val);
+ }
+ return wrap ? make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]) : val;
}
function merge_sequence(array, node) {
@@ -6905,72 +6908,70 @@ merge(Compressor.prototype, {
var SIGN_OPS = makePredicate("+ -");
var MULTIPLICATIVE_OPS = makePredicate("* / %");
OPT(AST_UnaryPrefix, function(self, compressor) {
- var e = self.expression;
+ var op = self.operator;
+ var exp = self.expression;
if (compressor.option("evaluate")
- && self.operator == "delete"
- && !(e instanceof AST_SymbolRef
- || e instanceof AST_PropAccess
- || is_identifier_atom(e))) {
- if (e instanceof AST_Sequence) {
- e = e.expressions.slice();
- e.push(make_node(AST_True, self));
- return make_sequence(self, e).optimize(compressor);
- }
- return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
- }
- if (compressor.option("sequences")) {
+ && op == "delete"
+ && !(exp instanceof AST_SymbolRef
+ || exp instanceof AST_PropAccess
+ || is_identifier_atom(exp))) {
+ if (exp instanceof AST_Sequence) {
+ exp = exp.expressions.slice();
+ exp.push(make_node(AST_True, self));
+ return make_sequence(self, exp).optimize(compressor);
+ }
+ return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor);
+ }
+ if (compressor.option("sequences") && !(op == "typeof" && is_undeclared_ref(exp.tail_node()))) {
var seq = lift_sequence_in_expression(self, compressor);
if (seq !== self) return seq.optimize(compressor);
}
- if (compressor.option("side_effects") && self.operator == "void") {
- e = e.drop_side_effect_free(compressor);
- if (e) {
- self.expression = e;
- return self;
- } else {
- return make_node(AST_Undefined, self).optimize(compressor);
- }
+ if (compressor.option("side_effects") && op == "void") {
+ exp = exp.drop_side_effect_free(compressor);
+ if (!exp) return make_node(AST_Undefined, self).optimize(compressor);
+ self.expression = exp;
+ return self;
}
if (compressor.option("booleans")) {
- if (self.operator == "!" && e.is_truthy()) {
- return make_sequence(self, [ e, make_node(AST_False, self) ]).optimize(compressor);
- } else if (compressor.in_boolean_context()) switch (self.operator) {
+ if (op == "!" && exp.is_truthy()) {
+ return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor);
+ } else if (compressor.in_boolean_context()) switch (op) {
case "!":
- if (e instanceof AST_UnaryPrefix && e.operator == "!") {
+ if (exp instanceof AST_UnaryPrefix && exp.operator == "!") {
// !!foo => foo, if we're in boolean context
- return e.expression;
+ return exp.expression;
}
- if (e instanceof AST_Binary) {
- self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor)));
+ if (exp instanceof AST_Binary) {
+ self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor)));
}
break;
case "typeof":
// typeof always returns a non-empty string, thus it's
// always true in booleans
AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
- return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [
- e,
+ return (exp instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [
+ exp,
make_node(AST_True, self)
])).optimize(compressor);
}
}
- if (self.operator == "-" && e instanceof AST_Infinity) e = e.transform(compressor);
+ if (op == "-" && exp instanceof AST_Infinity) exp = exp.transform(compressor);
if (compressor.option("evaluate")
- && e instanceof AST_Binary
- && SIGN_OPS[self.operator]
- && MULTIPLICATIVE_OPS[e.operator]
- && (e.left.is_constant() || !e.right.has_side_effects(compressor))) {
+ && exp instanceof AST_Binary
+ && SIGN_OPS[op]
+ && MULTIPLICATIVE_OPS[exp.operator]
+ && (exp.left.is_constant() || !exp.right.has_side_effects(compressor))) {
return make_node(AST_Binary, self, {
- operator: e.operator,
- left: make_node(AST_UnaryPrefix, e.left, {
- operator: self.operator,
- expression: e.left
+ operator: exp.operator,
+ left: make_node(AST_UnaryPrefix, exp.left, {
+ operator: op,
+ expression: exp.left
}),
- right: e.right
+ right: exp.right
});
}
// avoids infinite recursion of numerals
- return self.operator == "-" && (e instanceof AST_Number || e instanceof AST_Infinity)
+ return op == "-" && (exp instanceof AST_Number || exp instanceof AST_Infinity)
? self : try_evaluate(compressor, self);
});