保誠-保戶業務員媒合平台
HelenHuang
2022-06-09 9bdb95c9e34cef640534e5e5a1e2225a80442000
PAMapp/node_modules/uglify-js/lib/compress.js
@@ -116,12 +116,10 @@
    var global_defs = this.options["global_defs"];
    if (typeof global_defs == "object") for (var key in global_defs) {
        if (/^@/.test(key) && HOP(global_defs, key)) {
            global_defs[key.slice(1)] = parse(global_defs[key], {
                expression: true
            });
            global_defs[key.slice(1)] = parse(global_defs[key], { expression: true });
        }
    }
    if (this.options["inline"] === true) this.options["inline"] = 3;
    if (this.options["inline"] === true) this.options["inline"] = 4;
    this.drop_fargs = this.options["keep_fargs"] ? return_false : function(lambda, parent) {
        if (lambda.length_read) return false;
        var name = lambda.name;
@@ -185,88 +183,85 @@
    };
}
Compressor.prototype = new TreeTransformer;
merge(Compressor.prototype, {
    option: function(key) { return this.options[key] },
    exposed: function(def) {
        if (def.exported) return true;
        if (def.undeclared) return true;
        if (!(def.global || def.scope.resolve() instanceof AST_Toplevel)) return false;
        var toplevel = this.toplevel;
        return !all(def.orig, function(sym) {
            return toplevel[sym instanceof AST_SymbolDefun ? "funcs" : "vars"];
        });
    },
    compress: function(node) {
        node = node.resolve_defines(this);
        node.hoist_exports(this);
        if (this.option("expression")) {
            node.process_expression(true);
        }
        var passes = +this.options.passes || 1;
        var min_count = 1 / 0;
        var stopping = false;
        var mangle = { ie: this.option("ie") };
        for (var pass = 0; pass < passes; pass++) {
            node.figure_out_scope(mangle);
            if (pass > 0 || this.option("reduce_vars"))
                node.reset_opt_flags(this);
            node = node.transform(this);
            if (passes > 1) {
                var count = 0;
                node.walk(new TreeWalker(function() {
                    count++;
                }));
                AST_Node.info("pass {pass}: last_count: {min_count}, count: {count}", {
                    pass: pass,
                    min_count: min_count,
                    count: count,
                });
                if (count < min_count) {
                    min_count = count;
                    stopping = false;
                } else if (stopping) {
                    break;
                } else {
                    stopping = true;
                }
Compressor.prototype = new TreeTransformer(function(node, descend, in_list) {
    if (node._squeezed) return node;
    var is_scope = node instanceof AST_Scope;
    if (is_scope) {
        node.hoist_properties(this);
        node.hoist_declarations(this);
        node.process_returns(this);
    }
    // Before https://github.com/mishoo/UglifyJS/pull/1602 AST_Node.optimize()
    // would call AST_Node.transform() if a different instance of AST_Node is
    // produced after OPT().
    // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction.
    // Migrate and defer all children's AST_Node.transform() to below, which
    // will now happen after this parent AST_Node has been properly substituted
    // thus gives a consistent AST snapshot.
    descend(node, this);
    // Existing code relies on how AST_Node.optimize() worked, and omitting the
    // following replacement call would result in degraded efficiency of both
    // output and performance.
    descend(node, this);
    var opt = node.optimize(this);
    if (is_scope && opt === node && !this.has_directive("use asm") && !opt.pinned()) {
        opt.drop_unused(this);
        if (opt.merge_variables(this)) opt.drop_unused(this);
        descend(opt, this);
    }
    if (opt === node) opt._squeezed = true;
    return opt;
});
Compressor.prototype.option = function(key) {
    return this.options[key];
};
Compressor.prototype.exposed = function(def) {
    if (def.exported) return true;
    if (def.undeclared) return true;
    if (!(def.global || def.scope.resolve() instanceof AST_Toplevel)) return false;
    var toplevel = this.toplevel;
    return !all(def.orig, function(sym) {
        return toplevel[sym instanceof AST_SymbolDefun ? "funcs" : "vars"];
    });
};
Compressor.prototype.compress = function(node) {
    node = node.resolve_defines(this);
    node.hoist_exports(this);
    if (this.option("expression")) node.process_expression(true);
    var merge_vars = this.options.merge_vars;
    var passes = +this.options.passes || 1;
    var min_count = 1 / 0;
    var stopping = false;
    var mangle = { ie: this.option("ie") };
    for (var pass = 0; pass < passes; pass++) {
        node.figure_out_scope(mangle);
        if (pass > 0 || this.option("reduce_vars"))
            node.reset_opt_flags(this);
        this.options.merge_vars = merge_vars && (stopping || pass == passes - 1);
        node = node.transform(this);
        if (passes > 1) {
            var count = 0;
            node.walk(new TreeWalker(function() {
                count++;
            }));
            AST_Node.info("pass {pass}: last_count: {min_count}, count: {count}", {
                pass: pass,
                min_count: min_count,
                count: count,
            });
            if (count < min_count) {
                min_count = count;
                stopping = false;
            } else if (stopping) {
                break;
            } else {
                stopping = true;
            }
        }
        if (this.option("expression")) {
            node.process_expression(false);
        }
        return node;
    },
    before: function(node, descend, in_list) {
        if (node._squeezed) return node;
        var is_scope = node instanceof AST_Scope;
        if (is_scope) {
            node.hoist_properties(this);
            node.hoist_declarations(this);
            node.process_boolean_returns(this);
        }
        // Before https://github.com/mishoo/UglifyJS/pull/1602 AST_Node.optimize()
        // would call AST_Node.transform() if a different instance of AST_Node is
        // produced after OPT().
        // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction.
        // Migrate and defer all children's AST_Node.transform() to below, which
        // will now happen after this parent AST_Node has been properly substituted
        // thus gives a consistent AST snapshot.
        descend(node, this);
        // Existing code relies on how AST_Node.optimize() worked, and omitting the
        // following replacement call would result in degraded efficiency of both
        // output and performance.
        descend(node, this);
        var opt = node.optimize(this);
        if (is_scope && opt === node && !this.has_directive("use asm") && !opt.pinned()) {
            opt.merge_variables(this);
            opt.drop_unused(this);
            descend(opt, this);
        }
        if (opt === node) opt._squeezed = true;
        return opt;
    }
});
    if (this.option("expression")) node.process_expression(false);
    return node;
};
(function(OPT) {
    OPT(AST_Node, function(self, compressor) {
@@ -309,12 +304,19 @@
    AST_Scope.DEFMETHOD("process_expression", function(insert, transform) {
        var self = this;
        var tt = new TreeTransformer(function(node) {
            if (insert && node instanceof AST_SimpleStatement) {
                return transform ? transform(node) : make_node(AST_Return, node, { value: node.body });
            }
            if (!insert && node instanceof AST_Return) {
                return transform ? transform(node) : make_node(AST_SimpleStatement, node, {
                    body: node.value || make_node(AST_UnaryPrefix, node, {
            if (insert) {
                if (node instanceof AST_Directive) node = make_node(AST_SimpleStatement, node, {
                    body: make_node(AST_String, node, node),
                });
                if (node instanceof AST_SimpleStatement) {
                    return transform ? transform(node) : make_node(AST_Return, node, { value: node.body });
                }
            } else if (node instanceof AST_Return) {
                if (transform) return transform(node);
                var value = node.value;
                if (value instanceof AST_String) return make_node(AST_Directive, node, value);
                return make_node(AST_SimpleStatement, node, {
                    body: value || make_node(AST_UnaryPrefix, node, {
                        operator: "void",
                        expression: make_node(AST_Number, node, { value: 0 }),
                    }),
@@ -335,9 +337,7 @@
                }
            } else if (node instanceof AST_If) {
                node.body = node.body.transform(tt);
                if (node.alternative) {
                    node.alternative = node.alternative.transform(tt);
                }
                if (node.alternative) node.alternative = node.alternative.transform(tt);
            } else if (node instanceof AST_With) {
                node.body = node.body.transform(tt);
            }
@@ -389,7 +389,18 @@
        }
        var lhs = is_lhs(node, parent);
        if (lhs) return lhs;
        if (level == 0 && value && value.is_constant()) return;
        if (parent instanceof AST_Array) return is_modified(compressor, tw, parent, parent, level + 1);
        if (parent instanceof AST_Assign) switch (parent.operator) {
          case "=":
            return is_modified(compressor, tw, parent, value, level + 1, immutable, recursive);
          case "&&=":
          case "||=":
          case "??=":
            return is_modified(compressor, tw, parent, parent, level + 1);
          default:
            return;
        }
        if (parent instanceof AST_Binary) {
            if (!lazy_op[parent.operator]) return;
            return is_modified(compressor, tw, parent, parent, level + 1);
@@ -433,10 +444,6 @@
        return def.name == "arguments" && def.scope.uses_arguments;
    }
    function is_funarg(def) {
        return def.orig[0] instanceof AST_SymbolFunarg || def.orig[1] instanceof AST_SymbolFunarg;
    }
    function cross_scope(def, sym) {
        do {
            if (def === sym) return false;
@@ -445,10 +452,11 @@
    }
    function can_drop_symbol(ref, compressor, keep_lambda) {
        var def = ref.definition();
        var def = ref.redef || ref.definition();
        if (ref.in_arg && is_funarg(def)) return false;
        return all(def.orig, function(sym) {
            if (sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet) {
                if (sym instanceof AST_SymbolImport) return true;
                return compressor && can_varify(compressor, sym);
            }
            return !(keep_lambda && sym instanceof AST_SymbolLambda);
@@ -468,7 +476,8 @@
        function reset_def(tw, compressor, def) {
            def.assignments = 0;
            def.bool_fn = 0;
            def.bool_return = 0;
            def.drop_return = 0;
            def.cross_loop = false;
            def.direct_access = false;
            def.escaped = [];
@@ -480,7 +489,6 @@
            def.reassigned = 0;
            def.recursive_refs = 0;
            def.references = [];
            def.should_replace = undefined;
            def.single_use = undefined;
        }
@@ -519,6 +527,11 @@
            });
        }
        function safe_to_visit(tw, fn) {
            var marker = fn.safe_ids;
            return marker === undefined || marker === tw.safe_ids;
        }
        function walk_fn_def(tw, fn) {
            var was_scanning = tw.fn_scanning;
            tw.fn_scanning = fn;
@@ -533,14 +546,14 @@
                d.single_use = false;
                var fixed = d.fixed;
                if (typeof fixed == "function") fixed = fixed();
                if (fixed instanceof AST_Lambda && HOP(fixed, "safe_ids")) return;
                if (fixed instanceof AST_Lambda && fixed.safe_ids !== undefined) return;
                d.fixed = false;
            });
        }
        function mark_fn_def(tw, def, fn) {
            if (!HOP(fn, "safe_ids")) return;
            var marker = fn.safe_ids;
            if (marker === undefined) return;
            if (marker === false) return;
            if (fn.parent_scope.resolve().may_call_this === return_true) {
                if (member(fn, tw.fn_visited)) revisit_fn_def(tw, fn);
@@ -575,10 +588,10 @@
                walk_fn_def(tw, fn);
            });
            fn_defs.forEach(function(fn) {
                delete fn.safe_ids;
                fn.safe_ids = undefined;
            });
            delete scope.fn_defs;
            delete scope.may_call_this;
            scope.fn_defs = undefined;
            scope.may_call_this = undefined;
        }
        function push(tw) {
@@ -602,12 +615,14 @@
            if (def.single_use == "m") return false;
            var safe = tw.safe_ids[def.id];
            if (safe) {
                if (!HOP(tw.safe_ids, def.id)) safe.read = safe.read && safe.read !== tw.safe_ids ? true : tw.safe_ids;
                var in_order = HOP(tw.safe_ids, def.id);
                if (!in_order) safe.read = safe.read && safe.read !== tw.safe_ids ? true : tw.safe_ids;
                if (def.fixed == null) {
                    if (is_arguments(def)) return false;
                    if (def.global && def.name == "arguments") return false;
                    tw.loop_ids[def.id] = null;
                    def.fixed = make_node(AST_Undefined, def.orig[0]);
                    if (in_order) def.safe_ids = undefined;
                    return true;
                }
                return !safe.assign || safe.assign === tw.safe_ids;
@@ -625,16 +640,16 @@
            if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
                return !(sym instanceof AST_SymbolLet);
            });
            if (def.fixed === false) return false;
            if (def.fixed === false || def.fixed === 0) return false;
            var safe = tw.safe_ids[def.id];
            if (def.safe_ids) {
                def.safe_ids[def.id] = false;
                delete def.safe_ids;
                def.safe_ids = undefined;
                return def.fixed === null || HOP(tw.safe_ids, def.id) && !safe.read;
            }
            if (!HOP(tw.safe_ids, def.id)) {
                if (!safe) return false;
                if (safe.read) {
                if (safe.read || tw.in_loop) {
                    var scope = tw.find_parent(AST_BlockScope);
                    if (scope instanceof AST_Class) return false;
                    if (def.scope.resolve() !== scope.resolve()) return false;
@@ -654,6 +669,16 @@
            var node = make_node(AST_SymbolRef, ref, ref);
            node.fixed = fixed || make_node(AST_Undefined, ref);
            return node;
        }
        function replace_ref(ref, fixed) {
            return function() {
                var node = make_ref(ref, fixed);
                var def = ref.definition();
                def.references.push(node);
                def.replaced++;
                return node;
            };
        }
        function ref_once(compressor, def) {
@@ -690,6 +715,7 @@
                if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
                if (!d.escaped.depth || d.escaped.depth > depth) d.escaped.depth = depth;
                if (d.scope.resolve() !== scope.resolve()) d.escaped.cross_scope = true;
                if (d.fixed) d.fixed.escaped = d.escaped;
                return;
            } else if (value_in_use(node, parent)) {
                mark_escaped(tw, d, scope, parent, parent, level + 1, depth);
@@ -707,6 +733,7 @@
            if (parent instanceof AST_SimpleStatement) return;
            if (parent instanceof AST_Unary && !unary_side_effects[parent.operator]) return;
            d.direct_access = true;
            if (d.fixed) d.fixed.direct_access = true;
        }
        function mark_assignment_to_arguments(node) {
@@ -724,6 +751,34 @@
            });
        }
        function make_fixed(save, fn) {
            var prev_save, prev_value;
            return function() {
                var current = save();
                if (prev_save !== current) {
                    prev_save = current;
                    prev_value = fn(current);
                }
                return prev_value;
            };
        }
        function make_fixed_default(compressor, node, save) {
            var prev_save, prev_seq;
            return function() {
                var current = save();
                var ev;
                if (!is_undefined(current, compressor) && (ev = fuzzy_eval(compressor, current, true)) !== undefined) {
                    return ev instanceof AST_Node ? node : current;
                }
                if (prev_save !== current) {
                    prev_save = current;
                    prev_seq = make_sequence(node, [ current, node.value ]);
                }
                return prev_seq;
            };
        }
        function scan_declaration(tw, compressor, lhs, fixed, visit) {
            var scanner = new TreeWalker(function(node) {
                if (node instanceof AST_DefaultValue) {
@@ -732,15 +787,7 @@
                    node.value.walk(tw);
                    pop(tw);
                    var save = fixed;
                    if (save) fixed = function() {
                        var value = save();
                        var ev;
                        if (is_undefined(value, compressor)
                            || (ev = fuzzy_eval(compressor, value, true)) === undefined) {
                            return make_sequence(node, [ value, node.value ]);
                        }
                        return ev instanceof AST_Node ? node : value;
                    };
                    if (save) fixed = make_fixed_default(compressor, node, save);
                    node.name.walk(scanner);
                    fixed = save;
                    return true;
@@ -750,21 +797,25 @@
                    var save = fixed;
                    node.elements.forEach(function(node, index) {
                        if (node instanceof AST_Hole) return reset_flags(node);
                        if (save) fixed = function() {
                        if (save) fixed = make_fixed(save, function(value) {
                            return make_node(AST_Sub, node, {
                                expression: save(),
                                expression: value,
                                property: make_node(AST_Number, node, { value: index }),
                            });
                        };
                        });
                        node.walk(scanner);
                    });
                    if (node.rest) {
                        if (save) fixed = compressor.option("rests") && function() {
                            var value = save();
                            return value instanceof AST_Array ? make_node(AST_Array, node, {
                                elements: value.elements.slice(node.elements.length),
                            }) : node;
                        };
                        var fixed_node;
                        if (save) fixed = compressor.option("rests") && make_fixed(save, function(value) {
                            if (!(value instanceof AST_Array)) return node;
                            for (var i = 0, len = node.elements.length; i < len; i++) {
                                if (value.elements[i] instanceof AST_Spread) return node;
                            }
                            if (!fixed_node) fixed_node = make_node(AST_Array, node);
                            fixed_node.elements = value.elements.slice(len);
                            return fixed_node;
                        });
                        node.rest.walk(scanner);
                    }
                    fixed = save;
@@ -780,7 +831,7 @@
                            node.key.walk(tw);
                            pop(tw);
                        }
                        if (save) fixed = function() {
                        if (save) fixed = make_fixed(save, function(value) {
                            var key = node.key;
                            var type = AST_Sub;
                            if (typeof key == "string") {
@@ -791,10 +842,10 @@
                                }
                            }
                            return make_node(type, node, {
                                expression: save(),
                                property: key
                                expression: value,
                                property: key,
                            });
                        };
                        });
                        node.value.walk(scanner);
                    });
                    if (node.rest) {
@@ -843,11 +894,12 @@
                    return arg || make_node(AST_Undefined, iife);
                }, visit);
            });
            var rest = fn.rest;
            var rest = fn.rest, fixed_node;
            if (rest) scan_declaration(tw, compressor, rest, compressor.option("rests") && function() {
                return fn.rest === rest ? make_node(AST_Array, fn, {
                    elements: iife.args.slice(fn.argnames.length),
                }) : rest;
                if (fn.rest !== rest) return rest;
                if (!fixed_node) fixed_node = make_node(AST_Array, fn);
                fixed_node.elements = iife.args.slice(fn.argnames.length);
                return fixed_node;
            }, visit);
            walk_lambda(fn, tw);
            var safe_ids = tw.safe_ids;
@@ -879,7 +931,7 @@
                if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
                    right.walk(tw);
                    walk_prop(left);
                    node.__drop = true;
                    node.redundant = true;
                    return true;
                }
                if (ld && right instanceof AST_LambdaExpression) {
@@ -899,30 +951,22 @@
              case "&&=":
              case "||=":
              case "??=":
                left.walk(tw);
                push(tw);
                if (scan) {
                    right.walk(tw);
                    walk_assign();
                } else {
                    mark_assignment_to_arguments(left);
                    right.walk(tw);
                }
                pop(tw);
                return true;
                var lazy = true;
              default:
                if (!scan) {
                    mark_assignment_to_arguments(left);
                    return;
                    return walk_lazy();
                }
                ld.assignments++;
                var fixed = ld.fixed;
                if (is_modified(compressor, tw, node, node, 0)) {
                    ld.fixed = false;
                    return;
                    return walk_lazy();
                }
                var safe = safe_to_read(tw, ld);
                if (lazy) push(tw);
                right.walk(tw);
                if (lazy) pop(tw);
                if (safe && !left.in_arg && safe_to_assign(tw, ld)) {
                    push_ref(ld, left);
                    mark(tw, ld);
@@ -934,8 +978,9 @@
                            right: node.right,
                        });
                    };
                    left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
                    left.fixed.assigns = !fixed || !fixed.assigns ? [ ld.orig[0] ] : fixed.assigns.slice();
                    left.fixed.assigns.push(node);
                    left.fixed.to_binary = replace_ref(left, fixed);
                } else {
                    left.walk(tw);
                    ld.fixed = false;
@@ -978,7 +1023,13 @@
                    }
                    var d = sym.definition();
                    d.assignments++;
                    if (fixed && !modified && !sym.in_arg && safe_to_assign(tw, d)) {
                    if (!fixed || sym.in_arg || !safe_to_assign(tw, d)) {
                        walk();
                        d.fixed = false;
                    } else if (modified) {
                        walk();
                        d.fixed = 0;
                    } else {
                        push_ref(d, sym);
                        mark(tw, d);
                        if (left instanceof AST_Destructured
@@ -986,14 +1037,20 @@
                            d.single_use = false;
                        }
                        tw.loop_ids[d.id] = tw.in_loop;
                        mark_escaped(tw, d, sym.scope, node, right, 0, 1);
                        sym.fixed = d.fixed = fixed;
                        sym.fixed.assigns = [ node ];
                    } else {
                        walk();
                        d.fixed = false;
                        mark_escaped(tw, d, sym.scope, node, right, 0, 1);
                    }
                });
            }
            function walk_lazy() {
                if (!lazy) return;
                left.walk(tw);
                push(tw);
                right.walk(tw);
                pop(tw);
                return true;
            }
        });
        def(AST_Binary, function(tw) {
@@ -1021,12 +1078,11 @@
                if (iife) delete exp.reduce_vars;
                return true;
            }
            if (node.TYPE == "Call" && tw.in_boolean_context()) {
                if (exp instanceof AST_SymbolRef) {
                    exp.definition().bool_fn++;
                } else if (exp instanceof AST_Assign && exp.operator == "=" && exp.left instanceof AST_SymbolRef) {
                    exp.left.definition().bool_fn++;
                }
            if (node.TYPE == "Call") switch (tw.in_boolean_context()) {
              case "d":
                var drop = true;
              case true:
                mark_refs(exp, drop);
            }
            exp.walk(tw);
            var optional = node.optional;
@@ -1042,6 +1098,25 @@
                tw.find_parent(AST_Scope).may_call_this();
            }
            return true;
            function mark_refs(node, drop) {
                if (node instanceof AST_Assign) {
                    if (node.operator != "=") return;
                    mark_refs(node.left, drop);
                    mark_refs(node.right, drop);
                } else if (node instanceof AST_Binary) {
                    if (!lazy_op[node.operator]) return;
                    mark_refs(node.left, drop);
                    mark_refs(node.right, drop);
                } else if (node instanceof AST_Conditional) {
                    mark_refs(node.consequent, drop);
                    mark_refs(node.alternative, drop);
                } else if (node instanceof AST_SymbolRef) {
                    var def = node.definition();
                    def.bool_return++;
                    if (drop) def.drop_return++;
                }
            }
        });
        def(AST_Class, function(tw, descend, compressor) {
            var node = this;
@@ -1183,7 +1258,7 @@
        });
        def(AST_Lambda, function(tw, descend, compressor) {
            var fn = this;
            if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true;
            if (!safe_to_visit(tw, fn)) return true;
            if (!push_uniq(tw.fn_visited, fn)) return true;
            fn.inlined = false;
            push(tw);
@@ -1198,7 +1273,7 @@
            var def = fn.name.definition();
            var parent = tw.parent();
            if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
            if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true;
            if (!safe_to_visit(tw, fn)) return true;
            if (!push_uniq(tw.fn_visited, fn)) return true;
            fn.inlined = false;
            push(tw);
@@ -1261,7 +1336,7 @@
                if (!safe) return;
                safe.assign = true;
            });
            if (d.fixed === false) {
            if (d.fixed === false || d.fixed === 0) {
                var redef = d.redefined();
                if (redef && cross_scope(d.scope, this.scope)) redef.single_use = false;
            } else if (d.fixed === undefined || !safe_to_read(tw, d)) {
@@ -1286,7 +1361,7 @@
                    if (d.single_use) {
                        d.single_use = "m";
                    } else {
                        d.fixed = false;
                        d.fixed = 0;
                    }
                }
                if (d.fixed && tw.loop_ids[d.id] !== tw.in_loop) d.cross_loop = true;
@@ -1367,11 +1442,9 @@
                        operator: node.operator.slice(0, -1),
                        left: make_node(AST_UnaryPrefix, node, {
                            operator: "+",
                            expression: make_ref(exp, fixed)
                            expression: make_ref(exp, fixed),
                        }),
                        right: make_node(AST_Number, node, {
                            value: 1
                        })
                        right: make_node(AST_Number, node, { value: 1 }),
                    });
                };
                d.fixed.assigns = fixed && fixed.assigns ? fixed.assigns.slice() : [];
@@ -1382,10 +1455,11 @@
                    exp.fixed = function() {
                        return make_node(AST_UnaryPrefix, node, {
                            operator: "+",
                            expression: make_ref(exp, fixed)
                            expression: make_ref(exp, fixed),
                        });
                    };
                    exp.fixed.assigns = fixed && fixed.assigns;
                    exp.fixed.to_prefix = replace_ref(exp, d.fixed);
                }
            } else {
                exp.walk(tw);
@@ -1446,8 +1520,8 @@
    function reset_flags(node) {
        node._squeezed = false;
        node._optimized = false;
        delete node.fixed;
        if (node instanceof AST_Scope) delete node._var_names;
        if (node instanceof AST_BlockScope) node._var_names = undefined;
        if (node instanceof AST_SymbolRef) node.fixed = undefined;
    }
    AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
@@ -1471,14 +1545,19 @@
    AST_Symbol.DEFMETHOD("fixed_value", function() {
        var fixed = this.definition().fixed;
        if (fixed) {
            if (this.fixed) fixed = this.fixed;
            return (fixed instanceof AST_Node ? fixed : fixed()).tail_node();
        }
        fixed = fixed === 0 && this.fixed;
        if (!fixed) return fixed;
        if (this.fixed) fixed = this.fixed;
        return fixed instanceof AST_Node ? fixed : fixed();
        var value = (fixed instanceof AST_Node ? fixed : fixed()).tail_node();
        return value.is_constant() && value;
    });
    AST_SymbolRef.DEFMETHOD("is_immutable", function() {
        var def = this.redef || this.definition();
        return def.orig.length == 1 && def.orig[0] instanceof AST_SymbolLambda;
        return (this.in_arg || def.orig.length == 1) && def.orig[0] instanceof AST_SymbolLambda;
    });
    AST_Node.DEFMETHOD("convert_symbol", noop);
@@ -1511,6 +1590,12 @@
    }
    AST_SymbolDeclaration.DEFMETHOD("convert_symbol", convert_symbol);
    AST_SymbolRef.DEFMETHOD("convert_symbol", convert_symbol);
    function process_to_assign(ref) {
        var def = ref.definition();
        def.assignments++;
        def.references.push(ref);
    }
    function mark_destructured(process, tw) {
        var marker = new TreeWalker(function(node) {
@@ -1613,9 +1698,7 @@
    function make_node_from_constant(val, orig) {
        switch (typeof val) {
          case "string":
            return make_node(AST_String, orig, {
                value: val
            });
            return make_node(AST_String, orig, { value: val });
          case "number":
            if (isNaN(val)) return make_node(AST_NaN, orig);
            if (isFinite(val)) {
@@ -1626,7 +1709,7 @@
            }
            return val < 0 ? make_node(AST_UnaryPrefix, orig, {
                operator: "-",
                expression: make_node(AST_Infinity, orig)
                expression: make_node(AST_Infinity, orig),
            }) : make_node(AST_Infinity, orig);
          case "boolean":
            return make_node(val ? AST_True : AST_False, orig);
@@ -1634,7 +1717,7 @@
            return make_node(AST_Undefined, orig);
          default:
            if (val === null) {
                return make_node(AST_Null, orig, { value: null });
                return make_node(AST_Null, orig);
            }
            if (val instanceof RegExp) {
                return make_node(AST_RegExp, orig, { value: val });
@@ -1668,7 +1751,7 @@
    function merge_sequence(array, node) {
        if (node instanceof AST_Sequence) {
            array.push.apply(array, node.expressions);
            [].push.apply(array, node.expressions);
        } else {
            array.push(node);
        }
@@ -1782,35 +1865,90 @@
        return true;
    }
    // Certain combination of unused name + side effect leads to invalid AST:
    //    https://github.com/mishoo/UglifyJS/issues/44
    //    https://github.com/mishoo/UglifyJS/issues/1838
    //    https://github.com/mishoo/UglifyJS/issues/3371
    // We fix it at this stage by moving the `var` outside the `for`.
    function patch_for_init(node, in_list) {
        var block;
        if (node.init instanceof AST_BlockStatement) {
            block = node.init;
            node.init = block.body.pop();
            block.body.push(node);
        }
        if (node.init instanceof AST_Defun) {
            if (!block) block = make_node(AST_BlockStatement, node, { body: [ node ] });
            block.body.splice(-1, 0, node.init);
            node.init = null;
        } else if (node.init instanceof AST_SimpleStatement) {
            node.init = node.init.body;
        } else if (is_empty(node.init)) {
            node.init = null;
        }
        if (!block) return;
        return in_list ? List.splice(block.body) : block;
    }
    function tighten_body(statements, compressor) {
        var in_loop, in_try, scope;
        var in_lambda = last_of(compressor, function(node) {
            return node instanceof AST_Lambda;
        });
        var block_scope, in_loop, in_try, scope;
        find_loop_scope_try();
        var CHANGED, max_iter = 10;
        var changed, last_changed, max_iter = 10;
        do {
            CHANGED = false;
            eliminate_spurious_blocks(statements);
            last_changed = changed;
            changed = 0;
            if (eliminate_spurious_blocks(statements)) changed = 1;
            if (!changed && last_changed == 1) break;
            if (compressor.option("dead_code")) {
                eliminate_dead_code(statements, compressor);
                if (eliminate_dead_code(statements, compressor)) changed = 2;
                if (!changed && last_changed == 2) break;
            }
            if (compressor.option("if_return")) {
                handle_if_return(statements, compressor);
                if (handle_if_return(statements, compressor)) changed = 3;
                if (!changed && last_changed == 3) break;
            }
            if (compressor.option("awaits") && compressor.option("side_effects")) {
                if (trim_awaits(statements, compressor)) changed = 4;
                if (!changed && last_changed == 4) break;
            }
            if (compressor.option("inline") >= 4) {
                if (inline_iife(statements, compressor)) changed = 5;
                if (!changed && last_changed == 5) break;
            }
            if (compressor.sequences_limit > 0) {
                sequencesize(statements, compressor);
                sequencesize_2(statements, compressor);
                if (sequencesize(statements, compressor)) changed = 6;
                if (!changed && last_changed == 6) break;
                if (sequencesize_2(statements, compressor)) changed = 7;
                if (!changed && last_changed == 7) break;
            }
            if (compressor.option("join_vars")) {
                join_consecutive_vars(statements);
                if (join_consecutive_vars(statements)) changed = 8;
                if (!changed && last_changed == 8) break;
            }
            if (compressor.option("collapse_vars")) {
                collapse(statements, compressor);
                if (collapse(statements, compressor)) changed = 9;
            }
        } while (CHANGED && max_iter-- > 0);
        } while (changed && max_iter-- > 0);
        return statements;
        function last_of(compressor, predicate) {
            var block = compressor.self(), stat, level = 0;
            do {
                do {
                    if (predicate(block)) return true;
                    block = compressor.parent(level++);
                } while (block instanceof AST_If && (stat = block));
            } while ((block instanceof AST_BlockStatement || block instanceof AST_Scope)
                && is_last_statement(block.body, stat));
        }
        function find_loop_scope_try() {
            var node = compressor.self(), level = 0;
            do {
                if (!block_scope && node.variables) block_scope = node;
                if (node instanceof AST_Catch) {
                    if (compressor.parent(level).bfinally) {
                        if (!in_try) in_try = {};
@@ -1841,11 +1979,12 @@
        // Will not attempt to collapse assignments into or past code blocks
        // which are not sequentially executed, e.g. loops and conditionals.
        function collapse(statements, compressor) {
            if (scope.pinned()) return statements;
            if (scope.pinned()) return;
            var args;
            var assignments = Object.create(null);
            var assignments = new Dictionary();
            var candidates = [];
            var declare_only = Object.create(null);
            var changed = false;
            var declare_only = new Dictionary();
            var force_single;
            var stat_index = statements.length;
            var scanner = new TreeTransformer(function(node, descend) {
@@ -1860,15 +1999,51 @@
                    if (stop_after === node) abort = true;
                    return node;
                }
                // Stop immediately if these node types are encountered
                var parent = scanner.parent();
                if (should_stop(node, parent)) {
                    abort = true;
                    return node;
                }
                // Stop only if candidate is found within conditional branches
                if (!stop_if_hit && in_conditional(node, parent)) {
                    stop_if_hit = parent;
                }
                // Cascade compound assignments
                if (compound && scan_lhs && can_replace && !stop_if_hit
                    && node instanceof AST_Assign && node.operator != "=" && node.left.equivalent_to(lhs)) {
                    replaced++;
                    changed = true;
                    AST_Node.info("Cascading {node} [{file}:{line},{col}]", {
                        node: node,
                        file: node.start.file,
                        line: node.start.line,
                        col: node.start.col,
                    });
                    can_replace = false;
                    lvalues = get_lvalues(lhs);
                    node.right.transform(scanner);
                    clear_write_only(candidate);
                    var folded;
                    if (abort) {
                        folded = candidate;
                    } else {
                        abort = true;
                        folded = make_node(AST_Binary, candidate, {
                            operator: compound,
                            left: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_binary() : lhs,
                            right: rvalue,
                        });
                    }
                    return make_node(AST_Assign, node, {
                        operator: "=",
                        left: node.left,
                        right: make_node(AST_Binary, node, {
                            operator: node.operator.slice(0, -1),
                            left: folded,
                            right: node.right,
                        }),
                    });
                }
                // Stop immediately if these node types are encountered
                if (should_stop(node, parent)) {
                    abort = true;
                    return node;
                }
                // Skip transient nodes caused by single-use variable replacement
                if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node;
@@ -1884,52 +2059,70 @@
                    if (is_lhs(node, parent)) {
                        if (value_def && !hit_rhs) assign_used = true;
                        return node;
                    } else if (value_def) {
                    }
                    if (!hit_rhs && verify_ref && node.fixed !== lhs.fixed) {
                        abort = true;
                        return node;
                    }
                    if (value_def) {
                        if (stop_if_hit && assign_pos == 0) assign_pos = remaining - replaced;
                        if (!hit_rhs) replaced++;
                        return node;
                    } else {
                        replaced++;
                    }
                    CHANGED = abort = true;
                    replaced++;
                    changed = abort = true;
                    AST_Node.info("Collapsing {node} [{file}:{line},{col}]", {
                        node: node,
                        file: node.start.file,
                        line: node.start.line,
                        col: node.start.col,
                    });
                    if (candidate.TYPE == "Binary") return make_node(AST_Assign, candidate, {
                        operator: "=",
                        left: candidate.right.left,
                        right: make_node(AST_Conditional, candidate, {
                            condition: candidate.operator == "&&" ? candidate.left : candidate.left.negate(compressor),
                            consequent: candidate.right.right,
                            alternative: node,
                        }),
                    });
                    if (candidate instanceof AST_UnaryPostfix) {
                        if (lhs instanceof AST_SymbolRef) lhs.definition().fixed = false;
                        return make_node(AST_UnaryPrefix, candidate, candidate);
                    if (candidate.TYPE == "Binary") {
                        update_symbols(candidate, node);
                        return make_node(AST_Assign, candidate, {
                            operator: "=",
                            left: candidate.right.left,
                            right: candidate.operator == "&&" ? make_node(AST_Conditional, candidate, {
                                condition: candidate.left,
                                consequent: candidate.right.right,
                                alternative: node,
                            }) : make_node(AST_Conditional, candidate, {
                                condition: candidate.left,
                                consequent: node,
                                alternative: candidate.right.right,
                            }),
                        });
                    }
                    if (candidate instanceof AST_UnaryPostfix) return make_node(AST_UnaryPrefix, candidate, {
                        operator: candidate.operator,
                        expression: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_prefix() : lhs,
                    });
                    if (candidate instanceof AST_UnaryPrefix) {
                        clear_write_only(candidate);
                        return candidate;
                    }
                    update_symbols(rvalue, node);
                    if (candidate instanceof AST_VarDef) {
                        var def = candidate.name.definition();
                        if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
                            def.replaced++;
                            return maintain_this_binding(compressor, parent, node, candidate.value);
                            return maintain_this_binding(compressor, parent, node, rvalue);
                        }
                        return make_node(AST_Assign, candidate, {
                            operator: "=",
                            left: make_node(AST_SymbolRef, candidate.name, candidate.name),
                            right: candidate.value,
                            left: node,
                            right: rvalue,
                        });
                    }
                    var assign = candidate;
                    while (assign.write_only) {
                        assign.write_only = false;
                        if (!(assign instanceof AST_Assign)) break;
                        assign = assign.right;
                    }
                    return candidate;
                    clear_write_only(rvalue);
                    var assign = candidate.clone();
                    assign.right = rvalue;
                    return assign;
                }
                // Stop signals related to AST_SymbolRef
                if (should_stop_ref(node, parent)) {
                    abort = true;
                    return node;
                }
                // These node types have child nodes that execute sequentially,
                // but are otherwise not safe to scan into or beyond them.
@@ -1966,7 +2159,7 @@
                if (node instanceof AST_BlockScope
                    && !(node instanceof AST_Scope)
                    && !(node.variables && node.variables.all(function(def) {
                        return !lvalues.has(def.name);
                        return !enclosed.has(def.name) && !lvalues.has(def.name);
                    }))) {
                    var replace = can_replace;
                    can_replace = false;
@@ -1992,7 +2185,8 @@
                        var parent = multi_replacer.parent();
                        if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
                            value_def.replaced++;
                            return List.skip;
                            if (rvalue === rhs_value) return List.skip;
                            return make_sequence(rhs_value, rhs_value.expressions.slice(0, -1));
                        }
                        return rvalue;
                      case 1:
@@ -2010,6 +2204,12 @@
                if (node instanceof AST_SymbolRef && node.definition() === def) {
                    if (is_lhs(node, multi_replacer.parent())) return node;
                    if (!--replaced) abort = true;
                    AST_Node.info("Replacing {node} [{file}:{line},{col}]", {
                        node: node,
                        file: node.start.file,
                        line: node.start.line,
                        col: node.start.col,
                    });
                    var ref = rvalue.clone();
                    ref.scope = node.scope;
                    ref.reference();
@@ -2026,7 +2226,9 @@
                }
                // Skip (non-executed) functions and (leading) default case in switch statements
                if (node instanceof AST_Default || node instanceof AST_Scope) return node;
            }, patch_sequence);
            }, function(node) {
                return patch_sequence(node, multi_replacer);
            });
            while (--stat_index >= 0) {
                // Treat parameters as collapsible in IIFE, i.e.
                //   function(a, b){ ... }(x());
@@ -2042,15 +2244,18 @@
                    var candidate = hit_stack[hit_stack.length - 1];
                    var assign_pos = -1;
                    var assign_used = false;
                    var verify_ref = false;
                    var remaining;
                    var value_def = null;
                    var stop_after = null;
                    var stop_if_hit = null;
                    var lhs = get_lhs(candidate);
                    var side_effects = lhs && lhs.has_side_effects(compressor);
                    var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
                    var scan_lhs = lhs && (!side_effects || lhs instanceof AST_SymbolRef)
                            && !is_lhs_read_only(lhs, compressor);
                    var scan_rhs = foldable(candidate);
                    if (!scan_lhs && !scan_rhs) continue;
                    var compound = candidate instanceof AST_Assign && candidate.operator.slice(0, -1);
                    var funarg = candidate.name instanceof AST_SymbolFunarg;
                    var may_throw = return_false;
                    if (candidate.may_throw(compressor)) {
@@ -2062,11 +2267,16 @@
                    var read_toplevel = false;
                    var modify_toplevel = false;
                    // Locate symbols which may execute code outside of scanning range
                    var enclosed = new Dictionary();
                    var well_defined = true;
                    var lvalues = get_lvalues(candidate);
                    var lhs_local = is_lhs_local(lhs);
                    var rvalue = get_rvalue(candidate);
                    if (!side_effects) side_effects = value_has_side_effects();
                    var rhs_value = get_rvalue(candidate);
                    var rvalue = rhs_value;
                    if (!side_effects) {
                        if (!compound && rvalue instanceof AST_Sequence) rvalue = rvalue.tail_node();
                        side_effects = value_has_side_effects();
                    }
                    var check_destructured = in_try || !lhs_local ? function(node) {
                        return node instanceof AST_Destructured;
                    } : return_false;
@@ -2104,11 +2314,12 @@
                            && !compressor.exposed(def);
                        value_def.last_ref = false;
                        value_def.single_use = false;
                        CHANGED = true;
                        changed = true;
                    }
                    if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
                    if (replaced) remove_candidate(candidate);
                }
            }
            return changed;
            function signal_abort(node) {
                if (abort) return node;
@@ -2178,22 +2389,24 @@
                if (node instanceof AST_DestructuredKeyVal) return node.key instanceof AST_Node;
                if (node instanceof AST_DWLoop) return true;
                if (node instanceof AST_LoopControl) return true;
                if (node instanceof AST_SymbolRef) {
                    if (node.is_declared(compressor)) {
                        if (node.fixed_value()) return false;
                        if (can_drop_symbol(node)) {
                            return !(parent instanceof AST_PropAccess && parent.expression === node)
                                && is_arguments(node.definition());
                        }
                    } else if (is_direct_assignment(node, parent)) {
                        return false;
                    }
                    if (!replace_all) return true;
                    scan_rhs = false;
                    return false;
                }
                if (node instanceof AST_Try) return true;
                if (node instanceof AST_With) return true;
                return false;
            }
            function should_stop_ref(node, parent) {
                if (!(node instanceof AST_SymbolRef)) return false;
                if (node.is_declared(compressor)) {
                    if (node.fixed_value()) return false;
                    if (can_drop_symbol(node)) {
                        return !(parent instanceof AST_PropAccess && parent.expression === node)
                            && is_arguments(node.definition());
                    }
                } else if (is_direct_assignment(node, parent)) {
                    return false;
                }
                if (!replace_all) return true;
                scan_rhs = false;
                return false;
            }
@@ -2246,7 +2459,7 @@
                    stop_if_hit = if_hit;
                    stop_after = after;
                    can_replace = replace;
                    delete fn.collapse_scanning;
                    fn.collapse_scanning = false;
                    if (!abort) return false;
                    abort = false;
                    return true;
@@ -2374,7 +2587,7 @@
                    });
                    args = iife.args.slice();
                    var len = args.length;
                    var names = Object.create(null);
                    var names = new Dictionary();
                    for (var i = fn.argnames.length; --i >= 0;) {
                        var sym = fn.argnames[i];
                        var arg = args[i];
@@ -2389,9 +2602,9 @@
                            candidates.length = 0;
                            break;
                        }
                        if (sym.name in names) continue;
                        names[sym.name] = true;
                        if (value) arg = !arg || is_undefined(arg) ? value : null;
                        if (names.has(sym.name)) continue;
                        names.set(sym.name, true);
                        if (value) arg = is_undefined(arg) ? value : null;
                        if (!arg && !value) {
                            arg = make_node(AST_Undefined, sym).transform(compressor);
                        } else if (arg instanceof AST_Lambda && arg.pinned()) {
@@ -2423,7 +2636,7 @@
                    extract_candidates(lhs);
                    extract_candidates(expr.right);
                    if (lhs instanceof AST_SymbolRef && expr.operator == "=") {
                        assignments[lhs.name] = (assignments[lhs.name] || 0) + 1;
                        assignments.set(lhs.name, (assignments.get(lhs.name) || 0) + 1);
                    }
                } else if (expr instanceof AST_Await) {
                    extract_candidates(expr.expression, unused);
@@ -2515,7 +2728,7 @@
                                candidates.push(hit_stack.slice());
                            }
                        } else {
                            declare_only[expr.name.name] = (declare_only[expr.name.name] || 0) + 1;
                            declare_only.set(expr.name.name, (declare_only.get(expr.name.name) || 0) + 1);
                        }
                    }
                    if (expr.value) extract_candidates(expr.value);
@@ -2710,6 +2923,7 @@
                    return;
                }
                if (remaining < 1) return;
                rhs = rhs.tail_node();
                var value = rhs instanceof AST_Assign && rhs.operator == "=" ? rhs.left : rhs;
                if (!(value instanceof AST_SymbolRef)) return;
                var def = value.definition();
@@ -2731,13 +2945,12 @@
            }
            function remaining_refs(def) {
                return def.references.length - def.replaced - (assignments[def.name] || 0);
                return def.references.length - def.replaced - (assignments.get(def.name) || 0);
            }
            function get_lhs(expr) {
                if (expr instanceof AST_Assign) {
                    var lhs = expr.left;
                    if (expr.operator != "=") return lhs;
                    if (!(lhs instanceof AST_SymbolRef)) return lhs;
                    var def = lhs.definition();
                    if (scope.uses_arguments && is_funarg(def)) return lhs;
@@ -2750,9 +2963,10 @@
                        if (matches < remaining) {
                            remaining = matches;
                            assign_pos = 0;
                            verify_ref = true;
                        }
                    }
                    mangleable_var(expr.right);
                    if (expr.operator == "=") mangleable_var(expr.right);
                    return lhs;
                }
                if (expr instanceof AST_Binary) return expr.right.left;
