From a231a3dc400004d8fcae4dc9cf1ab6301a366a15 Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Fri, 28 May 2021 05:06:23 +0800 Subject: [PATCH] fix corner case in `collapse_vars` --- lib/compress.js | 43 +++++++++++++++++++++++++++-------- test/compress/destructured.js | 36 +++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index e04e0560994..b07e85ad047 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -5120,6 +5120,7 @@ merge(Compressor.prototype, { def(AST_Node, return_true); def(AST_Constant, return_false); + def(AST_Destructured, return_true); def(AST_EmptyStatement, return_false); def(AST_Lambda, return_false); def(AST_ObjectIdentity, return_false); @@ -5132,6 +5133,15 @@ merge(Compressor.prototype, { return false; } + function call_may_throw(exp, compressor) { + if (exp.may_throw(compressor)) return true; + if (exp instanceof AST_SymbolRef) exp = exp.fixed_value(); + if (!(exp instanceof AST_Lambda)) return true; + if (any(exp.argnames, compressor)) return true; + if (any(exp.body, compressor)) return true; + return is_arrow(exp) && exp.value && exp.value.may_throw(compressor); + } + def(AST_Array, function(compressor) { return any(this.elements, compressor); }); @@ -5155,9 +5165,10 @@ merge(Compressor.prototype, { def(AST_Call, function(compressor) { if (any(this.args, compressor)) return true; if (this.is_expr_pure(compressor)) return false; - if (this.expression.may_throw(compressor)) return true; - return !(this.expression instanceof AST_Lambda) - || any(this.expression.body, compressor); + this.may_throw = return_true; + var ret = call_may_throw(this.expression, compressor); + delete this.may_throw; + return ret; }); def(AST_Case, function(compressor) { return this.expression.may_throw(compressor) @@ -5168,6 +5179,10 @@ merge(Compressor.prototype, { || this.consequent.may_throw(compressor) || this.alternative.may_throw(compressor); }); + def(AST_DefaultValue, function(compressor) { + return this.name.may_throw(compressor) + || this.value && this.value.may_throw(compressor); + }); def(AST_Definitions, function(compressor) { return any(this.definitions, compressor); }); @@ -5187,8 +5202,8 @@ merge(Compressor.prototype, { return any(this.properties, compressor); }); def(AST_ObjectProperty, function(compressor) { - return this.key instanceof AST_Node && this.key.may_throw(compressor) - || this.value.may_throw(compressor); + return this.value.may_throw(compressor) + || this.key instanceof AST_Node && this.key.may_throw(compressor); }); def(AST_Return, function(compressor) { return this.value && this.value.may_throw(compressor); @@ -5211,18 +5226,26 @@ merge(Compressor.prototype, { def(AST_SymbolRef, function(compressor) { return !this.is_declared(compressor); }); + def(AST_Template, function(compressor) { + if (any(this.expressions, compressor)) return true; + if (this.is_expr_pure(compressor)) return false; + if (!this.tag) return false; + this.may_throw = return_true; + var ret = call_may_throw(this.tag, compressor); + delete this.may_throw; + return ret; + }); def(AST_Try, function(compressor) { return (this.bcatch ? this.bcatch.may_throw(compressor) : any(this.body, compressor)) || this.bfinally && this.bfinally.may_throw(compressor); }); def(AST_Unary, function(compressor) { - if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) - return false; - return this.expression.may_throw(compressor); + return this.expression.may_throw(compressor) + && !(this.operator == "typeof" && this.expression instanceof AST_SymbolRef); }); def(AST_VarDef, function(compressor) { - if (!this.value) return false; - return this.value.may_throw(compressor); + return this.name.may_throw(compressor) + || this.value && this.value.may_throw(compressor); }); })(function(node, func) { node.DEFMETHOD("may_throw", func); diff --git a/test/compress/destructured.js b/test/compress/destructured.js index dd2daca9b27..78cd686374f 100644 --- a/test/compress/destructured.js +++ b/test/compress/destructured.js @@ -1010,6 +1010,42 @@ collapse_vars_8: { node_version: ">=6" } +collapse_vars_9: { + options = { + collapse_vars: true, + } + input: { + console.log(function(a) { + try { + var b = function([ c ]) { + if (c) + return "FAIL 1"; + }(); + a = "FAIL 2"; + return b; + } catch (e) { + return a; + } + }("PASS")); + } + expect: { + console.log(function(a) { + try { + var b = function([ c ]) { + if (c) + return "FAIL 1"; + }(); + a = "FAIL 2"; + return b; + } catch (e) { + return a; + } + }("PASS")); + } + expect_stdout: "PASS" + node_version: ">=6" +} + conditionals: { options = { conditionals: true,