terser 5.16.0 → 5.16.1

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.
@@ -56,7 +56,6 @@ import {
56
56
  AST_Catch,
57
57
  AST_Chain,
58
58
  AST_Class,
59
- AST_ClassExpression,
60
59
  AST_ClassProperty,
61
60
  AST_ClassStaticBlock,
62
61
  AST_ConciseMethod,
@@ -66,7 +65,6 @@ import {
66
65
  AST_Debugger,
67
66
  AST_Default,
68
67
  AST_DefaultAssign,
69
- AST_DefClass,
70
68
  AST_Definitions,
71
69
  AST_Defun,
72
70
  AST_Destructuring,
@@ -110,8 +108,6 @@ import {
110
108
  AST_Switch,
111
109
  AST_SwitchBranch,
112
110
  AST_Symbol,
113
- AST_SymbolBlockDeclaration,
114
- AST_SymbolCatch,
115
111
  AST_SymbolClassProperty,
116
112
  AST_SymbolDeclaration,
117
113
  AST_SymbolDefun,
@@ -121,7 +117,6 @@ import {
121
117
  AST_SymbolLet,
122
118
  AST_SymbolMethod,
123
119
  AST_SymbolRef,
124
- AST_SymbolVar,
125
120
  AST_TemplateString,
126
121
  AST_This,
127
122
  AST_Toplevel,
@@ -149,10 +144,8 @@ import {
149
144
  import {
150
145
  defaults,
151
146
  HOP,
152
- keep_name,
153
147
  make_node,
154
148
  makePredicate,
155
- map_add,
156
149
  MAP,
157
150
  remove,
158
151
  return_false,
@@ -170,14 +163,12 @@ import {
170
163
  PRECEDENCE,
171
164
  } from "../parse.js";
172
165
  import { OutputStream } from "../output.js";
173
- import {
174
- base54,
175
- SymbolDef,
176
- } from "../scope.js";
166
+ import { base54, format_mangler_options } from "../scope.js";
177
167
  import "../size.js";
178
168
 
179
169
  import "./evaluate.js";
180
170
  import "./drop-side-effect-free.js";
171
+ import "./drop-unused.js";
181
172
  import "./reduce-vars.js";
182
173
  import {
183
174
  is_undeclared_ref,
@@ -192,7 +183,6 @@ import {
192
183
  OPTIMIZED,
193
184
  CLEAR_BETWEEN_PASSES,
194
185
  TOP,
195
- WRITE_ONLY,
196
186
  UNDEFINED,
197
187
  UNUSED,
198
188
  TRUTHY,
@@ -214,7 +204,6 @@ import {
214
204
  is_empty,
215
205
  is_identifier_atom,
216
206
  is_reachable,
217
- is_ref_of,
218
207
  can_be_evicted_from_block,
219
208
  as_statement_array,
220
209
  retain_top_func,
@@ -332,7 +321,9 @@ class Compressor extends TreeWalker {
332
321
  this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
333
322
  this.evaluated_regexps = new Map();
334
323
  this._toplevel = undefined;
335
- this.mangle_options = mangle_options;
324
+ this.mangle_options = mangle_options
325
+ ? format_mangler_options(mangle_options)
326
+ : mangle_options;
336
327
  }
337
328
 
338
329
  option(key) {
@@ -653,382 +644,6 @@ function opt_AST_Lambda(self, compressor) {
653
644
  }
654
645
  def_optimize(AST_Lambda, opt_AST_Lambda);
655
646
 
656
- const r_keep_assign = /keep_assign/;
657
- AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
658
- if (!compressor.option("unused")) return;
659
- if (compressor.has_directive("use asm")) return;
660
- var self = this;
661
- if (self.pinned()) return;
662
- var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
663
- var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
664
- const assign_as_unused = r_keep_assign.test(compressor.option("unused")) ? return_false : function(node) {
665
- if (node instanceof AST_Assign
666
- && !node.logical
667
- && (has_flag(node, WRITE_ONLY) || node.operator == "=")
668
- ) {
669
- return node.left;
670
- }
671
- if (node instanceof AST_Unary && has_flag(node, WRITE_ONLY)) {
672
- return node.expression;
673
- }
674
- };
675
- var in_use_ids = new Map();
676
- var fixed_ids = new Map();
677
- if (self instanceof AST_Toplevel && compressor.top_retain) {
678
- self.variables.forEach(function(def) {
679
- if (compressor.top_retain(def) && !in_use_ids.has(def.id)) {
680
- in_use_ids.set(def.id, def);
681
- }
682
- });
683
- }
684
- var var_defs_by_id = new Map();
685
- var initializations = new Map();
686
- // pass 1: find out which symbols are directly used in
687
- // this scope (not in nested scopes).
688
- var scope = this;
689
- var tw = new TreeWalker(function(node, descend) {
690
- if (node instanceof AST_Lambda && node.uses_arguments && !tw.has_directive("use strict")) {
691
- node.argnames.forEach(function(argname) {
692
- if (!(argname instanceof AST_SymbolDeclaration)) return;
693
- var def = argname.definition();
694
- if (!in_use_ids.has(def.id)) {
695
- in_use_ids.set(def.id, def);
696
- }
697
- });
698
- }
699
- if (node === self) return;
700
- if (node instanceof AST_Defun || node instanceof AST_DefClass) {
701
- var node_def = node.name.definition();
702
- const in_export = tw.parent() instanceof AST_Export;
703
- if (in_export || !drop_funcs && scope === self) {
704
- if (node_def.global && !in_use_ids.has(node_def.id)) {
705
- in_use_ids.set(node_def.id, node_def);
706
- }
707
- }
708
- if (node instanceof AST_DefClass) {
709
- if (
710
- node.extends
711
- && (node.extends.has_side_effects(compressor)
712
- || node.extends.may_throw(compressor))
713
- ) {
714
- node.extends.walk(tw);
715
- }
716
- for (const prop of node.properties) {
717
- if (
718
- prop.has_side_effects(compressor) ||
719
- prop.may_throw(compressor)
720
- ) {
721
- prop.walk(tw);
722
- }
723
- }
724
- }
725
- map_add(initializations, node_def.id, node);
726
- return true; // don't go in nested scopes
727
- }
728
- if (node instanceof AST_SymbolFunarg && scope === self) {
729
- map_add(var_defs_by_id, node.definition().id, node);
730
- }
731
- if (node instanceof AST_Definitions && scope === self) {
732
- const in_export = tw.parent() instanceof AST_Export;
733
- node.definitions.forEach(function(def) {
734
- if (def.name instanceof AST_SymbolVar) {
735
- map_add(var_defs_by_id, def.name.definition().id, def);
736
- }
737
- if (in_export || !drop_vars) {
738
- walk(def.name, node => {
739
- if (node instanceof AST_SymbolDeclaration) {
740
- const def = node.definition();
741
- if (
742
- (in_export || def.global)
743
- && !in_use_ids.has(def.id)
744
- ) {
745
- in_use_ids.set(def.id, def);
746
- }
747
- }
748
- });
749
- }
750
- if (def.value) {
751
- if (def.name instanceof AST_Destructuring) {
752
- def.walk(tw);
753
- } else {
754
- var node_def = def.name.definition();
755
- map_add(initializations, node_def.id, def.value);
756
- if (!node_def.chained && def.name.fixed_value() === def.value) {
757
- fixed_ids.set(node_def.id, def);
758
- }
759
- }
760
- if (def.value.has_side_effects(compressor)) {
761
- def.value.walk(tw);
762
- }
763
- }
764
- });
765
- return true;
766
- }
767
- return scan_ref_scoped(node, descend);
768
- });
769
- self.walk(tw);
770
- // pass 2: for every used symbol we need to walk its
771
- // initialization code to figure out if it uses other
772
- // symbols (that may not be in_use).
773
- tw = new TreeWalker(scan_ref_scoped);
774
- in_use_ids.forEach(function (def) {
775
- var init = initializations.get(def.id);
776
- if (init) init.forEach(function(init) {
777
- init.walk(tw);
778
- });
779
- });
780
- // pass 3: we should drop declarations not in_use
781
- var tt = new TreeTransformer(
782
- function before(node, descend, in_list) {
783
- var parent = tt.parent();
784
- if (drop_vars) {
785
- const sym = assign_as_unused(node);
786
- if (sym instanceof AST_SymbolRef) {
787
- var def = sym.definition();
788
- var in_use = in_use_ids.has(def.id);
789
- if (node instanceof AST_Assign) {
790
- if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
791
- return maintain_this_binding(parent, node, node.right.transform(tt));
792
- }
793
- } else if (!in_use) return in_list ? MAP.skip : make_node(AST_Number, node, {
794
- value: 0
795
- });
796
- }
797
- }
798
- if (scope !== self) return;
799
- var def;
800
- if (node.name
801
- && (node instanceof AST_ClassExpression
802
- && !keep_name(compressor.option("keep_classnames"), (def = node.name.definition()).name)
803
- || node instanceof AST_Function
804
- && !keep_name(compressor.option("keep_fnames"), (def = node.name.definition()).name))) {
805
- // any declarations with same name will overshadow
806
- // name of this anonymous function and can therefore
807
- // never be used anywhere
808
- if (!in_use_ids.has(def.id) || def.orig.length > 1) node.name = null;
809
- }
810
- if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
811
- var trim = !compressor.option("keep_fargs");
812
- for (var a = node.argnames, i = a.length; --i >= 0;) {
813
- var sym = a[i];
814
- if (sym instanceof AST_Expansion) {
815
- sym = sym.expression;
816
- }
817
- if (sym instanceof AST_DefaultAssign) {
818
- sym = sym.left;
819
- }
820
- // Do not drop destructuring arguments.
821
- // They constitute a type assertion, so dropping
822
- // them would stop that TypeError which would happen
823
- // if someone called it with an incorrectly formatted
824
- // parameter.
825
- if (!(sym instanceof AST_Destructuring) && !in_use_ids.has(sym.definition().id)) {
826
- set_flag(sym, UNUSED);
827
- if (trim) {
828
- a.pop();
829
- }
830
- } else {
831
- trim = false;
832
- }
833
- }
834
- }
835
- if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
836
- const def = node.name.definition();
837
- const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
838
- // Class "extends" and static blocks may have side effects
839
- const has_side_effects = !keep
840
- && node instanceof AST_Class
841
- && node.has_side_effects(compressor);
842
- if (!keep && !has_side_effects) {
843
- def.eliminated++;
844
- return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
845
- }
846
- }
847
- if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
848
- var drop_block = !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var);
849
- // place uninitialized names at the start
850
- var body = [], head = [], tail = [];
851
- // for unused names whose initialization has
852
- // side effects, we can cascade the init. code
853
- // into the next one, or next statement.
854
- var side_effects = [];
855
- node.definitions.forEach(function(def) {
856
- if (def.value) def.value = def.value.transform(tt);
857
- var is_destructure = def.name instanceof AST_Destructuring;
858
- var sym = is_destructure
859
- ? new SymbolDef(null, { name: "<destructure>" }) /* fake SymbolDef */
860
- : def.name.definition();
861
- if (drop_block && sym.global) return tail.push(def);
862
- if (!(drop_vars || drop_block)
863
- || is_destructure
864
- && (def.name.names.length
865
- || def.name.is_array
866
- || compressor.option("pure_getters") != true)
867
- || in_use_ids.has(sym.id)
868
- ) {
869
- if (def.value && fixed_ids.has(sym.id) && fixed_ids.get(sym.id) !== def) {
870
- def.value = def.value.drop_side_effect_free(compressor);
871
- }
872
- if (def.name instanceof AST_SymbolVar) {
873
- var var_defs = var_defs_by_id.get(sym.id);
874
- if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
875
- if (def.value) {
876
- var ref = make_node(AST_SymbolRef, def.name, def.name);
877
- sym.references.push(ref);
878
- var assign = make_node(AST_Assign, def, {
879
- operator: "=",
880
- logical: false,
881
- left: ref,
882
- right: def.value
883
- });
884
- if (fixed_ids.get(sym.id) === def) {
885
- fixed_ids.set(sym.id, assign);
886
- }
887
- side_effects.push(assign.transform(tt));
888
- }
889
- remove(var_defs, def);
890
- sym.eliminated++;
891
- return;
892
- }
893
- }
894
- if (def.value) {
895
- if (side_effects.length > 0) {
896
- if (tail.length > 0) {
897
- side_effects.push(def.value);
898
- def.value = make_sequence(def.value, side_effects);
899
- } else {
900
- body.push(make_node(AST_SimpleStatement, node, {
901
- body: make_sequence(node, side_effects)
902
- }));
903
- }
904
- side_effects = [];
905
- }
906
- tail.push(def);
907
- } else {
908
- head.push(def);
909
- }
910
- } else if (sym.orig[0] instanceof AST_SymbolCatch) {
911
- var value = def.value && def.value.drop_side_effect_free(compressor);
912
- if (value) side_effects.push(value);
913
- def.value = null;
914
- head.push(def);
915
- } else {
916
- var value = def.value && def.value.drop_side_effect_free(compressor);
917
- if (value) {
918
- side_effects.push(value);
919
- }
920
- sym.eliminated++;
921
- }
922
- });
923
- if (head.length > 0 || tail.length > 0) {
924
- node.definitions = head.concat(tail);
925
- body.push(node);
926
- }
927
- if (side_effects.length > 0) {
928
- body.push(make_node(AST_SimpleStatement, node, {
929
- body: make_sequence(node, side_effects)
930
- }));
931
- }
932
- switch (body.length) {
933
- case 0:
934
- return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
935
- case 1:
936
- return body[0];
937
- default:
938
- return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
939
- body: body
940
- });
941
- }
942
- }
943
- // certain combination of unused name + side effect leads to:
944
- // https://github.com/mishoo/UglifyJS2/issues/44
945
- // https://github.com/mishoo/UglifyJS2/issues/1830
946
- // https://github.com/mishoo/UglifyJS2/issues/1838
947
- // that's an invalid AST.
948
- // We fix it at this stage by moving the `var` outside the `for`.
949
- if (node instanceof AST_For) {
950
- descend(node, this);
951
- var block;
952
- if (node.init instanceof AST_BlockStatement) {
953
- block = node.init;
954
- node.init = block.body.pop();
955
- block.body.push(node);
956
- }
957
- if (node.init instanceof AST_SimpleStatement) {
958
- node.init = node.init.body;
959
- } else if (is_empty(node.init)) {
960
- node.init = null;
961
- }
962
- return !block ? node : in_list ? MAP.splice(block.body) : block;
963
- }
964
- if (node instanceof AST_LabeledStatement
965
- && node.body instanceof AST_For
966
- ) {
967
- descend(node, this);
968
- if (node.body instanceof AST_BlockStatement) {
969
- var block = node.body;
970
- node.body = block.body.pop();
971
- block.body.push(node);
972
- return in_list ? MAP.splice(block.body) : block;
973
- }
974
- return node;
975
- }
976
- if (node instanceof AST_BlockStatement) {
977
- descend(node, this);
978
- if (in_list && node.body.every(can_be_evicted_from_block)) {
979
- return MAP.splice(node.body);
980
- }
981
- return node;
982
- }
983
- if (node instanceof AST_Scope) {
984
- const save_scope = scope;
985
- scope = node;
986
- descend(node, this);
987
- scope = save_scope;
988
- return node;
989
- }
990
- }
991
- );
992
-
993
- self.transform(tt);
994
-
995
- function scan_ref_scoped(node, descend) {
996
- var node_def;
997
- const sym = assign_as_unused(node);
998
- if (sym instanceof AST_SymbolRef
999
- && !is_ref_of(node.left, AST_SymbolBlockDeclaration)
1000
- && self.variables.get(sym.name) === (node_def = sym.definition())
1001
- ) {
1002
- if (node instanceof AST_Assign) {
1003
- node.right.walk(tw);
1004
- if (!node_def.chained && node.left.fixed_value() === node.right) {
1005
- fixed_ids.set(node_def.id, node);
1006
- }
1007
- }
1008
- return true;
1009
- }
1010
- if (node instanceof AST_SymbolRef) {
1011
- node_def = node.definition();
1012
- if (!in_use_ids.has(node_def.id)) {
1013
- in_use_ids.set(node_def.id, node_def);
1014
- if (node_def.orig[0] instanceof AST_SymbolCatch) {
1015
- const redef = node_def.scope.is_block_scope()
1016
- && node_def.scope.get_defun_scope().variables.get(node_def.name);
1017
- if (redef) in_use_ids.set(redef.id, redef);
1018
- }
1019
- }
1020
- return true;
1021
- }
1022
- if (node instanceof AST_Scope) {
1023
- var save_scope = scope;
1024
- scope = node;
1025
- descend();
1026
- scope = save_scope;
1027
- return true;
1028
- }
1029
- }
1030
- });
1031
-
1032
647
  AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
