Compare commits

...

16 Commits

Author SHA1 Message Date
Alex Lam S.L
787dfbed64 enhance inline (#5871) 2024-06-30 14:00:05 +03:00
Alex Lam S.L
6b23899ef3 fix corner case in collapse_vars (#5870)
fixes #5869
2024-06-28 21:19:58 +03:00
Alex Lam S.L
8c5a899986 enhance collapse_vars, unsafe & unused (#5868) 2024-06-26 22:38:27 +03:00
Alex Lam S.L
ed36c1ec5c fix corner case in unused (#5867)
fixes #5866
2024-06-26 16:13:29 +03:00
Alex Lam S.L
ce8ef52e2b enhance hoist_vars (#5865) 2024-06-25 23:56:39 +03:00
Alex Lam S.L
6669ea19ef fix corner case in hoist_vars (#5864)
fixes #5863
2024-06-25 19:19:47 +03:00
Alex Lam S.L
205a1d1f19 fix corner case in reduce_vars (#5862)
fixes #5860
fixes #5861
2024-06-21 01:29:11 +03:00
Alex Lam S.L
95d3ede664 fix corner cases in pure_getters & reduce_vars (#5859)
fixes #5856
fixes #5857
fixes #5858
2024-06-20 17:43:55 +03:00
Alex Lam S.L
8195a664fd fix corner case in collapse_vars (#5855)
fixes #5854
2024-06-19 05:15:03 +03:00
Alex Lam S.L
9c80456634 enhance dead_code & side_effects (#5840)
closes #5794
2024-06-19 01:36:04 +03:00
Alex Lam S.L
dc7aa32172 fix corner case in inline (#5853)
fixes #5851
2024-06-17 10:37:18 +03:00
Alex Lam S.L
23d74bedeb fix corner cases in join_vars (#5852)
fixes #5849
fixes #5850
2024-06-17 09:11:11 +03:00
Alex Lam S.L
f31311e439 fix corner case in inline (#5848)
fixes #5844
2024-06-17 06:38:16 +03:00
Alex Lam S.L
87c9edbbc7 fix corner case in unused (#5847)
fixes #5843
2024-06-17 04:36:02 +03:00
Alex Lam S.L
8dc99fa25f fix corner case in inline (#5846)
fixes #5842
2024-06-17 02:09:06 +03:00
Alex Lam S.L
dc51a23d31 fix corner case in inline (#5845)
fixes #5841
2024-06-17 02:08:53 +03:00
17 changed files with 1170 additions and 92 deletions

View File

@@ -779,11 +779,11 @@ to be `false` and all symbol names will be omitted.
overhead (compression will be slower). Make sure symbols under `pure_funcs`
are also under `mangle.reserved` to avoid mangling.
- `pure_getters` (default: `"strict"`) — If you pass `true` for
this, UglifyJS will assume that object property access
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
`foo` is certain to not throw, i.e. not `null` or `undefined`.
- `pure_getters` (default: `"strict"`) — Pass `true` for UglifyJS to assume that
object property access (e.g. `foo.bar` or `a[42]`) does not throw exception or
alter program states via getter function. Pass `"strict"` to allow dropping or
reordering `foo.bar` only if `foo` is not `null` or `undefined` and is safe to
access as a variable. Pass `false` to retain all property accesses.
- `reduce_funcs` (default: `true`) — Allows single-use functions to be
inlined as function expressions when permissible allowing further

View File

@@ -169,8 +169,6 @@ DEF_BITPROPS(AST_Node, [
"private",
// AST_Call
"pure",
// AST_Assign
"redundant",
// AST_Node
"single_use",
// AST_ClassProperty

View File

@@ -185,7 +185,7 @@ function Compressor(options, false_by_default) {
};
}
Compressor.prototype = new TreeTransformer(function(node, descend, in_list) {
Compressor.prototype = new TreeTransformer(function(node, descend) {
if (node._squeezed) return node;
var is_scope = node instanceof AST_Scope;
if (is_scope) {
@@ -270,7 +270,7 @@ Compressor.prototype.compress = function(node) {
};
(function(OPT) {
OPT(AST_Node, function(self, compressor) {
OPT(AST_Node, function(self) {
return self;
});
@@ -638,15 +638,30 @@ Compressor.prototype.compress = function(node) {
}
function push(tw, sequential) {
var defined_ids = Object.create(tw.defined_ids);
var safe_ids = Object.create(tw.safe_ids);
if (!sequential) safe_ids.seq = {};
if (!sequential) {
defined_ids.seq = {};
safe_ids.seq = {};
}
tw.defined_ids = defined_ids;
tw.safe_ids = safe_ids;
}
function pop(tw) {
tw.defined_ids = Object.getPrototypeOf(tw.defined_ids);
tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
}
function access(tw, def) {
tw.defined_ids[def.id] = [ tw.defined_ids.seq ];
}
function assign(tw, def) {
var defined = tw.defined_ids[def.id];
if (defined) defined[0] = false;
}
function mark(tw, def) {
tw.safe_ids[def.id] = {};
}
@@ -939,9 +954,13 @@ Compressor.prototype.compress = function(node) {
return fixed_node;
}, visit);
walk_lambda(fn, tw);
var defined_ids = tw.defined_ids;
var safe_ids = tw.safe_ids;
pop_scope(tw, fn);
if (!aborts) tw.safe_ids = safe_ids;
if (!aborts) {
tw.defined_ids = defined_ids;
tw.safe_ids = safe_ids;
}
return true;
function visit(node, fixed) {
@@ -969,7 +988,6 @@ Compressor.prototype.compress = function(node) {
if (left.equals(right) && !left.has_side_effects(compressor)) {
right.walk(tw);
walk_prop(left);
node.redundant = true;
return true;
}
if (ld && right instanceof AST_LambdaExpression) {
@@ -995,6 +1013,7 @@ Compressor.prototype.compress = function(node) {
mark_assignment_to_arguments(left);
return walk_lazy();
}
assign(tw, ld);
ld.assignments++;
var fixed = ld.fixed;
if (is_modified(compressor, tw, node, node, 0)) {
@@ -1063,6 +1082,7 @@ Compressor.prototype.compress = function(node) {
return;
}
var d = sym.definition();
assign(tw, d);
d.assignments++;
if (!fixed || sym.in_arg || !safe_to_assign(tw, d)) {
walk();
@@ -1103,7 +1123,7 @@ Compressor.prototype.compress = function(node) {
def(AST_BlockScope, function(tw, descend, compressor) {
reset_block_variables(tw, compressor, this);
});
def(AST_Call, function(tw, descend) {
def(AST_Call, function(tw) {
var node = this;
var exp = node.expression;
if (exp instanceof AST_LambdaExpression) {
@@ -1134,6 +1154,7 @@ Compressor.prototype.compress = function(node) {
if (fixed instanceof AST_Lambda) {
mark_fn_def(tw, exp.definition(), fixed);
} else {
tw.defined_ids.seq = {};
tw.find_parent(AST_Scope).may_call_this();
}
return true;
@@ -1238,6 +1259,13 @@ Compressor.prototype.compress = function(node) {
tw.in_loop = save_loop;
return true;
});
def(AST_Dot, function(tw, descend) {
descend();
var node = this;
var expr = node.expression;
if (!node.optional && expr instanceof AST_SymbolRef) access(tw, expr.definition());
return true;
});
def(AST_For, function(tw, descend, compressor) {
var node = this;
reset_block_variables(tw, compressor, node);
@@ -1335,12 +1363,18 @@ Compressor.prototype.compress = function(node) {
pop_scope(tw, fn);
return true;
});
def(AST_Sub, function(tw) {
if (!this.optional) return;
this.expression.walk(tw);
push(tw, true);
this.property.walk(tw);
pop(tw);
def(AST_Sub, function(tw, descend) {
var node = this;
var expr = node.expression;
if (node.optional) {
expr.walk(tw);
push(tw, true);
node.property.walk(tw);
pop(tw);
} else {
descend();
if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
}
return true;
});
def(AST_Switch, function(tw, descend, compressor) {
@@ -1390,6 +1424,8 @@ Compressor.prototype.compress = function(node) {
var d = ref.definition();
var fixed = d.fixed || d.last_ref && d.last_ref.fixed;
push_ref(d, ref);
var defined = tw.defined_ids[d.id];
if (defined && defined[0] === tw.defined_ids.seq) ref.defined = true;
if (d.references.length == 1 && !d.fixed && d.orig[0] instanceof AST_SymbolDefun) {
tw.loop_ids[d.id] = tw.in_loop;
}
@@ -1577,6 +1613,7 @@ Compressor.prototype.compress = function(node) {
return node.value || make_node(AST_Undefined, node);
}, function(name, fixed) {
var d = name.definition();
assign(tw, d);
if (!d.first_decl && d.references.length == 0) d.first_decl = name;
if (fixed && safe_to_assign(tw, d, true)) {
mark(tw, d);
@@ -1618,6 +1655,9 @@ Compressor.prototype.compress = function(node) {
reset_flags(node);
return node.reduce_vars(tw, descend, compressor);
} : reset_flags);
// Side-effect tracking on sequential property access
tw.defined_ids = Object.create(null);
tw.defined_ids.seq = {};
// Flow control for visiting lambda definitions
tw.fn_scanning = null;
tw.fn_visited = [];
@@ -2653,13 +2693,13 @@ Compressor.prototype.compress = function(node) {
}
if (node instanceof AST_ObjectIdentity) return symbol_in_lvalues(node, parent);
if (node instanceof AST_PropAccess) {
if (side_effects) return true;
var exp = node.expression;
if (exp instanceof AST_SymbolRef && is_arguments(exp.definition())) return true;
if (compressor.option("unsafe")) {
if (is_undeclared_ref(exp) && global_names[exp.name]) return false;
if (is_static_fn(exp)) return false;
}
if (exp instanceof AST_SymbolRef && is_arguments(exp.definition())) return true;
if (side_effects) return true;
if (!well_defined) return true;
if (value_def) return false;
if (!in_try && lhs_local) return false;
@@ -2668,6 +2708,7 @@ Compressor.prototype.compress = function(node) {
}
if (node instanceof AST_Spread) return true;
if (node instanceof AST_SymbolRef) {
if (is_undeclared_ref(node) && node.is_declared(compressor)) return false;
if (symbol_in_lvalues(node, parent)) return !is_direct_assignment(node, parent);
if (side_effects && may_modify(node)) return true;
var def = node.definition();
@@ -2687,8 +2728,10 @@ Compressor.prototype.compress = function(node) {
if (sym instanceof AST_PropAccess) return true;
if (check_destructured(sym)) return true;
return sym.match_symbol(function(node) {
return node instanceof AST_SymbolRef
&& (lvalues.has(node.name) || read_toplevel && compressor.exposed(node.definition()));
if (node instanceof AST_PropAccess) return true;
if (node instanceof AST_SymbolRef) {
return lvalues.has(node.name) || read_toplevel && compressor.exposed(node.definition());
}
}, true);
function reject(node) {
@@ -3284,10 +3327,14 @@ Compressor.prototype.compress = function(node) {
}
function update_symbols(value, node) {
var clear_defined = node instanceof AST_SymbolRef && !node.defined;
var scope = node.scope || find_scope(scanner) || block_scope;
value.walk(new TreeWalker(function(node) {
if (node instanceof AST_BlockScope) return true;
if (node instanceof AST_Symbol) node.scope = scope;
if (node instanceof AST_Symbol) {
if (clear_defined && node instanceof AST_SymbolRef) node.defined = false;
node.scope = scope;
}
}));
}
@@ -4300,18 +4347,18 @@ Compressor.prototype.compress = function(node) {
if (prop instanceof AST_Node) return;
if (!RE_POSITIVE_INTEGER.test("" + prop)) return;
prop = +prop;
var len = value.elements.length;
var elements = value.elements;
var len = elements.length;
if (prop > len + 4) return;
for (var i = Math.min(len, prop + 1); --i >= 0;) {
if (elements[i] instanceof AST_Spread) return;
}
if (prop < len) {
var element = value.elements[prop];
if (element instanceof AST_Hole) {
value.elements[prop] = node.right;
} else {
value.elements[prop] = make_sequence(node, [ element, node.right ]).optimize(compressor);
}
var element = elements[prop].drop_side_effect_free(compressor);
elements[prop] = element ? make_sequence(node, [ element, node.right ]) : node.right;
} else {
while (prop > len) value.elements[len++] = make_node(AST_Hole, value);
value.elements[prop] = node.right;
while (prop > len) elements[len++] = make_node(AST_Hole, value);
elements[prop] = node.right;
}
return true;
}
@@ -4712,6 +4759,7 @@ Compressor.prototype.compress = function(node) {
return this.tail_node()._dot_throw(compressor);
});
def(AST_SymbolRef, function(compressor, force) {
if (this.defined) return false;
if (this.is_undefined) return true;
if (!is_strict(compressor, force)) return false;
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
@@ -7982,8 +8030,14 @@ Compressor.prototype.compress = function(node) {
prop.walk(tw);
});
if (node instanceof AST_Assign) {
var right = get_rhs(node), shared = false;
if (init && node.write_only === true && !right.has_side_effects(compressor)) {
var fixed = sym.fixed_value();
var right = get_rhs(node);
var safe = fixed && fixed.is_constant();
var shared = false;
if (init
&& node.write_only === true
&& (safe || node.left === sym || right.equals(sym))
&& !right.has_side_effects(compressor)) {
initializations.add(node_def.id, right);
} else {
right.walk(tw);
@@ -7993,11 +8047,8 @@ Compressor.prototype.compress = function(node) {
if (!node.write_only || shared) {
verify_safe_usage(node_def, sym, value_modified[node_def.id]);
}
} else {
var fixed = sym.fixed_value();
if (!fixed || !fixed.is_constant()) {
verify_safe_usage(node_def, value_read[node_def.id], true);
}
} else if (!safe) {
verify_safe_usage(node_def, value_read[node_def.id], true);
}
}
if (track_assigns(node_def, sym) && is_lhs(sym, node) !== sym) add_assigns(node_def, sym);
@@ -8083,6 +8134,7 @@ Compressor.prototype.compress = function(node) {
}
function trim_destructured(node, value, process, drop, root) {
var unwind = true;
var trimmer = new TreeTransformer(function(node) {
if (node instanceof AST_DefaultValue) {
if (!(compressor.option("default_values") && value && value.is_defined(compressor))) {
@@ -8100,21 +8152,27 @@ Compressor.prototype.compress = function(node) {
}
if (node instanceof AST_DestructuredArray) {
var save_drop = drop;
var save_unwind = unwind;
var save_value = value;
if (value instanceof AST_SymbolRef) {
drop = false;
value = value.fixed_value();
}
var native, values;
var last_side_effects, native, values;
if (value instanceof AST_Array) {
native = true;
values = value.elements;
if (save_unwind) for (last_side_effects = values.length; --last_side_effects >= 0;) {
if (values[last_side_effects].has_side_effects(compressor)) break;
}
} else {
native = value && value.is_string(compressor);
values = false;
last_side_effects = node.elements.length;
}
var elements = [], newValues = drop && [], pos = 0;
node.elements.forEach(function(element, index) {
if (save_unwind) unwind = index >= last_side_effects;
value = values && values[index];
if (value instanceof AST_Hole) {
value = null;
@@ -8157,6 +8215,7 @@ Compressor.prototype.compress = function(node) {
}
}
value = save_value;
unwind = save_unwind;
drop = save_drop;
if (values && newValues) {
fill_holes(value, newValues);
@@ -8165,22 +8224,34 @@ Compressor.prototype.compress = function(node) {
}
if (!native) {
elements.length = node.elements.length;
} else if (!node.rest) switch (elements.length) {
} else if (!node.rest) SHORTHAND: switch (elements.length) {
case 0:
if (node === root) break;
if (drop) value = value.drop_side_effect_free(compressor);
return null;
case 1:
default:
if (!drop) break;
if (!unwind) break;
if (node === root) break;
var sym = elements[0];
var pos = elements.length, sym;
while (--pos >= 0) {
var element = elements[pos];
if (element) {
sym = element;
break;
}
}
if (pos < 0) break;
for (var i = pos; --i >= 0;) {
if (elements[i]) break SHORTHAND;
}
if (sym.has_side_effects(compressor)) break;
if (value.has_side_effects(compressor) && sym.match_symbol(function(node) {
return node instanceof AST_PropAccess;
})) break;
value = make_node(AST_Sub, node, {
expression: value,
property: make_node(AST_Number, node, { value: 0 }),
property: make_node(AST_Number, node, { value: pos }),
});
return sym;
}
@@ -8190,16 +8261,19 @@ Compressor.prototype.compress = function(node) {
}
if (node instanceof AST_DestructuredObject) {
var save_drop = drop;
var save_unwind = unwind;
var save_value = value;
if (value instanceof AST_SymbolRef) {
drop = false;
value = value.fixed_value();
}
var prop_keys, prop_map, values;
var last_side_effects, prop_keys, prop_map, values;
if (value instanceof AST_Object) {
last_side_effects = -1;
prop_keys = [];
prop_map = new Dictionary();
values = value.properties.map(function(prop, index) {
if (save_unwind && prop.has_side_effects(compressor)) last_side_effects = index;
prop = prop.clone();
if (prop instanceof AST_Spread) {
prop_map = false;
@@ -8215,6 +8289,8 @@ Compressor.prototype.compress = function(node) {
}
return prop;
});
} else {
last_side_effects = node.properties.length;
}
if (node.rest) {
value = false;
@@ -8237,6 +8313,7 @@ Compressor.prototype.compress = function(node) {
return key;
}).forEach(function(key, index) {
var prop = node.properties[index], trimmed;
if (save_unwind) unwind = index >= last_side_effects;
if (key instanceof AST_Node) {
drop = false;
value = false;
@@ -8277,6 +8354,7 @@ Compressor.prototype.compress = function(node) {
}
});
value = save_value;
unwind = save_unwind;
drop = save_drop;
if (drop_keys && prop_keys) {
value = value.clone();
@@ -8284,6 +8362,7 @@ Compressor.prototype.compress = function(node) {
if (prop instanceof AST_Spread) return prop;
var key = prop_keys[index];
if (key instanceof AST_Node) return prop;
if (key === "__proto__") return prop;
if (drop_keys.has(key)) {
var mapped = drop_keys.get(key);
if (!mapped) return prop;
@@ -8310,6 +8389,7 @@ Compressor.prototype.compress = function(node) {
return null;
case 1:
if (!drop) break;
if (!unwind) break;
if (node === root) break;
var prop = properties[0];
if (prop.key instanceof AST_Node) break;
@@ -8317,7 +8397,10 @@ Compressor.prototype.compress = function(node) {
if (value.has_side_effects(compressor) && prop.value.match_symbol(function(node) {
return node instanceof AST_PropAccess;
})) break;
value = make_node(AST_Sub, node, {
value = is_identifier_string(prop.key) ? make_node(AST_Dot, node, {
expression: value,
property: prop.key,
}) : make_node(AST_Sub, node, {
expression: value,
property: make_node_from_constant(prop.key, prop),
});
@@ -8434,7 +8517,8 @@ Compressor.prototype.compress = function(node) {
&& self.find_variable(sym.name) === sym.definition();
})) return node;
node.definitions.forEach(function(defn) {
vars.set(defn.name.name, defn);
var name = defn.name.name;
if (!vars.has(name)) vars.set(name, defn);
});
var seq = node.to_assignments();
if (p instanceof AST_ForEnumeration && p.init === node) {
@@ -8461,13 +8545,14 @@ Compressor.prototype.compress = function(node) {
return !ref.in_arg;
})) vars.del(argname.name);
});
vars.each(function(defn, name) {
vars.each(function(defn) {
var name = defn.name;
defn = defn.clone();
defn.name = defn.name.clone();
defn.name = name.clone();
defn.value = null;
defns.push(defn);
vars.set(name, defn);
defn.name.definition().orig.unshift(defn.name);
var orig = name.definition().orig;
orig.splice(orig.indexOf(name), 0, defn.name);
});
if (defns.length > 0) hoisted.push(make_node(AST_Var, self, { definitions: defns }));
}
@@ -10298,10 +10383,9 @@ Compressor.prototype.compress = function(node) {
}
});
def.references.push(name);
def.assignments++;
}
def.assignments++;
def.eliminated++;
def.single_use = false;
return a;
}, []);
if (assignments.length == 0) return null;
@@ -10924,9 +11008,11 @@ Compressor.prototype.compress = function(node) {
&& (value = can_flatten_body(stat))) {
var replacing = exp === fn || def.single_use && def.references.length - def.replaced == 1;
if (can_substitute_directly()) {
self._optimized = true;
var retValue = value.optimize(compressor).clone(true);
var args = self.args.slice();
var refs = [];
var retValue = value.clone(true).transform(new TreeTransformer(function(node) {
retValue = retValue.transform(new TreeTransformer(function(node) {
if (node instanceof AST_SymbolRef) {
var def = node.definition();
if (fn.variables.get(node.name) !== def) {
@@ -11158,6 +11244,10 @@ Compressor.prototype.compress = function(node) {
return;
}
if (node instanceof AST_Class) return abort = true;
if (node instanceof AST_Destructured) {
side_effects = true;
return;
}
if (node instanceof AST_Scope) return abort = true;
if (avoid && node instanceof AST_Symbol && avoid[node.name]) return abort = true;
if (node instanceof AST_SymbolRef) {
@@ -12945,16 +13035,14 @@ Compressor.prototype.compress = function(node) {
if (compressor.option("dead_code")) {
if (self.left instanceof AST_PropAccess) {
if (self.operator == "=") {
if (self.redundant) {
var exprs = [ self.left.expression ];
if (self.left instanceof AST_Sub) exprs.push(self.left.property);
exprs.push(self.right);
return make_sequence(self, exprs).optimize(compressor);
}
if (self.left.equals(self.right) && !self.left.has_side_effects(compressor)) {
return self.right;
}
var exp = self.left.expression;
if (self.left.equals(self.right)) {
var defined = exp.defined;
exp.defined = false;
var drop_lhs = !self.left.has_side_effects(compressor);
exp.defined = defined;
if (drop_lhs) return self.right;
}
if (exp instanceof AST_Lambda
|| !compressor.has_directive("use strict")
&& exp instanceof AST_Constant
@@ -14162,7 +14250,8 @@ Compressor.prototype.compress = function(node) {
stat.walk(new TreeWalker(function(node) {
if (abort) return true;
if (node instanceof AST_Try) {
if (node.bfinally && all(node.body, function(stat) {
if (!node.bfinally) return;
if (all(node.body, function(stat) {
stat.walk(find_return);
return !abort;
}) && node.bcatch) node.bcatch.walk(find_return);

View File

@@ -1312,7 +1312,7 @@ issue_5653: {
}
expect: {
console.log((a => {
return console, +{};
return +{};
})());
}
expect_stdout: "NaN"

View File

@@ -4996,7 +4996,7 @@ cascade_forin: {
]
}
unsafe_builtin: {
unsafe_builtin_1: {
options = {
collapse_vars: true,
pure_getters: "strict",
@@ -5020,6 +5020,46 @@ unsafe_builtin: {
expect_stdout: "1 4"
}
unsafe_builtin_2: {
options = {
collapse_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
A = "PASS";
var a = A;
console.log(a);
}
expect: {
console.log(A = "PASS");
}
expect_stdout: "PASS"
}
unsafe_builtin_3: {
options = {
collapse_vars: true,
unsafe: true,
unused: true,
}
input: {
A = "PASS";
(function() {
var a = A;
console.log(a);
})();
}
expect: {
A = "PASS";
(function() {
console.log(A);
})();
}
expect_stdout: "PASS"
}
return_1: {
options = {
collapse_vars: true,
@@ -7350,30 +7390,39 @@ substitution_assign: {
b = 1 + (b = a);
console.log(a, b);
}
function f4(a, b) {
b = 1 + (a = b);
console.log(a, b);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
f4("bar", 41);
}
expect: {
function f1(a, b) {
console.log(f1 = a, a);
}
function f2(a, b) {
a = 1 + (b = a);
console.log(a, b);
console.log(a = 1 + (b = a), b);
}
function f3(a, b) {
b = 1 + (b = a);
console.log(a, b = 1 + (b = a));
}
function f4(a, b) {
b = 1 + (a = b);
console.log(a, b);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
f4("bar", 41);
}
expect_stdout: [
"42 42",
"43 42",
"42 43",
"41 42",
]
}
@@ -10284,3 +10333,27 @@ issue_1666_undefined_strict: {
}
expect_stdout: true
}
issue_5869: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a, b, log = console.log;
log();
a.p = 0;
b = a;
log(b);
}
expect: {
var a, log = console.log;
log();
log(void (a.p = 0));
}
expect_stdout: TypeError("Cannot set properties of undefined")
}

View File

@@ -2293,7 +2293,7 @@ issue_5340_3: {
}
expect: {
var a;
(function() {})(a = true["p"]);
(function() {})(a = true.p);
console.log(a);
}
expect_stdout: "undefined"
@@ -3107,3 +3107,31 @@ issue_5774: {
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5863: {
options = {
collapse_vars: true,
hoist_vars: true,
}
input: {
console.log(typeof function f(a = function() {
f = 42;
return f;
}()) {
var f;
var f;
return a;
}());
}
expect: {
console.log(typeof function f(a = function() {
f = 42;
return f;
}()) {
var f;
return a;
}());
}
expect_stdout: "function"
node_version: ">=6"
}

View File

@@ -1339,7 +1339,7 @@ maintain_position_var: {
}
expect: {
A = "FAIL";
var [ , b ] = [ A ];
var b = [ A ][1];
console.log(b || "PASS");
}
expect_stdout: "PASS"
@@ -1382,7 +1382,7 @@ side_effects_object: {
}
}
expect: {
var a = null, c = (console, 42["c"]);
var a = null, c = (console, 42..c);
try {
c[a = "PASS"];
} catch (e) {
@@ -1684,7 +1684,7 @@ singleton_1: {
expect: {
var b, a = "P"[0], o = {};
o.p = [ "FAIL"["1"] ][0];
o.q = { foo: "S"[0] }["foo"];
o.q = { foo: "S"[0] }.foo;
[ b = "S" ] = [];
console.log(a + o.p + o.q + b);
}
@@ -3886,3 +3886,358 @@ issue_5651: {
expect_stdout: true
node_version: ">=6"
}
issue_5843_1: {
options = {
unused: true,
}
input: {
var { p: a } = {
__proto__: {
p: "PASS",
},
};
console.log(a);
}
expect: {
var a = {
__proto__: {
p: "PASS",
},
}.p;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5843_2: {
options = {
side_effects: true,
unused: true,
}
input: {
var a;
({ p: a } = {
__proto__: {
p: "PASS",
},
});
console.log(a);
}
expect: {
var a;
a = {
__proto__: {
p: "PASS",
},
}.p;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5844: {
options = {
inline: true,
}
input: {
try {
(function(a) {
[ a.p ] = 42;
})(console.log("PASS"));
} catch (e) {}
}
expect: {
try {
(function(a) {
[ a.p ] = 42;
})(console.log("PASS"));
} catch (e) {}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5854_1: {
options = {
collapse_vars: true,
}
input: {
console.log(function(a) {
var b = a;
a++;
[ b[0] ] = [ "foo" ];
return a;
}([]) ? "PASS" : "FAIL");
}
expect: {
console.log(function(a) {
var b = a;
a++;
[ b[0] ] = [ "foo" ];
return a;
}([]) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5854_2: {
options = {
collapse_vars: true,
}
input: {
console.log(function(a) {
var b = a;
a++;
({ p: b[0] } = { p: "foo" });
return a;
}([]) ? "PASS" : "FAIL");
}
expect: {
console.log(function(a) {
var b = a;
a++;
({ p: b[0] } = { p: "foo" });
return a;
}([]) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_1: {
options = {
unused: true,
}
input: {
var a = {};
var { p: { q: b } } = {
p: a,
r: a.q = "PASS",
};
console.log(b);
}
expect: {
var a = {};
var { q: b } = {
p: a,
r: a.q = "PASS",
}.p;
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_2: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b;
({ p: { q: b } } = {
p: a,
r: a.q = "PASS",
});
console.log(b);
}
expect: {
var b, a = {};
({ q: b } = {
p: a,
r: a.q = "PASS",
}.p);
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_3: {
options = {
unused: true,
}
input: {
var a = {};
var [ { p: b } ] = [ a, a.p = "PASS" ];
console.log(b);
}
expect: {
var a = {};
var { p: b } = [ a, a.p = "PASS" ][0];
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_4: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b;
[ { p: b } ] = [ a, a.p = "PASS" ];
console.log(b);
}
expect: {
var b, a = {};
({ p: b } = [ a, a.p = "PASS" ][0]);
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_5: {
options = {
unused: true,
}
input: {
var a = [];
var [ [ b ] ] = [ a, a[0] = "PASS" ];
console.log(b);
}
expect: {
var a = [];
var [ b ] = [ a, a[0] = "PASS" ][0];
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_6: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = [], b;
[ [ b ] ] = [ a, a[0] = "PASS" ];
console.log(b);
}
expect: {
var b, a = [];
[ b ] = [ a, a[0] = "PASS" ][0];
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_7: {
options = {
unused: true,
}
input: {
var a = {};
var [ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var a = {};
var [ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_8: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b, c;
[ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var b, c, a = {};
[ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_9: {
options = {
unused: true,
}
input: {
var a = {};
var [ b, { p: c } ] = [ a.p = {}, a ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var a = {};
var [ b, c ] = [ a.p = {}, a.p ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_10: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b, c;
[ b, { p: c } ] = [ a.p = {}, a ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var b, c, a = {};
[ b, c ] = [ a.p = {}, a.p ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_11: {
options = {
unused: true,
}
input: {
var a = {};
var { p: { q: b } } = { p: a = { q: {} } };
console.log(a.q === b ? "PASS" : "FAIL");
}
expect: {
var a = {};
var b = { p: (a = { q: {} }).q }.p;
console.log(a.q === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_12: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b;
({ p: { q: b } } = { p: a = { q: {} } });
console.log(a.q === b ? "PASS" : "FAIL");
}
expect: {
var b, a = {};
b = { p: (a = { q: {} }).q }.p;
console.log(a.q === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -260,7 +260,7 @@ hoist_exports_2: {
}
}
expect: {
let e, a = 42["foo"];
let e, a = 42..foo;
function f(t, { [e]: o }) {
t(o, f);
}

View File

@@ -8817,3 +8817,157 @@ issue_5766_2: {
}
expect_stdout: "function"
}
issue_5841_1: {
options = {
conditionals: true,
evaluate: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = 42;
(function() {
f();
var b = f();
function f() {
if (console && a)
g && g();
}
function g() {
var c;
for (;console.log("foo"););
(function h(d) {
d && d.p;
})();
}
})();
}
expect: {
var a = 42;
(function() {
f();
f();
function f() {
{
if (console && a) {
for (;console.log("foo"););
return;
}
return;
}
}
})();
}
expect_stdout: [
"foo",
"foo",
]
}
issue_5841_2: {
options = {
conditionals: true,
evaluate: true,
if_return: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = 42;
(function() {
f();
var b = f();
function f() {
if (console && a)
g && g();
}
function g() {
var c;
for (;console.log("foo"););
(function h(d) {
d && d.p;
})();
}
})();
}
expect: {
var a = 42;
(function() {
f();
f();
function f() {
if (console && a)
for (;console.log("foo"););
}
})();
}
expect_stdout: [
"foo",
"foo",
]
}
issue_5851_1: {
options = {
inline: true,
reduce_vars: true,
toplevel: true,
}
input: {
console.log("PASS") && f();
function f() {
return f();
}
f;
}
expect: {
console.log("PASS") && f();
function f() {
return f();
}
f;
}
expect_stdout: "PASS"
}
issue_5851_2: {
options = {
conditionals: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = f();
f();
function f() {
if (console.log("foo"))
console && f();
}
}
expect: {
f();
f();
function f() {
console.log("foo") && console && f();
}
}
expect_stdout: [
"foo",
"foo",
]
}

View File

@@ -228,6 +228,7 @@ issue_4489: {
evaluate: true,
hoist_vars: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
@@ -363,6 +364,7 @@ issue_4893_1: {
evaluate: true,
hoist_vars: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
@@ -383,9 +385,8 @@ issue_4893_1: {
}
expect: {
try{
(function f() {
(function() {
null.p += 42;
f;
})();
} catch (e) {
console.log("PASS");
@@ -422,9 +423,7 @@ issue_4893_2: {
expect: {
try{
(function() {
var a;
a = null;
a.p += 42;
null.p += 42;
})();
} catch (e) {
console.log("PASS");
@@ -610,6 +609,7 @@ issue_5411_2: {
evaluate: true,
hoist_vars: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
@@ -622,9 +622,9 @@ issue_5411_2: {
}
expect: {
var b, c;
b++;
b++,
b = "PASS",
c;
c,
console.log(b);
}
expect_stdout: "PASS"

View File

@@ -26,7 +26,7 @@ record_update: {
currying: {
options = {
inline: true,
passes: 2,
passes: 3,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,

View File

@@ -23,7 +23,7 @@ join_array_assignments_1: {
}
input: {
console.log(function () {
var a = ["foo", , "bar"];
var a = [ "foo", , "bar" ];
a[1] = "baz";
a[7] = "moo";
a[0] = "moz";
@@ -32,7 +32,7 @@ join_array_assignments_1: {
}
expect: {
console.log(function () {
var a = [("foo", "moz"), "baz", "bar", , , , , "moo"];
var a = [ "moz", "baz", "bar", , , , , "moo" ];
return a;
}().join());
}
@@ -46,7 +46,7 @@ join_array_assignments_2: {
}
input: {
console.log(function () {
var a = ["foo"];
var a = [ "foo" ];
a[1] = "bar";
a[7] = "baz";
a[2] = "moo";
@@ -55,7 +55,7 @@ join_array_assignments_2: {
}
expect: {
console.log(function () {
var a = ["foo", "bar"];
var a = [ "foo", "bar" ];
a[7] = "baz";
a[2] = "moo";
return a;
@@ -71,7 +71,7 @@ join_array_assignments_3: {
}
input: {
console.log(function () {
var a = ["foo"];
var a = [ "foo" ];
a[1] = "bar";
a.b = "baz";
a[2] = "moo";
@@ -80,7 +80,7 @@ join_array_assignments_3: {
}
expect: {
console.log(function () {
var a = ["foo", "bar"];
var a = [ "foo", "bar" ];
a.b = "baz";
a[2] = "moo";
return a;
@@ -97,7 +97,7 @@ join_array_assignments_4: {
}
input: {
console.log(function () {
var a = ["foo"];
var a = [ "foo" ];
a[0] = "bar";
a[1] = a;
a[2] = "baz";
@@ -106,7 +106,7 @@ join_array_assignments_4: {
}
expect: {
console.log(function () {
var a = ["bar"];
var a = [ "bar" ];
a[1] = a;
a[2] = "baz";
return a;
@@ -1508,3 +1508,22 @@ issue_5831: {
}
expect_stdout: "PASS"
}
issue_5849: {
options = {
evaluate: true,
join_vars: true,
side_effects: true,
}
input: {
var a;
a = [ 42 ];
a[0] = "PASS";
console.log(a.join(""));
}
expect: {
var a, a = [ "PASS" ];
console.log(a.join(""));
}
expect_stdout: "PASS"
}

View File

@@ -617,3 +617,33 @@ issue_5292_sub_pure_getters_strict: {
]
node_version: ">=14"
}
issue_5856: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
try {
var a;
a?.p;
a.q;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
var a;
a?.p;
a.q;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=14"
}

View File

@@ -1687,3 +1687,31 @@ issue_4939: {
}
expect_stdout: "PASS"
}
issue_5856: {
options = {
pure_getters: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = [ "FAIL", "PASS" ];
(function(b) {
var c = b[0];
b[0] = b[1];
b[1] = c;
})(a);
console.log(a[0]);
}
expect: {
var a = [ "FAIL", "PASS" ];
(function(b) {
var c = b[0];
b[0] = b[1];
b[1] = c;
})(a);
console.log(a[0]);
}
expect_stdout: "PASS"
}

View File

@@ -724,3 +724,246 @@ retain_instanceof: {
}
expect_stdout: "PASS"
}
drop_access: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var o = {};
o.p;
try {
(function() {
o.q;
})();
console.log("PASS");
} catch (e) {
console.log("FAIL");
}
}
expect: {
var o = {};
o.p;
try {
console.log("PASS");
} catch (e) {
console.log("FAIL");
}
}
expect_stdout: "PASS"
}
keep_access: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var o = {};
o.p;
o = null;
try {
(function() {
o.q;
})();
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
var o = {};
o.p;
o = null;
try {
(function() {
o.q;
})();
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
keep_access_after_call: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var o = {};
o.p;
o.q;
f();
try {
o.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
function f() {
o = null;
}
}
expect: {
var o = {};
o.p;
f();
try {
o.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
function f() {
o = null;
}
}
expect_stdout: "PASS"
}
issue_5860_drop_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var a = {};
a.p;
var a;
a.q;
console.log("PASS");
}
expect: {
var a = {};
a.p;
var a;
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_5860_drop_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
a = {};
a.p;
var a;
a.q;
console.log("PASS");
}
expect: {
a = {};
a.p;
var a;
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_5860_keep_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var a = {};
a.p;
a.q;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
var a = {};
a.p;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_5860_keep_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
a = {};
a.p;
a.q;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
a = {};
a.p;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_5860_keep_3: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var a = {};
a.p;
a.q;
a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
var a = {};
a.p;
a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}

View File

@@ -1253,3 +1253,24 @@ issue_5602: {
]
node_version: ">=6"
}
issue_5850: {
options = {
evaluate: true,
join_vars: true,
unused: true,
}
input: {
var a = [ ..."FAIL" ];
a[0] = "P";
a[2] = a[3] = "S";
console.log(a.join(""));
}
expect: {
var a = [ ..."FAIL" ];
a[0] = "P";
a[2] = a[3] = "S";
console.log(a.join(""));
}
node_version: ">=6"
}

View File

@@ -1386,7 +1386,7 @@ issue_5076_1: {
expect: {
var a;
console.log("PASS"),
a = 42["a"];
a = 42..a;
}
expect_stdout: "PASS"
node_version: ">=6"
@@ -2207,3 +2207,43 @@ issue_5754: {
]
node_version: ">=10"
}
issue_5842: {
options = {
inline: true,
}
input: {
var a = "FAIL";
(async function*() {
(function() {
try {
try {
return console;
} finally {
a = "PASS";
}
} catch (e) {}
FAIL;
})();
})().next();
console.log(a);
}
expect: {
var a = "FAIL";
(async function*() {
(function() {
try {
try {
return console;
} finally {
a = "PASS";
}
} catch (e) {}
FAIL;
})();
})().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}