extend hoist_props (#3073)

- handle `AST_Assign` the same way as `AST_VarDef`
- inject `AST_Var` as succeeding statement

fixes #3071
This commit is contained in:
Alex Lam S.L
2018-04-11 02:48:15 +08:00
committed by GitHub
parent 90199d0a96
commit 4dd7d0e39b
2 changed files with 136 additions and 23 deletions

View File

@@ -3639,28 +3639,47 @@ merge(Compressor.prototype, {
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
var defs_by_id = Object.create(null);
return self.transform(new TreeTransformer(function(node, descend) {
if (node instanceof AST_VarDef) {
var sym = node.name, def, value;
if (sym.scope === self
&& (def = sym.definition()).escaped != 1
&& !def.assignments
&& !def.direct_access
&& !def.single_use
&& !top_retain(def)
&& (value = sym.fixed_value()) === node.value
&& value instanceof AST_Object) {
descend(node, this);
var defs = new Dictionary();
var assignments = [];
value.properties.forEach(function(prop) {
assignments.push(make_node(AST_VarDef, node, {
name: make_sym(prop.key),
value: prop.value
}));
if (node instanceof AST_Assign && node.operator == "=" && can_hoist(node.left, node.right, 1)) {
descend(node, this);
var defs = new Dictionary();
var assignments = [];
var decls = [];
node.right.properties.forEach(function(prop) {
var decl = make_sym(node.left, prop.key);
decls.push(make_node(AST_VarDef, node, {
name: decl,
value: null
}));
var sym = make_node(AST_SymbolRef, node, {
name: decl.name,
scope: self,
thedef: decl.definition()
});
defs_by_id[def.id] = defs;
return MAP.splice(assignments);
}
sym.reference({});
assignments.push(make_node(AST_Assign, node, {
operator: "=",
left: sym,
right: prop.value
}));
});
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
}));
return make_sequence(node, assignments);
}
if (node instanceof AST_VarDef && can_hoist(node.name, node.value, 0)) {
descend(node, this);
var defs = new Dictionary();
var var_defs = [];
node.value.properties.forEach(function(prop) {
var_defs.push(make_node(AST_VarDef, node, {
name: make_sym(node.name, prop.key),
value: prop.value
}));
});
defs_by_id[node.name.definition().id] = defs;
return MAP.splice(var_defs);
}
if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) {
var defs = defs_by_id[node.expression.definition().id];
@@ -3676,8 +3695,20 @@ merge(Compressor.prototype, {
}
}
function make_sym(key) {
var new_var = make_node(sym.CTOR, sym, {
function can_hoist(sym, right, count) {
if (sym.scope !== self) return;
var def = sym.definition();
if (def.assignments != count) return;
if (def.direct_access) return;
if (def.escaped == 1) return;
if (def.single_use) return;
if (top_retain(def)) return;
if (sym.fixed_value() !== right) return;
return right instanceof AST_Object;
}
function make_sym(sym, key) {
var new_var = make_node(AST_SymbolVar, sym, {
name: self.make_var_name(sym.name + "_" + key),
scope: self
});

View File

@@ -742,3 +742,85 @@ issue_3046: {
}
expect_stdout: "1"
}
issue_3071_1: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
var obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2_toplevel: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}