1033
648
  var self = this;
1034
649
  if (compressor.has_directive("use asm")) return self;
@@ -1173,8 +788,6 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
1173
788
  var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
1174
789
  var defs_by_id = new Map();
1175
790
  var hoister = new TreeTransformer(function(node, descend) {
1176
- if (node instanceof AST_Definitions
1177
- && hoister.parent() instanceof AST_Export) return node;
1178
791
  if (node instanceof AST_VarDef) {
1179
792
  const sym = node.name;
1180
793
  let def;
@@ -573,7 +573,6 @@ export function is_nullish(node, compressor) {
573
573
  return true;
574
574
  }
575
575
  if (node instanceof AST_This && this instanceof AST_Arrow) {
576
- // TODO check arguments too!
577
576
  result = false;
578
577
  return walk_abort;
579
578
  }
@@ -694,7 +693,7 @@ export function is_nullish(node, compressor) {
694
693
  return this.tail_node()._dot_throw(compressor);
695
694
  });
696
695
  def_may_throw_on_access(AST_SymbolRef, function(compressor) {
697
- if (this.name === "arguments") return false;
696
+ if (this.name === "arguments" && this.scope instanceof AST_Lambda) return false;
698
697
  if (has_flag(this, UNDEFINED)) return true;
699
698
  if (!is_strict(compressor)) return false;
700
699
  if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
@@ -57,10 +57,8 @@ import {
57
57
  AST_Expansion,
58
58
  AST_Export,
59
59
  AST_Function,
60
- AST_Infinity,
61
60
  AST_IterationStatement,
62
61
  AST_Lambda,
63
- AST_NaN,
64
62
  AST_Node,
65
63
  AST_Number,
66
64
  AST_Object,
@@ -81,7 +79,6 @@ import {
81
79
  AST_Undefined,
82
80
  AST_Var,
83
81
  AST_VarDef,
84
- AST_With,
85
82
 
86
83
  walk,
87
84
 
@@ -95,7 +92,7 @@ import "../size.js";
95
92
  import "./evaluate.js";
96
93
  import "./drop-side-effect-free.js";
97
94
  import "./reduce-vars.js";
98
- import { is_undeclared_ref, is_lhs } from "./inference.js";
95
+ import { is_lhs } from "./inference.js";
99
96
  import {
100
97
  SQUEEZED,
101
98
  INLINED,
@@ -146,21 +143,6 @@ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
146
143
  }
147
144
 
148
145
  export function inline_into_symbolref(self, compressor) {
149
- if (
150
- !compressor.option("ie8")
151
- && is_undeclared_ref(self)
152
- && !compressor.find_parent(AST_With)
153
- ) {
154
- switch (self.name) {
155
- case "undefined":
156
- return make_node(AST_Undefined, self).optimize(compressor);
157
- case "NaN":
158
- return make_node(AST_NaN, self).optimize(compressor);
159
- case "Infinity":
160
- return make_node(AST_Infinity, self).optimize(compressor);
161
- }
162
- }
163
-
164
146
  const parent = compressor.parent();
165
147
  if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
166
148
  const def = self.definition();
@@ -205,9 +205,10 @@ export function trim_unreachable_code(compressor, stat, target) {
205
205
 
206
206
  /** Tighten a bunch of statements together, and perform statement-level optimization. */
207
207
  export function tighten_body(statements, compressor) {
208
- var in_loop, in_try;
209
- var scope = compressor.find_parent(AST_Scope).get_defun_scope();
210
- find_loop_scope_try();
208
+ const nearest_scope = compressor.find_scope();
209
+ const defun_scope = nearest_scope.get_defun_scope();
210
+ const { in_loop, in_try } = find_loop_scope_try();
211
+
211
212
  var CHANGED, max_iter = 10;
212
213
  do {
213
214
  CHANGED = false;
@@ -231,19 +232,20 @@ export function tighten_body(statements, compressor) {
231
232
  } while (CHANGED && max_iter-- > 0);
232
233
 
233
234
  function find_loop_scope_try() {
234
- var node = compressor.self(), level = 0;
235
+ var node = compressor.self(), level = 0, in_loop = false, in_try = false;
235
236
  do {
236
237
  if (node instanceof AST_Catch || node instanceof AST_Finally) {
237
238
  level++;
238
239
  } else if (node instanceof AST_IterationStatement) {
239
240
  in_loop = true;
240
241
  } else if (node instanceof AST_Scope) {
241
- scope = node;
242
242
  break;
243
243
  } else if (node instanceof AST_Try) {
244
244
  in_try = true;
245
245
  }
246
246
  } while (node = compressor.parent(level++));
247
+
248
+ return { in_loop, in_try };
247
249
  }
248
250
 
249
251
  // Search from right to left for assignment-like expressions:
@@ -255,7 +257,7 @@ export function tighten_body(statements, compressor) {
255
257
  // Will not attempt to collapse assignments into or past code blocks
256
258
  // which are not sequentially executed, e.g. loops and conditionals.
257
259
  function collapse(statements, compressor) {
258
- if (scope.pinned())
260
+ if (nearest_scope.pinned() || defun_scope.pinned())
259
261
  return statements;
260
262
  var args;
261
263
  var candidates = [];
@@ -319,10 +321,11 @@ export function tighten_body(statements, compressor) {
319
321
  stop_if_hit = parent;
320
322
  }
321
323
  // Replace variable with assignment when found
322
- if (can_replace
324
+ if (
325
+ can_replace
323
326
  && !(node instanceof AST_SymbolDeclaration)
324
327
  && lhs.equivalent_to(node)
325
- && !shadows(node.scope, lvalues)
328
+ && !shadows(scanner.find_scope() || nearest_scope, lvalues)
326
329
  ) {
327
330
  if (stop_if_hit) {
328
331
  abort = true;
@@ -527,9 +530,9 @@ export function tighten_body(statements, compressor) {
527
530
  return true;
528
531
  if (node instanceof AST_SymbolRef && (fn.variables.has(node.name) || redefined_within_scope(node.definition(), fn))) {
529
532
  var s = node.definition().scope;
530
- if (s !== scope)
533
+ if (s !== defun_scope)
531
534
  while (s = s.parent_scope) {
532
- if (s === scope)
535
+ if (s === defun_scope)
533
536
  return true;
534
537
  }
535
538
  return found = true;
@@ -851,7 +854,7 @@ export function tighten_body(statements, compressor) {
851
854
  while (lhs instanceof AST_PropAccess)
852
855
  lhs = lhs.expression;
853
856
  return lhs instanceof AST_SymbolRef
854
- && lhs.definition().scope === scope
857
+ && lhs.definition().scope.get_defun_scope() === defun_scope
855
858
  && !(in_loop
856
859
  && (lvalues.has(lhs.name)
857
860
  || candidate instanceof AST_Unary
@@ -886,15 +889,11 @@ export function tighten_body(statements, compressor) {
886
889
  var def = sym.definition();
887
890
  if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun)
888
891
  return false;
889
- if (def.scope.get_defun_scope() !== scope)
892
+ if (def.scope.get_defun_scope() !== defun_scope)
890
893
  return true;
891
- return !def.references.every((ref) => {
892
- var s = ref.scope.get_defun_scope();
893
- // "block" scope within AST_Catch
894
- if (s.TYPE == "Scope")
895
- s = s.parent_scope;
896
- return s === scope;
897
- });
894
+ return def.references.some((ref) =>
895
+ ref.scope.get_defun_scope() !== defun_scope
896
+ );
898
897
  }
899
898
 
900
899
  function side_effects_external(node, lhs) {
@@ -910,18 +909,20 @@ export function tighten_body(statements, compressor) {
910
909
  if (node instanceof AST_Sub)
911
910
  return side_effects_external(node.expression, true);
912
911
  if (node instanceof AST_SymbolRef)
913
- return node.definition().scope !== scope;
912
+ return node.definition().scope.get_defun_scope() !== defun_scope;
914
913
  }
915
914
  return false;
916
915
  }
917
916
 
918
- function shadows(newScope, lvalues) {
919
- for (const {def} of lvalues.values()) {
920
- let current = newScope;
921
- while (current && current !== def.scope) {
922
- let nested_def = current.variables.get(def.name);
923
- if (nested_def && nested_def !== def) return true;
924
- current = current.parent_scope;
917
+ /**
918
+ * Will any of the pulled-in lvalues shadow a variable in newScope or parents?
919
+ * similar to scope_encloses_variables_in_this_scope */
920
+ function shadows(my_scope, lvalues) {
921
+ for (const { def } of lvalues.values()) {
922
+ const looked_up = my_scope.find_variable(def.name);
923
+ if (looked_up) {
924
+ if (looked_up === def) continue;
925
+ return true;
925
926
  }
926
927
  }
927
928
  return false;
@@ -1343,7 +1344,7 @@ export function tighten_body(statements, compressor) {
1343
1344
  break;
1344
1345
  if (def.name.name != sym.name)
1345
1346
  break;
1346
- if (!node.right.is_constant_expression(scope))
1347
+ if (!node.right.is_constant_expression(nearest_scope))
1347
1348
  break;
1348
1349
  var prop = node.left.property;
1349
1350
  if (prop instanceof AST_Node) {