diff --git a/lib/compress.js b/lib/compress.js index 78304c26e2..e9c7e2b7ee 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -497,6 +497,7 @@ Compressor.prototype.compress = function(node) { function has_escaped(d, scope, node, parent) { if (parent instanceof AST_Assign) return parent.operator == "=" && parent.right === node; if (parent instanceof AST_Call) return parent.expression !== node || parent instanceof AST_New; + if (parent instanceof AST_ClassField) return parent.value === node && !parent.static; if (parent instanceof AST_Exit) return parent.value === node && scope.resolve() !== d.scope.resolve(); if (parent instanceof AST_VarDef) return parent.value === node; } @@ -1164,7 +1165,11 @@ Compressor.prototype.compress = function(node) { if (node.extends) node.extends.walk(tw); var props = node.properties.filter(function(prop) { reset_flags(prop); - if (prop.key instanceof AST_Node) prop.key.walk(tw); + if (prop.key instanceof AST_Node) { + tw.push(prop); + prop.key.walk(tw); + tw.pop(); + } return prop.value; }); if (node.name) { @@ -1184,6 +1189,7 @@ Compressor.prototype.compress = function(node) { } } props.forEach(function(prop) { + tw.push(prop); if (!prop.static || is_static_field_or_init(prop) && prop.value.contains_this()) { push(tw); prop.value.walk(tw); @@ -1191,6 +1197,7 @@ Compressor.prototype.compress = function(node) { } else { prop.value.walk(tw); } + tw.pop(); }); return true; }); @@ -12296,7 +12303,7 @@ Compressor.prototype.compress = function(node) { var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor)); if (single_use) { if (is_lambda(fixed)) { - if ((def.scope !== self.scope.resolve() || def.in_loop) + if ((def.scope !== self.scope.resolve(true) || def.in_loop) && (!compressor.option("reduce_funcs") || def.escaped.depth == 1 || fixed.inlined)) { single_use = false; } else if (def.redefined()) { diff --git a/test/compress/classes.js b/test/compress/classes.js index 52ea8bf83b..8b6c8b59ae 100644 --- a/test/compress/classes.js +++ b/test/compress/classes.js @@ -599,6 +599,7 @@ drop_extends: { inline: true, passes: 2, pure_getters: "strict", + reduce_funcs: true, reduce_vars: true, sequences: true, side_effects: true, @@ -921,6 +922,7 @@ single_use_3: { single_use_4: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -1503,6 +1505,218 @@ keep_instanceof_3: { node_version: ">=4" } +keep_field_reference_1: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + function f() {} + class A { + p = f; + } + console.log(new A().p === new A().p ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + function f() {} + class A { + p = f; + } + console.log(new A().p === new A().p ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +keep_field_reference_2: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + function f() {} + var A = class { + p = f; + }; + console.log(new A().p === new A().p ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + function f() {} + var A = class { + p = f; + }; + console.log(new A().p === new A().p ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +keep_field_reference_3: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + class A {} + class B { + p = A; + } + console.log(new B().p === new B().p ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + class A {} + class B { + p = A; + } + console.log(new B().p === new B().p ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +keep_field_reference_4: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + var A = class {}; + var B = class { + p = A; + }; + console.log(new B().p === new B().p ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + var A = class {}; + var B = class { + p = A; + }; + console.log(new B().p === new B().p ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +keep_static_field_reference_1: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + function f() {} + class A { + static P = f; + } + console.log(A.P === A.P ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + class A { + static P = function() {}; + } + console.log(A.P === A.P ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +keep_static_field_reference_2: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + function f() {} + var A = class { + static P = f; + }; + console.log(A.P === A.P ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + var A = class { + static P = function() {}; + }; + console.log(A.P === A.P ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +keep_static_field_reference_3: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + class A {} + class B { + static P = A; + } + console.log(B.P === B.P ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + class B { + static P = class {}; + } + console.log(B.P === B.P ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +keep_static_field_reference_4: { + options = { + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + var A = class {}; + var B = class { + static P = A; + }; + console.log(B.P === B.P ? "PASS" : "FAIL"); + } + expect: { + "use strict"; + var B = class { + static P = class {}; + }; + console.log(B.P === B.P ? "PASS" : "FAIL"); + } + expect_stdout: "PASS" + node_version: ">=12" +} + issue_805_1: { options = { inline: true, @@ -2313,6 +2527,7 @@ issue_4962_1: { options = { ie: true, inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2344,6 +2559,7 @@ issue_4962_1_strict: { options = { ie: true, inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2371,6 +2587,7 @@ issue_4962_1_strict_direct: { options = { ie: true, inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2402,6 +2619,7 @@ issue_4962_2: { options = { ie: true, inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2433,6 +2651,7 @@ issue_4962_2_strict: { options = { ie: true, inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2461,6 +2680,7 @@ issue_4962_2_strict_direct: { options = { ie: true, inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2495,6 +2715,7 @@ issue_4962_2_strict_direct_inline: { ie: true, inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2878,6 +3099,7 @@ issue_5053_4: { issue_5082_1: { options = { inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2910,6 +3132,7 @@ issue_5082_1: { issue_5082_1_strict: { options = { inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2943,6 +3166,7 @@ issue_5082_2: { options = { inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2976,6 +3200,7 @@ issue_5082_2_static: { options = { inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, unused: true, }