fix corner cases related to in (#3964)
This commit is contained in:
@@ -1464,6 +1464,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_last_node(node, parent) {
|
function is_last_node(node, parent) {
|
||||||
|
if (node.TYPE == "Binary") return node.operator == "in" && !is_object(node.right.tail_node());
|
||||||
if (node instanceof AST_Call) {
|
if (node instanceof AST_Call) {
|
||||||
var fn = node.expression;
|
var fn = node.expression;
|
||||||
if (fn instanceof AST_SymbolRef) {
|
if (fn instanceof AST_SymbolRef) {
|
||||||
@@ -3824,7 +3825,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Assign, return_true);
|
def(AST_Assign, return_true);
|
||||||
def(AST_Binary, function(compressor) {
|
def(AST_Binary, function(compressor) {
|
||||||
return this.left.has_side_effects(compressor)
|
return this.left.has_side_effects(compressor)
|
||||||
|| this.right.has_side_effects(compressor);
|
|| this.right.has_side_effects(compressor)
|
||||||
|
|| this.operator == "in" && !is_object(this.right.tail_node());
|
||||||
});
|
});
|
||||||
def(AST_Block, function(compressor) {
|
def(AST_Block, function(compressor) {
|
||||||
return any(this.body, compressor);
|
return any(this.body, compressor);
|
||||||
@@ -5131,6 +5133,15 @@ merge(Compressor.prototype, {
|
|||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(compressor, first_in_statement) {
|
def(AST_Binary, function(compressor, first_in_statement) {
|
||||||
|
if (this.operator == "in" && !is_object(this.right.tail_node())) {
|
||||||
|
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
|
if (left === this.left) return this;
|
||||||
|
var node = this.clone();
|
||||||
|
node.left = left || make_node(AST_Number, this.left, {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
return node;
|
||||||
|
}
|
||||||
var right = this.right.drop_side_effect_free(compressor, first_in_statement);
|
var right = this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (lazy_op[this.operator] && !(right instanceof AST_Function)) {
|
if (lazy_op[this.operator] && !(right instanceof AST_Function)) {
|
||||||
@@ -6879,8 +6890,14 @@ merge(Compressor.prototype, {
|
|||||||
var indexFns = makePredicate("indexOf lastIndexOf");
|
var indexFns = makePredicate("indexOf lastIndexOf");
|
||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
function is_object(node) {
|
function is_object(node) {
|
||||||
|
while (node instanceof AST_SymbolRef) {
|
||||||
|
node = node.fixed_value();
|
||||||
|
if (!node) return false;
|
||||||
|
node = node.tail_node();
|
||||||
|
}
|
||||||
return node instanceof AST_Array
|
return node instanceof AST_Array
|
||||||
|| node instanceof AST_Lambda
|
|| node instanceof AST_Lambda
|
||||||
|
|| node instanceof AST_New
|
||||||
|| node instanceof AST_Object;
|
|| node instanceof AST_Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6980,7 +6997,7 @@ merge(Compressor.prototype, {
|
|||||||
else if (self.left instanceof AST_SymbolRef
|
else if (self.left instanceof AST_SymbolRef
|
||||||
&& self.right instanceof AST_SymbolRef
|
&& self.right instanceof AST_SymbolRef
|
||||||
&& self.left.definition() === self.right.definition()
|
&& self.left.definition() === self.right.definition()
|
||||||
&& is_object(self.left.fixed_value())) {
|
&& is_object(self.left)) {
|
||||||
return make_node(self.operator[0] == "=" ? AST_True : AST_False, self);
|
return make_node(self.operator[0] == "=" ? AST_True : AST_False, self);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -305,6 +305,7 @@ function OutputStream(options) {
|
|||||||
|| (ch == "/" && ch == prev)
|
|| (ch == "/" && ch == prev)
|
||||||
|| ((ch == "+" || ch == "-") && ch == last)
|
|| ((ch == "+" || ch == "-") && ch == last)
|
||||||
|| str == "--" && last == "!"
|
|| str == "--" && last == "!"
|
||||||
|
|| str == "in" && prev == "/"
|
||||||
|| last == "--" && ch == ">") {
|
|| last == "--" && ch == ">") {
|
||||||
OUTPUT += " ";
|
OUTPUT += " ";
|
||||||
current_col++;
|
current_col++;
|
||||||
|
|||||||
@@ -8164,3 +8164,34 @@ issue_3927: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator_in: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function log(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
0 in null;
|
||||||
|
log("FAIL", a);
|
||||||
|
} catch (e) {}
|
||||||
|
log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function log(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
0 in null;
|
||||||
|
log("FAIL", a);
|
||||||
|
} catch (e) {}
|
||||||
|
log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ relational: {
|
|||||||
side_effects :true,
|
side_effects :true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
foo() in foo();
|
foo() in new foo();
|
||||||
foo() instanceof bar();
|
foo() instanceof bar();
|
||||||
foo() < "bar";
|
foo() < "bar";
|
||||||
bar() > foo();
|
bar() > foo();
|
||||||
|
|||||||
@@ -274,3 +274,26 @@ drop_value: {
|
|||||||
foo(), bar();
|
foo(), bar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator_in: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
"foo" in true;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
0 in true;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -486,4 +486,19 @@ describe("operator", function() {
|
|||||||
assert.strictEqual(UglifyJS.parse(exp[0]).print_to_string(), exp[1] + ";");
|
assert.strictEqual(UglifyJS.parse(exp[0]).print_to_string(), exp[1] + ";");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should preserve space between /regex/ and `in`", function() {
|
||||||
|
[
|
||||||
|
"/regex/ in {}",
|
||||||
|
"/regex/g in {}",
|
||||||
|
"0 + /regex/ in {}",
|
||||||
|
"0 + /regex/g in {}",
|
||||||
|
].forEach(function(exp) {
|
||||||
|
var code = UglifyJS.parse(exp).print_to_string();
|
||||||
|
try {
|
||||||
|
assert.strictEqual(UglifyJS.parse(code).print_to_string(), code);
|
||||||
|
} catch (ex) {
|
||||||
|
assert.fail("Failed to reparse: " + exp + "\n" + ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ var VALUES = [
|
|||||||
"this",
|
"this",
|
||||||
];
|
];
|
||||||
|
|
||||||
var BINARY_OPS_NO_COMMA = [
|
var BINARY_OPS = [
|
||||||
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
|
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
|
||||||
" - ",
|
" - ",
|
||||||
"/",
|
"/",
|
||||||
@@ -190,9 +190,14 @@ var BINARY_OPS_NO_COMMA = [
|
|||||||
"%",
|
"%",
|
||||||
"&&",
|
"&&",
|
||||||
"||",
|
"||",
|
||||||
"^" ];
|
"^",
|
||||||
|
",",
|
||||||
var BINARY_OPS = [","].concat(BINARY_OPS_NO_COMMA);
|
];
|
||||||
|
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||||
|
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||||
|
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||||
|
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||||
|
BINARY_OPS.push(" in ");
|
||||||
|
|
||||||
var ASSIGNMENTS = [
|
var ASSIGNMENTS = [
|
||||||
"=",
|
"=",
|
||||||
@@ -879,7 +884,7 @@ function createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
}
|
}
|
||||||
function _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
function _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||||
return "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow)
|
return "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow)
|
||||||
+ createBinaryOp(noComma) + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
+ createBinaryOp(noComma, canThrow) + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
}
|
}
|
||||||
function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||||
// intentionally generate more hardcore ops
|
// intentionally generate more hardcore ops
|
||||||
@@ -929,9 +934,12 @@ function createValue() {
|
|||||||
return VALUES[rng(VALUES.length)];
|
return VALUES[rng(VALUES.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
function createBinaryOp(noComma) {
|
function createBinaryOp(noComma, canThrow) {
|
||||||
if (noComma) return BINARY_OPS_NO_COMMA[rng(BINARY_OPS_NO_COMMA.length)];
|
var op;
|
||||||
return BINARY_OPS[rng(BINARY_OPS.length)];
|
do {
|
||||||
|
op = BINARY_OPS[rng(BINARY_OPS.length)];
|
||||||
|
} while (noComma && op == "," || !canThrow && op == " in ");
|
||||||
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAssignment() {
|
function createAssignment() {
|
||||||
|
|||||||
Reference in New Issue
Block a user