diff --git a/lib/scope.js b/lib/scope.js index 630ee9b1a..ab822f3f3 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -116,6 +116,11 @@ const MASK_EXPORT_WANT_MANGLE = 1 << 1; let function_defs = null; let unmangleable_names = null; +/** + * When defined, there is a function declaration somewhere that's inside of a block. + * See https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#sec-block-level-function-declarations-web-legacy-compatibility-semantics +*/ +let scopes_with_block_defuns = null; class SymbolDef { constructor(scope, orig, init) { @@ -666,6 +671,15 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) { }); function next_mangled(scope, options) { + let defun_scope; + if ( + scopes_with_block_defuns + && (defun_scope = scope.get_defun_scope()) + && scopes_with_block_defuns.has(defun_scope) + ) { + scope = defun_scope; + } + var ext = scope.enclosed; var nth_identifier = options.nth_identifier; out: while (true) { @@ -800,6 +814,13 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) { lname = save_nesting; return true; // don't descend again in TreeWalker } + if ( + node instanceof AST_Defun + && !(tw.parent() instanceof AST_Scope) + ) { + scopes_with_block_defuns = scopes_with_block_defuns || new Set(); + scopes_with_block_defuns.add(node.parent_scope.get_defun_scope()); + } if (node instanceof AST_Scope) { node.variables.forEach(collect); return; @@ -848,6 +869,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) { function_defs = null; unmangleable_names = null; + scopes_with_block_defuns = null; function collect(symbol) { if (symbol.export & MASK_EXPORT_DONT_MANGLE) { diff --git a/test/compress/blocks.js b/test/compress/blocks.js index a3247f93f..96927aa93 100644 --- a/test/compress/blocks.js +++ b/test/compress/blocks.js @@ -183,6 +183,61 @@ issue_1672_if_strict: { expect_stdout: true } +issue_t1155_function_in_block: { + options = { unused: false } + mangle = {} + input: { + function f1() { + if ("aaaaaaa") { + function f2() { + return 1; + } + + const var1 = "bbbbbbb"; + } + } + } + expect: { + function f1() { + if ("aaaaaaa") { + function a() { + return 1; + } + + const b = "bbbbbbb"; + } + } + } +} + +issue_t1155_function_in_other_block: { + options = { unused: false } + mangle = {} + input: { + function f1() { + if ("aaaaaaaaaannnnnnn") { + function f2() { + return 1; + } + } + if ("aaaaaaaaaannnnnnn") { + const f2 = "aaaaaaaaaannnnnnn"; + } + } + } + expect: { + function f1() { + if ("aaaaaaaaaannnnnnn") + function a() { + return 1; + } + if ("aaaaaaaaaannnnnnn") { + const n = "aaaaaaaaaannnnnnn"; + } + } + } +} + issue_2946_else_const: { input: { if (1) {