def(AST_Assign, function(tw, descend, compressor) {
var node = this;
var left = node.left;
+ var right = node.right;
var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef;
switch (node.operator) {
case "=":
- if (left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
- node.right.walk(tw);
+ if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
+ right.walk(tw);
walk_prop(left);
node.__drop = true;
return true;
walk_assign();
} else {
mark_assignment_to_arguments(left);
- node.right.walk(tw);
+ right.walk(tw);
}
pop(tw);
return true;
return;
}
var safe = safe_to_read(tw, d);
- node.right.walk(tw);
+ right.walk(tw);
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
push_ref(d, left);
mark(tw, d);
return make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1),
left: make_ref(left, fixed),
- right: node.right
+ right: node.right,
});
};
left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
}
function walk_assign() {
- node.right.walk(tw);
+ right.walk(tw);
scan_declaration(tw, compressor, left, function() {
return node.right;
}, function(sym, fixed, walk) {
var d = sym.definition();
d.assignments++;
if (fixed
- && !is_modified(compressor, tw, node, node.right, 0)
+ && !is_modified(compressor, tw, node, right, 0, is_immutable(right), recursive_ref(tw, d))
&& !sym.in_arg
&& safe_to_assign(tw, d)) {
push_ref(d, sym);
mark(tw, d);
if (d.single_use && left instanceof AST_Destructured) d.single_use = false;
tw.loop_ids[d.id] = tw.in_loop;
- mark_escaped(tw, d, sym.scope, node, node.right, 0, 1);
+ mark_escaped(tw, d, sym.scope, node, right, 0, 1);
sym.fixed = d.fixed = fixed;
sym.fixed.assigns = [ node ];
} else {
// may_throw_on_access()
// returns true if this node may be null, undefined or contain `AST_Accessor`
(function(def) {
- AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
- return !compressor.option("pure_getters") || this._dot_throw(compressor);
+ AST_Node.DEFMETHOD("may_throw_on_access", function(compressor, force) {
+ return !compressor.option("pure_getters") || this._dot_throw(compressor, force);
});
- function is_strict(compressor) {
- return /strict/.test(compressor.option("pure_getters"));
+ function is_strict(compressor, force) {
+ return force || /strict/.test(compressor.option("pure_getters"));
}
def(AST_Node, is_strict);
def(AST_Array, return_false);
return this.consequent._dot_throw(compressor) || this.alternative._dot_throw(compressor);
});
def(AST_Constant, return_false);
- def(AST_Dot, function(compressor) {
- if (!is_strict(compressor)) return false;
+ def(AST_Dot, function(compressor, force) {
+ if (!is_strict(compressor, force)) return false;
var exp = this.expression;
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
return !(this.property == "prototype" && is_lambda(exp));
});
def(AST_Lambda, return_false);
def(AST_Null, return_true);
- def(AST_Object, function(compressor) {
- return is_strict(compressor) && !all(this.properties, function(prop) {
+ def(AST_Object, function(compressor, force) {
+ return is_strict(compressor, force) && !all(this.properties, function(prop) {
return prop instanceof AST_ObjectKeyVal;
});
});
- def(AST_ObjectIdentity, function(compressor) {
- return is_strict(compressor) && !this.scope.new;
+ def(AST_ObjectIdentity, function(compressor, force) {
+ return is_strict(compressor, force) && !this.scope.new;
});
def(AST_Sequence, function(compressor) {
return this.tail_node()._dot_throw(compressor);
});
- def(AST_SymbolRef, function(compressor) {
+ def(AST_SymbolRef, function(compressor, force) {
if (this.is_undefined) return true;
- if (!is_strict(compressor)) return false;
+ if (!is_strict(compressor, force)) return false;
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
if (this.is_immutable()) return false;
var def = this.definition();
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) {
var sym, nested = false;
if (node instanceof AST_Assign) {
- if (node.write_only || node.operator == "=") sym = node.left;
+ if (node.write_only || node.operator == "=") sym = extract_reference(node.left, props);
} else if (node instanceof AST_Unary) {
- if (node.write_only) sym = node.expression;
+ if (node.write_only) sym = extract_reference(node.expression, props);
}
- if (/strict/.test(compressor.option("pure_getters"))) sym = extract_reference(sym, props);
if (!(sym instanceof AST_SymbolRef)) return;
var def = sym.definition();
if (export_defaults[def.id]) return;
function extract_reference(node, props) {
if (node instanceof AST_PropAccess) {
var expr = node.expression;
- if (!expr.may_throw_on_access(compressor)) {
+ if (!expr.may_throw_on_access(compressor, true)) {
nested = true;
if (props && node instanceof AST_Sub) props.unshift(node.property);
return extract_reference(expr, props);
}
} else if (node instanceof AST_Assign && node.operator == "=") {
+ node.write_only = "p";
var ref = extract_reference(node.right);
- if (props) props.assign = node;
- return ref;
+ if (!props) return ref;
+ props.assign = node;
+ return ref instanceof AST_SymbolRef ? ref : node.left;
}
return node;
}
value = make_node(AST_Number, node, { value: 0 });
}
if (value) {
+ if (props.assign) {
+ var assign = props.assign.drop_side_effect_free(compressor);
+ if (assign) props.unshift(assign);
+ }
if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
value = value.drop_side_effect_free(compressor);
}
}
}, true);
}))) {
- if (props.assign) {
- props.assign.write_only = true;
- props.assign.walk(tw);
- delete props.assign.write_only;
+ if (node.write_only === "p" && node.right.may_throw_on_access(compressor, true)) return;
+ var assign = props.assign;
+ if (assign) {
+ assign.write_only = true;
+ assign.walk(tw);
+ assign.write_only = "p";
}
props.forEach(function(prop) {
prop.walk(tw);
});
if (node instanceof AST_Assign) {
- if (node.write_only === "p" && node.right.may_throw_on_access(compressor)) return;
var right = get_rhs(node);
if (init && node.write_only === true && node_def.scope === self && !right.has_side_effects(compressor)) {
initializations.add(node_def.id, right);
def(AST_Assign, function(compressor) {
var left = this.left;
if (left instanceof AST_PropAccess) {
- var expr = left.expression;
- if (expr instanceof AST_Assign && expr.operator == "=" && !expr.may_throw_on_access(compressor)) {
- expr.write_only = "p";
- }
- if (compressor.has_directive("use strict") && expr.is_constant()) return this;
+ if (left.expression.may_throw_on_access(compressor, true)) return this;
+ if (compressor.has_directive("use strict") && left.expression.is_constant()) return this;
}
if (left.has_side_effects(compressor)) return this;
var right = this.right;