@@ -2763,7 +2977,7 @@
                    if (def.const_redefs) return;
                    if (!member(lhs, def.orig)) return;
                    if (scope.uses_arguments && is_funarg(def)) return;
                    var declared = def.orig.length - def.eliminated - (declare_only[def.name] || 0);
                    var declared = def.orig.length - def.eliminated - (declare_only.get(def.name) || 0);
                    remaining = remaining_refs(def);
                    if (def.fixed) remaining = Math.min(remaining, def.references.filter(function(ref) {
                        if (!ref.fixed) return true;
@@ -2855,6 +3069,22 @@
                };
            }
            function clear_write_only(assign) {
                while (assign.write_only) {
                    assign.write_only = false;
                    if (!(assign instanceof AST_Assign)) break;
                    assign = assign.right;
                }
            }
            function update_symbols(value, node) {
                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;
                }));
            }
            function may_be_global(node) {
                if (node instanceof AST_SymbolRef) {
                    node = node.fixed_value();
@@ -2879,8 +3109,9 @@
                        if (!value) {
                            value = node;
                            var def = node.definition();
                            var escaped = node.fixed && node.fixed.escaped || def.escaped;
                            if (!def.undeclared
                                && (def.assignments || !def.escaped || def.escaped.cross_scope)
                                && (def.assignments || !escaped || escaped.cross_scope)
                                && (has_escaped(def, node.scope, node, tw.parent()) || !same_scope(def))) {
                                well_defined = false;
                            }
@@ -2888,8 +3119,36 @@
                    } else if (node instanceof AST_ObjectIdentity) {
                        value = node;
                    }
                    if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0));
                    if (find_arguments && node instanceof AST_Sub) {
                    if (value) {
                        lvalues.add(node.name, is_modified(compressor, tw, node, value, 0));
                    } else if (node instanceof AST_Lambda) {
                        for (var level = 0, parent, child = node; parent = tw.parent(level++); child = parent) {
                            if (parent instanceof AST_Assign) {
                                if (parent.left === child) break;
                                if (parent.operator == "=") continue;
                                if (lazy_op[parent.operator.slice(0, -1)]) continue;
                                break;
                            }
                            if (parent instanceof AST_Binary) {
                                if (lazy_op[parent.operator]) continue;
                                break;
                            }
                            if (parent instanceof AST_Call) return;
                            if (parent instanceof AST_Scope) return;
                            if (parent instanceof AST_Sequence) {
                                if (parent.tail_node() === child) continue;
                                break;
                            }
                            if (parent instanceof AST_Template) {
                                if (parent.tag) return;
                                break;
                            }
                        }
                        node.enclosed.forEach(function(def) {
                            if (def.scope !== node) enclosed.set(def.name, true);
                        });
                        return true;
                    } else if (find_arguments && node instanceof AST_Sub) {
                        scope.each_argname(function(argname) {
                            if (!compressor.option("reduce_vars") || argname.definition().assignments) {
                                if (!argname.definition().fixed) well_defined = false;
@@ -2918,63 +3177,79 @@
            }
            function remove_candidate(expr) {
                var value = rvalue === rhs_value ? null : make_sequence(rhs_value, rhs_value.expressions.slice(0, -1));
                var index = expr.name_index;
                if (index >= 0) {
                    var argname = scope.argnames[index];
                    var args, argname = scope.argnames[index];
                    if (argname instanceof AST_DefaultValue) {
                        argname.value = make_node(AST_Number, argname, {
                            value: 0
                        });
                        argname.name.definition().fixed = false;
                    } else {
                        var args = compressor.parent().args;
                        if (args[index]) {
                            args[index] = make_node(AST_Number, args[index], {
                                value: 0
                            });
                            argname.definition().fixed = false;
                        }
                        scope.argnames[index] = argname = argname.clone();
                        argname.value = value || make_node(AST_Number, argname, { value: 0 });
                    } else if ((args = compressor.parent().args)[index]) {
                        scope.argnames[index] = argname.clone();
                        args[index] = value || make_node(AST_Number, args[index], { value: 0 });
                    }
                    return true;
                    return;
                }
                var end = hit_stack.length - 1;
                if (hit_stack[end - 1].body === hit_stack[end]) end--;
                var last = hit_stack[end];
                if (last instanceof AST_VarDef || hit_stack[end - 1].body === last) end--;
                var tt = new TreeTransformer(function(node, descend, in_list) {
                    if (hit) return node;
                    if (node !== hit_stack[hit_index]) return node;
                    hit_index++;
                    if (hit_index <= end) return handle_custom_scan_order(node, tt);
                    hit = true;
                    if (node instanceof AST_VarDef) {
                        declare_only[node.name.name] = (declare_only[node.name.name] || 0) + 1;
                    if (node instanceof AST_Definitions) {
                        declare_only.set(last.name.name, (declare_only.get(last.name.name) || 0) + 1);
                        if (value_def) value_def.replaced++;
                        node = node.clone();
                        node.value = null;
                        return node;
                        var defns = node.definitions;
                        var index = defns.indexOf(last);
                        var defn = last.clone();
                        defn.value = null;
                        if (!value) {
                            node.definitions[index] = defn;
                            return node;
                        }
                        var body = [ make_node(AST_SimpleStatement, value, { body: value }) ];
                        if (index > 0) {
                            var head = node.clone();
                            head.definitions = defns.slice(0, index);
                            body.unshift(head);
                            node = node.clone();
                            node.definitions = defns.slice(index);
                        }
                        body.push(node);
                        node.definitions[0] = defn;
                        return in_list ? List.splice(body) : make_node(AST_BlockStatement, node, { body: body });
                    }
                    return in_list ? List.skip : null;
                }, patch_sequence);
                    if (!value) return in_list ? List.skip : null;
                    return is_statement(node) ? make_node(AST_SimpleStatement, value, { body: value }) : value;
                }, function(node, in_list) {
                    if (node instanceof AST_For) return patch_for_init(node, in_list);
                    return patch_sequence(node, tt);
                });
                abort = false;
                hit = false;
                hit_index = 0;
                return statements[stat_index].transform(tt);
                if (!(statements[stat_index] = statements[stat_index].transform(tt))) statements.splice(stat_index, 1);
            }
            function patch_sequence(node) {
            function patch_sequence(node, tt) {
                if (node instanceof AST_Sequence) switch (node.expressions.length) {
                  case 0: return null;
                  case 1: return maintain_this_binding(compressor, this.parent(), node, node.expressions[0]);
                  case 1: return maintain_this_binding(compressor, tt.parent(), node, node.expressions[0]);
                }
            }
            function is_lhs_local(lhs) {
                var sym = root_expr(lhs);
                return sym instanceof AST_SymbolRef
                    && sym.definition().scope.resolve() === scope
                    && !(in_loop
                        && (lvalues.has(sym.name) && lvalues.get(sym.name)[0] !== lhs
                            || candidate instanceof AST_Unary
                            || candidate instanceof AST_Assign && candidate.operator != "="));
                if (!(sym instanceof AST_SymbolRef)) return false;
                if (sym.definition().scope.resolve() !== scope) return false;
                if (!in_loop) return true;
                if (compound) return false;
                if (candidate instanceof AST_Unary) return false;
                var lvalue = lvalues.get(sym.name);
                return !lvalue || lvalue[0] === lhs;
            }
            function value_has_side_effects() {
@@ -2996,7 +3271,14 @@
                    return false;
                }
                var def = lhs.definition();
                return def.references.length - def.replaced == referenced;
                if (def.references.length - def.replaced == referenced) return true;
                if (!def.fixed) return false;
                if (!lhs.fixed) return false;
                if (def.references.filter(function(ref) {
                    return ref.fixed === lhs.fixed;
                }).length != referenced) return false;
                verify_ref = true;
                return true;
            }
            function symbol_in_lvalues(sym, parent) {
@@ -3014,7 +3296,7 @@
                if (def.scope.resolve() !== scope) return true;
                if (modify_toplevel && compressor.exposed(def)) return true;
                return !all(def.references, function(ref) {
                    return ref.scope.resolve() === scope;
                    return ref.scope.resolve(true) === scope;
                });
            }
@@ -3032,12 +3314,12 @@
        }
        function eliminate_spurious_blocks(statements) {
            var seen_dirs = [];
            var changed = false, seen_dirs = [];
            for (var i = 0; i < statements.length;) {
                var stat = statements[i];
                if (stat instanceof AST_BlockStatement) {
                    if (all(stat.body, safe_to_trim)) {
                        CHANGED = true;
                        changed = true;
                        eliminate_spurious_blocks(stat.body);
                        [].splice.apply(statements, [i, 1].concat(stat.body));
                        i += stat.body.length;
@@ -3046,28 +3328,28 @@
                }
                if (stat instanceof AST_Directive) {
                    if (member(stat.value, seen_dirs)) {
                        CHANGED = true;
                        changed = true;
                        statements.splice(i, 1);
                        continue;
                    }
                    seen_dirs.push(stat.value);
                }
                if (stat instanceof AST_EmptyStatement) {
                    CHANGED = true;
                    changed = true;
                    statements.splice(i, 1);
                    continue;
                }
                i++;
            }
            return changed;
        }
        function handle_if_return(statements, compressor) {
            var self = compressor.self();
            var changed = false;
            var parent = compressor.parent();
            var in_lambda = last_of(function(node) {
                return node instanceof AST_Lambda;
            });
            var in_iife = in_lambda && parent && parent.TYPE == "Call";
            var self = compressor.self();
            var in_iife = in_lambda && parent && parent.TYPE == "Call" && parent.expression === self;
            var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences");
            var multiple_if_returns = has_multiple_if_returns(statements);
            for (var i = statements.length; --i >= 0;) {
                var stat = statements[i];
@@ -3076,13 +3358,13 @@
                if (in_lambda && !next && stat instanceof AST_Return) {
                    if (!stat.value) {
                        CHANGED = true;
                        changed = true;
                        statements.splice(i, 1);
                        continue;
                    }
                    var tail = stat.value.tail_node();
                    if (tail instanceof AST_UnaryPrefix && tail.operator == "void") {
                        CHANGED = true;
                        changed = true;
                        var body;
                        if (tail === stat.value) {
                            body = tail.expression;
@@ -3090,9 +3372,7 @@
                            body = stat.value.clone();
                            body.expressions[body.length - 1] = tail.expression;
                        }
                        statements[i] = make_node(AST_SimpleStatement, stat, {
                            body: body,
                        });
                        statements[i] = make_node(AST_SimpleStatement, stat, { body: body });
                        continue;
                    }
                }
@@ -3101,27 +3381,26 @@
                    var ab = aborts(stat.body);
                    if (can_merge_flow(ab)) {
                        if (ab.label) remove(ab.label.thedef.references, ab);
                        CHANGED = true;
                        changed = true;
                        stat = stat.clone();
                        stat.condition = stat.condition.negate(compressor);
                        var body = as_statement_array_with_return(stat.body, ab);
                        stat.body = make_node(AST_BlockStatement, stat, {
                            body: as_statement_array(stat.alternative).concat(extract_functions())
                            body: as_statement_array_with_return(stat.body, ab),
                        });
                        stat.alternative = make_node(AST_BlockStatement, stat, {
                            body: body
                            body: as_statement_array(stat.alternative).concat(extract_functions()),
                        });
                        statements[i] = stat;
                        statements[i] = stat.transform(compressor);
                        continue;
                    }
                    if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) {
                        var negated = stat.condition.negate(compressor);
                        if (negated.print_to_string().length <= stat.condition.print_to_string().length) {
                            CHANGED = true;
                    if (ab && !stat.alternative && next instanceof AST_Jump) {
                        var cond = stat.condition;
                        cond = best_of_expression(cond, cond.negate(compressor), stat.body instanceof AST_BlockStatement);
                        if (cond !== stat.condition) {
                            changed = true;
                            stat = stat.clone();
                            stat.condition = negated;
                            stat.condition = cond;
                            statements[j] = stat.body;
                            stat.body = next;
                            statements[i] = stat;
@@ -3133,14 +3412,13 @@
                    var alt = aborts(stat.alternative);
                    if (can_merge_flow(alt)) {
                        if (alt.label) remove(alt.label.thedef.references, alt);
                        CHANGED = true;
                        changed = true;
                        stat = stat.clone();
                        stat.body = make_node(AST_BlockStatement, stat.body, {
                            body: as_statement_array(stat.body).concat(extract_functions())
                            body: as_statement_array(stat.body).concat(extract_functions()),
                        });
                        var body = as_statement_array_with_return(stat.alternative, alt);
                        stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
                            body: body
                            body: as_statement_array_with_return(stat.alternative, alt),
                        });
                        statements[i] = stat;
                        statements[i] = stat.transform(compressor);
@@ -3149,14 +3427,12 @@
                    if (compressor.option("typeofs")) {
                        if (ab && !alt) {
                            mark_locally_defined(stat.condition, null, make_node(AST_BlockStatement, self, {
                                body: statements.slice(i + 1)
                            }));
                            var stats = make_node(AST_BlockStatement, self, { body: statements.slice(i + 1) });
                            mark_locally_defined(stat.condition, null, stats);
                        }
                        if (!ab && alt) {
                            mark_locally_defined(stat.condition, make_node(AST_BlockStatement, self, {
                                body: statements.slice(i + 1)
                            }));
                            var stats = make_node(AST_BlockStatement, self, { body: statements.slice(i + 1) });
                            mark_locally_defined(stat.condition, stats);
                        }
                    }
                }
@@ -3165,20 +3441,9 @@
                    var value = stat.body.value;
                    var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool;
                    //---
                    // pretty silly case, but:
                    // if (foo()) return; return; ---> foo(); return;
                    if (!value && !stat.alternative
                        && (in_lambda && !next || next instanceof AST_Return && !next.value)) {
                        CHANGED = true;
                        statements[i] = make_node(AST_SimpleStatement, stat.condition, {
                            body: stat.condition
                        });
                        continue;
                    }
                    //---
                    // if (foo()) return x; return y; ---> return foo() ? x : y;
                    if (!stat.alternative && next instanceof AST_Return) {
                        CHANGED = true;
                        changed = true;
                        stat = stat.clone();
                        stat.alternative = next;
                        statements.splice(i, 1, stat.transform(compressor));
@@ -3188,11 +3453,9 @@
                    //---
                    // if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
                    if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) {
                        CHANGED = true;
                        changed = true;
                        stat = stat.clone();
                        stat.alternative = make_node(AST_Return, stat, {
                            value: null
                        });
                        stat.alternative = make_node(AST_Return, stat, { value: null });
                        statements.splice(i, 1, stat.transform(compressor));
                        continue;
                    }
@@ -3202,26 +3465,32 @@
                    // if sequences is not enabled, this can lead to an endless loop (issue #866).
                    // however, with sequences on this helps producing slightly better output for
                    // the example code.
                    var prev = statements[prev_index(i)];
                    if (compressor.option("sequences") && in_lambda && !stat.alternative
                        && (!prev && in_iife || prev instanceof AST_If && prev.body instanceof AST_Return)
                    var prev, prev_stat;
                    if (chain_if_returns && !stat.alternative
                        && (!(prev_stat = statements[prev = prev_index(i)]) && in_iife
                            || prev_stat instanceof AST_If && prev_stat.body instanceof AST_Return)
                        && next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
                        CHANGED = true;
                        changed = true;
                        var exprs = [];
                        var args = prev_stat ? trim_defns(prev, exprs) : [ i, 1 ];
                        stat = stat.clone();
                        exprs.push(stat.condition);
                        stat.condition = make_sequence(stat, exprs);
                        stat.alternative = make_node(AST_BlockStatement, next, {
                            body: [
                                next,
                                make_node(AST_Return, next, {
                                    value: null
                                })
                            ]
                                make_node(AST_Return, next, { value: null }),
                            ],
                        });
                        statements.splice(i, 1, stat.transform(compressor));
                        args.push(stat.transform(compressor));
                        statements.splice(j, 1);
                        [].splice.apply(statements, args);
                        i = prev + 1;
                        continue;
                    }
                }
            }
            return changed;
            function has_multiple_if_returns(statements) {
                var n = 0;
@@ -3234,29 +3503,14 @@
                return false;
            }
            function is_return_void(value) {
                return !value || value instanceof AST_UnaryPrefix && value.operator == "void";
            }
            function last_of(predicate) {
                var block = self, stat, level = 0;
                do {
                    do {
                        if (predicate(block)) return true;
                        block = compressor.parent(level++);
                    } while (block instanceof AST_If && (stat = block));
                } while ((block instanceof AST_BlockStatement || block instanceof AST_Scope)
                    && is_last_statement(block.body, stat));
            }
            function match_target(target) {
                return last_of(function(node) {
                return last_of(compressor, function(node) {
                    return node === target;
                });
            }
            function can_drop_abort(ab) {
                if (ab instanceof AST_Return) return in_lambda && is_return_void(ab.value);
                if (ab instanceof AST_Return) return in_lambda && is_undefined(ab.value);
                if (!(ab instanceof AST_LoopControl)) return false;
                var lct = compressor.loopcontrol_target(ab);
                if (ab instanceof AST_Continue) return match_target(loop_body(lct));
@@ -3303,9 +3557,7 @@
                    block = last.body;
                }
                block.pop();
                if (ab.value) block.push(make_node(AST_SimpleStatement, ab.value, {
                    body: ab.value.expression
                }));
                if (ab.value) block.push(make_node(AST_SimpleStatement, ab.value, { body: ab.value }));
                return body;
            }
@@ -3318,9 +3570,28 @@
            function prev_index(i) {
                for (var j = i; --j >= 0;) {
                    if (!is_declaration(statements[j])) break;
                    if (!(statements[j] instanceof AST_Var)) break;
                }
                return j;
            }
            function trim_defns(j, exprs) {
                var args = [ j + 1, i - j ];
                var var_defs = [];
                while (++j < i) {
                    var stat = statements[j];
                    stat.remove_initializers(compressor, var_defs);
                    stat.definitions.forEach(function(var_def) {
                        if (!var_def.value) return;
                        exprs.push(make_node(AST_Assign, var_def, {
                            operator: "=",
                            left: var_def.name.convert_symbol(AST_SymbolRef, process_to_assign),
                            right: var_def.value,
                        }));
                    });
                }
                if (var_defs.length > 0) args.push(make_node(AST_Var, stat, { definitions: var_defs }));
                return args;
            }
        }
@@ -3331,14 +3602,11 @@
                var stat = statements[i];
                if (stat instanceof AST_LoopControl) {
                    var lct = compressor.loopcontrol_target(stat);
                    if (stat instanceof AST_Break
                            && !(lct instanceof AST_IterationStatement)
                            && loop_body(lct) === self
                        || stat instanceof AST_Continue
                            && loop_body(lct) === self) {
                        if (stat.label) remove(stat.label.thedef.references, stat);
                    } else {
                    if (loop_body(lct) !== self
                        || stat instanceof AST_Break && lct instanceof AST_IterationStatement) {
                        statements[n++] = stat;
                    } else if (stat.label) {
                        remove(stat.label.thedef.references, stat);
                    }
                } else {
                    statements[n++] = stat;
@@ -3349,10 +3617,51 @@
                }
            }
            statements.length = n;
            CHANGED = n != len;
            if (has_quit) has_quit.forEach(function(stat) {
                extract_declarations_from_unreachable_code(compressor, stat, statements);
            });
            return statements.length != len;
        }
        function trim_awaits(statements, compressor) {
            if (!in_lambda || in_try && in_try.bfinally) return;
            var changed = false;
            for (var index = statements.length; --index >= 0;) {
                var stat = statements[index];
                if (!(stat instanceof AST_SimpleStatement)) break;
                var node = stat.body;
                if (!(node instanceof AST_Await)) break;
                var exp = node.expression;
                if (!is_primitive(compressor, exp)) break;
                changed = true;
                exp = exp.drop_side_effect_free(compressor, true);
                if (exp) {
                    stat.body = exp;
                    break;
                }
            }
            statements.length = index + 1;
            return changed;
        }
        function inline_iife(statements, compressor) {
            var changed = false;
            var index = statements.length - 1;
            if (in_lambda && index >= 0) {
                var inlined = statements[index].try_inline(compressor, block_scope);
                if (inlined) {
                    statements[index--] = inlined;
                    changed = true;
                }
            }
            var loop = in_loop && in_try && in_try.bfinally ? "try" : in_loop;
            for (; index >= 0; index--) {
                var inlined = statements[index].try_inline(compressor, block_scope, true, loop);
                if (!inlined) continue;
                statements[index] = inlined;
                changed = true;
            }
            return changed;
        }
        function sequencesize(statements, compressor) {
@@ -3368,9 +3677,7 @@
                var stat = statements[i];
                if (stat instanceof AST_SimpleStatement) {
                    if (seq.length >= compressor.sequences_limit) push_seq();
                    var body = stat.body;
                    if (seq.length > 0) body = body.drop_side_effect_free(compressor);
                    if (body) merge_sequence(seq, body);
                    merge_sequence(seq, stat.body);
                } else if (is_declaration(stat)) {
                    statements[n++] = stat;
                } else {
@@ -3380,7 +3687,7 @@
            }
            push_seq();
            statements.length = n;
            if (n != len) CHANGED = true;
            return n != len;
        }
        function to_simple_statement(block, decls) {
@@ -3400,13 +3707,7 @@
        }
        function sequencesize_2(statements, compressor) {
            function cons_seq(right) {
                n--;
                CHANGED = true;
                var left = prev.body;
                return make_sequence(left, [ left, right ]);
            }
            var n = 0, prev;
            var changed = false, n = 0, prev;
            for (var i = 0; i < statements.length; i++) {
                var stat = statements[i];
                if (prev) {
@@ -3429,7 +3730,7 @@
                                else {
                                    stat.init = prev.body;
                                    n--;
                                    CHANGED = true;
                                    changed = true;
                                }
                            }
                        }
@@ -3459,7 +3760,7 @@
                        i += len;
                        n += len + 1;
                        prev = null;
                        CHANGED = true;
                        changed = true;
                        continue;
                    }
                }
@@ -3467,6 +3768,14 @@
                prev = stat instanceof AST_SimpleStatement ? stat : null;
            }
            statements.length = n;
            return changed;
            function cons_seq(right) {
                n--;
                changed = true;
                var left = prev.body;
                return make_sequence(left, [ left, right ]);
            }
        }
        function extract_exprs(body) {
@@ -3477,19 +3786,30 @@
        function join_assigns(defn, body, keep) {
            var exprs = extract_exprs(body);
            if (!exprs) return;
            keep = keep || 0;
            var trimmed = false;
            for (var i = exprs.length - 1; --i >= 0;) {
            for (var i = exprs.length - keep; --i >= 0;) {
                var expr = exprs[i];
                if (!(expr instanceof AST_Assign)) continue;
                if (expr.operator != "=") continue;
                if (!(expr.left instanceof AST_SymbolRef)) continue;
                var tail = exprs.slice(i + 1);
                if (!can_trim(expr)) continue;
                var tail;
                if (expr.left instanceof AST_SymbolRef) {
                    tail = exprs.slice(i + 1);
                } else if (expr.left instanceof AST_PropAccess && can_trim(expr.left.expression)) {
                    tail = exprs.slice(i + 1);
                    var flattened = expr.clone();
                    expr = expr.left.expression;
                    flattened.left = flattened.left.clone();
                    flattened.left.expression = expr.left.clone();
                    tail.unshift(flattened);
                } else {
                    continue;
                }
                if (tail.length == 0) continue;
                if (!trim_assigns(expr.left, expr.right, tail)) continue;
                trimmed = true;
                exprs = exprs.slice(0, i + 1).concat(tail);
                exprs = exprs.slice(0, i).concat(expr, tail);
            }
            if (defn instanceof AST_Definitions) {
                keep = keep || 0;
                for (var i = defn.definitions.length; --i >= 0;) {
                    var def = defn.definitions[i];
                    if (!def.value) continue;
@@ -3500,6 +3820,10 @@
                if (defn instanceof AST_Var && join_var_assign(defn.definitions, exprs, keep)) trimmed = true;
            }
            return trimmed && exprs;
            function can_trim(node) {
                return node instanceof AST_Assign && node.operator == "=";
            }
        }
        function merge_assigns(prev, defn) {
@@ -3556,22 +3880,35 @@
        }
        function trim_assigns(name, value, exprs) {
            var names = new Dictionary();
            names.set(name.name, true);
            while (value instanceof AST_Assign && value.operator == "=") {
                if (value.left instanceof AST_SymbolRef) names.set(value.left.name, true);
                value = value.right;
            }
            if (!(value instanceof AST_Object)) return;
            var trimmed = false;
            do {
                var node = exprs[0];
                if (!(node instanceof AST_Assign)) break;
                if (node.operator != "=") break;
                if (!(node.left instanceof AST_PropAccess)) break;
                if (!try_join(exprs[0])) break;
                exprs.shift();
                trimmed = true;
            } while (exprs.length);
            return trimmed;
            function try_join(node) {
                if (!(node instanceof AST_Assign)) return;
                if (node.operator != "=") return;
                if (!(node.left instanceof AST_PropAccess)) return;
                var sym = node.left.expression;
                if (!(sym instanceof AST_SymbolRef)) break;
                if (name.name != sym.name) break;
                if (!node.right.is_constant_expression(scope)) break;
                if (!(sym instanceof AST_SymbolRef)) return;
                if (!names.has(sym.name)) return;
                if (!node.right.is_constant_expression(scope)) return;
                var prop = node.left.property;
                if (prop instanceof AST_Node) {
                    if (try_join(prop)) prop = node.left.property = prop.right.clone();
                    prop = prop.evaluate(compressor);
                }
                if (prop instanceof AST_Node) break;
                if (prop instanceof AST_Node) return;
                prop = "" + prop;
                var diff = prop == "__proto__" || compressor.has_directive("use strict") ? function(node) {
                    var key = node.key;
@@ -3583,29 +3920,27 @@
                    }
                    return key !== "__proto__";
                };
                if (!all(value.properties, diff)) break;
                if (!all(value.properties, diff)) return;
                value.properties.push(make_node(AST_ObjectKeyVal, node, {
                    key: prop,
                    value: node.right
                    value: node.right,
                }));
                exprs.shift();
                trimmed = true;
            } while (exprs.length);
            return trimmed;
                return true;
            }
        }
        function join_consecutive_vars(statements) {
            var defs;
            var changed = false, defs;
            for (var i = 0, j = -1; i < statements.length; i++) {
                var stat = statements[i];
                var prev = statements[j];
                if (stat instanceof AST_Definitions) {
                    if (prev && prev.TYPE == stat.TYPE) {
                        prev.definitions = prev.definitions.concat(stat.definitions);
                        CHANGED = true;
                        changed = true;
                    } else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
                        defs.definitions = defs.definitions.concat(stat.definitions);
                        CHANGED = true;
                        changed = true;
                    } else if (stat instanceof AST_Var) {
                        var exprs = merge_assigns(prev, stat);
                        if (exprs) {
@@ -3613,7 +3948,7 @@
                                prev.body = make_sequence(prev, exprs);
                                j++;
                            }
                            CHANGED = true;
                            changed = true;
                        } else {
                            j++;
                        }
@@ -3627,25 +3962,26 @@
                } else if (stat instanceof AST_For) {
                    var exprs = join_assigns(prev, stat.init);
                    if (exprs) {
                        CHANGED = true;
                        changed = true;
                        stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
                    } else if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
                        if (stat.init) {
                            prev.definitions = prev.definitions.concat(stat.init.definitions);
                        }
                        stat = stat.clone();
                        defs = stat.init = prev;
                        statements[j] = merge_defns(stat);
                        CHANGED = true;
                        changed = true;
                        continue;
                    } else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
                        defs.definitions = defs.definitions.concat(stat.init.definitions);
                        stat.init = null;
                        CHANGED = true;
                        changed = true;
                    } else if (stat.init instanceof AST_Var) {
                        defs = stat.init;
                        exprs = merge_assigns(prev, stat.init);
                        if (exprs) {
                            CHANGED = true;
                            changed = true;
                            if (exprs.length == 0) {
                                statements[j] = merge_defns(stat);
                                continue;
@@ -3664,17 +4000,24 @@
                            name.definition().references.push(ref);
                        });
                        defs.definitions = defns;
                        CHANGED = true;
                        changed = true;
                    }
                    stat.object = join_assigns_expr(stat.object);
                } else if (stat instanceof AST_If) {
                    stat.condition = join_assigns_expr(stat.condition);
                } else if (stat instanceof AST_SimpleStatement) {
                    var exprs = join_assigns(prev, stat.body);
                    var exprs = join_assigns(prev, stat.body), next;
                    if (exprs) {
                        CHANGED = true;
                        changed = true;
                        if (!exprs.length) continue;
                        stat.body = make_sequence(stat.body, exprs);
                    } else if (prev instanceof AST_Definitions
                        && (next = statements[i + 1])
                        && prev.TYPE == next.TYPE
                        && (next = next.definitions[0]).value) {
                        changed = true;
                        next.value = make_sequence(stat, [ stat.body, next.value ]);
                        continue;
                    }
                } else if (stat instanceof AST_Switch) {
                    stat.expression = join_assigns_expr(stat.expression);
@@ -3684,11 +4027,12 @@
                statements[++j] = defs ? merge_defns(stat) : stat;
            }
            statements.length = j + 1;
            return changed;
            function join_assigns_expr(value) {
                var exprs = join_assigns(prev, value, 1);
                if (!exprs) return value;
                CHANGED = true;
                changed = true;
                var tail = value.tail_node();
                if (exprs[exprs.length - 1] !== tail) exprs.push(tail.left);
                return make_sequence(value, exprs);
@@ -3703,7 +4047,7 @@
                        if (parent instanceof AST_ForEnumeration && parent.init === node) return node;
                        if (!declarations_only(node)) return node;
                        defs.definitions = defs.definitions.concat(node.definitions);
                        CHANGED = true;
                        changed = true;
                        if (parent instanceof AST_For && parent.init === node) return null;
                        return in_list ? List.skip : make_node(AST_EmptyStatement, node);
                    }
