Skip to content

Commit

Permalink
workaround function declaration quirks in ES6+ (#5833)
Browse files Browse the repository at this point in the history
fixes #1666
  • Loading branch information
alexlamsl authored Jun 8, 2024
1 parent 3dfb379 commit e7b9b4a
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 2 deletions.
41 changes: 39 additions & 2 deletions lib/compress.js
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,11 @@ Compressor.prototype.compress = function(node) {
var d = this.definition();
if (!d.first_decl && d.references.length == 0) d.first_decl = this;
});
def(AST_SymbolDefun, function() {
var d = this.definition();
if (!d.first_decl && d.references.length == 0) d.first_decl = this;
if (d.orig.length > 1 && d.scope.resolve() !== this.scope) d.fixed = false;
});
def(AST_SymbolImport, function() {
var d = this.definition();
d.first_decl = this;
Expand Down Expand Up @@ -1893,6 +1898,7 @@ Compressor.prototype.compress = function(node) {
if (stat instanceof AST_LambdaDefinition) {
var def = stat.name.definition();
var scope = stat.name.scope;
if (def.orig.length > 1 && def.scope.resolve() !== scope) return false;
return def.scope === scope || all(def.references, function(ref) {
var s = ref.scope;
do {
Expand Down Expand Up @@ -2405,6 +2411,7 @@ Compressor.prototype.compress = function(node) {
}
var read_toplevel = false;
var modify_toplevel = false;
var defun_scopes = get_defun_scopes(lhs);
// Locate symbols which may execute code outside of scanning range
var enclosed = new Dictionary();
var well_defined = true;
Expand Down Expand Up @@ -2535,8 +2542,11 @@ Compressor.prototype.compress = function(node) {
if (parent instanceof AST_For) {
if (node !== parent.init) return true;
}
if (node instanceof AST_Assign) {
return node.operator != "=" && lhs.equals(node.left);
if (node instanceof AST_Assign) return node.operator != "=" && lhs.equals(node.left);
if (node instanceof AST_BlockStatement) {
return defun_scopes && !all(defun_scopes, function(scope) {
return node !== scope;
});
}
if (node instanceof AST_Call) {
if (!(lhs instanceof AST_PropAccess)) return false;
Expand Down Expand Up @@ -3437,6 +3447,33 @@ Compressor.prototype.compress = function(node) {
}
}

function get_defun_scopes(lhs) {
if (!(lhs instanceof AST_SymbolDeclaration
|| lhs instanceof AST_SymbolRef
|| lhs instanceof AST_Destructured)) return;
var scopes = [];
lhs.mark_symbol(function(node) {
if (node instanceof AST_Symbol) {
var def = node.definition();
var scope = def.scope.resolve();
var found = false;
var avoid = def.orig.reduce(function(scopes, sym) {
if (sym instanceof AST_SymbolDefun) {
if (sym.scope !== scope) push_uniq(scopes, sym.scope);
} else {
found = true;
}
return scopes;
}, []);
if (found) avoid.forEach(function(scope) {
push_uniq(scopes, scope);
});
}
});
if (scopes.length == 0) return;
return scopes;
}

function is_lhs_local(lhs) {
var sym = root_expr(lhs);
if (!(sym instanceof AST_SymbolRef)) return false;
Expand Down
42 changes: 42 additions & 0 deletions test/compress/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,45 @@ keep_some_blocks: {
} else stuff();
}
}

issue_1666: {
input: {
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect: {
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect_stdout: true
}

issue_1666_strict: {
input: {
"use strict";
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect: {
"use strict";
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect_stdout: true
}
112 changes: 112 additions & 0 deletions test/compress/collapse_vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -10172,3 +10172,115 @@ issue_5779: {
}
expect_stdout: "PASS"
}

issue_1666: {
options = {
collapse_vars: true,
}
input: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}

issue_1666_strict: {
options = {
collapse_vars: true,
}
input: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}

issue_1666_undefined: {
options = {
collapse_vars: true,
}
input: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}

issue_1666_undefined_strict: {
options = {
collapse_vars: true,
}
input: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}
124 changes: 124 additions & 0 deletions test/compress/reduce_vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -8222,3 +8222,127 @@ issue_5777_2: {
}
expect_stdout: "PASS"
}

issue_1666: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}

issue_1666_strict: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}

issue_1666_undefined: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}

issue_1666_undefined_strict: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}

0 comments on commit e7b9b4a

Please sign in to comment.