workaround function declaration quirks in ES6+ (#5833)

fixes #1666
This commit is contained in:
Alex Lam S.L
2024-06-09 00:57:15 +03:00
committed by GitHub
parent 3dfb379486
commit e7b9b4aafb
4 changed files with 317 additions and 2 deletions

View File

@@ -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;
@@ -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 {
@@ -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;
@@ -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;
@@ -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;

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}