fix corner cases of catch variable inlining (#4169)
This commit is contained in:
@@ -1037,18 +1037,6 @@ merge(Compressor.prototype, {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_variable(compressor, name) {
|
|
||||||
var scope, i = 0;
|
|
||||||
while (scope = compressor.parent(i++)) {
|
|
||||||
if (scope instanceof AST_Scope) break;
|
|
||||||
if (scope instanceof AST_Catch) {
|
|
||||||
scope = scope.argname.definition().scope;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return scope.find_variable(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function make_node(ctor, orig, props) {
|
function make_node(ctor, orig, props) {
|
||||||
if (!props) props = {};
|
if (!props) props = {};
|
||||||
if (orig) {
|
if (orig) {
|
||||||
@@ -4177,13 +4165,7 @@ merge(Compressor.prototype, {
|
|||||||
var scopes = [];
|
var scopes = [];
|
||||||
self.walk(new TreeWalker(function(node, descend) {
|
self.walk(new TreeWalker(function(node, descend) {
|
||||||
if (!result) return true;
|
if (!result) return true;
|
||||||
if (node instanceof AST_Catch) {
|
if (node instanceof AST_BlockScope) {
|
||||||
scopes.push(node.argname.scope);
|
|
||||||
descend();
|
|
||||||
scopes.pop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Scope) {
|
|
||||||
if (node === self) return;
|
if (node === self) return;
|
||||||
scopes.push(node);
|
scopes.push(node);
|
||||||
descend();
|
descend();
|
||||||
@@ -4191,14 +4173,14 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
if (self.inlined) {
|
if (self.inlined || node.redef) {
|
||||||
result = false;
|
result = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (self.variables.has(node.name)) return true;
|
if (self.variables.has(node.name)) return true;
|
||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
if (member(def.scope, scopes)) return true;
|
if (member(def.scope, scopes)) return true;
|
||||||
if (scope) {
|
if (scope && !def.redefined()) {
|
||||||
var scope_def = scope.find_variable(node);
|
var scope_def = scope.find_variable(node);
|
||||||
if (def.undeclared ? !scope_def : scope_def === def) {
|
if (def.undeclared ? !scope_def : scope_def === def) {
|
||||||
result = "f";
|
result = "f";
|
||||||
@@ -5173,6 +5155,13 @@ merge(Compressor.prototype, {
|
|||||||
if (!(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
in_use.push(node_def);
|
in_use.push(node_def);
|
||||||
|
if (node.scope !== node_def.scope) {
|
||||||
|
var redef = node_def.redefined();
|
||||||
|
if (redef && !(redef.id in in_use_ids)) {
|
||||||
|
in_use_ids[redef.id] = true;
|
||||||
|
in_use.push(redef);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (track_assigns(node_def, node)) add_assigns(node_def, node);
|
if (track_assigns(node_def, node)) add_assigns(node_def, node);
|
||||||
return true;
|
return true;
|
||||||
@@ -6814,7 +6803,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !fn.pinned()
|
&& !fn.pinned()
|
||||||
&& !(fn.name && fn instanceof AST_Function)
|
&& !(fn.name && fn instanceof AST_Function)
|
||||||
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
||||||
&& fn.is_constant_expression(compressor.find_parent(AST_Scope)))
|
&& fn.is_constant_expression(compressor.find_parent(AST_BlockScope)))
|
||||||
&& (value = can_flatten_body(stat))
|
&& (value = can_flatten_body(stat))
|
||||||
&& !fn.contains_this()) {
|
&& !fn.contains_this()) {
|
||||||
var replacing = exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1;
|
var replacing = exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1;
|
||||||
@@ -8081,7 +8070,9 @@ merge(Compressor.prototype, {
|
|||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (fixed.name && fixed.name.definition() !== def) {
|
} else if (fixed.name && fixed.name.definition() !== def) {
|
||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
|
} else if (fixed.parent_scope !== self.scope
|
||||||
|
|| !(self.scope instanceof AST_Scope)
|
||||||
|
|| def.orig[0] instanceof AST_SymbolFunarg) {
|
||||||
single_use = fixed.is_constant_expression(self.scope);
|
single_use = fixed.is_constant_expression(self.scope);
|
||||||
if (single_use == "f") {
|
if (single_use == "f") {
|
||||||
var scope = self.scope;
|
var scope = self.scope;
|
||||||
@@ -8229,7 +8220,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Undefined, function(self, compressor) {
|
OPT(AST_Undefined, function(self, compressor) {
|
||||||
if (compressor.option("unsafe_undefined")) {
|
if (compressor.option("unsafe_undefined")) {
|
||||||
var undef = find_variable(compressor, "undefined");
|
var undef = compressor.find_parent(AST_BlockScope).find_variable("undefined");
|
||||||
if (undef) {
|
if (undef) {
|
||||||
var ref = make_node(AST_SymbolRef, self, {
|
var ref = make_node(AST_SymbolRef, self, {
|
||||||
name : "undefined",
|
name : "undefined",
|
||||||
@@ -8255,7 +8246,7 @@ merge(Compressor.prototype, {
|
|||||||
if (lhs && is_atomic(lhs, self)) return self;
|
if (lhs && is_atomic(lhs, self)) return self;
|
||||||
if (compressor.option("keep_infinity")
|
if (compressor.option("keep_infinity")
|
||||||
&& !(lhs && !is_atomic(lhs, self))
|
&& !(lhs && !is_atomic(lhs, self))
|
||||||
&& !find_variable(compressor, "Infinity"))
|
&& !compressor.find_parent(AST_BlockScope).find_variable("Infinity"))
|
||||||
return self;
|
return self;
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "/",
|
operator: "/",
|
||||||
@@ -8271,7 +8262,7 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_NaN, function(self, compressor) {
|
OPT(AST_NaN, function(self, compressor) {
|
||||||
var lhs = is_lhs(compressor.self(), compressor.parent());
|
var lhs = is_lhs(compressor.self(), compressor.parent());
|
||||||
if (lhs && !is_atomic(lhs, self)
|
if (lhs && !is_atomic(lhs, self)
|
||||||
|| find_variable(compressor, "NaN")) {
|
|| compressor.find_parent(AST_BlockScope).find_variable("NaN")) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "/",
|
operator: "/",
|
||||||
left: make_node(AST_Number, self, {
|
left: make_node(AST_Number, self, {
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
old_def.defun = new_def.scope;
|
old_def.defun = new_def.scope;
|
||||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
old_def.orig.concat(old_def.references).forEach(function(node) {
|
||||||
|
node.redef = true;
|
||||||
node.thedef = new_def;
|
node.thedef = new_def;
|
||||||
node.reference(options);
|
node.reference(options);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2992,3 +2992,34 @@ issue_4146: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single_use_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -4853,3 +4853,42 @@ direct_inline: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "21"
|
expect_stdout: "21"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
direct_inline_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, a, g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -2714,3 +2714,108 @@ issue_2737: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single_use_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use_inline_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_inline_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, a, g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user