support class literals (#4658)
This commit is contained in:
253
lib/compress.js
253
lib/compress.js
@@ -348,7 +348,7 @@ merge(Compressor.prototype, {
|
||||
var props = obj.properties;
|
||||
for (var i = props.length; --i >= 0;) {
|
||||
var prop = props[i];
|
||||
if (!(prop instanceof AST_ObjectKeyVal)) return;
|
||||
if (!can_hoist_property(prop)) return;
|
||||
if (!value && props[i].key === key) value = props[i].value;
|
||||
}
|
||||
}
|
||||
@@ -600,7 +600,7 @@ merge(Compressor.prototype, {
|
||||
if (!value) return false;
|
||||
return value.is_constant()
|
||||
|| value instanceof AST_Lambda
|
||||
|| value instanceof AST_This;
|
||||
|| value instanceof AST_ObjectIdentity;
|
||||
}
|
||||
|
||||
function has_escaped(d, node, parent) {
|
||||
@@ -933,6 +933,36 @@ merge(Compressor.prototype, {
|
||||
exp.left.definition().bool_fn++;
|
||||
}
|
||||
});
|
||||
def(AST_Class, function(tw, descend, compressor) {
|
||||
var node = this;
|
||||
node.variables.each(function(def) {
|
||||
reset_def(tw, compressor, def);
|
||||
});
|
||||
if (!node.name) return;
|
||||
var d = node.name.definition();
|
||||
if (safe_to_assign(tw, d, true)) {
|
||||
mark(tw, d);
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
d.fixed = function() {
|
||||
return node;
|
||||
};
|
||||
d.fixed.assigns = [ node ];
|
||||
if (!is_safe_lexical(d)) d.single_use = false;
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
});
|
||||
def(AST_ClassField, function(tw) {
|
||||
var node = this;
|
||||
if (node.static) return;
|
||||
if (node.key instanceof AST_Node) node.key.walk(tw);
|
||||
if (node.value) {
|
||||
push(tw);
|
||||
node.value.walk(tw);
|
||||
pop(tw);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
def(AST_Conditional, function(tw) {
|
||||
this.condition.walk(tw);
|
||||
push(tw);
|
||||
@@ -1374,12 +1404,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function is_lhs_read_only(lhs, compressor) {
|
||||
if (lhs instanceof AST_This) return true;
|
||||
if (lhs instanceof AST_SymbolRef) {
|
||||
if (lhs.is_immutable()) return true;
|
||||
var def = lhs.definition();
|
||||
return compressor.exposed(def) && identifier_atom[def.name];
|
||||
}
|
||||
if (lhs instanceof AST_ObjectIdentity) return true;
|
||||
if (lhs instanceof AST_PropAccess) {
|
||||
lhs = lhs.expression;
|
||||
if (lhs instanceof AST_SymbolRef) {
|
||||
@@ -1390,6 +1415,11 @@ merge(Compressor.prototype, {
|
||||
if (lhs.is_constant()) return true;
|
||||
return is_lhs_read_only(lhs, compressor);
|
||||
}
|
||||
if (lhs instanceof AST_SymbolRef) {
|
||||
if (lhs.is_immutable()) return true;
|
||||
var def = lhs.definition();
|
||||
return compressor.exposed(def) && identifier_atom[def.name];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1472,10 +1502,14 @@ merge(Compressor.prototype, {
|
||||
return array;
|
||||
}
|
||||
|
||||
function is_lexical_definition(stat) {
|
||||
return stat instanceof AST_Const || stat instanceof AST_DefClass || stat instanceof AST_Let;
|
||||
}
|
||||
|
||||
function as_statement_array(thing) {
|
||||
if (thing === null) return [];
|
||||
if (thing instanceof AST_BlockStatement) return all(thing.body, function(stat) {
|
||||
return !(stat instanceof AST_Const || stat instanceof AST_Let);
|
||||
return !is_lexical_definition(stat);
|
||||
}) ? thing.body : [ thing ];
|
||||
if (thing instanceof AST_EmptyStatement) return [];
|
||||
if (thing instanceof AST_Statement) return [ thing ];
|
||||
@@ -1851,7 +1885,12 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function handle_custom_scan_order(node, tt) {
|
||||
if (!(node instanceof AST_BlockScope)) return;
|
||||
if (!(node instanceof AST_BlockScope)) {
|
||||
if (!(node instanceof AST_ClassProperty && !node.static)) return;
|
||||
// Skip non-static class property values
|
||||
if (node.key instanceof AST_Node) node.key = node.key.transform(tt);
|
||||
return node;
|
||||
}
|
||||
// Skip (non-executed) functions
|
||||
if (node instanceof AST_Scope) return node;
|
||||
// Stop upon collision with block-scoped variables
|
||||
@@ -1905,6 +1944,7 @@ merge(Compressor.prototype, {
|
||||
if (!lhs.equivalent_to(node.expression)) return false;
|
||||
return !(rvalue instanceof AST_LambdaExpression && !rvalue.contains_this());
|
||||
}
|
||||
if (node instanceof AST_Class) return !compressor.has_directive("use strict");
|
||||
if (node instanceof AST_Debugger) return true;
|
||||
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
|
||||
if (node instanceof AST_DestructuredKeyVal) return node.key instanceof AST_Node;
|
||||
@@ -1990,6 +2030,7 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_Function) {
|
||||
return compressor.option("ie8") && node.name && lvalues.has(node.name.name);
|
||||
}
|
||||
if (node instanceof AST_ObjectIdentity) return symbol_in_lvalues(node, parent);
|
||||
if (node instanceof AST_PropAccess) {
|
||||
var exp = node.expression;
|
||||
return side_effects || !value_def && exp.may_throw_on_access(compressor)
|
||||
@@ -2003,7 +2044,6 @@ merge(Compressor.prototype, {
|
||||
return (in_try || def.scope.resolve() !== scope) && !can_drop_symbol(node);
|
||||
}
|
||||
if (node instanceof AST_Template) return node.tag && !is_raw_tag(compressor, node.tag);
|
||||
if (node instanceof AST_This) return symbol_in_lvalues(node, parent);
|
||||
if (node instanceof AST_VarDef) {
|
||||
if (check_destructured(node.name)) return true;
|
||||
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
|
||||
@@ -2079,7 +2119,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
arg = null;
|
||||
}
|
||||
if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) {
|
||||
if (node instanceof AST_ObjectIdentity && (fn_strict || !tw.find_parent(AST_Scope))) {
|
||||
arg = null;
|
||||
return true;
|
||||
}
|
||||
@@ -2473,12 +2513,12 @@ merge(Compressor.prototype, {
|
||||
expr.left.walk(marker);
|
||||
expr = expr.right;
|
||||
}
|
||||
if (expr instanceof AST_ObjectIdentity) return rhs_exact_match;
|
||||
if (expr instanceof AST_SymbolRef) {
|
||||
var value = expr.evaluate(compressor);
|
||||
if (value === expr) return rhs_exact_match;
|
||||
return rhs_fuzzy_match(value, rhs_exact_match);
|
||||
}
|
||||
if (expr instanceof AST_This) return rhs_exact_match;
|
||||
if (expr.is_truthy()) return rhs_fuzzy_match(true, return_false);
|
||||
if (expr.is_constant()) {
|
||||
var ev = expr.evaluate(compressor);
|
||||
@@ -2519,7 +2559,7 @@ merge(Compressor.prototype, {
|
||||
if (!node) return true;
|
||||
}
|
||||
if (node instanceof AST_Assign) return node.operator == "=" && may_be_global(node.right);
|
||||
return node instanceof AST_PropAccess || node instanceof AST_This;
|
||||
return node instanceof AST_PropAccess || node instanceof AST_ObjectIdentity;
|
||||
}
|
||||
|
||||
function get_lvalues(expr) {
|
||||
@@ -2531,7 +2571,7 @@ merge(Compressor.prototype, {
|
||||
var value;
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
value = node.fixed_value() || node;
|
||||
} else if (node instanceof AST_This) {
|
||||
} else if (node instanceof AST_ObjectIdentity) {
|
||||
value = node;
|
||||
}
|
||||
if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0));
|
||||
@@ -2681,7 +2721,7 @@ merge(Compressor.prototype, {
|
||||
var stat = statements[i];
|
||||
if (stat instanceof AST_BlockStatement) {
|
||||
if (all(stat.body, function(stat) {
|
||||
return !(stat instanceof AST_Const || stat instanceof AST_Let);
|
||||
return !is_lexical_definition(stat);
|
||||
})) {
|
||||
CHANGED = true;
|
||||
eliminate_spurious_blocks(stat.body);
|
||||
@@ -3025,7 +3065,7 @@ merge(Compressor.prototype, {
|
||||
var line = block.body[i];
|
||||
if (line instanceof AST_Var && declarations_only(line)) {
|
||||
decls.push(line);
|
||||
} else if (stat || line instanceof AST_Const || line instanceof AST_Let) {
|
||||
} else if (stat || is_lexical_definition(line)) {
|
||||
return false;
|
||||
} else {
|
||||
stat = line;
|
||||
@@ -3387,7 +3427,7 @@ merge(Compressor.prototype, {
|
||||
function push(node) {
|
||||
if (block) {
|
||||
block.push(node);
|
||||
if (node instanceof AST_Const || node instanceof AST_Let) block.required = true;
|
||||
if (is_lexical_definition(node)) block.required = true;
|
||||
} else {
|
||||
target.push(node);
|
||||
}
|
||||
@@ -3531,6 +3571,9 @@ merge(Compressor.prototype, {
|
||||
return prop instanceof AST_ObjectKeyVal;
|
||||
});
|
||||
});
|
||||
def(AST_ObjectIdentity, function(compressor) {
|
||||
return is_strict(compressor) && !this.scope.new;
|
||||
});
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node()._dot_throw(compressor);
|
||||
});
|
||||
@@ -3553,9 +3596,6 @@ merge(Compressor.prototype, {
|
||||
this._dot_throw = return_false;
|
||||
return false;
|
||||
});
|
||||
def(AST_This, function(compressor) {
|
||||
return is_strict(compressor) && !this.scope.new;
|
||||
});
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
@@ -4077,6 +4117,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
def(AST_Accessor, return_this);
|
||||
def(AST_BigInt, return_this);
|
||||
def(AST_Class, return_this);
|
||||
def(AST_Node, return_this);
|
||||
def(AST_Constant, function() {
|
||||
return this.value;
|
||||
@@ -4595,6 +4636,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return basic_negation(this);
|
||||
});
|
||||
def(AST_ClassExpression, function() {
|
||||
return basic_negation(this);
|
||||
});
|
||||
def(AST_Conditional, function(compressor, first_in_statement) {
|
||||
var self = this.clone();
|
||||
self.consequent = self.consequent.negate(compressor);
|
||||
@@ -4673,7 +4717,7 @@ merge(Compressor.prototype, {
|
||||
|| exp instanceof AST_Object && all(exp.properties, function(prop) {
|
||||
return !(prop instanceof AST_ObjectGetter || prop instanceof AST_Spread);
|
||||
})
|
||||
|| exp instanceof AST_This
|
||||
|| exp instanceof AST_ObjectIdentity
|
||||
|| exp instanceof AST_Unary);
|
||||
}
|
||||
|
||||
@@ -4697,7 +4741,7 @@ merge(Compressor.prototype, {
|
||||
var lhs = this.left;
|
||||
if (!(lhs instanceof AST_PropAccess)) return true;
|
||||
var node = lhs.expression;
|
||||
return !(node instanceof AST_This)
|
||||
return !(node instanceof AST_ObjectIdentity)
|
||||
|| !node.scope.new
|
||||
|| lhs instanceof AST_Sub && lhs.property.has_side_effects(compressor)
|
||||
|| this.right.has_side_effects(compressor);
|
||||
@@ -4721,6 +4765,13 @@ merge(Compressor.prototype, {
|
||||
return this.expression.has_side_effects(compressor)
|
||||
|| any(this.body, compressor);
|
||||
});
|
||||
def(AST_Class, function(compressor) {
|
||||
return this.extends || any(this.properties, compressor);
|
||||
});
|
||||
def(AST_ClassProperty, function(compressor) {
|
||||
return this.key instanceof AST_Node && this.key.has_side_effects(compressor)
|
||||
|| this.static && this.value && this.value.has_side_effects(compressor);
|
||||
});
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.condition.has_side_effects(compressor)
|
||||
|| this.consequent.has_side_effects(compressor)
|
||||
@@ -4760,6 +4811,7 @@ merge(Compressor.prototype, {
|
||||
return spread_side_effects(exp) || exp.has_side_effects(compressor);
|
||||
});
|
||||
});
|
||||
def(AST_ObjectIdentity, return_false);
|
||||
def(AST_ObjectProperty, function(compressor) {
|
||||
return this.key instanceof AST_Node && this.key.has_side_effects(compressor)
|
||||
|| this.value.has_side_effects(compressor);
|
||||
@@ -4786,7 +4838,6 @@ merge(Compressor.prototype, {
|
||||
def(AST_Template, function(compressor) {
|
||||
return this.tag && !is_raw_tag(compressor, this.tag) || any(this.expressions, compressor);
|
||||
});
|
||||
def(AST_This, return_false);
|
||||
def(AST_Try, function(compressor) {
|
||||
return any(this.body, compressor)
|
||||
|| this.bcatch && this.bcatch.has_side_effects(compressor)
|
||||
@@ -4810,8 +4861,8 @@ merge(Compressor.prototype, {
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_EmptyStatement, return_false);
|
||||
def(AST_Lambda, return_false);
|
||||
def(AST_ObjectIdentity, return_false);
|
||||
def(AST_SymbolDeclaration, return_false);
|
||||
def(AST_This, return_false);
|
||||
|
||||
function any(list, compressor) {
|
||||
for (var i = list.length; --i >= 0;)
|
||||
@@ -4933,6 +4984,12 @@ merge(Compressor.prototype, {
|
||||
&& this.right.is_constant_expression()
|
||||
&& (this.operator != "in" || is_object(this.right));
|
||||
});
|
||||
def(AST_Class, function() {
|
||||
return !this.extends && all(this.properties);
|
||||
});
|
||||
def(AST_ClassProperty, function() {
|
||||
return typeof this.key == "string" && (!this.value || this.value.is_constant_expression());
|
||||
});
|
||||
def(AST_Constant, return_true);
|
||||
def(AST_Lambda, function(scope) {
|
||||
var self = this;
|
||||
@@ -4965,7 +5022,7 @@ merge(Compressor.prototype, {
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_This) {
|
||||
if (node instanceof AST_ObjectIdentity) {
|
||||
if (scopes.length == 0 && is_arrow(self)) result = false;
|
||||
return true;
|
||||
}
|
||||
@@ -5042,7 +5099,7 @@ merge(Compressor.prototype, {
|
||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||
case 1:
|
||||
var stat = node.body[0];
|
||||
if (stat instanceof AST_Const || stat instanceof AST_Let) return node;
|
||||
if (is_lexical_definition(stat)) return node;
|
||||
if (parent instanceof AST_IterationStatement && stat instanceof AST_LambdaDefinition) return node;
|
||||
return stat;
|
||||
}
|
||||
@@ -5347,6 +5404,10 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolConst || node instanceof AST_SymbolLet) {
|
||||
references[node.definition().id] = false;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
mark(node, true);
|
||||
return true;
|
||||
@@ -5549,6 +5610,12 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return cl;
|
||||
}
|
||||
|
||||
function to_func_expr(defun, drop_name) {
|
||||
var ctor;
|
||||
switch (defun.CTOR) {
|
||||
@@ -5658,6 +5725,25 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (node === self) return;
|
||||
if (scope === self) {
|
||||
if (node instanceof AST_DefClass) {
|
||||
var def = node.name.definition();
|
||||
if ((!drop_funcs || def.exported) && !(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 = tw.parent() instanceof AST_ExportDefault;
|
||||
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) {
|
||||
prop.value.walk(tw);
|
||||
} else {
|
||||
initializations.add(def.id, prop.value);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_LambdaDefinition) {
|
||||
var def = node.name.definition();
|
||||
if ((!drop_funcs || def.exported) && !(def.id in in_use_ids)) {
|
||||
@@ -5855,13 +5941,32 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (node instanceof AST_Call) calls_to_drop_args.push(node);
|
||||
if (scope !== self) return;
|
||||
if (drop_funcs && node !== self && node instanceof AST_DefClass) {
|
||||
var def = node.name.definition();
|
||||
if (!(def.id in in_use_ids)) {
|
||||
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);
|
||||
if (trimmed) return make_node(AST_SimpleStatement, node, { body: trimmed });
|
||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_ClassExpression && node.name && drop_fn_name(node.name.definition())) {
|
||||
unused_fn_names.push(node);
|
||||
}
|
||||
if (node instanceof AST_Lambda) {
|
||||
if (drop_funcs && node !== self && node instanceof AST_LambdaDefinition) {
|
||||
var def = node.name.definition();
|
||||
if (!(def.id in in_use_ids)) {
|
||||
log(node.name, "Dropping unused function {name}");
|
||||
def.eliminated++;
|
||||
if (parent instanceof AST_ExportDefault) return to_func_expr(node, true);
|
||||
if (parent instanceof AST_ExportDefault) {
|
||||
descend_scope();
|
||||
return to_func_expr(node, true);
|
||||
}
|
||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||
}
|
||||
}
|
||||
@@ -6151,16 +6256,20 @@ merge(Compressor.prototype, {
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
var save_scope = scope;
|
||||
scope = node;
|
||||
descend(node, tt);
|
||||
scope = save_scope;
|
||||
descend_scope();
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_SymbolImport) {
|
||||
if (!compressor.option("imports") || node.definition().id in in_use_ids) return node;
|
||||
return in_list ? List.skip : null;
|
||||
}
|
||||
|
||||
function descend_scope() {
|
||||
var save_scope = scope;
|
||||
scope = node;
|
||||
descend(node, tt);
|
||||
scope = save_scope;
|
||||
}
|
||||
}, function(node, in_list) {
|
||||
if (node instanceof AST_BlockStatement) {
|
||||
return trim_block(node, tt.parent(), in_list);
|
||||
@@ -6740,6 +6849,7 @@ merge(Compressor.prototype, {
|
||||
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);
|
||||
});
|
||||
AST_Function.DEFMETHOD("process_boolean_returns", function(compressor) {
|
||||
@@ -6915,9 +7025,7 @@ merge(Compressor.prototype, {
|
||||
if (sym.fixed_value() !== right) return;
|
||||
return right instanceof AST_Object
|
||||
&& right.properties.length > 0
|
||||
&& all(right.properties, function(prop) {
|
||||
return prop instanceof AST_ObjectKeyVal && typeof prop.key == "string";
|
||||
})
|
||||
&& all(right.properties, can_hoist_property)
|
||||
&& all(def.references, function(ref) {
|
||||
return ref.fixed_value() === right;
|
||||
})
|
||||
@@ -6943,7 +7051,6 @@ merge(Compressor.prototype, {
|
||||
// returned if nothing changed.
|
||||
function trim(nodes, compressor, first_in_statement, spread) {
|
||||
var len = nodes.length;
|
||||
if (!len) return null;
|
||||
var ret = [], changed = false;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var node = nodes[i];
|
||||
@@ -6959,7 +7066,7 @@ merge(Compressor.prototype, {
|
||||
first_in_statement = false;
|
||||
}
|
||||
}
|
||||
return changed ? ret.length ? ret : null : nodes;
|
||||
return ret.length ? changed ? ret : nodes : null;
|
||||
}
|
||||
function array_spread(node, compressor, first_in_statement) {
|
||||
var exp = node.expression;
|
||||
@@ -7106,6 +7213,33 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return self;
|
||||
});
|
||||
def(AST_Class, function(compressor, first_in_statement) {
|
||||
if (this.extends) return this;
|
||||
var exprs = [], values = [];
|
||||
this.properties.forEach(function(prop) {
|
||||
if (prop.key instanceof AST_Node) exprs.push(prop.key);
|
||||
if (prop instanceof AST_ClassField && prop.static && prop.value) values.push(prop.value);
|
||||
});
|
||||
exprs = trim(exprs, compressor, first_in_statement);
|
||||
values = trim(values, compressor, first_in_statement);
|
||||
if (!exprs) {
|
||||
if (!values) return null;
|
||||
exprs = [];
|
||||
}
|
||||
if (values) {
|
||||
var fn = make_node(AST_Arrow, this, {
|
||||
argnames: [],
|
||||
body: [],
|
||||
value: make_sequence(this, values),
|
||||
});
|
||||
fn.init_vars(this.parent_scope);
|
||||
exprs.push(make_node(AST_Call, this, {
|
||||
args: [],
|
||||
expression: fn,
|
||||
}));
|
||||
}
|
||||
return make_sequence(this, exprs);
|
||||
});
|
||||
def(AST_Conditional, function(compressor) {
|
||||
var consequent = this.consequent.drop_side_effect_free(compressor);
|
||||
var alternative = this.alternative.drop_side_effect_free(compressor);
|
||||
@@ -7178,6 +7312,7 @@ merge(Compressor.prototype, {
|
||||
}) : node;
|
||||
}));
|
||||
});
|
||||
def(AST_ObjectIdentity, return_null);
|
||||
def(AST_Sequence, function(compressor, first_in_statement) {
|
||||
var expressions = trim(this.expressions, compressor, first_in_statement);
|
||||
if (!expressions) return null;
|
||||
@@ -7220,7 +7355,6 @@ merge(Compressor.prototype, {
|
||||
if (expressions.length == 0) return null;
|
||||
return make_sequence(this, expressions).drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
def(AST_This, return_null);
|
||||
def(AST_Unary, function(compressor, first_in_statement) {
|
||||
var exp = this.expression;
|
||||
if (unary_side_effects[this.operator]) {
|
||||
@@ -7485,7 +7619,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_ForEnumeration, function(self, compressor) {
|
||||
if (compressor.option("varify") && (self.init instanceof AST_Const || self.init instanceof AST_Let)) {
|
||||
if (compressor.option("varify") && is_lexical_definition(self.init)) {
|
||||
var name = self.init.definitions[0].name;
|
||||
if ((name instanceof AST_Destructured || name instanceof AST_SymbolLet)
|
||||
&& !name.match_symbol(function(node) {
|
||||
@@ -10009,6 +10143,7 @@ merge(Compressor.prototype, {
|
||||
def.single_use = false;
|
||||
fixed._squeezed = true;
|
||||
fixed.single_use = true;
|
||||
if (fixed instanceof AST_DefClass) fixed = to_class_expr(fixed);
|
||||
if (fixed instanceof AST_LambdaDefinition) fixed = to_func_expr(fixed);
|
||||
if (fixed instanceof AST_Lambda) {
|
||||
var scope = self.scope.resolve();
|
||||
@@ -10719,20 +10854,21 @@ merge(Compressor.prototype, {
|
||||
|| alternative.expression instanceof AST_PropAccess)
|
||||
|| is_tail_equivalent(consequent.expression, alternative.expression);
|
||||
}
|
||||
if (consequent instanceof AST_Dot) return consequent.property == alternative.property;
|
||||
if (consequent instanceof AST_Sub) return consequent.property.equivalent_to(alternative.property);
|
||||
if (!(consequent instanceof AST_PropAccess)) return;
|
||||
var p = consequent.property;
|
||||
var q = alternative.property;
|
||||
return (p instanceof AST_Node ? p.equivalent_to(q) : p == q)
|
||||
&& !(consequent.expression instanceof AST_Super || alternative.expression instanceof AST_Super);
|
||||
}
|
||||
|
||||
function combine_tail(consequent, alternative, top) {
|
||||
if (!is_tail_equivalent(consequent, alternative)) return !top && make_node(AST_Conditional, self, {
|
||||
condition: condition,
|
||||
consequent: consequent,
|
||||
alternative: alternative
|
||||
alternative: alternative,
|
||||
});
|
||||
var exp = combine_tail(consequent.expression, alternative.expression);
|
||||
if (!exp) return;
|
||||
var node = consequent.clone();
|
||||
node.expression = exp;
|
||||
node.expression = combine_tail(consequent.expression, alternative.expression);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -10960,6 +11096,21 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
AST_Arrow.DEFMETHOD("contains_super", return_false);
|
||||
AST_AsyncArrow.DEFMETHOD("contains_super", return_false);
|
||||
AST_Lambda.DEFMETHOD("contains_super", function() {
|
||||
var result;
|
||||
var self = this;
|
||||
self.walk(new TreeWalker(function(node) {
|
||||
if (result) return true;
|
||||
if (node instanceof AST_Super) return result = true;
|
||||
if (node !== self && node instanceof AST_Scope && !is_arrow(node)) return true;
|
||||
}));
|
||||
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_Scope.DEFMETHOD("contains_this", function() {
|
||||
@@ -10973,6 +11124,12 @@ merge(Compressor.prototype, {
|
||||
return result;
|
||||
});
|
||||
|
||||
function can_hoist_property(prop) {
|
||||
return prop instanceof AST_ObjectKeyVal
|
||||
&& typeof prop.key == "string"
|
||||
&& !(prop instanceof AST_ObjectMethod && prop.value.contains_super());
|
||||
}
|
||||
|
||||
AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
|
||||
if (!compressor.option("properties")) return;
|
||||
var expr = this.expression;
|
||||
@@ -10981,9 +11138,7 @@ merge(Compressor.prototype, {
|
||||
for (var i = props.length; --i >= 0;) {
|
||||
var prop = props[i];
|
||||
if (prop.key != key) continue;
|
||||
if (!all(props, function(prop) {
|
||||
return prop instanceof AST_ObjectKeyVal && typeof prop.key == "string";
|
||||
})) break;
|
||||
if (!all(props, can_hoist_property)) break;
|
||||
if (!safe_to_flatten(prop.value, compressor)) break;
|
||||
return make_node(AST_Sub, this, {
|
||||
expression: make_node(AST_Array, expr, {
|
||||
@@ -11145,7 +11300,7 @@ merge(Compressor.prototype, {
|
||||
key = prop.key = "" + key;
|
||||
}
|
||||
}
|
||||
if (prop instanceof AST_ObjectKeyVal && typeof key == "string") {
|
||||
if (can_hoist_property(prop)) {
|
||||
if (prop.value.has_side_effects(compressor)) flush();
|
||||
keys.add(key, prop);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user