Skip to content

Commit

Permalink
avoid drop-unused leaving behind the contents of an assignment. Relat…
Browse files Browse the repository at this point in the history
  • Loading branch information
fabiosantoscode committed Jun 5, 2024
1 parent 78d95b8 commit 14cc291
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 20 deletions.
19 changes: 12 additions & 7 deletions lib/compress/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,25 @@ export function has_break_or_continue(loop, parent) {
// func(something) because that changes the meaning of
// the func (becomes lexical instead of global).
export function maintain_this_binding(parent, orig, val) {
if (
if (requires_sequence_to_maintain_binding(parent, orig, val)) {
const zero = make_node(AST_Number, orig, { value: 0 });
return make_sequence(orig, [ zero, val ]);
} else {
return val;
}
}

/** Detect (1, x.noThis)(), (0, eval)(), which need sequences */
export function requires_sequence_to_maintain_binding(parent, orig, val) {
return (
parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|| parent instanceof AST_Call && parent.expression === orig
&& (
val instanceof AST_Chain
|| val instanceof AST_PropAccess
|| val instanceof AST_SymbolRef && val.name == "eval"
)
) {
const zero = make_node(AST_Number, orig, { value: 0 });
return make_sequence(orig, [ zero, val ]);
} else {
return val;
}
);
}

export function is_func_expr(node) {
Expand Down
54 changes: 53 additions & 1 deletion lib/compress/drop-unused.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
AST_Lambda,
AST_Number,
AST_Scope,
AST_Sequence,
AST_SimpleStatement,
AST_SymbolBlockDeclaration,
AST_SymbolCatch,
Expand Down Expand Up @@ -101,6 +102,7 @@ import {
is_empty,
is_ref_of,
can_be_evicted_from_block,
requires_sequence_to_maintain_binding,
} from "./common.js";

const r_keep_assign = /keep_assign/;
Expand Down Expand Up @@ -231,7 +233,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
var in_use = in_use_ids.has(def.id);
if (node instanceof AST_Assign) {
if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
return maintain_this_binding(parent, node, node.right.transform(tt));
const assignee = node.right.transform(tt);
if (!in_use && !assignee.has_side_effects(compressor) && !is_used_in_expression(tt)) {
return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
}
return maintain_this_binding(parent, node, assignee);
}
} else if (!in_use) {
return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
Expand Down Expand Up @@ -438,6 +444,14 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
scope = save_scope;
return node;
}
},
function after(node, in_list) {
if (node instanceof AST_Sequence && node.expressions.length === 1) {
switch (node.expressions.length) {
case 0: return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
case 1: return node.expressions[0];
}
}
}
);

Expand Down Expand Up @@ -484,3 +498,41 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
}
});

/**
* Check if a node may be used by the expression it's in
* void (0, 1, {node}, 2) -> false
* console.log(0, {node}) -> true
*/
function is_used_in_expression(tw) {
for (let p = -1, node, parent; node = tw.parent(p), parent = tw.parent(p + 1); p++) {
if (parent instanceof AST_Sequence) {
const nth_expression = parent.expressions.indexOf(node);
if (nth_expression !== parent.expressions.length - 1) {
// Detect (0, x.noThis)() constructs
const grandparent = tw.parent(p + 2);
if (
parent.expressions.length > 2
|| parent.expressions.length === 1
|| !requires_sequence_to_maintain_binding(grandparent, parent, parent.expressions[1])
) {
return false;
}
return true;
} else {
continue;
}
}
if (parent instanceof AST_Unary) {
const op = parent.operator;
if (op === "void") {
return false;
}
if (op === "typeof" || op === "+" || op === "-" || op === "!" || op === "~") {
continue;
}
}
return true;
}

return true;
}
62 changes: 50 additions & 12 deletions test/compress/drop-unused.js
Original file line number Diff line number Diff line change
Expand Up @@ -1139,12 +1139,12 @@ delete_assign_1: {
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
Expand All @@ -1167,12 +1167,12 @@ delete_assign_2: {
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((Infinity, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
Expand Down Expand Up @@ -2759,6 +2759,44 @@ unused_seq_elements: {
expect_stdout: "just-make-sure-it-is-compilable"
}

unused_assignments_caused_duplication: {
options = {
toplevel: true,
reduce_vars: true,
evaluate: true,
unused: true,
}
input: {
var R, fn = (R = "do not duplicate me", function(){ return useVar(R) });

leak(fn);
}
expect: {
var fn = function(){ return useVar("do not duplicate me") };

leak(fn);
}
}

unused_assignments_caused_duplication_preserve_this: {
options = {
toplevel: true,
reduce_vars: true,
evaluate: true,
unused: true,
}
input: {
var R, call = (R = "do preserve `this`", foo.bar)();

leak(call);
}
expect: {
var call = ("do preserve `this`", foo.bar)();

leak(call);
}
}

unused_class_with_static_props_side_effects: {
options = {
toplevel: true
Expand Down

0 comments on commit 14cc291

Please sign in to comment.