fix corner cases in typeofs (#5301)
This commit is contained in:
@@ -142,6 +142,7 @@ DEF_BITPROPS(AST_Node, [
|
|||||||
"_squeezed",
|
"_squeezed",
|
||||||
// AST_Call
|
// AST_Call
|
||||||
"call_only",
|
"call_only",
|
||||||
|
// AST_Lambda
|
||||||
"collapse_scanning",
|
"collapse_scanning",
|
||||||
// AST_SymbolRef
|
// AST_SymbolRef
|
||||||
"defined",
|
"defined",
|
||||||
|
|||||||
@@ -8715,6 +8715,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function mark_locally_defined(condition, consequent, alternative) {
|
function mark_locally_defined(condition, consequent, alternative) {
|
||||||
|
if (condition instanceof AST_Sequence) condition = condition.tail_node();
|
||||||
if (!(condition instanceof AST_Binary)) return;
|
if (!(condition instanceof AST_Binary)) return;
|
||||||
if (!(condition.left instanceof AST_String)) {
|
if (!(condition.left instanceof AST_String)) {
|
||||||
switch (condition.operator) {
|
switch (condition.operator) {
|
||||||
@@ -8749,6 +8750,8 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var abort = false;
|
var abort = false;
|
||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
var fn;
|
var fn;
|
||||||
|
var refs = [];
|
||||||
|
var scanned = [];
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
if (abort) return true;
|
if (abort) return true;
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
@@ -8765,11 +8768,40 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (node instanceof AST_Call) {
|
if (node instanceof AST_Call) {
|
||||||
descend();
|
descend();
|
||||||
fn = node.expression.tail_node();
|
fn = node.expression.tail_node();
|
||||||
if (fn instanceof AST_Lambda) {
|
var save;
|
||||||
fn.walk(tw);
|
if (fn instanceof AST_SymbolRef) {
|
||||||
} else {
|
fn = fn.fixed_value();
|
||||||
abort = true;
|
save = refs.length;
|
||||||
}
|
}
|
||||||
|
if (!(fn instanceof AST_Lambda)) {
|
||||||
|
abort = true;
|
||||||
|
} else if (push_uniq(scanned, fn)) {
|
||||||
|
fn.walk(tw);
|
||||||
|
}
|
||||||
|
if (save >= 0) refs.length = save;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_DWLoop) {
|
||||||
|
var save = refs.length;
|
||||||
|
descend();
|
||||||
|
if (abort) refs.length = save;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_For) {
|
||||||
|
if (node.init) node.init.walk(tw);
|
||||||
|
var save = refs.length;
|
||||||
|
if (node.condition) node.condition.walk(tw);
|
||||||
|
node.body.walk(tw);
|
||||||
|
if (node.step) node.step.walk(tw);
|
||||||
|
if (abort) refs.length = save;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_ForEnumeration) {
|
||||||
|
node.object.walk(tw);
|
||||||
|
var save = refs.length;
|
||||||
|
node.init.walk(tw);
|
||||||
|
node.body.walk(tw);
|
||||||
|
if (abort) refs.length = save;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
@@ -8777,11 +8809,14 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
if (node.definition() === def) node.defined = true;
|
if (node.definition() === def) refs.push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
body.walk(tw);
|
body.walk(tw);
|
||||||
|
refs.forEach(function(ref) {
|
||||||
|
ref.defined = true;
|
||||||
|
});
|
||||||
|
|
||||||
function negate(node) {
|
function negate(node) {
|
||||||
if (!(node instanceof AST_Binary)) return;
|
if (!(node instanceof AST_Binary)) return;
|
||||||
|
|||||||
@@ -527,6 +527,102 @@ reassign_conditional: {
|
|||||||
node_version: ">=15"
|
node_version: ">=15"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reassign_do: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
A = console;
|
||||||
|
(function() {
|
||||||
|
if ("undefined" == typeof A)
|
||||||
|
return;
|
||||||
|
var a = A, i = 2;
|
||||||
|
do {
|
||||||
|
console.log(void 0 === A, void 0 === a);
|
||||||
|
A = void 0;
|
||||||
|
} while (--i);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
A = console;
|
||||||
|
(function() {
|
||||||
|
if ("undefined" != typeof A) {
|
||||||
|
var a = A, i = 2;
|
||||||
|
do {
|
||||||
|
console.log(void 0 === A, (a, false));
|
||||||
|
A = void 0;
|
||||||
|
} while (--i);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"false false",
|
||||||
|
"true false",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
reassign_for: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (A = console, "undefined" != typeof A)
|
||||||
|
for (var a = A, i = 0; i < 2; i++)
|
||||||
|
console.log(void 0 === A, void 0 === a),
|
||||||
|
A = void 0;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
if (A = console, "undefined" != typeof A)
|
||||||
|
for (var a = A, i = 0; i < 2; i++)
|
||||||
|
console.log(void 0 === A, (a, false)),
|
||||||
|
A = void 0;
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"false false",
|
||||||
|
"true false",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
reassign_for_in: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(A = console) && "undefined" != typeof A && function(a) {
|
||||||
|
for (var k in [ a = A, 42 ]) {
|
||||||
|
console.log(void 0 === A, void 0 === a);
|
||||||
|
A = void 0;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(A = console) && "undefined" != typeof A && function(a) {
|
||||||
|
for (var k in [ a = A, 42 ]) {
|
||||||
|
console.log(void 0 === A, (a, false));
|
||||||
|
A = void 0;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"false false",
|
||||||
|
"true false",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
reassign_iife: {
|
reassign_iife: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
@@ -564,7 +660,7 @@ reassign_property: {
|
|||||||
console.log("FAIL 1");
|
console.log("FAIL 1");
|
||||||
else {
|
else {
|
||||||
A.p = void 0;
|
A.p = void 0;
|
||||||
while (console.log(void 0 === A ? "FAIL 2" : "PASS"));
|
console.log(void 0 === A ? "FAIL 2" : "PASS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -573,7 +669,7 @@ reassign_property: {
|
|||||||
console.log("FAIL 1");
|
console.log("FAIL 1");
|
||||||
else {
|
else {
|
||||||
A.p = void 0;
|
A.p = void 0;
|
||||||
while (console.log((A, false) ? "FAIL 2" : "PASS"));
|
console.log((A, false) ? "FAIL 2" : "PASS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
|
|||||||
Reference in New Issue
Block a user