@@ -1094,11 +1094,14 @@ merge(Compressor.prototype, {
|
|||||||
// func(something) because that changes the meaning of
|
// func(something) because that changes the meaning of
|
||||||
// the func (becomes lexical instead of global).
|
// the func (becomes lexical instead of global).
|
||||||
function maintain_this_binding(compressor, parent, orig, val) {
|
function maintain_this_binding(compressor, parent, orig, val) {
|
||||||
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
var wrap = false;
|
||||||
|| parent.TYPE == "Call" && parent.expression === orig && needs_unbinding(compressor, val)) {
|
if (parent.TYPE == "Call") {
|
||||||
return make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]);
|
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 val;
|
return wrap ? make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]) : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
function merge_sequence(array, node) {
|
function merge_sequence(array, node) {
|
||||||
@@ -6905,72 +6908,70 @@ merge(Compressor.prototype, {
|
|||||||
var SIGN_OPS = makePredicate("+ -");
|
var SIGN_OPS = makePredicate("+ -");
|
||||||
var MULTIPLICATIVE_OPS = makePredicate("* / %");
|
var MULTIPLICATIVE_OPS = makePredicate("* / %");
|
||||||
OPT(AST_UnaryPrefix, function(self, compressor) {
|
OPT(AST_UnaryPrefix, function(self, compressor) {
|
||||||
var e = self.expression;
|
var op = self.operator;
|
||||||
|
var exp = self.expression;
|
||||||
if (compressor.option("evaluate")
|
if (compressor.option("evaluate")
|
||||||
&& self.operator == "delete"
|
&& op == "delete"
|
||||||
&& !(e instanceof AST_SymbolRef
|
&& !(exp instanceof AST_SymbolRef
|
||||||
|| e instanceof AST_PropAccess
|
|| exp instanceof AST_PropAccess
|
||||||
|| is_identifier_atom(e))) {
|
|| is_identifier_atom(exp))) {
|
||||||
if (e instanceof AST_Sequence) {
|
if (exp instanceof AST_Sequence) {
|
||||||
e = e.expressions.slice();
|
exp = exp.expressions.slice();
|
||||||
e.push(make_node(AST_True, self));
|
exp.push(make_node(AST_True, self));
|
||||||
return make_sequence(self, e).optimize(compressor);
|
return make_sequence(self, exp).optimize(compressor);
|
||||||
}
|
}
|
||||||
return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
|
return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("sequences")) {
|
if (compressor.option("sequences") && !(op == "typeof" && is_undeclared_ref(exp.tail_node()))) {
|
||||||
var seq = lift_sequence_in_expression(self, compressor);
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects") && self.operator == "void") {
|
if (compressor.option("side_effects") && op == "void") {
|
||||||
e = e.drop_side_effect_free(compressor);
|
exp = exp.drop_side_effect_free(compressor);
|
||||||
if (e) {
|
if (!exp) return make_node(AST_Undefined, self).optimize(compressor);
|
||||||
self.expression = e;
|
self.expression = exp;
|
||||||
return self;
|
return self;
|
||||||
} else {
|
|
||||||
return make_node(AST_Undefined, self).optimize(compressor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (compressor.option("booleans")) {
|
if (compressor.option("booleans")) {
|
||||||
if (self.operator == "!" && e.is_truthy()) {
|
if (op == "!" && exp.is_truthy()) {
|
||||||
return make_sequence(self, [ e, make_node(AST_False, self) ]).optimize(compressor);
|
return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor);
|
||||||
} else if (compressor.in_boolean_context()) switch (self.operator) {
|
} else if (compressor.in_boolean_context()) switch (op) {
|
||||||
case "!":
|
case "!":
|
||||||
if (e instanceof AST_UnaryPrefix && e.operator == "!") {
|
if (exp instanceof AST_UnaryPrefix && exp.operator == "!") {
|
||||||
// !!foo => foo, if we're in boolean context
|
// !!foo => foo, if we're in boolean context
|
||||||
return e.expression;
|
return exp.expression;
|
||||||
}
|
}
|
||||||
if (e instanceof AST_Binary) {
|
if (exp instanceof AST_Binary) {
|
||||||
self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor)));
|
self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "typeof":
|
case "typeof":
|
||||||
// typeof always returns a non-empty string, thus it's
|
// typeof always returns a non-empty string, thus it's
|
||||||
// always true in booleans
|
// always true in booleans
|
||||||
AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
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, [
|
return (exp instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [
|
||||||
e,
|
exp,
|
||||||
make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
])).optimize(compressor);
|
])).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")
|
if (compressor.option("evaluate")
|
||||||
&& e instanceof AST_Binary
|
&& exp instanceof AST_Binary
|
||||||
&& SIGN_OPS[self.operator]
|
&& SIGN_OPS[op]
|
||||||
&& MULTIPLICATIVE_OPS[e.operator]
|
&& MULTIPLICATIVE_OPS[exp.operator]
|
||||||
&& (e.left.is_constant() || !e.right.has_side_effects(compressor))) {
|
&& (exp.left.is_constant() || !exp.right.has_side_effects(compressor))) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: e.operator,
|
operator: exp.operator,
|
||||||
left: make_node(AST_UnaryPrefix, e.left, {
|
left: make_node(AST_UnaryPrefix, exp.left, {
|
||||||
operator: self.operator,
|
operator: op,
|
||||||
expression: e.left
|
expression: exp.left
|
||||||
}),
|
}),
|
||||||
right: e.right
|
right: exp.right
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// avoids infinite recursion of numerals
|
// 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);
|
? self : try_evaluate(compressor, self);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1155,3 +1155,25 @@ issue_3703: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4079: {
|
||||||
|
options = {
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
typeof (0, A);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
A;
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user