@@ -3768,7 +4112,8 @@
    }
    function is_undefined(node, compressor) {
        return node.is_undefined
        return node == null
            || node.is_undefined
            || node instanceof AST_Undefined
            || node instanceof AST_UnaryPrefix
                && node.operator == "void"
@@ -4091,9 +4436,6 @@
            "setUTCMonth",
            "setUTCSeconds",
            "setYear",
            "toExponential",
            "toFixed",
            "toPrecision",
        ]);
        def(AST_Call, function(compressor) {
            if (!compressor.option("unsafe")) return false;
@@ -4109,9 +4451,15 @@
        def(AST_Sequence, function(compressor) {
            return this.tail_node().is_number(compressor);
        });
        def(AST_SymbolRef, function(compressor) {
        def(AST_SymbolRef, function(compressor, keep_unary) {
            var fixed = this.fixed_value();
            if (!fixed) return false;
            if (keep_unary
                && fixed instanceof AST_UnaryPrefix
                && fixed.operator == "+"
                && fixed.expression.equivalent_to(this)) {
                return false;
            }
            this.is_number = return_false;
            var result = fixed.is_number(compressor);
            delete this.is_number;
@@ -4144,7 +4492,10 @@
            "charAt",
            "substr",
            "substring",
            "toExponential",
            "toFixed",
            "toLowerCase",
            "toPrecision",
            "toString",
            "toUpperCase",
            "trim",
@@ -4443,6 +4794,7 @@
        });
        var scan_modified = new TreeWalker(function(node) {
            if (node instanceof AST_Assign) modified(node.left);
            if (node instanceof AST_ForEnumeration) modified(node.init);
            if (node instanceof AST_Unary && UNARY_POSTFIX[node.operator]) modified(node.expression);
        });
        function modified(node) {
@@ -4537,7 +4889,6 @@
            }
            return this;
        });
        var nonsafe_props = makePredicate("__proto__ toString valueOf");
        def(AST_Object, function(compressor, ignore_side_effects, cached, depth) {
            if (compressor.option("unsafe")) {
                var val = {};
@@ -4549,7 +4900,12 @@
                        key = key._eval(compressor, ignore_side_effects, cached, depth);
                        if (key === prop.key) return this;
                    }
                    if (nonsafe_props[key]) return this;
                    switch (key) {
                      case "__proto__":
                      case "toString":
                      case "valueOf":
                        return this;
                    }
                    val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth);
                    if (val[key] === prop.value) return this;
                }
@@ -4681,7 +5037,7 @@
            return result;
            function decimals(operand) {
                var match = /(\.[0-9]*)?(e.+)?$/.exec(+operand);
                var match = /(\.[0-9]*)?(e[^e]+)?$/.exec(+operand);
                return (match[1] || ".").length - 1 - (match[2] || "").slice(1);
            }
        });
@@ -4808,10 +5164,11 @@
                if (!all(fn.argnames, function(sym, index) {
                    if (sym instanceof AST_DefaultValue) {
                        if (!args) return false;
                        if (args[index] !== undefined) return false;
                        var value = sym.value._eval(compressor, ignore_side_effects, cached, depth);
                        if (value === sym.value) return false;
                        args[index] = value;
                        if (args[index] === undefined) {
                            var value = sym.value._eval(compressor, ignore_side_effects, cached, depth);
                            if (value === sym.value) return false;
                            args[index] = value;
                        }
                        sym = sym.name;
                    }
                    return !(sym instanceof AST_Destructured);
@@ -4834,7 +5191,7 @@
                            }
                            if (node instanceof AST_Scope && node !== fn) return true;
                        }));
                        delete fn.evaluating;
                        fn.evaluating = false;
                        if (!found) return;
                    }
                    return this;
@@ -4845,9 +5202,12 @@
                if (!args || all(fn.argnames, function(sym, i) {
                    return assign(sym, args[i]);
                }) && !(fn.rest && !assign(fn.rest, args.slice(fn.argnames.length))) || ignore_side_effects) {
                    if (ignore_side_effects) fn.argnames.forEach(function(sym) {
                        if (sym instanceof AST_DefaultValue) sym.value.walk(scan_modified);
                    });
                    fn.evaluating = true;
                    val = val._eval(compressor, ignore_side_effects, cached, depth);
                    delete fn.evaluating;
                    fn.evaluating = false;
                }
                cached_args.forEach(function(node) {
                    delete node._eval;
@@ -4925,11 +5285,9 @@
            return this;
            function decode(str) {
                return str.replace(/\\(u\{[^}]*\}?|u[\s\S]{0,4}|x[\s\S]{0,2}|[0-9]+|[\s\S])/g, function(match, seq) {
                    var s = decode_escape_sequence(seq);
                    if (typeof s != "string") malformed = true;
                    return s;
                });
                str = decode_template(str);
                if (typeof str != "string") malformed = true;
                return str;
            }
        });
    })(function(node, func) {
@@ -5070,21 +5428,42 @@
        return map && map[prop];
    });
    function spread_side_effects(exp) {
        while ((exp = exp.tail_node()) instanceof AST_SymbolRef) {
            exp = exp.fixed_value();
            if (!exp) return true;
        }
        return !(exp instanceof AST_Array
            || exp.TYPE == "Binary" && !lazy_op[exp.operator]
            || exp instanceof AST_Constant
            || exp instanceof AST_Lambda
            || exp instanceof AST_Object && all(exp.properties, function(prop) {
    // determine if object spread syntax may cause runtime exception
    (function(def) {
        def(AST_Node, return_false);
        def(AST_Array, return_true);
        def(AST_Assign, function() {
            switch (this.operator) {
              case "=":
                return this.right.safe_to_spread();
              case "&&=":
              case "||=":
              case "??=":
                return this.left.safe_to_spread() && this.right.safe_to_spread();
            }
            return true;
        });
        def(AST_Binary, function() {
            return !lazy_op[this.operator] || this.left.safe_to_spread() && this.right.safe_to_spread();
        });
        def(AST_Constant, return_true);
        def(AST_Lambda, return_true);
        def(AST_Object, function() {
            return all(this.properties, function(prop) {
                return !(prop instanceof AST_ObjectGetter || prop instanceof AST_Spread);
            })
            || exp instanceof AST_ObjectIdentity
            || exp instanceof AST_Unary);
    }
            });
        });
        def(AST_Sequence, function() {
            return this.tail_node().safe_to_spread();
        });
        def(AST_SymbolRef, function() {
            var fixed = this.fixed_value();
            return fixed && fixed.safe_to_spread();
        });
        def(AST_Unary, return_true);
    })(function(node, func) {
        node.DEFMETHOD("safe_to_spread", func);
    });
    // determine if expression has side effects
    (function(def) {
@@ -5096,7 +5475,8 @@
            });
        }
        function array_spread(node, compressor) {
            return !node.expression.is_string(compressor) || node.expression.has_side_effects(compressor);
            var exp = node.expression;
            return !exp.is_string(compressor) || exp.has_side_effects(compressor);
        }
        def(AST_Node, return_true);
        def(AST_Array, function(compressor) {
@@ -5162,7 +5542,7 @@
            return any(this.properties, compressor);
        });
        def(AST_Dot, function(compressor) {
            return !this.optional && this.expression.may_throw_on_access(compressor)
            return this.expression.may_throw_on_access(compressor)
                || this.expression.has_side_effects(compressor);
        });
        def(AST_EmptyStatement, return_false);
@@ -5178,7 +5558,7 @@
        def(AST_Object, function(compressor) {
            return any(this.properties, compressor, function(node, compressor) {
                var exp = node.expression;
                return spread_side_effects(exp) || exp.has_side_effects(compressor);
                return !exp.safe_to_spread() || exp.has_side_effects(compressor);
            });
        });
        def(AST_ObjectIdentity, return_false);
@@ -5193,7 +5573,7 @@
            return this.body.has_side_effects(compressor);
        });
        def(AST_Sub, function(compressor) {
            return !this.optional && this.expression.may_throw_on_access(compressor)
            return this.expression.may_throw_on_access(compressor)
                || this.expression.has_side_effects(compressor)
                || this.property.has_side_effects(compressor);
        });
@@ -5229,7 +5609,6 @@
        def(AST_Node, return_true);
        def(AST_Constant, return_false);
        def(AST_Destructured, return_true);
        def(AST_EmptyStatement, return_false);
        def(AST_Lambda, return_false);
        def(AST_ObjectIdentity, return_false);
@@ -5262,6 +5641,9 @@
                return false;
            }
            return this.left.may_throw(compressor);
        });
        def(AST_Await, function(compressor) {
            return this.expression.may_throw(compressor);
        });
        def(AST_Binary, function(compressor) {
            return this.left.may_throw(compressor)
@@ -5298,6 +5680,14 @@
        def(AST_Dot, function(compressor) {
            return !this.optional && this.expression.may_throw_on_access(compressor)
                || this.expression.may_throw(compressor);
        });
        def(AST_ForEnumeration, function(compressor) {
            if (this.init.may_throw(compressor)) return true;
            var obj = this.object;
            if (obj.may_throw(compressor)) return true;
            obj = obj.tail_node();
            if (!(obj instanceof AST_Array || obj.is_string(compressor))) return true;
            return this.body.may_throw(compressor);
        });
        def(AST_If, function(compressor) {
            return this.condition.may_throw(compressor)
@@ -5485,6 +5875,21 @@
        return compressor.option("unused") && self.label.references.length == 0 ? self.body : self;
    });
    OPT(AST_LoopControl, function(self, compressor) {
        if (!compressor.option("dead_code")) return self;
        var label = self.label;
        if (label) {
            var lct = compressor.loopcontrol_target(self);
            self.label = null;
            if (compressor.loopcontrol_target(self) === lct) {
                remove(label.thedef.references, self);
            } else {
                self.label = label;
            }
        }
        return self;
    });
    OPT(AST_Block, function(self, compressor) {
        self.body = tighten_body(self.body, compressor);
        return self;
@@ -5563,6 +5968,7 @@
                    fn = fn.fixed_value();
                }
                if (!(fn instanceof AST_Defun || fn instanceof AST_Function)) break;
                if (fn.rest) break;
                if (fn.uses_arguments) break;
                if (fn === call.expression) {
                    if (fn.parent_scope !== self) break;
@@ -5665,10 +6071,7 @@
            }
            if (node instanceof AST_Binary) {
                if (!lazy_op[node.operator]) return;
                node.left.walk(tw);
                push();
                node.right.walk(tw);
                pop();
                walk_cond(node);
                return true;
            }
            if (node instanceof AST_Break) {
@@ -5678,28 +6081,37 @@
            }
            if (node instanceof AST_Call) {
                var exp = node.expression;
                var tail = exp.tail_node();
                if (!(tail instanceof AST_LambdaExpression)) {
                if (exp instanceof AST_LambdaExpression) {
                    node.args.forEach(function(arg) {
                        arg.walk(tw);
                    });
                    exp.walk(tw);
                } else {
                    descend();
                    return mark_expression(exp);
                    mark_expression(exp);
                }
                if (exp !== tail) exp.expressions.slice(0, -1).forEach(function(node) {
                    node.walk(tw);
                return true;
            }
            if (node instanceof AST_Class) {
                if (node.name) node.name.walk(tw);
                if (node.extends) node.extends.walk(tw);
                node.properties.filter(function(prop) {
                    if (prop.key instanceof AST_Node) prop.key.walk(tw);
                    return prop.value;
                }).forEach(function(prop) {
                    if (prop.static) {
                        prop.value.walk(tw);
                    } else {
                        push();
                        segment.block = node;
                        prop.value.walk(tw);
                        pop();
                    }
                });
                node.args.forEach(function(arg) {
                    arg.walk(tw);
                });
                tail.walk(tw);
                return true;
            }
            if (node instanceof AST_Conditional) {
                node.condition.walk(tw);
                push();
                node.consequent.walk(tw);
                pop();
                push();
                node.alternative.walk(tw);
                pop();
                walk_cond(node.condition, node.consequent, node.alternative);
                return true;
            }
            if (node instanceof AST_Continue) {
@@ -5740,15 +6152,7 @@
                return true;
            }
            if (node instanceof AST_If) {
                node.condition.walk(tw);
                push();
                node.body.walk(tw);
                pop();
                if (node.alternative) {
                    push();
                    node.alternative.walk(tw);
                    pop();
                }
                walk_cond(node.condition, node.body, node.alternative);
                return true;
            }
            if (node instanceof AST_LabeledStatement) {
@@ -5766,6 +6170,8 @@
                if (node === self) root = segment;
                if (node instanceof AST_Lambda) {
                    if (node.name) references[node.name.definition().id] = false;
                    var parent = tw.parent();
                    var in_iife = parent && parent.TYPE == "Call" && parent.expression === node;
                    var marker = node.uses_arguments && !tw.has_directive("use strict") ? function(node) {
                        if (node instanceof AST_SymbolFunarg) references[node.definition().id] = false;
                    } : function(node) {
@@ -5781,11 +6187,13 @@
                            || node.parent_scope.find_variable(ref.name) === def)) {
                            references[def.id] = false;
                            references[ldef.id] = false;
                        } else {
                        } else if (in_iife) {
                            var save = segment;
                            pop();
                            mark(ref, true);
                            segment = save;
                        } else {
                            mark(ref, true);
                        }
                        return true;
                    });
@@ -5808,7 +6216,8 @@
                } else {
                    descend();
                }
                return mark_expression(exp);
                mark_expression(exp);
                return true;
            }
            if (node instanceof AST_Switch) {
                node.expression.walk(tw);
@@ -5840,9 +6249,7 @@
            if (node instanceof AST_Try) {
                var save_try = in_try;
                in_try = node;
                var save = segment;
                walk_body(node, tw);
                segment = save;
                if (node.bcatch) {
                    if (node.bcatch.argname) node.bcatch.argname.mark_symbol(function(node) {
                        if (node instanceof AST_SymbolCatch) {
@@ -5860,7 +6267,6 @@
                    }
                }
                in_try = save_try;
                segment = save;
                if (node.bfinally) node.bfinally.walk(tw);
                return true;
            }
@@ -5910,62 +6316,95 @@
            }
            function mark_expression(exp) {
                if (compressor.option("ie")) {
                    var sym = root_expr(exp);
                    if (sym instanceof AST_SymbolRef) sym.walk(tw);
                if (!compressor.option("ie")) return;
                var sym = root_expr(exp);
                if (sym instanceof AST_SymbolRef) sym.walk(tw);
            }
            function walk_cond(condition, consequent, alternative) {
                var save = segment;
                var segments = [ save, save ];
                if (condition instanceof AST_Binary) switch (condition.operator) {
                  case "&&":
                    segments[0] = walk_cond(condition.left, condition.right)[0];
                    break;
                  case "||":
                  case "??":
                    segments[1] = walk_cond(condition.left, null, condition.right)[1];
                    break;
                  default:
                    condition.walk(tw);
                    break;
                } else if (condition instanceof AST_Conditional) {
                    walk_cond(condition.condition, condition.consequent, condition.alternative);
                } else {
                    condition.walk(tw);
                }
                return true;
                segment = segments[0];
                if (consequent) {
                    push();
                    consequent.walk(tw);
                }
                segments[0] = segment;
                segment = segments[1];
                if (alternative) {
                    push();
                    alternative.walk(tw);
                }
                segments[1] = segment;
                segment = save;
                return segments;
            }
        });
        tw.directives = Object.create(compressor.directives);
        self.walk(tw);
        var changed = false;
        var merged = Object.create(null);
        while (first.length && last.length) {
            var head = first.pop();
            var def = head.definition;
            if (!(def.id in prev)) continue;
            if (!references[def.id]) continue;
            var head_refs = {
                start: references[def.id].start,
            };
            var tail = last.shift();
            if (!tail) continue;
            var def = tail.definition;
            var tail_refs = references[def.id];
            if (!tail_refs) continue;
            tail_refs = { end: tail_refs.end };
            while (def.id in merged) def = merged[def.id];
            head_refs.end = references[def.id].end;
            tail_refs.start = references[def.id].start;
            var skipped = [];
            do {
                var tail = last.pop();
                if (!tail) continue;
                var head = first.shift();
                if (tail.index > head.index) continue;
                var id = tail.definition.id;
                var tail_refs = references[id];
                if (!tail_refs) continue;
                var id = head.definition.id;
                if (!(id in prev)) continue;
                var head_refs = references[id];
                if (!head_refs) continue;
                if (head_refs.start.block !== tail_refs.start.block
                    || !mergeable(head_refs, tail_refs)
                    || (head_refs.start.loop || !same_scope(def)) && !mergeable(tail_refs, head_refs)
                    || compressor.option("webkit") && is_funarg(def) !== is_funarg(tail.definition)
                    || !all(tail_refs, function(sym) {
                    || compressor.option("webkit") && is_funarg(def) !== is_funarg(head.definition)
                    || head.definition.const_redefs
                    || !all(head_refs, function(sym) {
                        return sym.scope.find_variable(def.name) === def;
                    })) {
                    skipped.unshift(tail);
                    skipped.push(head);
                    continue;
                }
                var orig = [], refs = [];
                tail_refs.forEach(function(sym) {
                head_refs.forEach(function(sym) {
                    sym.thedef = def;
                    sym.name = def.name;
                    if (sym instanceof AST_SymbolRef) {
                        refs.push(sym);
                        def.references.push(sym);
                    } else {
                        orig.push(sym);
                        def.orig.push(sym);
                    }
                });
                def.orig = orig.concat(def.orig);
                def.references = refs.concat(def.references);
                def.fixed = tail.definition.fixed && def.fixed;
                if (!head.definition.fixed) def.fixed = false;
                merged[id] = def;
                changed = true;
                break;
            } while (last.length);
            if (skipped.length) last = last.concat(skipped);
            } while (first.length);
            if (skipped.length) first = skipped.concat(first);
        }
        return changed;
        function push() {
            segment = Object.create(segment);
@@ -6057,7 +6496,7 @@
    function to_class_expr(defcl, drop_name) {
        var cl = make_node(AST_ClassExpression, defcl, defcl);
        cl.name = drop_name ? null : make_node(AST_SymbolClass, defcl.name, defcl.name);
        if (cl.name) cl.name = drop_name ? null : make_node(AST_SymbolClass, cl.name, cl.name);
        return cl;
    }
@@ -6175,27 +6614,28 @@
            if (scope === self) {
                if (node instanceof AST_DefClass) {
                    var def = node.name.definition();
                    if ((!drop_funcs || def.exported) && !(def.id in in_use_ids)) {
                    var drop = drop_funcs && !def.exported;
                    if (!drop && !(def.id in in_use_ids)) {
                        in_use_ids[def.id] = true;
                        in_use.push(def);
                    }
                    if (node.extends) node.extends.walk(tw);
                    var is_export = false;
                    if (tw.parent() instanceof AST_ExportDefault) {
                        is_export = true;
                        export_defaults[def.id] = true;
                    }
                    var used = tw.parent() instanceof AST_ExportDefault;
                    if (used) export_defaults[def.id] = true;
                    var values = [];
                    node.properties.forEach(function(prop) {
                        if (prop.key instanceof AST_Node) prop.key.walk(tw);
                        if (!prop.value) return;
                        if (is_export || prop instanceof AST_ClassField && prop.static) {
                            var save_scope = scope;
                            scope = node;
                            prop.value.walk(tw);
                            scope = save_scope;
                        var value = prop.value;
                        if (!value) return;
                        if (prop instanceof AST_ClassField && prop.static) {
                            if (!used && value.contains_this()) used = true;
                            walk_class_prop(value);
                        } else {
                            initializations.add(def.id, prop.value);
                            values.push(value);
                        }
                    });
                    values.forEach(drop && used ? walk_class_prop : function(value) {
                        initializations.add(def.id, value);
                    });
                    return true;
                }
@@ -6262,6 +6702,13 @@
                }
            }
            return scan_ref_scoped(node, descend, true);
            function walk_class_prop(value) {
                var save_scope = scope;
                scope = node;
                value.walk(tw);
                scope = save_scope;
            }
        });
        tw.directives = Object.create(compressor.directives);
        self.walk(tw);
@@ -6327,7 +6774,6 @@
            }
        });
        // pass 3: we should drop declarations not in_use
        var trim_defns = [];
        var unused_fn_names = [];
        var calls_to_drop_args = [];
        var fns_with_marked_args = [];
@@ -6422,11 +6868,18 @@
                    && indexOf_assign(node.expression.definition(), node) < 0) {
                    return make_node(AST_UnaryPrefix, node, {
                        operator: "+",
                        expression: node.expression
                        expression: node.expression,
                    });
                }
            }
            if (node instanceof AST_Call) calls_to_drop_args.push(node);
            if (node instanceof AST_Call) {
                calls_to_drop_args.push(node);
                node.args = node.args.map(function(arg) {
                    return arg.transform(tt);
                });
                node.expression = node.expression.transform(tt);
                return node;
            }
            if (scope !== self) return;
            if (drop_funcs && node !== self && node instanceof AST_DefClass) {
                var def = node.name.definition();
@@ -6434,9 +6887,9 @@
                    log(node.name, "Dropping unused class {name}");
                    def.eliminated++;
                    descend(node, tt);
                    if (parent instanceof AST_ExportDefault) return to_class_expr(node, true);
                    var trimmed = node.drop_side_effect_free(compressor, true);
                    if (trimmed === node) trimmed = to_class_expr(node, true);
                    var trimmed = to_class_expr(node, true);
                    if (parent instanceof AST_ExportDefault) return trimmed;
                    trimmed = trimmed.drop_side_effect_free(compressor, true);
                    if (trimmed) return make_node(AST_SimpleStatement, node, { body: trimmed });
                    return in_list ? List.skip : make_node(AST_EmptyStatement, node);
                }
@@ -6461,8 +6914,28 @@
                    unused_fn_names.push(node);
                }
                if (!(node instanceof AST_Accessor)) {
                    if (node.rest) {
                        var rest = node.rest.transform(trimmer);
                    var args, spread, trim = compressor.drop_fargs(node, parent);
                    if (trim && parent instanceof AST_Call && parent.expression === node) {
                        args = parent.args;
                        for (spread = 0; spread < args.length; spread++) {
                            if (args[spread] instanceof AST_Spread) break;
                        }
                    }
                    var argnames = node.argnames;
                    var rest = node.rest;
                    if (rest) {
                        if (!args || spread < argnames.length || rest instanceof AST_SymbolFunarg) {
                            rest = rest.transform(trimmer);
                        } else {
                            var trimmed = trim_destructured(rest, make_node(AST_Array, parent, {
                                elements: args.slice(argnames.length),
                            }), function(node) {
                                return node.definition().id in in_use_ids ? node : null;
                            }, !node.uses_arguments, rest);
                            rest = trimmed.name;
                            args.length = argnames.length;
                            if (trimmed.value.elements.length) [].push.apply(args, trimmed.value.elements);
                        }
                        if (rest instanceof AST_Destructured && !rest.rest
                            && (!node.uses_arguments || tt.has_directive("use strict"))) {
                            if (rest instanceof AST_DestructuredArray) {
@@ -6472,38 +6945,44 @@
                            }
                        }
                        node.rest = rest;
                        if (rest) trim = false;
                    }
                    var argnames = node.argnames;
                    var trim = compressor.drop_fargs(node, parent) && !node.rest;
                    var default_length = trim ? -1 : node.length();
                    for (var i = argnames.length; --i >= 0;) {
                        var sym = argnames[i];
                        if (!(sym instanceof AST_SymbolFunarg)) {
                            var arg = sym.transform(trimmer);
                            if (arg) {
                        if (sym instanceof AST_SymbolFunarg) {
                            var def = sym.definition();
                            if (def.id in in_use_ids) {
                                trim = false;
                                if (indexOf_assign(def, sym) < 0) sym.unused = null;
                            } else if (trim) {
                                log(sym, "Dropping unused function argument {name}");
                                argnames.pop();
                            } else {
                                sym.unused = true;
                            }
                        } else {
                            var funarg;
                            if (!args || spread < i) {
                                funarg = sym.transform(trimmer);
                            } else {
                                funarg = trim_destructured(sym, args[i], function(node) {
                                    return node.definition().id in in_use_ids ? node : null;
                                }, !node.uses_arguments, sym).name;
                            }
                            if (funarg) {
                                trim = false;
                            } else if (trim) {
                                log(sym.name, "Dropping unused default argument {name}");
                                log_default(sym, "Dropping unused default argument {name}");
                                argnames.pop();
                            } else if (i > default_length) {
                                log(sym.name, "Dropping unused default argument assignment {name}");
                                sym.name.__unused = true;
                                log_default(sym, "Dropping unused default argument assignment {name}");
                                if (sym.name instanceof AST_SymbolFunarg) sym.name.unused = true;
                                argnames[i] = sym.name;
                            } else {
                                log(sym.name, "Dropping unused default argument value {name}");
                                log_default(sym, "Dropping unused default argument value {name}");
                                sym.value = make_node(AST_Number, sym, { value: 0 });
                            }
                            continue;
                        }
                        var def = sym.definition();
                        if (def.id in in_use_ids) {
                            trim = false;
                            if (indexOf_assign(def, sym) < 0) sym.__unused = null;
                        } else if (trim) {
                            log(sym, "Dropping unused function argument {name}");
                            argnames.pop();
                        } else {
                            sym.__unused = true;
                        }
                    }
                    fns_with_marked_args.push(node);
@@ -6546,16 +7025,21 @@
                    var sym = def.name.definition();
                    var drop_sym = is_var ? can_drop_symbol(def.name) : is_safe_lexical(sym);
                    if (!drop_sym || !drop_vars || sym.id in in_use_ids) {
                        if (value && indexOf_assign(sym, def) < 0) {
                        var index;
                        if (value && ((index = indexOf_assign(sym, def)) < 0 || self_assign(value.tail_node()))) {
                            def = def.clone();
                            value = value.drop_side_effect_free(compressor);
                            if (value) {
                                AST_Node.warn("Side effects in last use of variable {name} [{file}:{line},{col}]", template(def.name));
                                side_effects.push(value);
                            if (value) AST_Node.warn("Side effects in definition of variable {name} [{file}:{line},{col}]", template(def.name));
                            if (node instanceof AST_Const) {
                                def.value = value || make_node(AST_Number, def, { value: 0 });
                            } else {
                                def.value = null;
                                if (value) side_effects.push(value);
                            }
                            value = null;
                            trim_defns.push(def);
                            if (index >= 0) assign_in_use[sym.id][index] = def;
                        }
                        var old_def;
                        var old_def, fn;
                        if (!value && !(node instanceof AST_Let)) {
                            if (parent instanceof AST_ExportDeclaration) {
                                flush();
@@ -6569,17 +7053,18 @@
                        } else if (compressor.option("functions")
                            && !compressor.option("ie")
                            && drop_sym
                            && value
                            && var_defs[sym.id] == 1
                            && sym.assignments == 0
                            && value instanceof AST_LambdaExpression
                            && (fn = value.tail_node()) instanceof AST_LambdaExpression
                            && !is_arguments(sym)
                            && !is_arrow(value)
                            && assigned_once(value, sym.references)
                            && can_declare_defun(value)
                            && (old_def = rename_def(value, def.name.name)) !== false) {
                            && !is_arrow(fn)
                            && assigned_once(fn, sym.references)
                            && can_declare_defun(fn)
                            && (old_def = rename_def(fn, def.name.name)) !== false) {
                            AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
                            var ctor;
                            switch (value.CTOR) {
                            switch (fn.CTOR) {
                              case AST_AsyncFunction:
                                ctor = AST_AsyncDefun;
                                break;
@@ -6593,7 +7078,7 @@
                                ctor = AST_GeneratorDefun;
                                break;
                            }
                            var defun = make_node(ctor, def, value);
                            var defun = make_node(ctor, def, fn);
                            defun.name = make_node(AST_SymbolDefun, def.name, def.name);
                            var name_def = def.name.scope.resolve().def_function(defun.name);
                            if (old_def) old_def.forEach(function(node) {
@@ -6602,6 +7087,7 @@
                                node.reference();
                            });
                            body.push(defun);
                            if (value !== fn) [].push.apply(side_effects, value.expressions.slice(0, -1));
                        } else {
                            if (drop_sym
                                && var_defs[sym.id] > 1
@@ -6624,7 +7110,7 @@
                            head.push(def);
                        }
                    } else {
                        value = value && !value.single_use && value.drop_side_effect_free(compressor);
                        value = value && value.drop_side_effect_free(compressor);
                        if (value) {
                            AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
                            side_effects.push(value);
@@ -6632,6 +7118,10 @@
                            log(def.name, "Dropping unused variable {name}");
                        }
                        sym.eliminated++;
                    }
                    function self_assign(ref) {
                        return ref instanceof AST_SymbolRef && ref.definition() === sym;
                    }
                    function assigned_once(fn, refs) {
@@ -6656,6 +7146,7 @@
                        if (def.orig.length > 1) return null;
                        if (def.assignments > 0) return false;
                        if (def.name == name) return def;
                        if (compressor.option("keep_fnames")) return false;
                        var forbidden;
                        switch (name) {
                          case "await":
@@ -6713,7 +7204,7 @@
                            var assign = make_node(AST_Assign, def, {
                                operator: "=",
                                left: ref,
                                right: def.value
                                right: def.value,
                            });
                            var index = indexOf_assign(sym, def);
                            if (index >= 0) assign_in_use[sym.id][index] = assign;
@@ -6732,13 +7223,18 @@
                        }
                    }
                  default:
                    var seq;
                    if (tail.length > 0 && (seq = tail[0].value) instanceof AST_Sequence) {
                        tail[0].value = seq.tail_node();
                        body.push(make_node(AST_SimpleStatement, node, {
                            body: make_sequence(seq, seq.expressions.slice(0, -1)),
                        }));
                    }
                    node.definitions = head.concat(tail);
                    body.push(node);
                }
                if (side_effects.length > 0) {
                    body.push(make_node(AST_SimpleStatement, node, {
                        body: make_sequence(node, side_effects)
                    }));
                    body.push(make_node(AST_SimpleStatement, node, { body: make_sequence(node, side_effects) }));
                }
                return insert_statements(body, node, in_list);
            }
@@ -6787,33 +7283,7 @@
            }
        }, function(node, in_list) {
            if (node instanceof AST_BlockStatement) return trim_block(node, tt.parent(), in_list);
            // Certain combination of unused name + side effect leads to invalid AST:
            //    https://github.com/mishoo/UglifyJS/issues/44
            //    https://github.com/mishoo/UglifyJS/issues/1838
            //    https://github.com/mishoo/UglifyJS/issues/3371
            // We fix it at this stage by moving the `var` outside the `for`.
            if (node instanceof AST_For) {
                var block;
                if (node.init instanceof AST_BlockStatement) {
                    block = node.init;
                    node.init = block.body.pop();
                    block.body.push(node);
                }
                if (node.init instanceof AST_Defun) {
                    if (!block) {
                        block = make_node(AST_BlockStatement, node, {
                            body: [ node ]
                        });
                    }
                    block.body.splice(-1, 0, node.init);
                    node.init = null;
                } else if (node.init instanceof AST_SimpleStatement) {
                    node.init = node.init.body;
                } else if (is_empty(node.init)) {
                    node.init = null;
                }
                return !block ? node : in_list ? List.splice(block.body) : block;
            }
            if (node instanceof AST_For) return patch_for_init(node, in_list);
            if (node instanceof AST_ForIn) {
                if (!drop_vars || !compressor.option("loops")) return;
                if (!is_empty(node.body)) return;
@@ -6853,9 +7323,6 @@
            && self.body[0].value == "use strict") {
            self.body.length = 0;
        }
        trim_defns.forEach(function(def) {
            def.value = null;
        });
        unused_fn_names.forEach(function(fn) {
            fn.name = null;
        });
@@ -6865,6 +7332,19 @@
        function log(sym, text) {
            AST_Node[sym.definition().references.length > 0 ? "info" : "warn"](text + " [{file}:{line},{col}]", template(sym));
        }
        function log_default(node, text) {
            if (node.name instanceof AST_SymbolFunarg) {
                log(node.name, text);
            } else {
                AST_Node.info(text + " [{file}:{line},{col}]", {
                    name: node,
                    file: node.start.file,
                    line: node.start.line,
                    col : node.start.col,
                });
            }
        }
        function template(sym) {
@@ -7057,24 +7537,26 @@
                var value = node.value.drop_side_effect_free(compressor);
                if (!value) return null;
                log(node.name, "Side effects in default value of unused variable {name}");
                node.name.__unused = null;
                node.name.unused = null;
                node.value = value;
            }
            return node;
        }
        function trim_destructured(node, value, process, drop) {
        function trim_destructured(node, value, process, drop, root) {
            var trimmer = new TreeTransformer(function(node) {
                if (node instanceof AST_DefaultValue) {
                    if (compressor.option("default_values") && value && value.is_defined(compressor)) {
                        node = node.name;
                    } else {
                    if (!(compressor.option("default_values") && value && value.is_defined(compressor))) {
                        var save_drop = drop;
                        drop = false;
                        var trimmed = trim_default(trimmer, node);
                        drop = save_drop;
                        if (!trimmed && drop && value) value = value.drop_side_effect_free(compressor);
                        return trimmed;
                    } else if (node === root) {
                        root = node = node.name;
                    } else {
                        node = node.name;
                    }
                }
                if (node instanceof AST_DestructuredArray) {
@@ -7137,12 +7619,17 @@
                    if (!node.rest && (value instanceof AST_Array
                        || value && value.is_string(compressor))) switch (elements.length) {
                      case 0:
                        if (node === root) break;
                        if (drop) value = value.drop_side_effect_free(compressor);
                        return null;
                      case 1:
                        if (!drop) break;
                        if (node === root) break;
                        var sym = elements[0];
                        if (!(sym instanceof AST_Symbol)) break;
                        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 }),
@@ -7163,7 +7650,7 @@
                    var prop_keys, prop_map;
                    if (value instanceof AST_Object) {
                        prop_keys = [];
                        prop_map = Object.create(null);
                        prop_map = new Dictionary();
                        value.properties.forEach(function(prop, index) {
                            if (prop instanceof AST_Spread) return prop_map = false;
                            var key = prop.key;
@@ -7171,7 +7658,7 @@
                            if (key instanceof AST_Node) {
                                prop_map = false;
                            } else if (prop_map && !(prop instanceof AST_ObjectSetter)) {
                                prop_map[key] = prop;
                                prop_map.set(key, prop);
                            }
                            prop_keys[index] = key;
                        });
@@ -7180,8 +7667,8 @@
                        value = false;
                        node.rest = node.rest.transform(compressor.option("rests") ? trimmer : tt);
                    }
                    var can_drop = Object.create(null);
                    var drop_keys = drop && Object.create(null);
                    var can_drop = new Dictionary();
                    var drop_keys = drop && new Dictionary();
                    var properties = [];
                    node.properties.map(function(prop) {
                        var key = prop.key;
@@ -7192,7 +7679,7 @@
                        if (key instanceof AST_Node) {
                            drop_keys = false;
                        } else {
                            can_drop[key] = !(key in can_drop);
                            can_drop.set(key, !can_drop.has(key));
                        }
                        return key;
                    }).forEach(function(key, index) {
@@ -7202,8 +7689,8 @@
                            value = false;
                            trimmed = prop.value.transform(trimmer) || retain_lhs(prop.value);
                        } else {
                            drop = drop_keys && can_drop[key];
                            var mapped = prop_map && prop_map[key];
                            drop = drop_keys && can_drop.get(key);
                            var mapped = prop_map && prop_map.get(key);
                            if (mapped) {
                                value = mapped.value;
                                if (value instanceof AST_Accessor) value = false;
@@ -7213,21 +7700,21 @@
                            trimmed = prop.value.transform(trimmer);
                            if (!trimmed) {
                                if (node.rest || retain_key(prop)) trimmed = retain_lhs(prop.value);
                                if (drop_keys && !(key in drop_keys)) {
                                if (drop_keys && !drop_keys.has(key)) {
                                    if (mapped) {
                                        drop_keys[key] = mapped;
                                        drop_keys.set(key, mapped);
                                        if (value === null) {
                                            prop_map[key] = retain_key(mapped) && make_node(AST_ObjectKeyVal, mapped, {
                                            prop_map.set(key, retain_key(mapped) && make_node(AST_ObjectKeyVal, mapped, {
                                                key: mapped.key,
                                                value: make_node(AST_Number, mapped, { value: 0 }),
                                            });
                                            }));
                                        }
                                    } else {
                                        drop_keys[key] = true;
                                        drop_keys.set(key, true);
                                    }
                                }
                            } else if (drop_keys) {
                                drop_keys[key] = false;
                                drop_keys.set(key, false);
                            }
                            if (value) mapped.value = value;
                        }
@@ -7242,10 +7729,10 @@
                        if (prop instanceof AST_Spread) return prop;
                        var key = prop_keys[index];
                        if (key instanceof AST_Node) return prop;
                        if (key in drop_keys) {
                            var mapped = drop_keys[key];
                        if (drop_keys.has(key)) {
                            var mapped = drop_keys.get(key);
                            if (!mapped) return prop;
                            if (mapped === prop) return prop_map[key] || List.skip;
                            if (mapped === prop) return prop_map.get(key) || List.skip;
                        } else if (node.rest) {
                            return prop;
                        }
@@ -7261,14 +7748,19 @@
                    });
                    if (value && !node.rest) switch (properties.length) {
                      case 0:
                        if (node === root) break;
                        if (value.may_throw_on_access(compressor, true)) break;
                        if (drop) value = value.drop_side_effect_free(compressor);
                        return null;
                      case 1:
                        if (!drop) break;
                        if (node === root) break;
                        var prop = properties[0];
                        if (prop.key instanceof AST_Node) break;
                        if (!(prop.value instanceof AST_Symbol)) break;
                        if (prop.value.has_side_effects(compressor)) break;
                        if (value.has_side_effects(compressor) && prop.value.match_symbol(function(node) {
                            return node instanceof AST_PropAccess;
                        })) break;
                        value = make_node(AST_Sub, node, {
                            expression: value,
                            property: make_node_from_constant(prop.key, prop),
@@ -7295,20 +7787,41 @@
                return prop.key instanceof AST_Node && prop.key.has_side_effects(compressor);
            }
            function clear_write_only(node) {
                if (node instanceof AST_Assign) {
                    node.write_only = false;
                    clear_write_only(node.right);
                } else if (node instanceof AST_Binary) {
                    if (!lazy_op[node.operator]) return;
                    clear_write_only(node.left);
                    clear_write_only(node.right);
                } else if (node instanceof AST_Conditional) {
                    clear_write_only(node.consequent);
                    clear_write_only(node.alternative);
                } else if (node instanceof AST_Sequence) {
                    clear_write_only(node.tail_node());
                } else if (node instanceof AST_Unary) {
                    node.write_only = false;
                }
            }
            function retain_lhs(node) {
                if (node instanceof AST_DefaultValue) return retain_lhs(node.name);
                if (node instanceof AST_Destructured) {
                    if (value === null) {
                        value = make_node(AST_Number, node, { value: 0 });
                    } else if (value && (value.tail_node().write_only === true
                        || value.may_throw_on_access(compressor, true))) {
                        value = make_node(AST_Array, node, {
                            elements: value instanceof AST_Sequence ? value.expressions : [ value ],
                        });
                    } else if (value) {
                        if (value.may_throw_on_access(compressor, true)) {
                            value = make_node(AST_Array, node, {
                                elements: value instanceof AST_Sequence ? value.expressions : [ value ],
                            });
                        } else {
                            clear_write_only(value);
                        }
                    }
                    return make_node(AST_DestructuredObject, node, { properties: [] });
                }
                node.__unused = null;
                node.unused = null;
                return node;
            }
        }
@@ -7335,10 +7848,10 @@
            if (var_decl <= 1) hoist_vars = false;
        }
        if (!hoist_funs && !hoist_vars) return;
        var consts = Object.create(null);
        var consts = new Dictionary();
        var dirs = [];
        var hoisted = [];
        var vars = new Dictionary(), vars_found = 0;
        var vars = new Dictionary();
        var tt = new TreeTransformer(function(node, descend, in_list) {
            if (node === self) return;
            if (node instanceof AST_Directive) {
@@ -7361,18 +7874,17 @@
                if (!all(node.definitions, function(defn) {
                    var sym = defn.name;
                    return sym instanceof AST_SymbolVar
                        && !consts[sym.name]
                        && !consts.has(sym.name)
                        && self.find_variable(sym.name) === sym.definition();
                })) return node;
                node.definitions.forEach(function(def) {
                    vars.set(def.name.name, def);
                    ++vars_found;
                node.definitions.forEach(function(defn) {
                    vars.set(defn.name.name, defn);
                });
                var seq = node.to_assignments();
                if (p instanceof AST_ForEnumeration && p.init === node) {
                    if (seq) return seq;
                    var def = node.definitions[0].name;
                    return make_node(AST_SymbolRef, def, def);
                    var sym = node.definitions[0].name;
                    return make_node(AST_SymbolRef, sym, sym);
                }
                if (p instanceof AST_For && p.init === node) return seq;
                if (!seq) return in_list ? List.skip : make_node(AST_EmptyStatement, node);
@@ -7380,28 +7892,29 @@
            }
            if (node instanceof AST_Scope) return node;
            if (node instanceof AST_SymbolConst) {
                consts[node.name] = true;
                consts.set(node.name, true);
                return node;
            }
        });
        self.transform(tt);
        if (vars_found > 0) {
        if (vars.size() > 0) {
            // collect only vars which don't show up in self's arguments list
            var defs = [];
            var defns = [];
            if (self instanceof AST_Lambda) self.each_argname(function(argname) {
                vars.del(argname.name);
            });
            vars.each(function(def, name) {
                def = def.clone();
                def.value = null;
                defs.push(def);
                vars.set(name, def);
            vars.each(function(defn, name) {
                defn = defn.clone();
                defn.name = defn.name.clone();
                defn.value = null;
                defns.push(defn);
                vars.set(name, defn);
                defn.name.definition().orig.unshift(defn.name);
            });
            if (defs.length > 0) {
            if (defns.length > 0) {
                // try to merge in assignments
                insert_vars(self.body);
                defs = make_node(AST_Var, self, { definitions: defs });
                hoisted.push(defs);
                hoisted.push(make_node(AST_Var, self, { definitions: defns }));
            }
        }
        self.body = dirs.concat(hoisted, self.body);
@@ -7415,13 +7928,13 @@
                        && expr.operator == "="
                        && (sym = expr.left) instanceof AST_Symbol
                        && vars.has(sym.name)) {
                        var def = vars.get(sym.name);
                        if (def.value) break;
                        var defn = vars.get(sym.name);
                        if (defn.value) break;
                        var value = expr.right;
                        if (value instanceof AST_Sequence) value = value.clone();
                        def.value = value;
                        remove(defs, def);
                        defs.push(def);
                        defn.value = value;
                        remove(defns, defn);
                        defns.push(defn);
                        body.shift();
                        continue;
                    }
@@ -7430,11 +7943,11 @@
                        && assign.operator == "="
                        && (sym = assign.left) instanceof AST_Symbol
                        && vars.has(sym.name)) {
                        var def = vars.get(sym.name);
                        if (def.value) break;
                        def.value = assign.right;
                        remove(defs, def);
                        defs.push(def);
                        var defn = vars.get(sym.name);
                        if (defn.value) break;
                        defn.value = assign.right;
                        remove(defns, defn);
                        defns.push(defn);
                        stat.body = make_sequence(expr, expr.expressions.slice(1));
                        continue;
                    }
@@ -7463,7 +7976,7 @@
        }));
    }
    function map_bool_returns(fn) {
    function map_self_returns(fn) {
        var map = Object.create(null);
        scan_local_returns(fn, function(node) {
            var value = node.value;
@@ -7476,9 +7989,14 @@
        return map;
    }
    function all_bool(def, bool_returns, compressor) {
        return def.bool_fn + (bool_returns[def.id] || 0) === def.references.length - def.replaced
            && !compressor.exposed(def);
    function can_trim_returns(def, self_returns, compressor) {
        if (compressor.exposed(def)) return false;
        switch (def.references.length - def.replaced - (self_returns[def.id] || 0)) {
          case def.drop_return:
            return "d";
          case def.bool_return:
            return true;
        }
    }
    function process_boolean_returns(fn, compressor) {
@@ -7504,50 +8022,85 @@
        });
    }
    AST_Scope.DEFMETHOD("process_boolean_returns", noop);
    AST_Defun.DEFMETHOD("process_boolean_returns", function(compressor) {
    AST_Scope.DEFMETHOD("process_returns", noop);
    AST_Defun.DEFMETHOD("process_returns", function(compressor) {
        if (!compressor.option("booleans")) return;
        var bool_returns = map_bool_returns(this);
        if (!all_bool(this.name.definition(), bool_returns, compressor)) return;
        if (compressor.parent() instanceof AST_ExportDefault) return;
        process_boolean_returns(this, compressor);
        switch (can_trim_returns(this.name.definition(), map_self_returns(this), compressor)) {
          case "d":
            drop_returns(compressor, this, true);
            break;
          case true:
            process_boolean_returns(this, compressor);
            break;
        }
    });
    AST_Function.DEFMETHOD("process_boolean_returns", function(compressor) {
    AST_Function.DEFMETHOD("process_returns", function(compressor) {
        if (!compressor.option("booleans")) return;
        var bool_returns = map_bool_returns(this);
        if (this.name && !all_bool(this.name.definition(), bool_returns, compressor)) return;
        var drop = true;
        var self_returns = map_self_returns(this);
        if (this.name && !can_trim(this.name.definition())) return;
        var parent = compressor.parent();
        if (parent instanceof AST_Assign) {
            if (parent.operator != "=") return;
            var sym = parent.left;
            if (!(sym instanceof AST_SymbolRef)) return;
            if (!all_bool(sym.definition(), bool_returns, compressor)) return;
            if (!can_trim(sym.definition())) return;
        } else if (parent instanceof AST_Call && parent.expression !== this) {
            var exp = parent.expression;
            if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
            if (!(exp instanceof AST_Lambda)) return;
            if (exp.uses_arguments || exp.pinned()) return;
            var sym = exp.argnames[parent.args.indexOf(this)];
            var args = parent.args, sym;
            for (var i = 0; i < args.length; i++) {
                var arg = args[i];
                if (arg === this) {
                    sym = exp.argnames[i];
                    if (!sym && exp.rest) return;
                    break;
                }
                if (arg instanceof AST_Spread) return;
            }
            if (sym instanceof AST_DefaultValue) sym = sym.name;
            if (sym instanceof AST_SymbolFunarg && !all_bool(sym.definition(), bool_returns, compressor)) return;
            if (sym instanceof AST_SymbolFunarg && !can_trim(sym.definition())) return;
        } else if (parent.TYPE == "Call") {
            compressor.pop();
            var in_bool = compressor.in_boolean_context();
            compressor.push(this);
            if (!in_bool) return;
            switch (in_bool) {
              case true:
                drop = false;
              case "d":
                break;
              default:
                return;
            }
        } else return;
        process_boolean_returns(this, compressor);
        if (drop) {
            drop_returns(compressor, this, true);
        } else {
            process_boolean_returns(this, compressor);
        }
        function can_trim(def) {
            switch (can_trim_returns(def, self_returns, compressor)) {
              case true:
                drop = false;
              case "d":
                return true;
            }
        }
    });
    AST_BlockScope.DEFMETHOD("var_names", function() {
        var var_names = this._var_names;
        if (!var_names) {
            this._var_names = var_names = Object.create(null);
            this._var_names = var_names = new Dictionary();
            this.enclosed.forEach(function(def) {
                var_names[def.name] = true;
                var_names.set(def.name, true);
            });
            this.variables.each(function(def, name) {
                var_names[name] = true;
                var_names.set(name, true);
            });
        }
        return var_names;
@@ -7563,10 +8116,10 @@
                s = s.parent_scope;
            } while (s && s !== this);
        });
        prefix = prefix.replace(/(?:^[^a-z_$]|[^a-z0-9_$])/ig, "_");
        prefix = prefix.replace(/^[^a-z_$]|[^a-z0-9_$]/gi, "_");
        var name = prefix;
        for (var i = 0; !all(scopes, function(scope) {
            return !scope.var_names()[name];
            return !scope.var_names().has(name);
        }); i++) name = prefix + "$" + i;
        var sym = make_node(type, orig, {
            name: name,
@@ -7575,7 +8128,7 @@
        var def = this.def_variable(sym);
        scopes.forEach(function(scope) {
            scope.enclosed.push(def);
            scope.var_names()[name] = true;
            scope.var_names().set(name, true);
        });
        return sym;
    });
@@ -7612,6 +8165,7 @@
                        right: prop.value,
                    }));
                });
                defs.value = node.right;
                defs_by_id[node.left.definition().id] = defs;
                self.body.splice(self.body.indexOf(this.stack[1]) + 1, 0, make_node(AST_Var, node, {
                    definitions: decls,
@@ -7624,12 +8178,16 @@
                descend(node, this);
                var defs = new Dictionary();
                var var_defs = [];
                var decl = node.clone();
                decl.value = node.name instanceof AST_SymbolConst ? make_node(AST_Number, node, { value: 0 }) : null;
                var_defs.push(decl);
                node.value.properties.forEach(function(prop) {
                    var_defs.push(make_node(AST_VarDef, node, {
                        name: make_sym(node.name.CTOR, node.name, prop.key),
                        value: prop.value,
                    }));
                });
                defs.value = node.value;
                defs_by_id[node.name.definition().id] = defs;
                return List.splice(var_defs);
            }
@@ -7645,6 +8203,7 @@
                if (!(node.expression instanceof AST_SymbolRef)) return;
                var defs = defs_by_id[node.expression.definition().id];
                if (!defs) return;
                if (node.expression.fixed_value() !== defs.value) return;
                var def = defs.get(node.get_property());
                var sym = make_node(AST_SymbolRef, node, {
                    name: def.name,
@@ -7655,7 +8214,9 @@
                return sym;
            }
            if (node instanceof AST_SymbolRef) {
                if (!(node.definition().id in defs_by_id)) return;
                var defs = defs_by_id[node.definition().id];
                if (!defs) return;
                if (node.fixed_value() !== defs.value) return;
                return make_node(AST_Object, node, { properties: [] });
            }
        }));
@@ -7664,18 +8225,16 @@
            if (!(sym instanceof AST_Symbol)) return;
            var def = sym.definition();
            if (def.assignments != count) return;
            if (def.direct_access) return;
            if (def.escaped.depth == 1) return;
            if (def.references.length - def.replaced == count) return;
            if (def.single_use) return;
            if (top_retain(def)) return;
            if (sym.fixed_value() !== right) return;
            var fixed = sym.fixed || def.fixed;
            if (fixed.direct_access) return;
            if (fixed.escaped && fixed.escaped.depth == 1) return;
            return right instanceof AST_Object
                && right.properties.length > 0
                && all(right.properties, can_hoist_property)
                && all(def.references, function(ref) {
                    return ref.fixed_value() === right;
                })
                && can_drop_symbol(sym, compressor);
        }
    });
@@ -7687,6 +8246,118 @@
        return all(def.references, function(sym) {
            return !(sym instanceof AST_SymbolRef);
        });
    }
    function drop_returns(compressor, exp, ignore_name) {
        if (!(exp instanceof AST_Lambda)) return;
        var arrow = is_arrow(exp);
        var async = is_async(exp);
        var changed = false;
        var drop_body = false;
        if (arrow && compressor.option("arrows")) {
            if (!exp.value) {
                drop_body = true;
            } else if (!async || is_primitive(compressor, exp.value)) {
                var dropped = exp.value.drop_side_effect_free(compressor);
                if (dropped !== exp.value) {
                    changed = true;
                    exp.value = dropped;
                }
            }
        } else if (!is_generator(exp)) {
            if (!ignore_name && exp.name) {
                var def = exp.name.definition();
                drop_body = def.references.length == def.replaced;
            } else {
                drop_body = true;
            }
        }
        if (drop_body) {
            exp.process_expression(false, function(node) {
                var value = node.value;
                if (value) {
                    if (async && !is_primitive(compressor, value)) return node;
                    value = value.drop_side_effect_free(compressor, true);
                }
                changed = true;
                if (!value) return make_node(AST_EmptyStatement, node);
                return make_node(AST_SimpleStatement, node, { body: value });
            });
            scan_local_returns(exp, function(node) {
                var value = node.value;
                if (value) {
                    if (async && !is_primitive(compressor, value)) return;
                    var dropped = value.drop_side_effect_free(compressor);
                    if (dropped !== value) {
                        changed = true;
                        node.value = dropped;
                    }
                }
            });
        }
        if (async && compressor.option("awaits")) {
            if (drop_body) exp.process_expression("awaits", function(node) {
                var body = node.body;
                if (body instanceof AST_Await) {
                    if (is_primitive(compressor, body.expression)) {
                        changed = true;
                        body = body.expression.drop_side_effect_free(compressor, true);
                        if (!body) return make_node(AST_EmptyStatement, node);
                        node.body = body;
                    }
                } else if (body instanceof AST_Sequence) {
                    var exprs = body.expressions;
                    for (var i = exprs.length; --i >= 0;) {
                        var tail = exprs[i];
                        if (!(tail instanceof AST_Await)) break;
                        var value = tail.expression;
                        if (!is_primitive(compressor, value)) break;
                        changed = true;
                        if (exprs[i] = value.drop_side_effect_free(compressor)) break;
                    }
                    switch (i) {
                      case -1:
                        return make_node(AST_EmptyStatement, node);
                      case 0:
                        node.body = exprs[0];
                        break;
                      default:
                        exprs.length = i + 1;
                        break;
                    }
                }
                return node;
            });
            var abort = !drop_body && exp.name || arrow && exp.value && !is_primitive(compressor, exp.value);
            var tw = new TreeWalker(function(node) {
                if (abort) return true;
                if (tw.parent() === exp && node.may_throw(compressor)) return abort = true;
                if (node instanceof AST_Await) return abort = true;
                if (node instanceof AST_ForAwaitOf) return abort = true;
                if (node instanceof AST_Return) {
                    if (node.value && !is_primitive(compressor, node.value)) return abort = true;
                    return;
                }
                if (node instanceof AST_Scope && node !== exp) return true;
            });
            exp.walk(tw);
            if (!abort) {
                var ctor;
                switch (exp.CTOR) {
                  case AST_AsyncArrow:
                    ctor = AST_Arrow;
                    break;
                  case AST_AsyncFunction:
                    ctor = AST_Function;
                    break;
                  case AST_AsyncGeneratorFunction:
                    ctor = AST_GeneratorFunction;
                    break;
                }
                return make_node(ctor, exp, exp);
            }
        }
        return changed && exp.clone();
    }
    // drop_side_effect_free()
@@ -7721,9 +8392,7 @@
            return exp.drop_side_effect_free(compressor, first_in_statement);
        }
        function convert_spread(node) {
            return node instanceof AST_Spread ? make_node(AST_Array, node, {
                elements: [ node ]
            }) : node;
            return node instanceof AST_Spread ? make_node(AST_Array, node, { elements: [ node ] }) : node;
        }
        def(AST_Node, return_this);
        def(AST_Accessor, return_null);
@@ -7743,21 +8412,25 @@
                if (compressor.has_directive("use strict") && expr.is_constant()) return this;
            }
            if (left.has_side_effects(compressor)) return this;
            var right = this.right;
            if (!lazy_op[this.operator.slice(0, -1)]) {
                this.write_only = true;
                if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
                    return right.drop_side_effect_free(compressor);
                }
            }
            return this;
            if (lazy_op[this.operator.slice(0, -1)]) return this;
            this.write_only = true;
            if (!root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) return this;
            return this.right.drop_side_effect_free(compressor);
        });
        def(AST_Await, function(compressor) {
            if (!compressor.option("awaits")) return this;
            var exp = this.expression;
            if (!is_primitive(compressor, exp)) return this;
            if (exp instanceof AST_UnaryPrefix && exp.operator == "!") exp = exp.expression;
            var dropped = exp.drop_side_effect_free(compressor);
            if (dropped === exp) return this;
            if (!dropped) {
                dropped = make_node(AST_Number, exp, { value: 0 });
            } else if (!is_primitive(compressor, dropped)) {
                dropped = dropped.negate(compressor);
            }
            var node = this.clone();
            node.expression = exp.drop_side_effect_free(compressor) || make_node(AST_Number, this, { value: 0 });
            node.expression = dropped;
            return node;
        });
        def(AST_Binary, function(compressor, first_in_statement) {
@@ -7780,12 +8453,12 @@
                    node.right = rhs.drop_side_effect_free(compressor);
                }
                if (op == "??") return node;
                var negated = make_node(AST_Binary, this, {
                    operator: op == "&&" ? "||" : "&&",
                    left: left.negate(compressor, first_in_statement),
                    right: node.right,
                });
                return first_in_statement ? best_of_statement(node, negated) : best_of_expression(node, negated);
                var negated = node.clone();
                negated.operator = op == "&&" ? "||" : "&&";
                negated.left = left.negate(compressor, first_in_statement);
                if (negated.operator == negated.right.operator) swap_chain(negated);
                var best = first_in_statement ? best_of_statement : best_of_expression;
                return op == "&&" ? best(node, negated) : best(negated, node);
            }
            var lhs = left.drop_side_effect_free(compressor, first_in_statement);
            if (!lhs) return rhs;
@@ -7793,102 +8466,15 @@
            if (!rhs) return lhs;
            return make_sequence(this, [ lhs, rhs ]);
        });
        function drop_returns(compressor, exp) {
            var arrow = is_arrow(exp);
            var async = is_async(exp);
            var drop_body = false;
            if (arrow && compressor.option("arrows")) {
                if (!exp.value) {
                    drop_body = true;
                } else if (!async || is_primitive(compressor, exp.value)) {
                    exp.value = exp.value.drop_side_effect_free(compressor);
                }
            } else if (exp instanceof AST_AsyncFunction || exp instanceof AST_Function) {
                if (exp.name) {
                    var def = exp.name.definition();
                    drop_body = def.references.length == def.replaced;
                } else {
                    drop_body = true;
                }
            }
            if (drop_body) {
                exp.process_expression(false, function(node) {
                    var value = node.value;
                    if (value) {
                        if (async && !is_primitive(compressor, value)) return node;
                        value = value.drop_side_effect_free(compressor, true);
                    }
                    if (!value) return make_node(AST_EmptyStatement, node);
                    return make_node(AST_SimpleStatement, node, { body: value });
                });
                scan_local_returns(exp, function(node) {
                    var value = node.value;
                    if (value) {
                        if (async && !is_primitive(compressor, value)) return;
                        node.value = value.drop_side_effect_free(compressor);
                    }
                });
            }
            if (async && compressor.option("awaits")) {
                if (drop_body) exp.process_expression("awaits", function(node) {
                    var body = node.body;
                    if (body instanceof AST_Await) {
                        if (is_primitive(compressor, body.expression)) {
                            body = body.expression.drop_side_effect_free(compressor, true);
                            if (!body) return make_node(AST_EmptyStatement, node);
                            node.body = body;
                        }
                    } else if (body instanceof AST_Sequence) {
                        var exprs = body.expressions;
                        for (var i = exprs.length; --i >= 0;) {
                            var tail = exprs[i];
                            if (!(tail instanceof AST_Await)) break;
                            if (!is_primitive(compressor, tail.expression)) break;
                            if (exprs[i] = tail.expression.drop_side_effect_free(compressor)) break;
                        }
                        switch (i) {
                          case -1:
                            return make_node(AST_EmptyStatement, node);
                          case 0:
                            node.body = exprs[0];
                            break;
                          default:
                            exprs.length = i + 1;
                            break;
                        }
                    }
                    return node;
                });
                var abort = !drop_body && exp.name || arrow && exp.value && !is_primitive(compressor, exp.value);
                var tw = new TreeWalker(function(node) {
                    if (abort) return true;
                    if (tw.parent() === exp && node.may_throw(compressor)) return abort = true;
                    if (node instanceof AST_Await) return abort = true;
                    if (node instanceof AST_ForAwaitOf) return abort = true;
                    if (node instanceof AST_Return) {
                        if (node.value && !is_primitive(compressor, node.value)) return abort = true;
                        return;
                    }
                    if (node instanceof AST_Scope && node !== exp) return true;
                });
                exp.walk(tw);
                if (!abort) {
                    var ctor;
                    switch (exp.CTOR) {
                      case AST_AsyncArrow:
                        ctor = AST_Arrow;
                        break;
                      case AST_AsyncFunction:
                        ctor = AST_Function;
                        break;
                      case AST_AsyncGeneratorFunction:
                        ctor = AST_GeneratorFunction;
                        break;
                    }
                    return make_node(ctor, exp, exp);
                }
            }
            return drop_body && exp.clone();
        function assign_this_only(fn, compressor) {
            fn.new = true;
            var result = all(fn.body, function(stat) {
                return !stat.has_side_effects(compressor);
            }) && all(fn.argnames, function(argname) {
                return !argname.match_symbol(return_false);
            }) && !(fn.rest && fn.rest.match_symbol(return_false));
            fn.new = false;
            return result;
        }
        def(AST_Call, function(compressor, first_in_statement) {
            var self = this;
@@ -7929,23 +8515,18 @@
                        exprs = trim(exprs, compressor, first_in_statement, array_spread);
                        return exprs && make_sequence(self, exprs.map(convert_spread));
                    }
                    if (!fn.contains_this()) self = make_node(AST_Call, self, self);
                    if (!fn.contains_this()) {
                        self = make_node(AST_Call, self, self);
                        self.expression = self.expression.clone();
                        self.args = self.args.slice();
                    }
                }
            }
            self.call_only = true;
            return self;
        });
        function assign_this_only(fn, compressor) {
            fn.new = true;
            var result = all(fn.body, function(stat) {
                return !stat.has_side_effects(compressor);
            }) && all(fn.argnames, function(argname) {
                return !argname.match_symbol(return_false);
            }) && !(fn.rest && fn.rest.match_symbol(return_false));
            delete fn.new;
            return result;
        }
        function drop_class(self, compressor, first_in_statement) {
        def(AST_ClassExpression, function(compressor, first_in_statement) {
            var self = this;
            var exprs = [], values = [];
            var props = self.properties;
            for (var i = 0; i < props.length; i++) {
@@ -7968,20 +8549,29 @@
            if (exprs) first_in_statement = false;
            values = trim(values, compressor, first_in_statement);
            if (!exprs) {
                if (!base && !values) return null;
                if (!base && !values && !self.name) return null;
                exprs = [];
            }
            if (base) {
                var node = to_class_expr(self, true);
            if (base || self.name || !compressor.has_directive("use strict")) {
                var node = to_class_expr(self);
                if (!base) node.extends = null;
                node.properties = [];
                if (exprs.length) node.properties.push(make_node(AST_ClassMethod, self, {
                    key: make_sequence(self, exprs),
                    value: make_node(AST_Function, self, {
                        argnames: [],
                        body: [],
                    }).init_vars(node),
                }));
                exprs = [ node ];
                if (values) {
                    node.properties.push(make_node(AST_ClassField, self, {
                        static: true,
                        key: exprs.length ? make_sequence(self, exprs) : "c",
                        value: make_sequence(self, values),
                    }));
                } else if (exprs.length) {
                    node.properties.push(make_node(AST_ClassMethod, self, {
                        key: make_sequence(self, exprs),
                        value: make_node(AST_Function, self, {
                            argnames: [],
                            body: [],
                        }).init_vars(node),
                    }));
                }
                return node;
            }
            if (values) exprs.push(make_node(AST_Call, self, {
                expression: make_node(AST_Arrow, self, {
@@ -7992,12 +8582,6 @@
                args: [],
            }));
            return make_sequence(self, exprs);
        }
        def(AST_ClassExpression, function(compressor, first_in_statement) {
            var self = this;
            var name = self.name;
            if (name && name.fixed_value() !== self && name.definition().references.length > 0) return self;
            return drop_class(self, compressor, first_in_statement);
        });
        def(AST_Conditional, function(compressor) {
            var consequent = this.consequent.drop_side_effect_free(compressor);
@@ -8020,30 +8604,27 @@
                node = alternative ? make_node(AST_Binary, this, {
                    operator: "||",
                    left: this.condition,
                    right: alternative
                    right: alternative,
                }) : this.condition.drop_side_effect_free(compressor);
            } else if (!alternative) {
                node = make_node(AST_Binary, this, {
                    operator: "&&",
                    left: this.condition,
                    right: consequent
                    right: consequent,
                });
            } else {
                node = this.clone();
                node.consequent = consequent;
                node.alternative = alternative;
            }
            if (!compressor.option("ie")) return node;
            if (!exprs) return node;
            if (node) exprs.push(node);
            return exprs.length == 0 ? null : make_sequence(this, exprs);
        });
        def(AST_Constant, return_null);
        def(AST_DefClass, function(compressor, first_in_statement) {
            return drop_class(this, compressor, first_in_statement);
        });
        def(AST_Dot, function(compressor, first_in_statement) {
            var expr = this.expression;
            if (!this.optional && expr.may_throw_on_access(compressor)) return this;
            if (expr.may_throw_on_access(compressor)) return this;
            return expr.drop_side_effect_free(compressor, first_in_statement);
        });
        def(AST_Function, function(compressor) {
@@ -8062,16 +8643,14 @@
            });
            var values = trim(exprs, compressor, first_in_statement, function(node, compressor, first_in_statement) {
                var exp = node.expression;
                return spread_side_effects(exp) ? node : exp.drop_side_effect_free(compressor, first_in_statement);
                return exp.safe_to_spread() ? exp.drop_side_effect_free(compressor, first_in_statement) : node;
            });
            if (!values) return null;
            if (values === exprs && !all(values, function(node) {
                return !(node instanceof AST_Spread);
            })) return this;
            return make_sequence(this, values.map(function(node) {
                return node instanceof AST_Spread ? make_node(AST_Object, node, {
                    properties: [ node ],
                }) : node;
                return node instanceof AST_Spread ? make_node(AST_Object, node, { properties: [ node ] }) : node;
            }));
        });
        def(AST_ObjectIdentity, return_null);
@@ -8083,7 +8662,8 @@
            if (compressor.option("awaits") && end > 0 && last instanceof AST_Await && last.expression.is_constant()) {
                expressions = expressions.slice(0, -1);
                end--;
                last.expression = expressions[end];
                var expr = expressions[end];
                last.expression = is_primitive(compressor, expr) ? expr : expr.negate(compressor);
                expressions[end] = last;
            }
            var assign, cond, lhs;
@@ -8102,17 +8682,8 @@
        });
        def(AST_Sub, function(compressor, first_in_statement) {
            var expr = this.expression;
            if (expr.may_throw_on_access(compressor)) return this;
            var prop = this.property;
            if (expr.may_throw_on_access(compressor)) {
                if (!this.optional) return this;
                if (prop.has_side_effects(compressor)) {
                    prop = prop.drop_side_effect_free(compressor);
                    if (!prop) return expr.drop_side_effect_free(compressor, first_in_statement);
                    var node = this.clone();
                    node.property = prop;
                    return node;
                }
            }
            expr = expr.drop_side_effect_free(compressor, first_in_statement);
            if (!expr) return prop.drop_side_effect_free(compressor, first_in_statement);
            prop = prop.drop_side_effect_free(compressor);
@@ -8407,6 +8978,7 @@
    });
    function mark_locally_defined(condition, consequent, alternative) {
        if (condition instanceof AST_Sequence) condition = condition.tail_node();
        if (!(condition instanceof AST_Binary)) return;
        if (!(condition.left instanceof AST_String)) {
            switch (condition.operator) {
@@ -8438,16 +9010,76 @@
            return;
        }
        if (!body) return;
        var abort = false;
        var def = sym.definition();
        var tw = new TreeWalker(function(node) {
            if (node instanceof AST_Scope) {
                var parent = tw.parent();
                if (parent instanceof AST_Call && parent.expression === node) return;
        var fn;
        var refs = [];
        var scanned = [];
        var tw = new TreeWalker(function(node, descend) {
            if (abort) return true;
            if (node instanceof AST_Assign) {
                var ref = node.left;
                if (!(ref instanceof AST_SymbolRef && ref.definition() === def)) return;
                node.right.walk(tw);
                switch (node.operator) {
                  case "=":
                  case "&&=":
                    abort = true;
                }
                return true;
            }
            if (node instanceof AST_SymbolRef && node.definition() === def) node.defined = true;
            if (node instanceof AST_Call) {
                descend();
                fn = node.expression.tail_node();
                var save;
                if (fn instanceof AST_SymbolRef) {
                    fn = fn.fixed_value();
                    save = refs.length;
                }
                if (!(fn instanceof AST_Lambda)) {
                    abort = true;
                } else if (push_uniq(scanned, fn)) {
                    fn.walk(tw);
                }
                if (save >= 0) refs.length = save;
                return true;
            }
            if (node instanceof AST_DWLoop) {
                var save = refs.length;
                descend();
                if (abort) refs.length = save;
                return true;
            }
            if (node instanceof AST_For) {
                if (node.init) node.init.walk(tw);
                var save = refs.length;
                if (node.condition) node.condition.walk(tw);
                node.body.walk(tw);
                if (node.step) node.step.walk(tw);
                if (abort) refs.length = save;
                return true;
            }
            if (node instanceof AST_ForEnumeration) {
                node.object.walk(tw);
                var save = refs.length;
                node.init.walk(tw);
                node.body.walk(tw);
                if (abort) refs.length = save;
                return true;
            }
            if (node instanceof AST_Scope) {
                if (node === fn) return;
                return true;
            }
            if (node instanceof AST_SymbolRef) {
                if (node.definition() === def) refs.push(node);
                return true;
            }
        });
        body.walk(tw);
        refs.forEach(function(ref) {
            ref.defined = true;
        });
        function negate(node) {
            if (!(node instanceof AST_Binary)) return;
@@ -8558,14 +9190,16 @@
            var cond = fuzzy_eval(compressor, self.condition);
            if (!cond) {
                AST_Node.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
                var body = [ make_node(AST_SimpleStatement, self.condition, { body: self.condition }) ];
                var body = [
                    make_node(AST_SimpleStatement, self.condition, { body: self.condition }).transform(compressor),
                ];
                extract_declarations_from_unreachable_code(compressor, self.body, body);
                if (self.alternative) body.push(self.alternative);
                return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
            } else if (!(cond instanceof AST_Node)) {
                AST_Node.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
                var body = [
                    make_node(AST_SimpleStatement, self.condition, { body: self.condition }),
                    make_node(AST_SimpleStatement, self.condition, { body: self.condition }).transform(compressor),
                    self.body,
                ];
                if (self.alternative) extract_declarations_from_unreachable_code(compressor, self.alternative, body);
@@ -8582,21 +9216,64 @@
            // here because they are only used in an equality comparison later on.
            self.condition = negated;
            var tmp = self.body;
            self.body = self.alternative || make_node(AST_EmptyStatement, self);
            self.alternative = tmp;
            self.body = self.alternative;
            self.alternative = is_empty(tmp) ? null : tmp;
        }
        var body = [], var_defs = [], refs = [];
        var body_exprs = sequencesize(self.body, body, var_defs, refs);
        var alt_exprs = sequencesize(self.alternative, body, var_defs, refs);
        if (body_exprs && alt_exprs) {
        var body_defuns = [];
        var body_var_defs = [];
        var body_refs = [];
        var body_exprs = sequencesize(self.body, body_defuns, body_var_defs, body_refs);
        var alt_defuns = [];
        var alt_var_defs = [];
        var alt_refs = [];
        var alt_exprs = sequencesize(self.alternative, alt_defuns, alt_var_defs, alt_refs);
        if (body_exprs instanceof AST_BlockStatement || alt_exprs instanceof AST_BlockStatement) {
            var body = [], var_defs = [];
            if (body_exprs) {
                [].push.apply(body, body_defuns);
                [].push.apply(var_defs, body_var_defs);
                if (body_exprs instanceof AST_BlockStatement) {
                    self.body = body_exprs;
                } else if (body_exprs.length == 0) {
                    self.body = make_node(AST_EmptyStatement, self.body);
                } else {
                    self.body = make_node(AST_SimpleStatement, self.body, {
                        body: make_sequence(self.body, body_exprs),
                    });
                }
                body_refs.forEach(process_to_assign);
            }
            if (alt_exprs) {
                [].push.apply(body, alt_defuns);
                [].push.apply(var_defs, alt_var_defs);
                if (alt_exprs instanceof AST_BlockStatement) {
                    self.alternative = alt_exprs;
                } else if (alt_exprs.length == 0) {
                    self.alternative = null;
                } else {
                    self.alternative = make_node(AST_SimpleStatement, self.alternative, {
                        body: make_sequence(self.alternative, alt_exprs),
                    });
                }
                alt_refs.forEach(process_to_assign);
            }
            if (var_defs.length > 0) body.push(make_node(AST_Var, self, { definitions: var_defs }));
            if (body.length > 0) {
                body.push(self);
                return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
            }
        } else if (body_exprs && alt_exprs) {
            var body = body_defuns.concat(alt_defuns);
            if (body_var_defs.length > 0 || alt_var_defs.length > 0) body.push(make_node(AST_Var, self, {
                definitions: body_var_defs.concat(alt_var_defs),
            }));
            if (body_exprs.length == 0) {
                body.push(make_node(AST_SimpleStatement, self.condition, {
                    body: alt_exprs.length > 0 ? make_node(AST_Binary, self, {
                        operator : "||",
                        left     : self.condition,
                        right    : make_sequence(self.alternative, alt_exprs)
                    }).transform(compressor) : self.condition.clone()
                        operator: "||",
                        left: self.condition,
                        right: make_sequence(self.alternative, alt_exprs),
                    }).transform(compressor) : self.condition.clone(),
                }).optimize(compressor));
            } else if (alt_exprs.length == 0) {
                if (self_condition_length === negated_length && !negated_is_best
@@ -8608,79 +9285,63 @@
                }
                body.push(make_node(AST_SimpleStatement, self, {
                    body: make_node(AST_Binary, self, {
                        operator : negated_is_best ? "||" : "&&",
                        left     : negated_is_best ? negated : self.condition,
                        right    : make_sequence(self.body, body_exprs)
                    }).transform(compressor)
                        operator: negated_is_best ? "||" : "&&",
                        left: negated_is_best ? negated : self.condition,
                        right: make_sequence(self.body, body_exprs),
                    }).transform(compressor),
                }).optimize(compressor));
            } else {
                body.push(make_node(AST_SimpleStatement, self, {
                    body: make_node(AST_Conditional, self, {
                        condition   : self.condition,
                        consequent  : make_sequence(self.body, body_exprs),
                        alternative : make_sequence(self.alternative, alt_exprs)
                    })
                        condition: self.condition,
                        consequent: make_sequence(self.body, body_exprs),
                        alternative: make_sequence(self.alternative, alt_exprs),
                    }),
                }).optimize(compressor));
            }
            refs.forEach(function(ref) {
                ref.definition().references.push(ref);
            });
            return make_node(AST_BlockStatement, self, {
                body: body
            }).optimize(compressor);
            body_refs.forEach(process_to_assign);
            alt_refs.forEach(process_to_assign);
            return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
        }
        if (is_empty(self.body)) {
            self = make_node(AST_If, self, {
                condition: negated,
                body: self.alternative,
                alternative: null
            });
        }
        if (self.body instanceof AST_Exit
            && self.alternative instanceof AST_Exit
            && self.body.TYPE == self.alternative.TYPE) {
        if (is_empty(self.body)) self = make_node(AST_If, self, {
            condition: negated,
            body: self.alternative,
            alternative: null,
        });
        if (self.alternative instanceof AST_Exit && self.body.TYPE == self.alternative.TYPE) {
            var exit = make_node(self.body.CTOR, self, {
                value: make_node(AST_Conditional, self, {
                    condition   : self.condition,
                    consequent  : self.body.value || make_node(AST_Undefined, self.body).transform(compressor),
                    alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).transform(compressor)
                })
                    condition: self.condition,
                    consequent: self.body.value || make_node(AST_Undefined, self.body).transform(compressor),
                    alternative: self.alternative.value
                        || make_node(AST_Undefined, self.alternative).transform(compressor),
                }),
            });
            if (exit instanceof AST_Return) {
                exit.in_bool = self.body.in_bool || self.alternative.in_bool;
            }
            if (exit instanceof AST_Return) exit.in_bool = self.body.in_bool || self.alternative.in_bool;
            return exit;
        }
        if (self.body instanceof AST_If
            && !self.body.alternative
            && !self.alternative) {
        if (self.body instanceof AST_If && !self.body.alternative && !self.alternative) {
            self = make_node(AST_If, self, {
                condition: make_node(AST_Binary, self.condition, {
                    operator: "&&",
                    left: self.condition,
                    right: self.body.condition
                    right: self.body.condition,
                }),
                body: self.body.body,
                alternative: null
                alternative: null,
            });
        }
        if (aborts(self.body)) {
            if (self.alternative) {
                var alt = self.alternative;
                self.alternative = null;
                return make_node(AST_BlockStatement, self, {
                    body: [ self, alt ]
                }).optimize(compressor);
            }
        if (aborts(self.body) && self.alternative) {
            var alt = self.alternative;
            self.alternative = null;
            return make_node(AST_BlockStatement, self, { body: [ self, alt ] }).optimize(compressor);
        }
        if (aborts(self.alternative)) {
            var body = self.body;
            self.body = self.alternative;
            self.condition = negated_is_best ? negated : self.condition.negate(compressor);
            self.alternative = null;
            return make_node(AST_BlockStatement, self, {
                body: [ self, body ]
            }).optimize(compressor);
            return make_node(AST_BlockStatement, self, { body: [ self, body ] }).optimize(compressor);
        }
        if (compressor.option("typeofs")) mark_locally_defined(self.condition, self.body, self.alternative);
        return self;
@@ -8691,10 +9352,21 @@
                var exprs = [];
                for (var i = 0; i < stat.body.length; i++) {
                    var line = stat.body[i];
                    if (line instanceof AST_EmptyStatement) continue;
                    if (line instanceof AST_Exit) {
                        if (i == 0) return;
                        if (exprs.length > 0) {
                            line = line.clone();
                            exprs.push(line.value || make_node(AST_Undefined, line).transform(compressor));
                            line.value = make_sequence(stat, exprs);
                        }
                        var block = stat.clone();
                        block.body = block.body.slice(i + 1);
                        block.body.unshift(line);
                        return block;
                    }
                    if (line instanceof AST_LambdaDefinition) {
                        defuns.push(line);
                    } else if (line instanceof AST_EmptyStatement) {
                        continue;
                    } else if (line instanceof AST_SimpleStatement) {
                        if (!compressor.option("sequences") && exprs.length > 0) return;
                        exprs.push(line.body);
@@ -8728,7 +9400,7 @@
                    left: var_def.name.convert_symbol(AST_SymbolRef, function(ref) {
                        refs.push(ref);
                    }),
                    right: var_def.value
                    right: var_def.value,
                }));
            }
        }
@@ -8856,20 +9528,12 @@
                    left: self.expression,
                    right: exp,
                }),
                body: make_node(AST_BlockStatement, self, {
                    body: statements,
                }),
                body: make_node(AST_BlockStatement, self, { body: statements }),
                alternative: null,
            }).optimize(compressor);
            if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, {
                body: exp,
            }));
            statements.unshift(make_node(AST_SimpleStatement, self.expression, {
                body:self.expression,
            }));
            return make_node(AST_BlockStatement, self, {
                body: statements,
            }).optimize(compressor);
            if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, { body: exp }));
            statements.unshift(make_node(AST_SimpleStatement, self.expression, { body: self.expression }));
            return make_node(AST_BlockStatement, self, { body: statements }).optimize(compressor);
          case 2:
            if (!member(default_branch, body) || !no_break(body[1])) break;
            var statements = body[0].body.slice();
@@ -8887,14 +9551,10 @@
                    left: self.expression,
                    right: body[0].expression,
                }),
                body: make_node(AST_BlockStatement, body[0], {
                    body: statements,
                }),
                body: make_node(AST_BlockStatement, body[0], { body: statements }),
                alternative: exclusive && alternative || null,
            });
            if (!exclusive && alternative) node = make_node(AST_BlockStatement, self, {
                body: [ node, alternative ],
            });
            if (!exclusive && alternative) node = make_node(AST_BlockStatement, self, { body: [ node, alternative ] });
            return node.optimize(compressor);
        }
        return self;
@@ -8949,16 +9609,12 @@
                if (self.bfinally) {
                    body.push(make_node(AST_BlockStatement, self.bfinally, self.bfinally).optimize(compressor));
                }
                return make_node(AST_BlockStatement, self, {
                    body: body
                }).optimize(compressor);
                return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
            }
            if (self.bfinally && has_declarations_only(self.bfinally)) {
                var body = make_node(AST_BlockStatement, self.bfinally, self.bfinally).optimize(compressor);
                body = self.body.concat(body);
                if (!self.bcatch) return make_node(AST_BlockStatement, self, {
                    body: body
                }).optimize(compressor);
                if (!self.bcatch) return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
                self.body = body;
                self.bfinally = null;
            }
@@ -9001,16 +9657,28 @@
                    right: value,
                });
                a.push(assign);
                name.fixed = function() {
                var fixed = function() {
                    return assign.right;
                };
                name.fixed.assigns = [ assign ];
                fixed.assigns = [ assign ];
                fixed.direct_access = def.direct_access;
                fixed.escaped = def.escaped;
                name.fixed = fixed;
                def.references.forEach(function(ref) {
                    var assigns = ref.fixed && ref.fixed.assigns;
                    if (assigns && assigns[0] === defn) assigns[0] = assign;
                    if (!ref.fixed) return;
                    var assigns = ref.fixed.assigns;
                    if (!assigns) return;
                    if (assigns[0] !== defn) return;
                    if (assigns.length > 1 || ref.fixed.to_binary || ref.fixed.to_prefix) {
                        assigns[0] = assign;
                    } else {
                        ref.fixed = fixed;
                        if (def.fixed === ref.fixed) def.fixed = fixed;
                    }
                });
                def.references.push(name);
            }
            def.assignments++;
            def.eliminated++;
            def.single_use = false;
            return a;
@@ -9028,7 +9696,7 @@
        var scope = def.scope.resolve();
        for (var s = def.scope; s !== scope;) {
            s = s.parent_scope;
            if (s.var_names()[def.name]) return true;
            if (s.var_names().has(def.name)) return true;
        }
    }
@@ -9044,7 +9712,7 @@
                        def.scope = scope;
                        scope.variables.set(def.name, def);
                        scope.enclosed.push(def);
                        scope.var_names()[def.name] = true;
                        scope.var_names().set(def.name, true);
                    }),
                    value: defn.value,
                });
@@ -9130,7 +9798,7 @@
            if (argname instanceof AST_DestructuredObject) {
                return argname.properties.length == 0 && !argname.rest && arg && !arg.may_throw_on_access(compressor);
            }
            return argname.__unused;
            return argname.unused;
        } : return_false;
        var side_effects = [];
        for (var i = 0; i < args.length; i++) {
@@ -9138,7 +9806,7 @@
            if (drop_defaults && argname instanceof AST_DefaultValue && args[i].is_defined(compressor)) {
                argnames[i] = argname = argname.name;
            }
            if (!argname || "__unused" in argname) {
            if (!argname || argname.unused !== undefined) {
                var node = args[i].drop_side_effect_free(compressor);
                if (drop_fargs(argname)) {
                    if (argname) argnames.splice(i, 1);
@@ -9155,9 +9823,7 @@
                        args[pos++] = make_sequence(call, side_effects);
                        side_effects = [];
                    } else {
                        args[pos++] = make_node(AST_Number, args[i], {
                            value: 0
                        });
                        args[pos++] = make_node(AST_Number, args[i], { value: 0 });
                        continue;
                    }
                }
@@ -9187,6 +9853,33 @@
            operator: "void",
            expression: arg,
        }) : arg);
    }
    function avoid_await_yield(parent_scope) {
        var avoid = [];
        if (is_async(parent_scope)) avoid.push("await");
        if (is_generator(parent_scope)) avoid.push("yield");
        return avoid.length && makePredicate(avoid);
    }
    function safe_from_await_yield(fn, avoid) {
        if (!avoid) return true;
        var safe = true;
        var tw = new TreeWalker(function(node) {
            if (!safe) return true;
            if (node instanceof AST_Scope) {
                if (node === fn) return;
                if (is_arrow(node)) {
                    for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw);
                } else if (node instanceof AST_LambdaDefinition && avoid[node.name.name]) {
                    safe = false;
                }
                return true;
            }
            if (node instanceof AST_Symbol && avoid[node.name] && node !== fn.name) safe = false;
        });
        fn.walk(tw);
        return safe;
    }
    OPT(AST_Call, function(self, compressor) {
@@ -9407,7 +10100,7 @@
                            expression: exp.expression,
                            property: "call",
                        }),
                        args: args
                        args: args,
                    }).optimize(compressor);
                }
                break;
@@ -9421,11 +10114,11 @@
                        self.args[0],
                        make_node(AST_Call, self, {
                            expression: exp.expression,
                            args: self.args.slice(1)
                        })
                            args: self.args.slice(1),
                        }),
                    ]) : make_node(AST_Call, self, {
                        expression: exp.expression,
                        args: []
                        args: [],
                    })).optimize(compressor);
                }
                break;
@@ -9503,24 +10196,27 @@
            if (argname instanceof AST_DefaultValue) {
                if (!has_default) has_default = 1;
                var arg = has_default == 1 && self.args[index];
                if (arg && !is_undefined(arg)) has_default = 2;
                if (has_arg_refs(argname.value)) return false;
                if (!is_undefined(arg)) has_default = 2;
                if (has_arg_refs(fn, argname.value)) return false;
                argname = argname.name;
            }
            if (argname instanceof AST_Destructured) {
                has_destructured = true;
                if (has_arg_refs(argname)) return false;
                if (has_arg_refs(fn, argname)) return false;
            }
            return true;
        }) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn.rest));
        }) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn, fn.rest));
        var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
        if (can_inline && stat instanceof AST_Return) {
            var value = stat.value;
            if (exp === fn && !fn.name && (!value || value.is_constant_expression()) && safe_from_await_yield(fn)) {
            if (exp === fn
                && !fn.name
                && (!value || value.is_constant_expression())
                && safe_from_await_yield(fn, avoid_await_yield(compressor.find_parent(AST_Scope)))) {
                return make_sequence(self, convert_args(value)).optimize(compressor);
            }
        }
        if (is_func) {
        if (is_func && !fn.contains_this()) {
            var def, value, var_assigned = false;
            if (can_inline
                && !fn.uses_arguments
@@ -9528,14 +10224,12 @@
                && !(fn.name && fn instanceof AST_LambdaExpression)
                && (exp === fn || !recursive_ref(compressor, def = exp.definition(), fn)
                    && fn.is_constant_expression(find_scope(compressor)))
                && !has_spread
                && (value = can_flatten_body(stat))
                && !fn.contains_this()) {
                && (value = can_flatten_body(stat))) {
                var replacing = exp === fn || def.single_use && def.references.length - def.replaced == 1;
                if (can_substitute_directly()) {
                    var args = self.args.slice();
                    var refs = [];
                    args.push(value.clone(true).transform(new TreeTransformer(function(node) {
                    var retValue = value.clone(true).transform(new TreeTransformer(function(node) {
                        if (node instanceof AST_SymbolRef) {
                            var def = node.definition();
                            if (fn.variables.get(node.name) !== def) {
@@ -9549,12 +10243,20 @@
                            var parent = this.parent();
                            return parent ? maintain_this_binding(compressor, parent, node, arg) : arg;
                        }
                    })));
                    }));
                    var save_inlined = fn.inlined;
                    if (exp !== fn) fn.inlined = true;
                    var node = make_sequence(self, args.filter(function(arg) {
                        return arg;
                    })).optimize(compressor);
                    var exprs = [];
                    args.forEach(function(arg) {
                        if (!arg) return;
                        arg = arg.clone(true);
                        arg.walk(new TreeWalker(function(node) {
                            if (node instanceof AST_SymbolRef) refs.push(node);
                        }));
                        exprs.push(arg);
                    }, []);
                    exprs.push(retValue);
                    var node = make_sequence(self, exprs).optimize(compressor);
                    fn.inlined = save_inlined;
                    node = maintain_this_binding(compressor, parent, current, node);
                    if (replacing || best_of_expression(node, self) === node) {
@@ -9567,7 +10269,12 @@
                        });
                        return node;
                    } else if (!node.has_side_effects(compressor)) {
                        self.drop_side_effect_free = return_null;
                        self.drop_side_effect_free = function(compressor, first_in_statement) {
                            var self = this;
                            var exprs = self.args.slice();
                            exprs.unshift(self.expression);
                            return make_sequence(self, exprs).drop_side_effect_free(compressor, first_in_statement);
                        };
                    }
                }
                var arg_used, insert, in_loop, scope;
@@ -9583,7 +10290,7 @@
                && all(fn.body, is_empty)
                && (fn === exp ? fn_name_unused(fn, compressor) : !has_default && !has_destructured && !fn.rest)
                && !(is_arrow(fn) && fn.value)
                && safe_from_await_yield(fn)) {
                && safe_from_await_yield(fn, avoid_await_yield(compressor.find_parent(AST_Scope)))) {
                return make_sequence(self, convert_args()).optimize(compressor);
            }
        }
@@ -9602,17 +10309,6 @@
            return self.negate(compressor, true);
        }
        return try_evaluate(compressor, self);
        function has_arg_refs(node) {
            var found = false;
            node.walk(new TreeWalker(function(node) {
                if (found) return true;
                if (node instanceof AST_SymbolRef && fn.variables.get(node.name) === node.definition()) {
                    return found = true;
                }
            }));
            return found;
        }
        function make_void_lhs(orig) {
            return make_node(AST_Dot, orig, {
@@ -9691,35 +10387,6 @@
            return args;
        }
        function avoid_await_yield() {
            var avoid = [];
            var parent_scope = scope || compressor.find_parent(AST_Scope);
            if (is_async(parent_scope)) avoid.push("await");
            if (is_generator(parent_scope)) avoid.push("yield");
            return avoid.length && makePredicate(avoid);
        }
        function safe_from_await_yield(node) {
            var avoid = avoid_await_yield();
            if (!avoid) return true;
            var safe = true;
            var tw = new TreeWalker(function(node) {
                if (!safe) return true;
                if (node instanceof AST_Scope) {
                    if (node === fn) return;
                    if (is_arrow(node)) {
                        for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw);
                    } else if (node instanceof AST_LambdaDefinition && avoid[node.name.name]) {
                        safe = false;
                    }
                    return true;
                }
                if (node instanceof AST_Symbol && avoid[node.name] && node !== fn.name) safe = false;
            });
            node.walk(tw);
            return safe;
        }
        function noop_value() {
            return self.call_only ? make_node(AST_Number, self, { value: 0 }) : make_node(AST_Undefined, self);
        }
@@ -9746,10 +10413,14 @@
            for (var i = 0; i < len; i++) {
                var line = fn.body[i];
                if (line instanceof AST_Var) {
                    var assigned = var_assigned || !declarations_only(line);
                    if (assigned) {
                    if (var_assigned) {
                        if (!stat) continue;
                        if (!(stat instanceof AST_SimpleStatement)) return false;
                        if (!declarations_only(line)) stat = null;
                    } else if (!declarations_only(line)) {
                        if (stat && !(stat instanceof AST_SimpleStatement)) return false;
                        stat = null;
                        var_assigned = true;
                        if (stat) return false;
                    }
                } else if (line instanceof AST_AsyncDefun
                    || line instanceof AST_Defun
@@ -9771,13 +10442,14 @@
        }
        function can_substitute_directly() {
            if (has_default || has_destructured || var_assigned || fn.rest) return;
            if (has_default || has_destructured || has_spread || var_assigned || fn.rest) return;
            if (compressor.option("inline") < 2 && fn.argnames.length) return;
            if (!fn.variables.all(function(def) {
                return def.references.length - def.replaced < 2 && def.orig[0] instanceof AST_SymbolFunarg;
            })) return;
            var scope = compressor.find_parent(AST_Scope);
            var abort = false;
            var avoid = avoid_await_yield();
            var avoid = avoid_await_yield(scope);
            var begin;
            var in_order = [];
            var side_effects = false;
@@ -9821,8 +10493,7 @@
                while (end-- > begin && fn.argnames[end] === in_order.pop());
                end++;
            }
            var scope = side_effects && !in_order && compressor.find_parent(AST_Scope);
            return end <= begin || all(self.args.slice(begin, end), scope ? function(funarg) {
            return end <= begin || all(self.args.slice(begin, end), side_effects && !in_order ? function(funarg) {
                return funarg.is_constant_expression(scope);
            } : function(funarg) {
                return !funarg.has_side_effects(compressor);
@@ -9830,30 +10501,33 @@
        }
        function var_exists(defined, name) {
            return defined[name] || identifier_atom[name] || scope.var_names()[name];
            return defined.has(name) || identifier_atom[name] || scope.var_names().has(name);
        }
        function can_inject_args(defined, used, safe_to_inject) {
        function can_inject_args(defined, safe_to_inject) {
            var abort = false;
            fn.each_argname(function(arg) {
                if (abort) return;
                if (arg.__unused) return;
                if (arg.unused) return;
                if (!safe_to_inject || var_exists(defined, arg.name)) return abort = true;
                used[arg.name] = true;
                arg_used.set(arg.name, true);
                if (in_loop) in_loop.push(arg.definition());
            });
            return !abort;
        }
        function can_inject_vars(defined, used, safe_to_inject) {
        function can_inject_vars(defined, safe_to_inject) {
            for (var i = 0; i < fn.body.length; i++) {
                var stat = fn.body[i];
                if (stat instanceof AST_LambdaDefinition) {
                    if (!safe_to_inject || var_exists(used, stat.name.name)) return false;
                    var name = stat.name;
                    if (!safe_to_inject) return false;
                    if (arg_used.has(name.name)) return false;
                    if (var_exists(defined, name.name)) return false;
                    if (!all(stat.enclosed, function(def) {
                        return def.scope === stat || !defined[def.name];
                        return def.scope === scope || def.scope === stat || !defined.has(def.name);
                    })) return false;
                    if (in_loop) in_loop.push(stat.name.definition());
                    if (in_loop) in_loop.push(name.definition());
                    continue;
                }
                if (!(stat instanceof AST_Var)) continue;
@@ -9868,12 +10542,12 @@
        }
        function can_inject_symbols() {
            var defined = Object.create(null);
            var defined = new Dictionary();
            var level = 0, child;
            scope = current;
            do {
                if (scope.variables) scope.variables.each(function(def) {
                    defined[def.name] = true;
                    defined.set(def.name, true);
                });
                child = scope;
                scope = compressor.parent(level++);
@@ -9886,33 +10560,30 @@
                    if (scope.init === child) continue;
                    if (scope.object === child) continue;
                    in_loop = [];
                } else if (scope instanceof AST_SymbolRef) {
                    if (scope.fixed_value() instanceof AST_Scope) return false;
                }
            } while (!(scope instanceof AST_Scope));
            insert = scope.body.indexOf(child) + 1;
            if (!insert) return false;
            if (!safe_from_await_yield(fn)) return false;
            var safe_to_inject = exp !== fn || fn.parent_scope.resolve() === scope;
            if (!safe_from_await_yield(fn, avoid_await_yield(scope))) return false;
            var safe_to_inject = (exp !== fn || fn.parent_scope.resolve() === scope) && !scope.pinned();
            if (scope instanceof AST_Toplevel) {
                if (compressor.toplevel.vars) {
                    defined["arguments"] = true;
                    defined.set("arguments", true);
                } else {
                    safe_to_inject = false;
                }
            }
            arg_used = new Dictionary();
            var inline = compressor.option("inline");
            arg_used = Object.create(defined);
            if (!can_inject_args(defined, arg_used, inline >= 2 && safe_to_inject)) return false;
            var used = Object.create(arg_used);
            if (!can_inject_vars(defined, used, inline >= 3 && safe_to_inject)) return false;
            if (!can_inject_args(defined, inline >= 2 && safe_to_inject)) return false;
            if (!can_inject_vars(defined, inline >= 3 && safe_to_inject)) return false;
            return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
        }
        function append_var(decls, expressions, name, value) {
            var def = name.definition();
            if (!scope.var_names()[name.name]) {
                scope.var_names()[name.name] = true;
            if (!scope.var_names().has(name.name)) {
                scope.var_names().set(name.name, true);
                decls.push(make_node(AST_VarDef, name, {
                    name: name,
                    value: null,
@@ -9922,6 +10593,7 @@
            scope.enclosed.push(def);
            if (!value) return;
            var sym = make_node(AST_SymbolRef, name, name);
            def.assignments++;
            def.references.push(sym);
            expressions.push(make_node(AST_Assign, self, {
                operator: "=",
@@ -9946,12 +10618,14 @@
                    name = argname;
                }
                var value = self.args[i];
                if (name.__unused || scope.var_names()[name.name]) {
                if (name.unused || scope.var_names().has(name.name)) {
                    if (value) expressions.push(value);
                } else {
                    var symbol = make_node(AST_SymbolVar, name, name);
                    name.definition().orig.push(symbol);
                    if ("__unused" in name) {
                    var def = name.definition();
                    def.orig.push(symbol);
                    def.eliminated++;
                    if (name.unused !== undefined) {
                        append_var(decls, expressions, symbol);
                        if (value) expressions.push(value);
                    } else {
@@ -9964,7 +10638,7 @@
            expressions.reverse();
            for (i = default_args.length; --i >= 0;) {
                var node = default_args[i];
                if ("__unused" in node.name) {
                if (node.name.unused !== undefined) {
                    expressions.push(node.value);
                } else {
                    var sym = make_node(AST_SymbolRef, node.name, node.name);
@@ -9983,7 +10657,7 @@
                operator: "=",
                left: make_node(AST_DestructuredArray, self, {
                    elements: fn.argnames.map(function(argname) {
                        if (argname.__unused) return make_node(AST_Hole, argname);
                        if (argname.unused) return make_node(AST_Hole, argname);
                        return argname.convert_symbol(AST_SymbolRef, process);
                    }),
                    rest: fn.rest && fn.rest.convert_symbol(AST_SymbolRef, process),
@@ -9993,61 +10667,60 @@
            function process(ref, name) {
                var def = name.definition();
                def.assignments++;
                def.references.push(ref);
                var symbol = make_node(AST_SymbolVar, name, name);
                def.orig.push(symbol);
                def.eliminated++;
                append_var(decls, expressions, symbol);
            }
        }
        function flatten_var(name) {
            var redef = name.definition().redefined();
            if (redef) {
                name = name.clone();
                name.thedef = redef;
            }
            return name;
        }
        function flatten_vars(decls, expressions) {
            var args = [ insert, 0 ];
            var decl_var = [], expr_var = [], expr_loop = [];
            for (var i = 0; i < fn.body.length; i++) {
                var stat = fn.body[i];
                if (stat instanceof AST_LambdaDefinition) {
                    if (in_loop) {
                        var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name));
                        name.definition().orig.push(name);
                        append_var(decls, expressions, name, to_func_expr(stat, true));
                    } else {
                        var def = stat.name.definition();
                        scope.functions.set(def.name, def);
                        scope.variables.set(def.name, def);
                        scope.enclosed.push(def);
                        scope.var_names()[def.name] = true;
                        args.push(stat);
                    }
                    continue;
            var decl_var = [], expr_fn = [], expr_var = [], expr_loop = [], exprs = [];
            fn.body.filter(in_loop ? function(stat) {
                if (!(stat instanceof AST_LambdaDefinition)) return true;
                var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name));
                var def = name.definition();
                def.fixed = false;
                def.orig.push(name);
                def.eliminated++;
                append_var(decls, expr_fn, name, to_func_expr(stat, true));
                return false;
            } : function(stat) {
                if (!(stat instanceof AST_LambdaDefinition)) return true;
                var def = stat.name.definition();
                scope.functions.set(def.name, def);
                scope.variables.set(def.name, def);
                scope.enclosed.push(def);
                scope.var_names().set(def.name, true);
                args.push(stat);
                return false;
            }).forEach(function(stat) {
                if (!(stat instanceof AST_Var)) {
                    if (stat instanceof AST_SimpleStatement) exprs.push(stat.body);
                    return;
                }
                if (!(stat instanceof AST_Var)) continue;
                for (var j = 0; j < stat.definitions.length; j++) {
                    var var_def = stat.definitions[j];
                    var name = flatten_var(var_def.name);
                    append_var(decl_var, expr_var, name, var_def.value);
                    if (in_loop && !HOP(arg_used, name.name)) {
                        var def = fn.variables.get(name.name);
                        var sym = make_node(AST_SymbolRef, name, name);
                        def.references.push(sym);
                        expr_loop.push(make_node(AST_Assign, var_def, {
                            operator: "=",
                            left: sym,
                            right: make_node(AST_Undefined, name),
                        }));
                    var value = var_def.value;
                    if (value && exprs.length > 0) {
                        exprs.push(value);
                        value = make_sequence(var_def, exprs);
                        exprs = [];
                    }
                    append_var(decl_var, expr_var, name, value);
                    if (!in_loop) continue;
                    if (arg_used.has(name.name)) continue;
                    if (name.definition().orig.length == 1 && fn.functions.has(name.name)) continue;
                    expr_loop.push(init_ref(compressor, name));
                }
            }
            });
            [].push.apply(decls, decl_var);
            [].push.apply(expressions, expr_loop);
            [].push.apply(expressions, expr_fn);
            [].push.apply(expressions, expr_var);
            return args;
        }
@@ -10055,21 +10728,19 @@
        function flatten_fn() {
            var decls = [];
            var expressions = [];
            if (has_default > 1 || has_destructured || fn.rest) {
            if (has_default > 1 || has_destructured || has_spread || fn.rest) {
                flatten_destructured(decls, expressions);
            } else {
                flatten_args(decls, expressions);
            }
            var args = flatten_vars(decls, expressions);
            expressions.push(value);
            if (decls.length) args.push(make_node(AST_Var, fn, {
                definitions: decls
            }));
            if (decls.length) args.push(make_node(AST_Var, fn, { definitions: decls }));
            [].splice.apply(scope.body, args);
            fn.enclosed.forEach(function(def) {
                if (scope.var_names()[def.name]) return;
                if (scope.var_names().has(def.name)) return;
                scope.enclosed.push(def);
                scope.var_names()[def.name] = true;
                scope.var_names().set(def.name, true);
            });
            return expressions;
        }
@@ -10215,42 +10886,52 @@
    OPT(AST_UnaryPrefix, function(self, compressor) {
        var op = self.operator;
        var exp = self.expression;
        if (compressor.option("evaluate") && op == "delete" && !may_not_delete(exp)) {
            return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor);
        }
        if (compressor.option("sequences") && can_lift()) {
            var seq = lift_sequence_in_expression(self, compressor);
            if (seq !== self) return seq.optimize(compressor);
        }
        if (compressor.option("side_effects") && op == "void") {
        switch (op) {
          case "+":
            if (!compressor.option("evaluate")) break;
            if (!exp.is_number(compressor, true)) break;
            var parent = compressor.parent();
            if (parent instanceof AST_UnaryPrefix && parent.operator == "delete") break;
            return exp;
          case "-":
            if (exp instanceof AST_Infinity) exp = exp.transform(compressor);
            // avoids infinite recursion of numerals
            if (exp instanceof AST_Number || exp instanceof AST_Infinity) return self;
            break;
          case "!":
            if (!compressor.option("booleans")) break;
            if (exp.is_truthy()) return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor);
            if (compressor.in_boolean_context()) {
                // !!foo ---> foo, if we're in boolean context
                if (exp instanceof AST_UnaryPrefix && exp.operator == "!") return exp.expression;
                if (exp instanceof AST_Binary) {
                    self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor)));
                }
            }
            break;
          case "delete":
            if (!compressor.option("evaluate")) break;
            if (may_not_delete(exp)) break;
            return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor);
          case "typeof":
            if (!compressor.option("booleans")) break;
            if (!compressor.in_boolean_context()) break;
            // typeof always returns a non-empty string, thus always truthy
            AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
            var exprs = [ make_node(AST_True, self) ];
            if (!(exp instanceof AST_SymbolRef && can_drop_symbol(exp, compressor))) exprs.unshift(exp);
            return make_sequence(self, exprs).optimize(compressor);
          case "void":
            if (!compressor.option("side_effects")) break;
            exp = exp.drop_side_effect_free(compressor);
            if (!exp) return make_node(AST_Undefined, self).optimize(compressor);
            self.expression = exp;
            return self;
        }
        if (compressor.option("booleans")) {
            if (op == "!" && exp.is_truthy()) {
                return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor);
            } else if (compressor.in_boolean_context()) switch (op) {
              case "!":
                if (exp instanceof AST_UnaryPrefix && exp.operator == "!") {
                    // !!foo ---> foo, if we're in boolean context
                    return exp.expression;
                }
                if (exp instanceof AST_Binary) {
                    self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor)));
                }
                break;
              case "typeof":
                // typeof always returns a non-empty string, thus it's
                // always true in booleans
                AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
                var exprs = [ make_node(AST_True, self) ];
                if (!(exp instanceof AST_SymbolRef && can_drop_symbol(exp, compressor))) exprs.unshift(exp);
                return make_sequence(self, exprs).optimize(compressor);
            }
        }
        if (op == "-" && exp instanceof AST_Infinity) exp = exp.transform(compressor);
        if (compressor.option("evaluate")
            && exp instanceof AST_Binary
            && SIGN_OPS[op]
@@ -10260,14 +10941,12 @@
                operator: exp.operator,
                left: make_node(AST_UnaryPrefix, exp.left, {
                    operator: op,
                    expression: exp.left
                    expression: exp.left,
                }),
                right: exp.right
                right: exp.right,
            });
        }
        // avoids infinite recursion of numerals
        return op == "-" && (exp instanceof AST_Number || exp instanceof AST_Infinity)
            ? self : try_evaluate(compressor, self);
        return try_evaluate(compressor, self);
        function may_not_delete(node) {
            return node instanceof AST_Infinity
@@ -10299,13 +10978,7 @@
        if (compressor.option("side_effects")) {
            var exp = self.expression;
            if (exp instanceof AST_Await) return exp.optimize(compressor);
            if (exp instanceof AST_UnaryPrefix) {
                if (exp.expression instanceof AST_Await) return exp.optimize(compressor);
                if (exp.operator == "void") return make_node(AST_UnaryPrefix, self, {
                    operator: "void",
                    expression: make_node(AST_Await, self, { expression: exp.expression }),
                }).optimize(compressor);
            }
            if (exp instanceof AST_UnaryPrefix && exp.expression instanceof AST_Await) return exp.optimize(compressor);
            for (var level = 0, node = self, parent; parent = compressor.parent(level++); node = parent) {
                if (is_arrow(parent)) {
                    if (parent.value === node) return exp.optimize(compressor);
@@ -10314,7 +10987,7 @@
                    do {
                        node = parent;
                        parent = compressor.parent(level++);
                        if (parent instanceof AST_Try && parent.bfinally && parent.bfinally !== node) {
                        if (parent instanceof AST_Try && (parent.bfinally || parent.bcatch) !== node) {
                            drop = false;
                            break;
                        }
@@ -10427,33 +11100,24 @@
        return !node.has_side_effects(compressor);
    }
    OPT(AST_Binary, function(self, compressor) {
        function reversible() {
            return self.left.is_constant()
                || self.right.is_constant()
                || !self.left.has_side_effects(compressor)
                    && !self.right.has_side_effects(compressor);
        }
        function reverse(op) {
            if (reversible()) {
                if (op) self.operator = op;
                var tmp = self.left;
                self.left = self.right;
                self.right = tmp;
            }
        }
        function swap_chain() {
            var rhs = self.right;
            self.left = make_node(AST_Binary, self, {
                operator: self.operator,
                left: self.left,
                right: rhs.left,
                start: self.left.start,
                end: rhs.left.end
            });
            self.right = rhs.right;
    function swap_chain(self, compressor) {
        var rhs = self.right;
        self.left = make_node(AST_Binary, self, {
            operator: self.operator,
            left: self.left,
            right: rhs.left,
            start: self.left.start,
            end: rhs.left.end
        });
        self.right = rhs.right;
        if (compressor) {
            self.left = self.left.transform(compressor);
        } else if (self.operator == rhs.left.operator) {
            swap_chain(self.left);
        }
    }
    OPT(AST_Binary, function(self, compressor) {
        if (commutativeOperators[self.operator]
            && self.right.is_constant()
            && !self.left.is_constant()
@@ -10476,9 +11140,15 @@
                && assign instanceof AST_Assign
                && assign.operator == "="
                && self.left.equivalent_to(assign.left)) {
                self.right = assign.right;
                assign.right = self;
                return assign;
                return make_node(AST_Assign, self, {
                    operator: "=",
                    left: assign.left,
                    right: make_node(AST_Binary, self, {
                        operator: self.operator,
                        left: self.left,
                        right: assign.right,
                    }),
                }).optimize(compressor);
            }
        }
        if (compressor.option("comparisons")) switch (self.operator) {
@@ -10532,30 +11202,20 @@
            // void 0 !== x && null !== x ---> null != x
            // void 0 === x || null === x ---> null == x
            var lhs = self.left;
            if (lhs.operator == self.operator) {
                lhs = lhs.right;
            }
            if (lhs.operator == self.operator) lhs = lhs.right;
            var expr = lhs.right;
            if (expr instanceof AST_Assign && expr.operator == "=") expr = expr.left;
            if (lhs instanceof AST_Binary
                && lhs.operator == (self.operator == "&&" ? "!==" : "===")
                && self.right instanceof AST_Binary
                && lhs.operator == self.right.operator
                && (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null
                    || lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor))
                && !lhs.right.has_side_effects(compressor)
                && lhs.right.equivalent_to(self.right.right)) {
                var combined = make_node(AST_Binary, self, {
                    operator: lhs.operator.slice(0, -1),
                    left: make_node(AST_Null, self),
                    right: lhs.right
                });
                if (lhs !== self.left) {
                    combined = make_node(AST_Binary, self, {
                        operator: self.operator,
                        left: self.left.left,
                        right: combined
                    });
                }
                return combined;
                && !expr.has_side_effects(compressor)
                && expr.equivalent_to(self.right.right)) {
                lhs.operator = lhs.operator.slice(0, -1);
                lhs.left = make_node(AST_Null, self);
                return self.left;
            }
            break;
        }
@@ -10573,21 +11233,17 @@
        }
        if (in_bool) switch (self.operator) {
          case "+":
            var ll = self.left.evaluate(compressor);
            var rr = self.right.evaluate(compressor);
            if (ll && typeof ll == "string") {
            var ev = self.left.evaluate(compressor, true);
            if (ev && typeof ev == "string" || (ev = self.right.evaluate(compressor, true)) && typeof ev == "string") {
                AST_Node.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
                return make_sequence(self, [
                    self.right,
                    make_node(AST_True, self)
                ]).optimize(compressor);
            }
            if (rr && typeof rr == "string") {
                AST_Node.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
                return make_sequence(self, [
                    self.left,
                    make_node(AST_True, self)
                ]).optimize(compressor);
                var exprs = [];
                if (self.left.evaluate(compressor) instanceof AST_Node) exprs.push(self.left);
                if (self.right.evaluate(compressor) instanceof AST_Node) exprs.push(self.right);
                if (exprs.length < 2) {
                    exprs.push(make_node(AST_True, self));
                    return make_sequence(self, exprs).optimize(compressor);
                }
                self.truthy = true;
            }
            break;
          case "==":
@@ -10623,7 +11279,7 @@
            && lazy_op[self.operator]
            && self.right instanceof AST_Binary
            && self.operator == self.right.operator) {
            swap_chain();
            swap_chain(self, compressor);
        }
        if (compressor.option("strings") && self.operator == "+") {
            // "foo" + 42 + "" ---> "foo" + 42
@@ -10643,7 +11299,8 @@
                && self.left.operator == "+"
                && self.left.left instanceof AST_String
                && self.left.left.value == ""
                && self.right.is_string(compressor)) {
                && self.right.is_string(compressor)
                && (self.left.right.is_constant() || !self.right.has_side_effects(compressor))) {
                self.left = self.left.right;
                return self.optimize(compressor);
            }
@@ -10654,7 +11311,7 @@
                && (self.left.is_string(compressor) && self.right.is_string(compressor)
                    || self.right.left.is_string(compressor)
                        && (self.left.is_constant() || !self.right.right.has_side_effects(compressor)))) {
                swap_chain();
                swap_chain(self, compressor);
            }
        }
        if (compressor.option("evaluate")) {
@@ -10669,20 +11326,15 @@
                    AST_Node.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
                    return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
                }
                var rr = self.right.evaluate(compressor);
                if (!rr) {
                    if (in_bool) {
                if (!self.right.evaluate(compressor, true)) {
                    if (in_bool && !(self.right.evaluate(compressor) instanceof AST_Node)) {
                        AST_Node.warn("Boolean && always false [{file}:{line},{col}]", self.start);
                        return make_sequence(self, [
                            self.left,
                            make_node(AST_False, self)
                        ]).optimize(compressor);
                        return make_sequence(self, [ self.left, make_node(AST_False, self) ]).optimize(compressor);
                    } else self.falsy = true;
                } else if (!(rr instanceof AST_Node)) {
                    if (in_bool || parent.operator == "&&" && parent.left === compressor.self()) {
                        AST_Node.warn("Dropping side-effect-free && [{file}:{line},{col}]", self.start);
                        return self.left.optimize(compressor);
                    }
                } else if ((in_bool || parent.operator == "&&" && parent.left === compressor.self())
                    && !(self.right.evaluate(compressor) instanceof AST_Node)) {
                    AST_Node.warn("Dropping side-effect-free && [{file}:{line},{col}]", self.start);
                    return self.left.optimize(compressor);
                }
                // (x || false) && y ---> x ? y : false
                if (self.left.operator == "||") {
@@ -10717,25 +11369,21 @@
                    });
                    return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor);
                }
                var rr = self.right.evaluate(compressor);
                if (!rr) {
                    if (in_bool || parent.operator == "||" && parent.left === compressor.self()) {
                        AST_Node.warn("Dropping side-effect-free {operator} [{file}:{line},{col}]", {
                            operator: self.operator,
                            file: self.start.file,
                            line: self.start.line,
                            col: self.start.col,
                        });
                        return self.left.optimize(compressor);
                    }
                } else if (!nullish && !(rr instanceof AST_Node)) {
                    if (in_bool) {
                var rr;
                if (!nullish && (rr = self.right.evaluate(compressor, true)) && !(rr instanceof AST_Node)) {
                    if (in_bool && !(self.right.evaluate(compressor) instanceof AST_Node)) {
                        AST_Node.warn("Boolean || always true [{file}:{line},{col}]", self.start);
                        return make_sequence(self, [
                            self.left,
                            make_node(AST_True, self)
                        ]).optimize(compressor);
                        return make_sequence(self, [ self.left, make_node(AST_True, self) ]).optimize(compressor);
                    } else self.truthy = true;
                } else if ((in_bool || parent.operator == "||" && parent.left === compressor.self())
                    && !self.right.evaluate(compressor)) {
                    AST_Node.warn("Dropping side-effect-free {operator} [{file}:{line},{col}]", {
                        operator: self.operator,
                        file: self.start.file,
                        line: self.start.line,
                        col: self.start.col,
                    });
                    return self.left.optimize(compressor);
                }
                // x && true || y ---> x ? true : y
                if (!nullish && self.left.operator == "&&") {
@@ -10938,19 +11586,17 @@
                    if (self.left.value == 0) {
                        if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
                            operator: "+",
                            expression: self.right
                            expression: self.right,
                        }).optimize(compressor);
                        if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right;
                    }
                    break;
                  // 1 * n ---> n
                  case "*":
                    if (self.left.value == 1) {
                        return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, {
                            operator: "+",
                            expression: self.right
                        }).optimize(compressor);
                    }
                    if (self.left.value == 1) return make_node(AST_UnaryPrefix, self, {
                        operator: "+",
                        expression: self.right,
                    }).optimize(compressor);
                    break;
                }
                if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) {
@@ -10959,28 +11605,24 @@
                    if (self.right.value == 0) {
                        if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
                            operator: "+",
                            expression: self.left
                            expression: self.left,
                        }).optimize(compressor);
                        if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left;
                    }
                    break;
                  // n - 0 ---> n
                  case "-":
                    if (self.right.value == 0) {
                        return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
                            operator: "+",
                            expression: self.left
                        }).optimize(compressor);
                    }
                    if (self.right.value == 0) return make_node(AST_UnaryPrefix, self, {
                        operator: "+",
                        expression: self.left,
                    }).optimize(compressor);
                    break;
                  // n / 1 ---> n
                  case "/":
                    if (self.right.value == 1) {
                        return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
                            operator: "+",
                            expression: self.left
                        }).optimize(compressor);
                    }
                    if (self.right.value == 1) return make_node(AST_UnaryPrefix, self, {
                        operator: "+",
                        expression: self.left,
                    }).optimize(compressor);
                    break;
                }
            }
@@ -11105,6 +11747,22 @@
                        && self.left.expression instanceof AST_Number && self.left.expression.value == 1;
            }
        }
        function reversible() {
            return self.left.is_constant()
                || self.right.is_constant()
                || !self.left.has_side_effects(compressor)
                    && !self.right.has_side_effects(compressor);
        }
        function reverse(op) {
            if (reversible()) {
                if (op) self.operator = op;
                var tmp = self.left;
                self.left = self.right;
                self.right = tmp;
            }
        }
    });
    OPT(AST_SymbolExport, function(self) {
@@ -11190,9 +11848,9 @@
                    var scope = self.scope.resolve();
                    fixed.enclosed.forEach(function(def) {
                        if (fixed.variables.has(def.name)) return;
                        if (scope.var_names()[def.name]) return;
                        if (scope.var_names().has(def.name)) return;
                        scope.enclosed.push(def);
                        scope.var_names()[def.name] = true;
                        scope.var_names().set(def.name, true);
                    });
                }
                var value;
@@ -11261,11 +11919,11 @@
                def.replaced++;
                return value;
            }
            var local = self.fixed !== def.fixed;
            if (fixed && (local || def.should_replace !== false)) {
            var state;
            if (fixed && (state = self.fixed || def.fixed).should_replace !== false) {
                var ev, init;
                if (fixed instanceof AST_This) {
                    if (!is_funarg(def) && same_scope(def)) init = fixed;
                    if (!is_funarg(def) && same_scope(def) && !cross_class(def)) init = fixed;
                } else if ((ev = fixed.evaluate(compressor, true)) !== fixed
                    && typeof ev != "function"
                    && (ev === null
@@ -11275,20 +11933,22 @@
                    init = make_node_from_constant(ev, fixed);
                }
                if (init) {
                    if (!local && def.should_replace === undefined) {
                    if (state.should_replace === undefined) {
                        var value_length = init.optimize(compressor).print_to_string().length;
                        if (!has_symbol_ref(fixed)) {
                            value_length = Math.min(value_length, fixed.print_to_string().length);
                        }
                        var name_length = def.name.length;
                        if (compressor.option("unused") && !compressor.exposed(def)) {
                            var referenced = def.references.length - def.replaced;
                            name_length += (name_length + 2 + value_length) / (referenced - def.assignments);
                            var refs = def.references.length - def.replaced - def.assignments;
                            refs = Math.min(refs, def.references.filter(function(ref) {
                                return ref.fixed === state;
                            }).length);
                            name_length += (name_length + 2 + value_length) / Math.max(1, refs);
                        }
                        var delta = value_length - Math.floor(name_length);
                        def.should_replace = delta < compressor.eval_threshold;
                        state.should_replace = value_length - Math.floor(name_length) < compressor.eval_threshold;
                    }
                    if (local || def.should_replace) {
                    if (state.should_replace) {
                        var value;
                        if (has_symbol_ref(fixed)) {
                            value = init.optimize(compressor);
@@ -11304,6 +11964,14 @@
            }
        }
        return self;
        function cross_class(def) {
            var scope = self.scope;
            while (scope !== def.scope) {
                if (scope instanceof AST_Class) return true;
                scope = scope.parent_scope;
            }
        }
        function has_symbol_ref(value) {
            var found;
@@ -11323,42 +11991,98 @@
            && tag.expression.name == "String";
    }
    function decode_template(str) {
        var malformed = false;
        str = str.replace(/\\(u\{[^{}]*\}?|u[\s\S]{0,4}|x[\s\S]{0,2}|[0-9]+|[\s\S])/g, function(match, seq) {
            var ch = decode_escape_sequence(seq);
            if (typeof ch == "string") return ch;
            malformed = true;
        });
        if (!malformed) return str;
    }
    OPT(AST_Template, function(self, compressor) {
        if (!compressor.option("templates")) return self;
        var tag = self.tag;
        if (!tag || is_raw_tag(compressor, tag)) {
            var exprs = self.expressions.slice();
            var strs = self.strings.slice();
            var CHANGED = false;
            for (var i = exprs.length; --i >= 0;) {
                var node = exprs[i];
                var ev = node.evaluate(compressor);
                if (ev === node) continue;
                if (tag && /\r|\\|`/.test(ev)) continue;
                ev = ("" + ev).replace(/\r|\\|`/g, function(s) {
                    return "\\" + (s == "\r" ? "r" : s);
                });
                if (ev.length > node.print_to_string().length + 3) continue;
                var combined = strs[i] + ev + strs[i + 1];
                if (typeof make_node(AST_Template, self, {
                    expressions: [],
                    strings: [ combined ],
                    tag: tag,
                }).evaluate(compressor) != typeof make_node(AST_Template, self, {
                    expressions: [ node ],
                    strings: strs.slice(i, i + 2),
                    tag: tag,
                }).evaluate(compressor)) continue;
                exprs.splice(i, 1);
                strs.splice(i, 2, combined);
                CHANGED = true;
            var exprs = [];
            var strs = [];
            for (var i = 0, status; i < self.strings.length; i++) {
                var str = self.strings[i];
                if (!tag) {
                    var trimmed = decode_template(str);
                    if (trimmed) str = escape_literal(trimmed);
                }
                if (i > 0) {
                    var node = self.expressions[i - 1];
                    var value = should_join(node);
                    if (value) {
                        var prev = strs[strs.length - 1];
                        var joined = prev + value + str;
                        var decoded;
                        if (tag || typeof (decoded = decode_template(joined)) == status) {
                            strs[strs.length - 1] = decoded ? escape_literal(decoded) : joined;
                            continue;
                        }
                    }
                    exprs.push(node);
                }
                strs.push(str);
                if (!tag) status = typeof trimmed;
            }
            if (CHANGED) {
                self.expressions = exprs;
                self.strings = strs;
            if (!tag && strs.length > 1) {
                if (strs[strs.length - 1] == "") return make_node(AST_Binary, self, {
                    operator: "+",
                    left: make_node(AST_Template, self, {
                        expressions: exprs.slice(0, -1),
                        strings: strs.slice(0, -1),
                        tag: tag,
                    }).transform(compressor),
                    right: exprs[exprs.length - 1],
                }).optimize(compressor);
                if (strs[0] == "") {
                    var left = make_node(AST_Binary, self, {
                        operator: "+",
                        left: make_node(AST_String, self, { value: "" }),
                        right: exprs[0],
                    });
                    for (var i = 1; strs[i] == "" && i < exprs.length; i++) {
                        left = make_node(AST_Binary, self, {
                            operator: "+",
                            left: left,
                            right: exprs[i],
                        });
                    }
                    return best_of(compressor, self, make_node(AST_Binary, self, {
                        operator: "+",
                        left: left.transform(compressor),
                        right: make_node(AST_Template, self, {
                            expressions: exprs.slice(i),
                            strings: strs.slice(i),
                            tag: tag,
                        }).transform(compressor),
                    }).optimize(compressor));
                }
            }
            self.expressions = exprs;
            self.strings = strs;
        }
        return try_evaluate(compressor, self);
        function escape_literal(str) {
            return str.replace(/\r|\\|`|\${/g, function(s) {
                return "\\" + (s == "\r" ? "r" : s);
            });
        }
        function should_join(node) {
            var ev = node.evaluate(compressor);
            if (ev === node) return;
            if (tag && /\r|\\|`/.test(ev)) return;
            ev = escape_literal("" + ev);
            if (ev.length > node.print_to_string().length + "${}".length) return;
            return ev;
        }
    });
    function is_atomic(lhs, self) {
@@ -11382,9 +12106,7 @@
        if (lhs && is_atomic(lhs, self)) return self;
        return make_node(AST_UnaryPrefix, self, {
            operator: "void",
            expression: make_node(AST_Number, self, {
                value: 0
            })
            expression: make_node(AST_Number, self, { value: 0 }),
        });
    });
@@ -11396,12 +12118,8 @@
        }
        return make_node(AST_Binary, self, {
            operator: "/",
            left: make_node(AST_Number, self, {
                value: 1
            }),
            right: make_node(AST_Number, self, {
                value: 0
            })
            left: make_node(AST_Number, self, { value: 1 }),
            right: make_node(AST_Number, self, { value: 0 }),
        });
    });
@@ -11411,12 +12129,8 @@
        if (!lhs && !find_scope(compressor).find_variable("NaN")) return self;
        return make_node(AST_Binary, self, {
            operator: "/",
            left: make_node(AST_Number, self, {
                value: 0
            }),
            right: make_node(AST_Number, self, {
                value: 0
            })
            left: make_node(AST_Number, self, { value: 0 }),
            right: make_node(AST_Number, self, { value: 0 }),
        });
    });
@@ -11424,9 +12138,7 @@
        var reachable = false;
        var find_ref = new TreeWalker(function(node) {
            if (reachable) return true;
            if (node instanceof AST_SymbolRef && member(node.definition(), defs)) {
                return reachable = true;
            }
            if (node instanceof AST_SymbolRef && member(node.definition(), defs)) return reachable = true;
        });
        var scan_scope = new TreeWalker(function(node) {
            if (reachable) return true;
@@ -11449,7 +12161,7 @@
        if (compressor.option("dead_code")) {
            if (self.left instanceof AST_PropAccess) {
                if (self.operator == "=") {
                    if (self.__drop) {
                    if (self.redundant) {
                        var exprs = [ self.left.expression ];
                        if (self.left instanceof AST_Sub) exprs.push(self.left.property);
                        exprs.push(self.right);
@@ -11485,16 +12197,14 @@
                    node = parent;
                    parent = compressor.parent(level++);
                    if (parent instanceof AST_Assign) {
                        var found = false;
                        if (parent.left instanceof AST_SymbolRef && parent.left.definition() === def) {
                            if (in_try(level, parent)) break;
                            return strip_assignment(def);
                        }
                        if (parent.left.match_symbol(function(node) {
                            if (node instanceof AST_PropAccess) return true;
                            if (!found && node instanceof AST_SymbolRef && node.definition() === def) {
                                if (in_try(level, parent)) return true;
                                found = true;
                            }
                        })) break;
                        if (!found) continue;
                        return strip_assignment(def);
                        continue;
                    }
                    if (parent instanceof AST_Exit) {
                        if (!local) break;
@@ -11528,22 +12238,29 @@
        }
        if (compressor.option("assignments")) {
            if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
                var ref;
                // x = expr1 OP expr2
                if (self.right.left instanceof AST_SymbolRef
                    && self.right.left.name == self.left.name
                if ((ref = self.right.left) instanceof AST_SymbolRef
                    && ref.name == self.left.name
                    && ASSIGN_OPS[self.right.operator]) {
                    // x = x - 2 ---> x -= 2
                    if (self.left.fixed) self.left.fixed.to_binary = function() {
                        return ref;
                    };
                    return make_node(AST_Assign, self, {
                        operator: self.right.operator + "=",
                        left: self.left,
                        right: self.right.right,
                    });
                }
                if (self.right.right instanceof AST_SymbolRef
                    && self.right.right.name == self.left.name
                if ((ref = self.right.right) instanceof AST_SymbolRef
                    && ref.name == self.left.name
                    && ASSIGN_OPS_COMMUTATIVE[self.right.operator]
                    && !self.right.left.has_side_effects(compressor)) {
                    // x = 2 & x ---> x &= 2
                    if (self.left.fixed) self.left.fixed.to_binary = function() {
                        return ref;
                    };
                    return make_node(AST_Assign, self, {
                        operator: self.right.operator + "=",
                        left: self.left,
@@ -11981,18 +12698,14 @@
        }
        function pop_seq(node) {
            if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, {
                value: 0
            });
            if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, { value: 0 });
            return make_sequence(node, node.expressions.slice(0, -1));
        }
    });
    OPT(AST_Boolean, function(self, compressor) {
        if (!compressor.option("booleans")) return self;
        if (compressor.in_boolean_context()) return make_node(AST_Number, self, {
            value: +self.value
        });
        if (compressor.in_boolean_context()) return make_node(AST_Number, self, { value: +self.value });
        var p = compressor.parent();
        if (p instanceof AST_Binary && (p.operator == "==" || p.operator == "!=")) {
            AST_Node.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {
@@ -12002,15 +12715,11 @@
                line     : p.start.line,
                col      : p.start.col,
            });
            return make_node(AST_Number, self, {
                value: +self.value
            });
            return make_node(AST_Number, self, { value: +self.value });
        }
        return make_node(AST_UnaryPrefix, self, {
            operator: "!",
            expression: make_node(AST_Number, self, {
                value: 1 - self.value
            })
            expression: make_node(AST_Number, self, { value: 1 - self.value }),
        });
    });
@@ -12118,7 +12827,7 @@
                if (assigned) def.reassigned--;
                var sym = make_node(AST_SymbolRef, self, argname);
                sym.reference();
                delete argname.__unused;
                argname.unused = undefined;
                return sym;
            }
        }
@@ -12171,7 +12880,8 @@
                if (flatten) {
                    values.push(retValue);
                    return make_sequence(self, values).optimize(compressor);
                } else return make_node(AST_Sub, self, {
                }
                return make_node(AST_Sub, self, {
                    expression: make_node(AST_Array, expr, { elements: values }),
                    property: make_node(AST_Number, prop, { value: index }),
                });
@@ -12196,10 +12906,8 @@
        }
    });
    AST_Arrow.DEFMETHOD("contains_super", return_false);
    AST_AsyncArrow.DEFMETHOD("contains_super", return_false);
    AST_Lambda.DEFMETHOD("contains_super", function() {
        var result;
    AST_LambdaExpression.DEFMETHOD("contains_super", function() {
        var result = false;
        var self = this;
        self.walk(new TreeWalker(function(node) {
            if (result) return true;
@@ -12208,20 +12916,26 @@
        }));
        return result;
    });
    AST_LambdaDefinition.DEFMETHOD("contains_super", return_false);
    AST_Scope.DEFMETHOD("contains_super", return_false);
    AST_Arrow.DEFMETHOD("contains_this", return_false);
    AST_AsyncArrow.DEFMETHOD("contains_this", return_false);
    AST_Node.DEFMETHOD("contains_this", function() {
        var result;
        var self = this;
        self.walk(new TreeWalker(function(node) {
            if (result) return true;
            if (node instanceof AST_This) return result = true;
            if (node !== self && node instanceof AST_Scope && !is_arrow(node)) return true;
        }));
        return result;
    // contains_this()
    // returns false only if context bound by the specified scope (or scope
    // containing the specified expression) is not referenced by `this`
    (function(def) {
        // scope of arrow function cannot bind to any context
        def(AST_Arrow, return_false);
        def(AST_AsyncArrow, return_false);
        def(AST_Node, function() {
            var result = false;
            var self = this;
            self.walk(new TreeWalker(function(node) {
                if (result) return true;
                if (node instanceof AST_This) return result = true;
                if (node !== self && node instanceof AST_Scope && !is_arrow(node)) return true;
            }));
            return result;
        });
    })(function(node, func) {
        node.DEFMETHOD("contains_this", func);
    });
    function can_hoist_property(prop) {
@@ -12233,28 +12947,44 @@
    AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
        if (!compressor.option("properties")) return;
        if (key === "__proto__") return;
        var expr = this.expression;
        if (expr instanceof AST_Object) {
            var props = expr.properties;
            for (var i = props.length; --i >= 0;) {
                var prop = props[i];
                if (prop.key !== key) continue;
                if (!all(props, can_hoist_property)) break;
                if (!safe_to_flatten(prop.value, compressor)) break;
                props = props.map(function(prop) {
                    return prop.value;
                });
                if (prop instanceof AST_ObjectMethod
                    && prop.value instanceof AST_Function
                    && !(compressor.parent() instanceof AST_Call)) {
                    if (prop.value.uses_arguments) break;
                    props[i] = make_node(AST_Arrow, prop.value, prop.value);
        var self = this;
        var expr = self.expression;
        if (!(expr instanceof AST_Object)) return;
        var props = expr.properties;
        for (var i = props.length; --i >= 0;) {
            var prop = props[i];
            if (prop.key !== key) continue;
            if (!all(props, can_hoist_property)) return;
            if (!safe_to_flatten(prop.value, compressor)) return;
            var call, scope, values = [];
            for (var j = 0; j < props.length; j++) {
                var value = props[j].value;
                if (props[j] instanceof AST_ObjectMethod) {
                    var arrow = !(value.uses_arguments || is_generator(value) || value.contains_this());
                    if (arrow) {
                        if (!scope) scope = compressor.find_parent(AST_Scope);
                        var avoid = avoid_await_yield(scope);
                        value.each_argname(function(argname) {
                            if (avoid[argname.name]) arrow = false;
                        });
                    }
                    var ctor;
                    if (arrow) {
                        ctor = is_async(value) ? AST_AsyncArrow : AST_Arrow;
                    } else if (i != j
                        || (call = compressor.parent()) instanceof AST_Call && call.expression === self) {
                        ctor = value.CTOR;
                    } else {
                        return;
                    }
                    value = make_node(ctor, value, value);
                }
                return make_node(AST_Sub, this, {
                    expression: make_node(AST_Array, expr, { elements: props }),
                    property: make_node(AST_Number, this, { value: i }),
                });
                values.push(value);
            }
            return make_node(AST_Sub, self, {
                expression: make_node(AST_Array, expr, { elements: values }),
                property: make_node(AST_Number, self, { value: i }),
            });
        }
    });
@@ -12283,35 +13013,25 @@
            var exp = self.expression.expression;
            if (is_undeclared_ref(exp)) switch (exp.name) {
              case "Array":
                self.expression = make_node(AST_Array, self.expression, {
                    elements: []
                });
                self.expression = make_node(AST_Array, self.expression, { elements: [] });
                break;
              case "Function":
                self.expression = make_node(AST_Function, self.expression, {
                    argnames: [],
                    body: []
                    body: [],
                }).init_vars(exp.scope);
                break;
              case "Number":
                self.expression = make_node(AST_Number, self.expression, {
                    value: 0
                });
                self.expression = make_node(AST_Number, self.expression, { value: 0 });
                break;
              case "Object":
                self.expression = make_node(AST_Object, self.expression, {
                    properties: []
                });
                self.expression = make_node(AST_Object, self.expression, { properties: [] });
                break;
              case "RegExp":
                self.expression = make_node(AST_RegExp, self.expression, {
                    value: /t/
                });
                self.expression = make_node(AST_RegExp, self.expression, { value: /t/ });
                break;
              case "String":
                self.expression = make_node(AST_String, self.expression, {
                    value: ""
                });
                self.expression = make_node(AST_String, self.expression, { value: "" });
                break;
            }
        }
@@ -12347,7 +13067,8 @@
        var found = false;
        var generated = false;
        var keep_duplicate = compressor.has_directive("use strict");
        var keys = new Dictionary();
        var keys = [];
        var map = new Dictionary();
        var values = [];
        self.properties.forEach(function(prop) {
            if (!(prop instanceof AST_Spread)) return process(prop);
@@ -12390,19 +13111,27 @@
        return make_node(AST_Object, self, { properties: values });
        function flush() {
            keys.each(function(props) {
                if (props.length == 1) return values.push(props[0]);
            keys.forEach(function(key) {
                var props = map.get(key);
                switch (props.length) {
                  case 0:
                    return;
                  case 1:
                    return values.push(props[0]);
                }
                changed = true;
                var tail = keep_duplicate && !generated && props.pop();
                values.push(props.length == 1 ? props[0] : make_node(AST_ObjectKeyVal, self, {
                    key: props[0].key,
                    value: make_sequence(self, props.map(function(prop) {
                        return prop.value;
                    }))
                    })),
                }));
                if (tail) values.push(tail);
                props.length = 0;
            });
            keys = new Dictionary();
            keys = [];
            map = new Dictionary();
        }
        function process(prop) {
@@ -12418,23 +13147,524 @@
            }
            if (can_hoist_property(prop)) {
                if (prop.value.has_side_effects(compressor)) flush();
                keys.add(key, prop);
                keys.push(key);
                map.add(key, prop);
            } else {
                flush();
                values.push(prop);
            }
            if (found && !generated && typeof key == "string" && RE_POSITIVE_INTEGER.test(key)) {
                generated = true;
                if (keys.has(key)) prop = keys.get(key)[0];
                if (map.has(key)) prop = map.get(key)[0];
                prop.key = make_node(AST_Number, prop, { value: +key });
            }
        }
    });
    function flatten_var(name) {
        var redef = name.definition().redefined();
        if (redef) {
            name = name.clone();
            name.thedef = redef;
        }
        return name;
    }
    function has_arg_refs(fn, node) {
        var found = false;
        node.walk(new TreeWalker(function(node) {
            if (found) return true;
            if (node instanceof AST_SymbolRef && fn.variables.get(node.name) === node.definition()) {
                return found = true;
            }
        }));
        return found;
    }
    function insert_assign(def, assign) {
        var visited = [];
        def.references.forEach(function(ref) {
            var fixed = ref.fixed;
            if (!fixed || !push_uniq(visited, fixed)) return;
            if (fixed.assigns) {
                fixed.assigns.unshift(assign);
            } else {
                fixed.assigns = [ assign ];
            }
        });
    }
    function init_ref(compressor, name) {
        var sym = make_node(AST_SymbolRef, name, name);
        var assign = make_node(AST_Assign, name, {
            operator: "=",
            left: sym,
            right: make_node(AST_Undefined, name).transform(compressor),
        });
        var def = name.definition();
        if (def.fixed) {
            sym.fixed = function() {
                return assign.right;
            };
            sym.fixed.assigns = [ assign ];
            insert_assign(def, assign);
        }
        def.assignments++;
        def.references.push(sym);
        return assign;
    }
    (function(def) {
        def(AST_Node, noop);
        def(AST_Assign, noop);
        def(AST_Await, function(compressor, scope, no_return, in_loop) {
            var self = this;
            var inlined = sync(self.expression).try_inline(compressor, scope, no_return, in_loop);
            if (!inlined) return;
            if (!no_return) scan_local_returns(inlined, function(node) {
                node.in_bool = false;
                var value = node.value;
                if (value instanceof AST_Await) return;
                node.value = make_node(AST_Await, self, {
                    expression: value || make_node(AST_Undefined, node).transform(compressor),
                });
            });
            return aborts(inlined) ? inlined : make_node(AST_BlockStatement, self, {
                body: [ inlined, make_node(AST_SimpleStatement, self, {
                    body: make_node(AST_Await, self, { expression: make_node(AST_Number, self, { value: 0 })}),
                }) ],
            });
            function sync(node) {
                if (!no_return) return node;
                if (node.TYPE != "Call") return node;
                var fn = node.expression;
                switch (fn.CTOR) {
                  case AST_AsyncArrow:
                    fn = make_node(AST_Arrow, fn, fn);
                    break;
                  case AST_AsyncFunction:
                    fn = make_node(AST_Function, fn, fn);
                    break;
                  case AST_AsyncGeneratorFunction:
                    fn = make_node(AST_GeneratorFunction, fn, fn);
                    break;
                  default:
                    return node;
                }
                node = node.clone();
                node.expression = fn;
                return node;
            }
        });
        def(AST_Binary, function(compressor, scope, no_return, in_loop) {
            if (no_return === undefined) return;
            var self = this;
            var op = self.operator;
            if (!lazy_op[op]) return;
            var inlined = self.right.try_inline(compressor, scope, no_return, in_loop);
            if (!inlined) return;
            return make_node(AST_If, self, {
                condition: make_condition(self.left),
                body: inlined,
                alternative: no_return ? null : make_node(AST_Return, self, { value: null }),
            });
            function make_condition(cond) {
                switch (op) {
                  case "&&":
                    return cond;
                  case "||":
                    return cond.negate(compressor);
                  case "??":
                    return make_node(AST_Binary, self, {
                        operator: "==",
                        left: make_node(AST_Null, self),
                        right: cond,
                    });
                }
            }
        });
        def(AST_BlockStatement, function(compressor, scope, no_return, in_loop) {
            if (no_return) return;
            if (!this.variables) return;
            var body = this.body;
            var last = body.length - 1;
            if (last < 0) return;
            var inlined = body[last].try_inline(compressor, this, no_return, in_loop);
            if (!inlined) return;
            body[last] = inlined;
            return this;
        });
        def(AST_Call, function(compressor, scope, no_return, in_loop) {
            if (compressor.option("inline") < 4) return;
            var call = this;
            if (call.is_expr_pure(compressor)) return;
            var fn = call.expression;
            if (!(fn instanceof AST_LambdaExpression)) return;
            if (fn.name) return;
            if (fn.uses_arguments) return;
            if (fn.pinned()) return;
            if (is_generator(fn)) return;
            var arrow = is_arrow(fn);
            if (arrow && fn.value) return;
            if (fn.body[0] instanceof AST_Directive) return;
            if (fn.contains_this()) return;
            if (!scope) scope = find_scope(compressor);
            if (in_async_generator(scope)) return;
            var defined = new Dictionary();
            defined.set("NaN", true);
            while (!(scope instanceof AST_Scope)) {
                scope.variables.each(function(def) {
                    defined.set(def.name, true);
                });
                scope = scope.parent_scope;
            }
            if (!member(scope, compressor.stack)) return;
            if (scope.pinned() && fn.variables.size() > (arrow ? 0 : 1)) return;
            if (scope instanceof AST_Toplevel) {
                if (fn.variables.size() > (arrow ? 0 : 1)) {
                    if (!compressor.toplevel.vars) return;
                    if (fn.functions.size() > 0 && !compressor.toplevel.funcs) return;
                }
                defined.set("arguments", true);
            }
            var async = is_async(fn);
            if (async) {
                if (!compressor.option("awaits")) return;
                if (!is_async(scope)) return;
                if (call.may_throw(compressor)) return;
            }
            var names = scope.var_names();
            if (in_loop) in_loop = [];
            if (!fn.variables.all(function(def, name) {
                if (in_loop) in_loop.push(def);
                if (!defined.has(name) && !names.has(name)) return true;
                return !arrow && name == "arguments" && def.orig.length == 1;
            })) return;
            if (in_loop && in_loop.length > 0 && is_reachable(fn, in_loop)) return;
            var simple_argnames = true;
            if (!all(fn.argnames, function(argname) {
                var abort = false;
                var tw = new TreeWalker(function(node) {
                    if (abort) return true;
                    if (node instanceof AST_DefaultValue) {
                        if (has_arg_refs(fn, node.value)) return abort = true;
                        node.name.walk(tw);
                        return true;
                    }
                    if (node instanceof AST_DestructuredKeyVal) {
                        if (node.key instanceof AST_Node && has_arg_refs(fn, node.key)) return abort = true;
                        node.value.walk(tw);
                        return true;
                    }
                    if (node instanceof AST_SymbolFunarg && !all(node.definition().orig, function(sym) {
                        return !(sym instanceof AST_SymbolDefun);
                    })) return abort = true;
                });
                argname.walk(tw);
                if (abort) return false;
                if (!(argname instanceof AST_SymbolFunarg)) simple_argnames = false;
                return true;
            })) return;
            if (fn.rest) {
                if (has_arg_refs(fn, fn.rest)) return;
                simple_argnames = false;
            }
            if (no_return && !all(fn.body, function(stat) {
                var abort = false;
                stat.walk(new TreeWalker(function(node) {
                    if (abort) return true;
                    if (async && node instanceof AST_Await || node instanceof AST_Return) return abort = true;
                    if (node instanceof AST_Scope && node !== fn) return true;
                }));
                return !abort;
            })) return;
            if (!safe_from_await_yield(fn, avoid_await_yield(scope))) return;
            fn.functions.each(function(def, name) {
                scope.functions.set(name, def);
            });
            var body = [];
            fn.variables.each(function(def, name) {
                if (!arrow && name == "arguments" && def.orig.length == 1) return;
                names.set(name, true);
                scope.enclosed.push(def);
                scope.variables.set(name, def);
                def.single_use = false;
                if (!in_loop) return;
                if (def.references.length == def.replaced) return;
                if (def.orig.length == def.eliminated) return;
                if (def.orig.length == 1 && fn.functions.has(name)) return;
                if (!all(def.orig, function(sym) {
                    if (sym instanceof AST_SymbolConst) return false;
                    if (sym instanceof AST_SymbolFunarg) return def.scope.resolve() !== fn;
                    if (sym instanceof AST_SymbolLet) return false;
                    return true;
                })) return;
                var sym = def.orig[0];
                if (sym instanceof AST_SymbolCatch) return;
                body.push(make_node(AST_SimpleStatement, sym, { body: init_ref(compressor, flatten_var(sym)) }));
            });
            var defs = Object.create(null), syms = new Dictionary();
            if (simple_argnames && all(call.args, function(arg) {
                return !(arg instanceof AST_Spread);
            })) {
                var values = call.args.slice();
                fn.argnames.forEach(function(argname) {
                    var value = values.shift();
                    if (argname.unused) {
                        if (value) body.push(make_node(AST_SimpleStatement, call, { body: value }));
                        return;
                    }
                    var defn = make_node(AST_VarDef, call, {
                        name: argname.convert_symbol(AST_SymbolVar, process),
                        value: value || make_node(AST_Undefined, call).transform(compressor),
                    });
                    if (argname instanceof AST_SymbolFunarg) insert_assign(argname.definition(), defn);
                    body.push(make_node(AST_Var, call, { definitions: [ defn ] }));
                });
                if (values.length) body.push(make_node(AST_SimpleStatement, call, {
                    body: make_sequence(call, values),
                }));
            } else {
                body.push(make_node(AST_Var, call, {
                    definitions: [ make_node(AST_VarDef, call, {
                        name: make_node(AST_DestructuredArray, call, {
                            elements: fn.argnames.map(function(argname) {
                                if (argname.unused) return make_node(AST_Hole, argname);
                                return argname.convert_symbol(AST_SymbolVar, process);
                            }),
                            rest: fn.rest && fn.rest.convert_symbol(AST_SymbolVar, process),
                        }),
                        value: make_node(AST_Array, call, { elements: call.args.slice() }),
                    }) ],
                }));
            }
            syms.each(function(orig, id) {
                var def = defs[id];
                [].unshift.apply(def.orig, orig);
                def.eliminated += orig.length;
            });
            [].push.apply(body, in_loop ? fn.body.filter(function(stat) {
                if (!(stat instanceof AST_LambdaDefinition)) return true;
                var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name));
                var def = name.definition();
                def.fixed = false;
                def.orig.push(name);
                def.eliminated++;
                body.push(make_node(AST_Var, stat, {
                    definitions: [ make_node(AST_VarDef, stat, {
                        name: name,
                        value: to_func_expr(stat, true),
                    }) ],
                }));
                return false;
            }) : fn.body);
            var inlined = make_node(AST_BlockStatement, call, { body: body });
            if (!no_return) {
                if (async) scan_local_returns(inlined, function(node) {
                    var value = node.value;
                    if (is_undefined(value)) return;
                    node.value = make_node(AST_Await, call, { expression: value });
                });
                body.push(make_node(AST_Return, call, { value: null }));
            }
            return inlined;
            function process(sym, argname) {
                var def = argname.definition();
                defs[def.id] = def;
                syms.add(def.id, sym);
            }
        });
        def(AST_Conditional, function(compressor, scope, no_return, in_loop) {
            var self = this;
            var body = self.consequent.try_inline(compressor, scope, no_return, in_loop);
            var alt = self.alternative.try_inline(compressor, scope, no_return, in_loop);
            if (!body && !alt) return;
            return make_node(AST_If, self, {
                condition: self.condition,
                body: body || make_body(self.consequent),
                alternative: alt || make_body(self.alternative),
            });
            function make_body(value) {
                if (no_return) return make_node(AST_SimpleStatement, value, { body: value });
                return make_node(AST_Return, value, { value: value });
            }
        });
        def(AST_For, function(compressor, scope, no_return, in_loop) {
            var body = this.body.try_inline(compressor, scope, true, true);
            if (body) this.body = body;
            var inlined = this.init;
            if (inlined) {
                inlined = inlined.try_inline(compressor, scope, true, in_loop);
                if (inlined) {
                    this.init = null;
                    if (inlined instanceof AST_BlockStatement) {
                        inlined.body.push(this);
                        return inlined;
                    }
                    return make_node(AST_BlockStatement, inlined, { body: [ inlined, this ] });
                }
            }
            return body && this;
        });
        def(AST_ForEnumeration, function(compressor, scope, no_return, in_loop) {
            var body = this.body.try_inline(compressor, scope, true, true);
            if (body) this.body = body;
            var obj = this.object;
            if (obj instanceof AST_Sequence) {
                var inlined = inline_sequence(compressor, scope, true, in_loop, obj, 1);
                if (inlined) {
                    this.object = obj.tail_node();
                    inlined.body.push(this);
                    return inlined;
                }
            }
            return body && this;
        });
        def(AST_If, function(compressor, scope, no_return, in_loop) {
            var body = this.body.try_inline(compressor, scope, no_return, in_loop);
            if (body) this.body = body;
            var alt = this.alternative;
            if (alt) {
                alt = alt.try_inline(compressor, scope, no_return, in_loop);
                if (alt) this.alternative = alt;
            }
            var cond = this.condition;
            if (cond instanceof AST_Sequence) {
                var inlined = inline_sequence(compressor, scope, true, in_loop, cond, 1);
                if (inlined) {
                    this.condition = cond.tail_node();
                    inlined.body.push(this);
                    return inlined;
                }
            }
            return (body || alt) && this;
        });
        def(AST_IterationStatement, function(compressor, scope, no_return, in_loop) {
            var body = this.body.try_inline(compressor, scope, true, true);
            if (!body) return;
            this.body = body;
            return this;
        });
        def(AST_LabeledStatement, function(compressor, scope, no_return, in_loop) {
            var body = this.body.try_inline(compressor, scope, no_return, in_loop);
            if (!body) return;
            if (this.body instanceof AST_IterationStatement && body instanceof AST_BlockStatement) {
                var loop = body.body.pop();
                this.body = loop;
                body.body.push(this);
                return body;
            }
            this.body = body;
            return this;
        });
        def(AST_New, noop);
        def(AST_Return, function(compressor, scope, no_return, in_loop) {
            var value = this.value;
            return value && value.try_inline(compressor, scope, undefined, in_loop === "try");
        });
        function inline_sequence(compressor, scope, no_return, in_loop, node, skip) {
            var body = [], exprs = node.expressions, no_ret = no_return;
            for (var i = exprs.length - (skip || 0), j = i; --i >= 0; no_ret = true) {
                var inlined = exprs[i].try_inline(compressor, scope, no_ret, in_loop);
                if (!inlined) continue;
                flush();
                body.push(inlined);
            }
            if (body.length == 0) return;
            flush();
            if (!no_return && body[0] instanceof AST_SimpleStatement) {
                body[0] = make_node(AST_Return, node, { value: body[0].body });
            }
            return make_node(AST_BlockStatement, node, { body: body.reverse() });
            function flush() {
                if (j > i + 1) body.push(make_node(AST_SimpleStatement, node, {
                    body: make_sequence(node, exprs.slice(i + 1, j)),
                }));
                j = i;
            }
        }
        def(AST_Sequence, function(compressor, scope, no_return, in_loop) {
            return inline_sequence(compressor, scope, no_return, in_loop, this);
        });
        def(AST_SimpleStatement, function(compressor, scope, no_return, in_loop) {
            var body = this.body;
            while (body instanceof AST_UnaryPrefix) {
                var op = body.operator;
                if (unary_side_effects[op]) break;
                if (op == "void") break;
                body = body.expression;
            }
            if (!no_return && !is_undefined(body)) body = make_node(AST_UnaryPrefix, this, {
                operator: "void",
                expression: body,
            });
            return body.try_inline(compressor, scope, no_return || false, in_loop);
        });
        def(AST_UnaryPrefix, function(compressor, scope, no_return, in_loop) {
            var self = this;
            var op = self.operator;
            if (unary_side_effects[op]) return;
            if (!no_return && op == "void") no_return = false;
            var inlined = self.expression.try_inline(compressor, scope, no_return, in_loop);
            if (!inlined) return;
            if (!no_return) scan_local_returns(inlined, function(node) {
                node.in_bool = false;
                var value = node.value;
                if (op == "void" && is_undefined(value)) return;
                node.value = make_node(AST_UnaryPrefix, self, {
                    operator: op,
                    expression: value || make_node(AST_Undefined, node).transform(compressor),
                });
            });
            return inlined;
        });
        def(AST_With, function(compressor, scope, no_return, in_loop) {
            var body = this.body.try_inline(compressor, scope, no_return, in_loop);
            if (body) this.body = body;
            var exp = this.expression;
            if (exp instanceof AST_Sequence) {
                var inlined = inline_sequence(compressor, scope, true, in_loop, exp, 1);
                if (inlined) {
                    this.expression = exp.tail_node();
                    inlined.body.push(this);
                    return inlined;
                }
            }
            return body && this;
        });
        def(AST_Yield, function(compressor, scope, no_return, in_loop) {
            if (!compressor.option("yields")) return;
            if (!this.nested) return;
            var call = this.expression;
            if (call.TYPE != "Call") return;
            var fn = call.expression;
            switch (fn.CTOR) {
              case AST_AsyncGeneratorFunction:
                fn = make_node(AST_AsyncFunction, fn, fn);
                break;
              case AST_GeneratorFunction:
                fn = make_node(AST_Function, fn, fn);
                break;
              default:
                return;
            }
            call = call.clone();
            call.expression = fn;
            return call.try_inline(compressor, scope, no_return, in_loop);
        });
    })(function(node, func) {
        node.DEFMETHOD("try_inline", func);
    });
    OPT(AST_Return, function(self, compressor) {
        if (compressor.option("side_effects")
            && self.value
            && is_undefined(self.value, compressor)
        var value = self.value;
        if (value && compressor.option("side_effects")
            && is_undefined(value, compressor)
            && !in_async_generator(compressor.find_parent(AST_Scope))) {
            self.value = null;
        }