terser 5.16.2 → 5.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.16.3
4
+
5
+ - Ensure function definitions, don't assume the values of variables defined after them.
6
+
3
7
  ## v5.16.2
4
8
 
5
9
  - Fix sourcemaps with non-ascii characters (#1318)
@@ -15352,15 +15352,17 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15352
15352
 
15353
15353
  ***********************************************************************/
15354
15354
 
15355
- // Define the method AST_Node#reduce_vars, which goes through the AST in
15356
- // execution order to perform basic flow analysis
15357
-
15355
+ /**
15356
+ * Define the method AST_Node#reduce_vars, which goes through the AST in
15357
+ * execution order to perform basic flow analysis
15358
+ */
15358
15359
  function def_reduce_vars(node, func) {
15359
15360
  node.DEFMETHOD("reduce_vars", func);
15360
15361
  }
15361
15362
 
15362
15363
  def_reduce_vars(AST_Node, noop);
15363
15364
 
15365
+ /** Clear definition properties */
15364
15366
  function reset_def(compressor, def) {
15365
15367
  def.assignments = 0;
15366
15368
  def.chained = false;
@@ -15369,7 +15371,10 @@ function reset_def(compressor, def) {
15369
15371
  def.recursive_refs = 0;
15370
15372
  def.references = [];
15371
15373
  def.single_use = undefined;
15372
- if (def.scope.pinned()) {
15374
+ if (
15375
+ def.scope.pinned()
15376
+ || (def.orig[0] instanceof AST_SymbolFunarg && def.scope.uses_arguments)
15377
+ ) {
15373
15378
  def.fixed = false;
15374
15379
  } else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
15375
15380
  def.fixed = def.init;
@@ -15691,15 +15696,23 @@ def_reduce_vars(AST_Default, function(tw, descend) {
15691
15696
 
15692
15697
  function mark_lambda(tw, descend, compressor) {
15693
15698
  clear_flag(this, INLINED);
15694
- push(tw);
15695
- reset_variables(tw, compressor, this);
15696
- if (this.uses_arguments) {
15697
- descend();
15698
- pop(tw);
15699
- return;
15699
+
15700
+ // Sometimes we detach the lambda for safety, and instead of push()
15701
+ // we go to an entirely fresh lineage of safe_ids.
15702
+ let previous_safe_ids;
15703
+ if (this instanceof AST_Defun || this.uses_arguments || this.pinned()) {
15704
+ previous_safe_ids = tw.safe_ids;
15705
+ tw.safe_ids = Object.create(null);
15706
+ } else {
15707
+ push(tw);
15700
15708
  }
15709
+
15710
+ reset_variables(tw, compressor, this);
15711
+
15701
15712
  var iife;
15702
15713
  if (!this.name
15714
+ && !this.uses_arguments
15715
+ && !this.pinned()
15703
15716
  && (iife = tw.parent()) instanceof AST_Call
15704
15717
  && iife.expression === this
15705
15718
  && !iife.args.some(arg => arg instanceof AST_Expansion)
@@ -15725,7 +15738,13 @@ function mark_lambda(tw, descend, compressor) {
15725
15738
  });
15726
15739
  }
15727
15740
  descend();
15728
- pop(tw);
15741
+
15742
+ if (previous_safe_ids) {
15743
+ tw.safe_ids = previous_safe_ids;
15744
+ } else {
15745
+ pop(tw);
15746
+ }
15747
+
15729
15748
  return true;
15730
15749
  }
15731
15750
 
@@ -17334,6 +17353,13 @@ function tighten_body(statements, compressor) {
17334
17353
 
17335
17354
  ***********************************************************************/
17336
17355
 
17356
+ /**
17357
+ * Module that contains the inlining logic.
17358
+ *
17359
+ * @module
17360
+ *
17361
+ * The stars of the show are `inline_into_symbolref` and `inline_into_call`.
17362
+ */
17337
17363
 
17338
17364
  function within_array_or_object_literal(compressor) {
17339
17365
  var node, level = 0;
@@ -17364,136 +17390,135 @@ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
17364
17390
 
17365
17391
  function inline_into_symbolref(self, compressor) {
17366
17392
  const parent = compressor.parent();
17367
- if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
17368
- const def = self.definition();
17369
- const nearest_scope = compressor.find_scope();
17370
- if (compressor.top_retain && def.global && compressor.top_retain(def)) {
17371
- def.fixed = false;
17372
- def.single_use = false;
17373
- return self;
17393
+
17394
+ const def = self.definition();
17395
+ const nearest_scope = compressor.find_scope();
17396
+ if (compressor.top_retain && def.global && compressor.top_retain(def)) {
17397
+ def.fixed = false;
17398
+ def.single_use = false;
17399
+ return self;
17400
+ }
17401
+
17402
+ let fixed = self.fixed_value();
17403
+ let single_use = def.single_use
17404
+ && !(parent instanceof AST_Call
17405
+ && (parent.is_callee_pure(compressor))
17406
+ || has_annotation(parent, _NOINLINE))
17407
+ && !(parent instanceof AST_Export
17408
+ && fixed instanceof AST_Lambda
17409
+ && fixed.name);
17410
+
17411
+ if (single_use && fixed instanceof AST_Node) {
17412
+ single_use =
17413
+ !fixed.has_side_effects(compressor)
17414
+ && !fixed.may_throw(compressor);
17415
+ }
17416
+
17417
+ if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
17418
+ if (retain_top_func(fixed, compressor)) {
17419
+ single_use = false;
17420
+ } else if (def.scope !== self.scope
17421
+ && (def.escaped == 1
17422
+ || has_flag(fixed, INLINED)
17423
+ || within_array_or_object_literal(compressor)
17424
+ || !compressor.option("reduce_funcs"))) {
17425
+ single_use = false;
17426
+ } else if (is_recursive_ref(compressor, def)) {
17427
+ single_use = false;
17428
+ } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
17429
+ single_use = fixed.is_constant_expression(self.scope);
17430
+ if (single_use == "f") {
17431
+ var scope = self.scope;
17432
+ do {
17433
+ if (scope instanceof AST_Defun || is_func_expr(scope)) {
17434
+ set_flag(scope, INLINED);
17435
+ }
17436
+ } while (scope = scope.parent_scope);
17437
+ }
17374
17438
  }
17439
+ }
17375
17440
 
17376
- let fixed = self.fixed_value();
17377
- let single_use = def.single_use
17378
- && !(parent instanceof AST_Call
17379
- && (parent.is_callee_pure(compressor))
17380
- || has_annotation(parent, _NOINLINE))
17381
- && !(parent instanceof AST_Export
17382
- && fixed instanceof AST_Lambda
17383
- && fixed.name);
17384
-
17385
- if (single_use && fixed instanceof AST_Node) {
17386
- single_use =
17387
- !fixed.has_side_effects(compressor)
17388
- && !fixed.may_throw(compressor);
17389
- }
17390
-
17391
- if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
17392
- if (retain_top_func(fixed, compressor)) {
17393
- single_use = false;
17394
- } else if (def.scope !== self.scope
17395
- && (def.escaped == 1
17396
- || has_flag(fixed, INLINED)
17397
- || within_array_or_object_literal(compressor)
17398
- || !compressor.option("reduce_funcs"))) {
17399
- single_use = false;
17400
- } else if (is_recursive_ref(compressor, def)) {
17401
- single_use = false;
17402
- } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
17403
- single_use = fixed.is_constant_expression(self.scope);
17404
- if (single_use == "f") {
17405
- var scope = self.scope;
17406
- do {
17407
- if (scope instanceof AST_Defun || is_func_expr(scope)) {
17408
- set_flag(scope, INLINED);
17409
- }
17410
- } while (scope = scope.parent_scope);
17441
+ if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
17442
+ single_use =
17443
+ def.scope === self.scope
17444
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
17445
+ || parent instanceof AST_Call
17446
+ && parent.expression === self
17447
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
17448
+ && !(fixed.name && fixed.name.definition().recursive_refs > 0);
17449
+ }
17450
+
17451
+ if (single_use && fixed) {
17452
+ if (fixed instanceof AST_DefClass) {
17453
+ set_flag(fixed, SQUEEZED);
17454
+ fixed = make_node(AST_ClassExpression, fixed, fixed);
17455
+ }
17456
+ if (fixed instanceof AST_Defun) {
17457
+ set_flag(fixed, SQUEEZED);
17458
+ fixed = make_node(AST_Function, fixed, fixed);
17459
+ }
17460
+ if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
17461
+ const defun_def = fixed.name.definition();
17462
+ let lambda_def = fixed.variables.get(fixed.name.name);
17463
+ let name = lambda_def && lambda_def.orig[0];
17464
+ if (!(name instanceof AST_SymbolLambda)) {
17465
+ name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
17466
+ name.scope = fixed;
17467
+ fixed.name = name;
17468
+ lambda_def = fixed.def_function(name);
17469
+ }
17470
+ walk(fixed, node => {
17471
+ if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
17472
+ node.thedef = lambda_def;
17473
+ lambda_def.references.push(node);
17411
17474
  }
17412
- }
17475
+ });
17413
17476
  }
17477
+ if (
17478
+ (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
17479
+ && fixed.parent_scope !== nearest_scope
17480
+ ) {
17481
+ fixed = fixed.clone(true, compressor.get_toplevel());
17414
17482
 
17415
- if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
17416
- single_use =
17417
- def.scope === self.scope
17418
- && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
17419
- || parent instanceof AST_Call
17420
- && parent.expression === self
17421
- && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
17422
- && !(fixed.name && fixed.name.definition().recursive_refs > 0);
17483
+ nearest_scope.add_child_scope(fixed);
17423
17484
  }
17485
+ return fixed.optimize(compressor);
17486
+ }
17424
17487
 
17425
- if (single_use && fixed) {
17426
- if (fixed instanceof AST_DefClass) {
17427
- set_flag(fixed, SQUEEZED);
17428
- fixed = make_node(AST_ClassExpression, fixed, fixed);
17429
- }
17430
- if (fixed instanceof AST_Defun) {
17431
- set_flag(fixed, SQUEEZED);
17432
- fixed = make_node(AST_Function, fixed, fixed);
17433
- }
17434
- if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
17435
- const defun_def = fixed.name.definition();
17436
- let lambda_def = fixed.variables.get(fixed.name.name);
17437
- let name = lambda_def && lambda_def.orig[0];
17438
- if (!(name instanceof AST_SymbolLambda)) {
17439
- name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
17440
- name.scope = fixed;
17441
- fixed.name = name;
17442
- lambda_def = fixed.def_function(name);
17443
- }
17444
- walk(fixed, node => {
17445
- if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
17446
- node.thedef = lambda_def;
17447
- lambda_def.references.push(node);
17448
- }
17449
- });
17488
+ // multiple uses
17489
+ if (fixed) {
17490
+ let replace;
17491
+
17492
+ if (fixed instanceof AST_This) {
17493
+ if (!(def.orig[0] instanceof AST_SymbolFunarg)
17494
+ && def.references.every((ref) =>
17495
+ def.scope === ref.scope
17496
+ )) {
17497
+ replace = fixed;
17450
17498
  }
17499
+ } else {
17500
+ var ev = fixed.evaluate(compressor);
17451
17501
  if (
17452
- (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
17453
- && fixed.parent_scope !== nearest_scope
17502
+ ev !== fixed
17503
+ && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
17454
17504
  ) {
17455
- fixed = fixed.clone(true, compressor.get_toplevel());
17456
-
17457
- nearest_scope.add_child_scope(fixed);
17505
+ replace = make_node_from_constant(ev, fixed);
17458
17506
  }
17459
- return fixed.optimize(compressor);
17460
17507
  }
17461
17508
 
17462
- // multiple uses
17463
- if (fixed) {
17464
- let replace;
17509
+ if (replace) {
17510
+ const name_length = self.size(compressor);
17511
+ const replace_size = replace.size(compressor);
17465
17512
 
17466
- if (fixed instanceof AST_This) {
17467
- if (!(def.orig[0] instanceof AST_SymbolFunarg)
17468
- && def.references.every((ref) =>
17469
- def.scope === ref.scope
17470
- )) {
17471
- replace = fixed;
17472
- }
17473
- } else {
17474
- var ev = fixed.evaluate(compressor);
17475
- if (
17476
- ev !== fixed
17477
- && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
17478
- ) {
17479
- replace = make_node_from_constant(ev, fixed);
17480
- }
17513
+ let overhead = 0;
17514
+ if (compressor.option("unused") && !compressor.exposed(def)) {
17515
+ overhead =
17516
+ (name_length + 2 + replace_size) /
17517
+ (def.references.length - def.assignments);
17481
17518
  }
17482
17519
 
17483
- if (replace) {
17484
- const name_length = self.size(compressor);
17485
- const replace_size = replace.size(compressor);
17486
-
17487
- let overhead = 0;
17488
- if (compressor.option("unused") && !compressor.exposed(def)) {
17489
- overhead =
17490
- (name_length + 2 + replace_size) /
17491
- (def.references.length - def.assignments);
17492
- }
17493
-
17494
- if (replace_size <= name_length + overhead) {
17495
- return replace;
17496
- }
17520
+ if (replace_size <= name_length + overhead) {
17521
+ return replace;
17497
17522
  }
17498
17523
  }
17499
17524
  }
@@ -92,7 +92,6 @@ import "../size.js";
92
92
  import "./evaluate.js";
93
93
  import "./drop-side-effect-free.js";
94
94
  import "./reduce-vars.js";
95
- import { is_lhs } from "./inference.js";
96
95
  import {
97
96
  SQUEEZED,
98
97
  INLINED,
@@ -114,6 +113,13 @@ import {
114
113
  retain_top_func,
115
114
  } from "./common.js";
116
115
 
116
+ /**
117
+ * Module that contains the inlining logic.
118
+ *
119
+ * @module
120
+ *
121
+ * The stars of the show are `inline_into_symbolref` and `inline_into_call`.
122
+ */
117
123
 
118
124
  function within_array_or_object_literal(compressor) {
119
125
  var node, level = 0;
@@ -144,136 +150,135 @@ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
144
150
 
145
151
  export function inline_into_symbolref(self, compressor) {
146
152
  const parent = compressor.parent();
147
- if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
148
- const def = self.definition();
149
- const nearest_scope = compressor.find_scope();
150
- if (compressor.top_retain && def.global && compressor.top_retain(def)) {
151
- def.fixed = false;
152
- def.single_use = false;
153
- return self;
154
- }
155
153
 
156
- let fixed = self.fixed_value();
157
- let single_use = def.single_use
158
- && !(parent instanceof AST_Call
159
- && (parent.is_callee_pure(compressor))
160
- || has_annotation(parent, _NOINLINE))
161
- && !(parent instanceof AST_Export
162
- && fixed instanceof AST_Lambda
163
- && fixed.name);
164
-
165
- if (single_use && fixed instanceof AST_Node) {
166
- single_use =
167
- !fixed.has_side_effects(compressor)
168
- && !fixed.may_throw(compressor);
169
- }
154
+ const def = self.definition();
155
+ const nearest_scope = compressor.find_scope();
156
+ if (compressor.top_retain && def.global && compressor.top_retain(def)) {
157
+ def.fixed = false;
158
+ def.single_use = false;
159
+ return self;
160
+ }
170
161
 
171
- if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
172
- if (retain_top_func(fixed, compressor)) {
173
- single_use = false;
174
- } else if (def.scope !== self.scope
175
- && (def.escaped == 1
176
- || has_flag(fixed, INLINED)
177
- || within_array_or_object_literal(compressor)
178
- || !compressor.option("reduce_funcs"))) {
179
- single_use = false;
180
- } else if (is_recursive_ref(compressor, def)) {
181
- single_use = false;
182
- } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
183
- single_use = fixed.is_constant_expression(self.scope);
184
- if (single_use == "f") {
185
- var scope = self.scope;
186
- do {
187
- if (scope instanceof AST_Defun || is_func_expr(scope)) {
188
- set_flag(scope, INLINED);
189
- }
190
- } while (scope = scope.parent_scope);
191
- }
162
+ let fixed = self.fixed_value();
163
+ let single_use = def.single_use
164
+ && !(parent instanceof AST_Call
165
+ && (parent.is_callee_pure(compressor))
166
+ || has_annotation(parent, _NOINLINE))
167
+ && !(parent instanceof AST_Export
168
+ && fixed instanceof AST_Lambda
169
+ && fixed.name);
170
+
171
+ if (single_use && fixed instanceof AST_Node) {
172
+ single_use =
173
+ !fixed.has_side_effects(compressor)
174
+ && !fixed.may_throw(compressor);
175
+ }
176
+
177
+ if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
178
+ if (retain_top_func(fixed, compressor)) {
179
+ single_use = false;
180
+ } else if (def.scope !== self.scope
181
+ && (def.escaped == 1
182
+ || has_flag(fixed, INLINED)
183
+ || within_array_or_object_literal(compressor)
184
+ || !compressor.option("reduce_funcs"))) {
185
+ single_use = false;
186
+ } else if (is_recursive_ref(compressor, def)) {
187
+ single_use = false;
188
+ } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
189
+ single_use = fixed.is_constant_expression(self.scope);
190
+ if (single_use == "f") {
191
+ var scope = self.scope;
192
+ do {
193
+ if (scope instanceof AST_Defun || is_func_expr(scope)) {
194
+ set_flag(scope, INLINED);
195
+ }
196
+ } while (scope = scope.parent_scope);
192
197
  }
193
198
  }
199
+ }
194
200
 
195
- if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
196
- single_use =
197
- def.scope === self.scope
198
- && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
199
- || parent instanceof AST_Call
200
- && parent.expression === self
201
- && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
202
- && !(fixed.name && fixed.name.definition().recursive_refs > 0);
203
- }
201
+ if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
202
+ single_use =
203
+ def.scope === self.scope
204
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
205
+ || parent instanceof AST_Call
206
+ && parent.expression === self
207
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
208
+ && !(fixed.name && fixed.name.definition().recursive_refs > 0);
209
+ }
204
210
 
205
- if (single_use && fixed) {
206
- if (fixed instanceof AST_DefClass) {
207
- set_flag(fixed, SQUEEZED);
208
- fixed = make_node(AST_ClassExpression, fixed, fixed);
209
- }
210
- if (fixed instanceof AST_Defun) {
211
- set_flag(fixed, SQUEEZED);
212
- fixed = make_node(AST_Function, fixed, fixed);
211
+ if (single_use && fixed) {
212
+ if (fixed instanceof AST_DefClass) {
213
+ set_flag(fixed, SQUEEZED);
214
+ fixed = make_node(AST_ClassExpression, fixed, fixed);
215
+ }
216
+ if (fixed instanceof AST_Defun) {
217
+ set_flag(fixed, SQUEEZED);
218
+ fixed = make_node(AST_Function, fixed, fixed);
219
+ }
220
+ if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
221
+ const defun_def = fixed.name.definition();
222
+ let lambda_def = fixed.variables.get(fixed.name.name);
223
+ let name = lambda_def && lambda_def.orig[0];
224
+ if (!(name instanceof AST_SymbolLambda)) {
225
+ name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
226
+ name.scope = fixed;
227
+ fixed.name = name;
228
+ lambda_def = fixed.def_function(name);
213
229
  }
214
- if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
215
- const defun_def = fixed.name.definition();
216
- let lambda_def = fixed.variables.get(fixed.name.name);
217
- let name = lambda_def && lambda_def.orig[0];
218
- if (!(name instanceof AST_SymbolLambda)) {
219
- name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
220
- name.scope = fixed;
221
- fixed.name = name;
222
- lambda_def = fixed.def_function(name);
230
+ walk(fixed, node => {
231
+ if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
232
+ node.thedef = lambda_def;
233
+ lambda_def.references.push(node);
223
234
  }
224
- walk(fixed, node => {
225
- if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
226
- node.thedef = lambda_def;
227
- lambda_def.references.push(node);
228
- }
229
- });
235
+ });
236
+ }
237
+ if (
238
+ (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
239
+ && fixed.parent_scope !== nearest_scope
240
+ ) {
241
+ fixed = fixed.clone(true, compressor.get_toplevel());
242
+
243
+ nearest_scope.add_child_scope(fixed);
244
+ }
245
+ return fixed.optimize(compressor);
246
+ }
247
+
248
+ // multiple uses
249
+ if (fixed) {
250
+ let replace;
251
+
252
+ if (fixed instanceof AST_This) {
253
+ if (!(def.orig[0] instanceof AST_SymbolFunarg)
254
+ && def.references.every((ref) =>
255
+ def.scope === ref.scope
256
+ )) {
257
+ replace = fixed;
230
258
  }
259
+ } else {
260
+ var ev = fixed.evaluate(compressor);
231
261
  if (
232
- (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
233
- && fixed.parent_scope !== nearest_scope
262
+ ev !== fixed
263
+ && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
234
264
  ) {
235
- fixed = fixed.clone(true, compressor.get_toplevel());
236
-
237
- nearest_scope.add_child_scope(fixed);
265
+ replace = make_node_from_constant(ev, fixed);
238
266
  }
239
- return fixed.optimize(compressor);
240
267
  }
241
268
 
242
- // multiple uses
243
- if (fixed) {
244
- let replace;
269
+ if (replace) {
270
+ const name_length = self.size(compressor);
271
+ const replace_size = replace.size(compressor);
245
272
 
246
- if (fixed instanceof AST_This) {
247
- if (!(def.orig[0] instanceof AST_SymbolFunarg)
248
- && def.references.every((ref) =>
249
- def.scope === ref.scope
250
- )) {
251
- replace = fixed;
252
- }
253
- } else {
254
- var ev = fixed.evaluate(compressor);
255
- if (
256
- ev !== fixed
257
- && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
258
- ) {
259
- replace = make_node_from_constant(ev, fixed);
260
- }
273
+ let overhead = 0;
274
+ if (compressor.option("unused") && !compressor.exposed(def)) {
275
+ overhead =
276
+ (name_length + 2 + replace_size) /
277
+ (def.references.length - def.assignments);
261
278
  }
262
279
 
263
- if (replace) {
264
- const name_length = self.size(compressor);
265
- const replace_size = replace.size(compressor);
266
-
267
- let overhead = 0;
268
- if (compressor.option("unused") && !compressor.exposed(def)) {
269
- overhead =
270
- (name_length + 2 + replace_size) /
271
- (def.references.length - def.assignments);
272
- }
273
-
274
- if (replace_size <= name_length + overhead) {
275
- return replace;
276
- }
280
+ if (replace_size <= name_length + overhead) {
281
+ return replace;
277
282
  }
278
283
  }
279
284
  }
@@ -103,15 +103,17 @@ import { lazy_op, is_modified } from "./inference.js";
103
103
  import { INLINED, clear_flag } from "./compressor-flags.js";
104
104
  import { read_property, has_break_or_continue, is_recursive_ref } from "./common.js";
105
105
 
106
- // Define the method AST_Node#reduce_vars, which goes through the AST in
107
- // execution order to perform basic flow analysis
108
-
106
+ /**
107
+ * Define the method AST_Node#reduce_vars, which goes through the AST in
108
+ * execution order to perform basic flow analysis
109
+ */
109
110
  function def_reduce_vars(node, func) {
110
111
  node.DEFMETHOD("reduce_vars", func);
111
112
  }
112
113
 
113
114
  def_reduce_vars(AST_Node, noop);
114
115
 
116
+ /** Clear definition properties */
115
117
  function reset_def(compressor, def) {
116
118
  def.assignments = 0;
117
119
  def.chained = false;
@@ -120,7 +122,10 @@ function reset_def(compressor, def) {
120
122
  def.recursive_refs = 0;
121
123
  def.references = [];
122
124
  def.single_use = undefined;
123
- if (def.scope.pinned()) {
125
+ if (
126
+ def.scope.pinned()
127
+ || (def.orig[0] instanceof AST_SymbolFunarg && def.scope.uses_arguments)
128
+ ) {
124
129
  def.fixed = false;
125
130
  } else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
126
131
  def.fixed = def.init;
@@ -442,15 +447,23 @@ def_reduce_vars(AST_Default, function(tw, descend) {
442
447
 
443
448
  function mark_lambda(tw, descend, compressor) {
444
449
  clear_flag(this, INLINED);
445
- push(tw);
446
- reset_variables(tw, compressor, this);
447
- if (this.uses_arguments) {
448
- descend();
449
- pop(tw);
450
- return;
450
+
451
+ // Sometimes we detach the lambda for safety, and instead of push()
452
+ // we go to an entirely fresh lineage of safe_ids.
453
+ let previous_safe_ids;
454
+ if (this instanceof AST_Defun || this.uses_arguments || this.pinned()) {
455
+ previous_safe_ids = tw.safe_ids;
456
+ tw.safe_ids = Object.create(null);
457
+ } else {
458
+ push(tw);
451
459
  }
460
+
461
+ reset_variables(tw, compressor, this);
462
+
452
463
  var iife;
453
464
  if (!this.name
465
+ && !this.uses_arguments
466
+ && !this.pinned()
454
467
  && (iife = tw.parent()) instanceof AST_Call
455
468
  && iife.expression === this
456
469
  && !iife.args.some(arg => arg instanceof AST_Expansion)
@@ -476,7 +489,13 @@ function mark_lambda(tw, descend, compressor) {
476
489
  });
477
490
  }
478
491
  descend();
479
- pop(tw);
492
+
493
+ if (previous_safe_ids) {
494
+ tw.safe_ids = previous_safe_ids;
495
+ } else {
496
+ pop(tw);
497
+ }
498
+
480
499
  return true;
481
500
  }
482
501
 
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "homepage": "https://terser.org",
5
5
  "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
6
6
  "license": "BSD-2-Clause",
7
- "version": "5.16.2",
7
+ "version": "5.16.3",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },