@@ -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 ]);
|
||||
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 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);
|
||||
&& 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, [ 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);
|
||||
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;
|
||||
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;
|
||||
} else {
|
||||
return make_node(AST_Undefined, self).optimize(compressor);
|
||||
}
|
||||
}
|
||||
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);
|
||||
});
|
||||
|
||||
|
||||
@@ -1155,3 +1155,25 @@ issue_3703: {
|
||||
}
|
||||
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