improve collapsible value detection (#1638)
- #1634 bars variables with cross-scope references in between to collapse - but if assigned value is side-effect-free, no states can be modified, so it is safe to move
This commit is contained in:
@@ -592,9 +592,10 @@ merge(Compressor.prototype, {
|
|||||||
// Restrict var replacement to constants if side effects encountered.
|
// Restrict var replacement to constants if side effects encountered.
|
||||||
if (side_effects_encountered |= lvalues_encountered) continue;
|
if (side_effects_encountered |= lvalues_encountered) continue;
|
||||||
|
|
||||||
|
var value_has_side_effects = var_decl.value.has_side_effects(compressor);
|
||||||
// Non-constant single use vars can only be replaced in same scope.
|
// Non-constant single use vars can only be replaced in same scope.
|
||||||
if (ref.scope !== self) {
|
if (ref.scope !== self) {
|
||||||
side_effects_encountered |= var_decl.value.has_side_effects(compressor);
|
side_effects_encountered |= value_has_side_effects;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +621,7 @@ merge(Compressor.prototype, {
|
|||||||
|| (parent instanceof AST_If && node !== parent.condition)
|
|| (parent instanceof AST_If && node !== parent.condition)
|
||||||
|| (parent instanceof AST_Conditional && node !== parent.condition)
|
|| (parent instanceof AST_Conditional && node !== parent.condition)
|
||||||
|| (node instanceof AST_SymbolRef
|
|| (node instanceof AST_SymbolRef
|
||||||
|
&& value_has_side_effects
|
||||||
&& !are_references_in_scope(node.definition(), self))
|
&& !are_references_in_scope(node.definition(), self))
|
||||||
|| (parent instanceof AST_Binary
|
|| (parent instanceof AST_Binary
|
||||||
&& (parent.operator == "&&" || parent.operator == "||")
|
&& (parent.operator == "&&" || parent.operator == "||")
|
||||||
|
|||||||
@@ -1522,3 +1522,71 @@ issue_1631_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "6"
|
expect_stdout: "6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var_side_effects_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var print = console.log.bind(console);
|
||||||
|
function foo(x) {
|
||||||
|
var twice = x * 2;
|
||||||
|
print('Foo:', twice);
|
||||||
|
}
|
||||||
|
foo(10);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var print = console.log.bind(console);
|
||||||
|
function foo(x) {
|
||||||
|
print('Foo:', 2 * x);
|
||||||
|
}
|
||||||
|
foo(10);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
var_side_effects_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var print = console.log.bind(console);
|
||||||
|
function foo(x) {
|
||||||
|
var twice = x.y * 2;
|
||||||
|
print('Foo:', twice);
|
||||||
|
}
|
||||||
|
foo({ y: 10 });
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var print = console.log.bind(console);
|
||||||
|
function foo(x) {
|
||||||
|
var twice = 2 * x.y;
|
||||||
|
print('Foo:', twice);
|
||||||
|
}
|
||||||
|
foo({ y: 10 });
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
var_side_effects_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var print = console.log.bind(console);
|
||||||
|
function foo(x) {
|
||||||
|
var twice = x.y * 2;
|
||||||
|
print('Foo:', twice);
|
||||||
|
}
|
||||||
|
foo({ y: 10 });
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var print = console.log.bind(console);
|
||||||
|
function foo(x) {
|
||||||
|
print('Foo:', 2 * x.y);
|
||||||
|
}
|
||||||
|
foo({ y: 10 });
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ var path = require("path");
|
|||||||
describe("minify() with input file globs", function() {
|
describe("minify() with input file globs", function() {
|
||||||
it("minify() with one input file glob string.", function() {
|
it("minify() with one input file glob string.", function() {
|
||||||
var result = Uglify.minify("test/input/issue-1242/foo.*");
|
var result = Uglify.minify("test/input/issue-1242/foo.*");
|
||||||
assert.strictEqual(result.code, 'function foo(o){var n=2*o;print("Foo:",n)}var print=console.log.bind(console);');
|
assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);');
|
||||||
});
|
});
|
||||||
it("minify() with an array of one input file glob.", function() {
|
it("minify() with an array of one input file glob.", function() {
|
||||||
var result = Uglify.minify([
|
var result = Uglify.minify([
|
||||||
@@ -20,7 +20,7 @@ describe("minify() with input file globs", function() {
|
|||||||
], {
|
], {
|
||||||
compress: { toplevel: true }
|
compress: { toplevel: true }
|
||||||
});
|
});
|
||||||
assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){var o=2*n;print("Foo:",o)}(11);');
|
assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);');
|
||||||
});
|
});
|
||||||
it("should throw with non-matching glob string", function() {
|
it("should throw with non-matching glob string", function() {
|
||||||
var glob = "test/input/issue-1242/blah.*";
|
var glob = "test/input/issue-1242/blah.*";
|
||||||
|
|||||||
Reference in New Issue
Block a user