From: Alex Lam S.L Date: Fri, 5 Jun 2020 10:51:21 +0000 (+0100) Subject: fix corner cases in `reduce_vars` & `unused` (#3955) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=eb481cee8cebcb0bee778827cab6d625e5cb30b8;p=UglifyJS.git fix corner cases in `reduce_vars` & `unused` (#3955) fixes #3953 fixes #3956 fixes #3957 --- diff --git a/lib/compress.js b/lib/compress.js index 23a9f923..db445bbc 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -495,6 +495,12 @@ merge(Compressor.prototype, { }); } + function to_value(def, sym, fixed) { + if (fixed instanceof AST_Node) return fixed; + if (typeof fixed == "function") return fixed(); + return make_node(AST_Undefined, sym); + } + function ref_once(compressor, def) { return compressor.option("unused") && !def.scope.pinned() @@ -576,8 +582,9 @@ merge(Compressor.prototype, { var eq = node.operator == "="; var value = eq ? node.right : node; if (is_modified(compressor, tw, node, value, 0)) return; + var safe = eq || safe_to_read(tw, d); node.right.walk(tw); - if ((eq || safe_to_read(tw, d)) && safe_to_assign(tw, d)) { + if (safe && safe_to_assign(tw, d)) { push_ref(d, sym); mark(tw, d); if (eq) { @@ -587,9 +594,8 @@ merge(Compressor.prototype, { return node.right; }; } else { - if (fixed == null) fixed = make_node(AST_Undefined, d.orig[0]); sym.fixed = d.fixed = function() { - var value = fixed instanceof AST_Node ? fixed : fixed(); + var value = to_value(d, sym, fixed); return value && make_node(AST_Binary, node, { operator: node.operator.slice(0, -1), left: value, @@ -597,7 +603,7 @@ merge(Compressor.prototype, { }); }; } - sym.fixed.assigns = eq || !fixed.assigns ? [] : fixed.assigns.slice(); + sym.fixed.assigns = eq || !fixed || !fixed.assigns ? [] : fixed.assigns.slice(); sym.fixed.assigns.push(node); } else { sym.walk(tw); @@ -740,8 +746,8 @@ merge(Compressor.prototype, { fn.argnames.forEach(function(arg, i) { var d = arg.definition(); if (d.fixed === undefined && (!fn.uses_arguments || tw.has_directive("use strict"))) { - tw.loop_ids[d.id] = tw.in_loop; mark(tw, d); + tw.loop_ids[d.id] = tw.in_loop; var value = iife.args[i]; d.fixed = function() { var j = fn.argnames.indexOf(arg); @@ -870,9 +876,8 @@ merge(Compressor.prototype, { if (safe_to_read(tw, d) && safe_to_assign(tw, d)) { push_ref(d, exp); mark(tw, d); - if (fixed == null) fixed = make_node(AST_Undefined, d.orig[0]); d.fixed = function() { - var value = fixed instanceof AST_Node ? fixed : fixed(); + var value = to_value(d, exp, fixed); return value && make_node(AST_Binary, node, { operator: node.operator.slice(0, -1), left: make_node(AST_UnaryPrefix, node, { @@ -884,19 +889,19 @@ merge(Compressor.prototype, { }) }); }; - d.fixed.assigns = fixed.assigns ? fixed.assigns.slice() : []; + d.fixed.assigns = fixed && fixed.assigns ? fixed.assigns.slice() : []; d.fixed.assigns.push(node); if (node instanceof AST_UnaryPrefix) { exp.fixed = d.fixed; } else { exp.fixed = function() { - var value = fixed instanceof AST_Node ? fixed : fixed(); + var value = to_value(d, exp, fixed); return value && make_node(AST_UnaryPrefix, node, { operator: "+", expression: value }); }; - exp.fixed.assigns = fixed.assigns; + exp.fixed.assigns = fixed && fixed.assigns; } } else { exp.walk(tw); @@ -4429,6 +4434,7 @@ merge(Compressor.prototype, { if (!drop_vars || sym.id in in_use_ids) { if (def.value && indexOf_assign(sym, def) < 0) { def.value = def.value.drop_side_effect_free(compressor); + if (def.value) def.value.tail_node().write_only = false; } var old_def, var_defs = var_defs_by_id.get(sym.id); if (!def.value) { diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index f3aeab21..a4a8595b 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -2652,3 +2652,41 @@ issue_3951: { "0", ] } + +issue_3956: { + options = { + collapse_vars: true, + evaluate: true, + inline: true, + passes: 2, + reduce_vars: true, + sequences: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + (function(a) { + function f(b) { + console.log(b); + a = 1; + } + var c = f(c += 0); + (function(d) { + console.log(d); + })(console.log(a) ^ 1, c); + })(); + } + expect: { + var c, d; + c += 0, + console.log(NaN), + d = 1 ^ console.log(1), + console.log(d); + } + expect_stdout: [ + "NaN", + "1", + "1", + ] +} diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index fd8deab5..0f3a9fd1 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -2715,3 +2715,23 @@ issue_3944: { } expect_stdout: "false" } + +issue_3953: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + function f(a) { + (a += 0 * (a = 0)) && console.log("PASS"); + } + f(1); + } + expect: { + function f(a) { + (a += 0 * (a = 0)) && console.log("PASS"); + } + f(1); + } + expect_stdout: "PASS" +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 3368cc6f..1a782b44 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -7273,3 +7273,53 @@ local_assignment_loop: { } expect_stdout: "PASS" } + +issue_3957_1: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + function f(a) { + while (a += console.log(a = 0)) + a = 0; + } + f("FAIL"); + } + expect: { + function f(a) { + while (a += console.log(a = 0)) + a = 0; + } + f("FAIL"); + } + expect_stdout: [ + "0", + "0", + ] +} + +issue_3957_2: { + options = { + reduce_vars: true, + unused: true, + } + input: { + function f(a) { + while (a += console.log(a = 0)) + a = 0; + } + f("FAIL"); + } + expect: { + function f(a) { + while (a += console.log(a = 0)) + a = 0; + } + f("FAIL"); + } + expect_stdout: [ + "0", + "0", + ] +}