Compare commits

..

14 Commits

Author SHA1 Message Date
Alex Lam S.L
f8ff349ba7 harmony-v3.2.2 2017-12-11 00:16:36 +08:00
alexlamsl
f2b179ae94 fix escape analysis for AST_Expansion 2017-12-10 23:05:22 +08:00
alexlamsl
c7e8fc4830 fix escape analysis for `AST_Await
fixes #2566
2017-12-10 23:03:29 +08:00
alexlamsl
f778a0aa01 fix escape analysis for AST_Yield
fixes #2565
2017-12-10 23:02:20 +08:00
alexlamsl
7fd4b66eaa fix tests 2017-12-10 14:16:54 +08:00
alexlamsl
21c986ff5b Merge branch 'master' into harmony-v3.2.2 2017-12-10 14:12:24 +08:00
Alex Lam S.L
2441827408 v3.2.2 2017-12-10 13:46:17 +08:00
Alex Lam S.L
0aff037a35 improve unused on assign-only symbols (#2568) 2017-12-09 06:19:29 +08:00
Alex Lam S.L
74a2f53683 fix escape analysis for AST_Throw (#2564) 2017-12-08 02:54:37 +08:00
Alex Lam S.L
e20935c3f2 fix escape analysis for AST_Conditional & AST_Sequence (#2563)
fixes #2560
2017-12-08 01:50:38 +08:00
Alex Lam S.L
3e34f62a1c account for side-effects in conditional call inversion (#2562)
fixes #2560
2017-12-08 01:15:31 +08:00
Alex Lam S.L
d21cb84696 eliminate noop calls more aggressively (#2559) 2017-12-07 01:22:08 +08:00
Alex Lam S.L
3dd495ecdd improve if_return (#2558)
`return void x()` => `x()`
2017-12-07 01:01:52 +08:00
Alex Lam S.L
87bae623e9 simplify computed properties for methods, getters & setters (#2555)
fixes #2554
2017-12-04 00:18:48 +08:00
9 changed files with 940 additions and 148 deletions

View File

@@ -680,11 +680,16 @@ merge(Compressor.prototype, {
}
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|| parent instanceof AST_Call && node !== parent.expression
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) {
|| parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value
|| parent instanceof AST_Yield && node === parent.value && node.scope !== d.scope) {
d.escaped = true;
return;
} else if (parent instanceof AST_Array) {
} else if (parent instanceof AST_Array
|| parent instanceof AST_Await
|| parent instanceof AST_Conditional && node !== parent.condition
|| parent instanceof AST_Expansion
|| parent instanceof AST_Sequence && node === parent.tail_node()) {
mark_escaped(d, scope, parent, parent, level + 1);
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
var obj = tw.parent(level + 1);
@@ -1298,10 +1303,19 @@ merge(Compressor.prototype, {
var stat = statements[i];
var next = statements[i + 1];
if (in_lambda && stat instanceof AST_Return && !stat.value && !next) {
CHANGED = true;
statements.length--;
continue;
if (in_lambda && !next && stat instanceof AST_Return) {
if (!stat.value) {
CHANGED = true;
statements.length--;
continue;
}
if (stat.value instanceof AST_UnaryPrefix && stat.value.operator == "void") {
CHANGED = true;
statements[i] = make_node(AST_SimpleStatement, stat, {
body: stat.value.expression
});
continue;
}
}
if (stat instanceof AST_If) {
@@ -1388,9 +1402,16 @@ merge(Compressor.prototype, {
&& prev instanceof AST_If && prev.body instanceof AST_Return
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
CHANGED = true;
statements.push(make_node(AST_Return, next, {
value: null
}).transform(compressor));
stat = stat.clone();
stat.alternative = make_node(AST_BlockStatement, next, {
body: [
next,
make_node(AST_Return, next, {
value: null
})
]
});
statements.splice(i, 2, stat.transform(compressor));
continue;
}
}
@@ -2627,6 +2648,21 @@ merge(Compressor.prototype, {
// pass 3: we should drop declarations not in_use
var tt = new TreeTransformer(
function before(node, descend, in_list) {
var parent = tt.parent();
if (drop_vars) {
var sym = assign_as_unused(node);
if (sym instanceof AST_SymbolRef
&& !((sym = sym.definition()).id in in_use_ids)
&& (drop_vars || !sym.global)) {
if (node instanceof AST_Assign) {
return maintain_this_binding(parent, node, node.right.transform(tt));
}
return make_node(AST_Number, node, {
value: 0
});
}
}
if (scope !== self) return;
if (node.name
&& (!compressor.option("keep_classnames") && node instanceof AST_ClassExpression
|| !compressor.option("keep_fnames") && node instanceof AST_Function)) {
@@ -2672,9 +2708,7 @@ merge(Compressor.prototype, {
def.eliminated++;
return make_node(AST_EmptyStatement, node);
}
return node;
}
var parent = tt.parent();
if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
var drop_block = !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var);
// place uninitialized names at the start
@@ -2757,19 +2791,6 @@ merge(Compressor.prototype, {
});
}
}
if (drop_vars) {
var def = assign_as_unused(node);
if (def instanceof AST_SymbolRef
&& !((def = def.definition()).id in in_use_ids)
&& (drop_vars || !def.global)) {
if (node instanceof AST_Assign) {
return maintain_this_binding(parent, node, node.right.transform(tt));
}
return make_node(AST_Number, node, {
value: 0
});
}
}
// certain combination of unused name + side effect leads to:
// https://github.com/mishoo/UglifyJS2/issues/44
// https://github.com/mishoo/UglifyJS2/issues/1830
@@ -2807,8 +2828,13 @@ merge(Compressor.prototype, {
return MAP.splice(node.body);
}
}
if (node instanceof AST_Scope && node !== self)
if (node instanceof AST_Scope) {
var save_scope = scope;
scope = node;
descend(node, this);
scope = save_scope;
return node;
}
function template(sym) {
return {
@@ -2824,8 +2850,7 @@ merge(Compressor.prototype, {
function scan_ref_scoped(node, descend) {
var sym;
if (scope === self
&& (sym = assign_as_unused(node)) instanceof AST_SymbolRef
if ((sym = assign_as_unused(node)) instanceof AST_SymbolRef
&& !is_ref_of(node.left, AST_SymbolBlockDeclaration)
&& self.variables.get(sym.name) === sym.definition()) {
if (node instanceof AST_Assign) node.right.walk(tw);
@@ -3674,12 +3699,12 @@ merge(Compressor.prototype, {
var simple_args = all(self.args, function(arg) {
return !(arg instanceof AST_Expansion);
});
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
fn = fn.fixed_value();
}
if (compressor.option("unused")
&& simple_args
&& (is_func_expr(fn)
|| compressor.option("reduce_vars")
&& fn instanceof AST_SymbolRef
&& is_func_expr(fn = fn.fixed_value()))
&& is_func_expr(fn)
&& !fn.uses_arguments
&& !fn.uses_eval) {
var pos = 0, last = 0;
@@ -3930,15 +3955,16 @@ merge(Compressor.prototype, {
return make_sequence(self, args).optimize(compressor);
}
}
if (is_func_expr(exp) && !exp.is_generator && !exp.async) {
if (is_func_expr(fn) && !fn.is_generator && !fn.async) {
if (compressor.option("inline")
&& exp === fn
&& simple_args
&& !exp.name
&& !exp.uses_arguments
&& !exp.uses_eval
&& (exp.body instanceof AST_Node || exp.body.length == 1)
&& !exp.contains_this()
&& all(exp.argnames, function(arg) {
&& !fn.name
&& !fn.uses_arguments
&& !fn.uses_eval
&& (fn.body instanceof AST_Node || fn.body.length == 1)
&& !fn.contains_this()
&& all(fn.argnames, function(arg) {
if (arg instanceof AST_Expansion) return arg.expression.__unused;
return arg.__unused;
})
@@ -3957,7 +3983,7 @@ merge(Compressor.prototype, {
return make_sequence(self, args).optimize(compressor);
}
}
if (compressor.option("side_effects") && !(exp.body instanceof AST_Node) && all(exp.body, is_empty)) {
if (compressor.option("side_effects") && !(fn.body instanceof AST_Node) && all(fn.body, is_empty)) {
var args = self.args.concat(make_node(AST_Undefined, self));
return make_sequence(self, args).optimize(compressor);
}
@@ -4930,20 +4956,22 @@ merge(Compressor.prototype, {
});
}
// x ? y(a) : y(b) --> y(x ? a : b)
var arg_index;
if (consequent instanceof AST_Call
&& alternative.TYPE === consequent.TYPE
&& consequent.args.length == 1
&& alternative.args.length == 1
&& !(consequent.args[0] instanceof AST_Expansion)
&& !(alternative.args[0] instanceof AST_Expansion)
&& consequent.args.length > 0
&& consequent.args.length == alternative.args.length
&& consequent.expression.equivalent_to(alternative.expression)
&& !consequent.expression.has_side_effects(compressor)) {
consequent.args[0] = make_node(AST_Conditional, self, {
&& !self.condition.has_side_effects(compressor)
&& !consequent.expression.has_side_effects(compressor)
&& typeof (arg_index = single_arg_diff()) == "number") {
var node = consequent.clone();
node.args[arg_index] = make_node(AST_Conditional, self, {
condition: self.condition,
consequent: consequent.args[0],
alternative: alternative.args[0]
consequent: consequent.args[arg_index],
alternative: alternative.args[arg_index]
});
return consequent;
return node;
}
// x?y?z:a:a --> x&&y?z:a
if (consequent instanceof AST_Conditional
@@ -5040,6 +5068,22 @@ merge(Compressor.prototype, {
&& node.expression instanceof AST_Constant
&& node.expression.getValue());
}
function single_arg_diff() {
var a = consequent.args;
var b = alternative.args;
for (var i = 0, len = a.length; i < len; i++) {
if (a[i] instanceof AST_Expansion) return;
if (!a[i].equivalent_to(b[i])) {
if (b[i] instanceof AST_Expansion) return;
for (var j = i + 1; j < len; j++) {
if (a[j] instanceof AST_Expansion) return;
if (!a[j].equivalent_to(b[j])) return;
}
return i;
}
}
}
});
OPT(AST_Boolean, function(self, compressor){
@@ -5341,7 +5385,31 @@ merge(Compressor.prototype, {
return self;
});
// ["p"]:1 ---> p:1
// [42]:1 ---> 42:1
function lift_key(self, compressor) {
if (!compressor.option("computed_props")) return self;
// save a comparison in the typical case
if (!(self.key instanceof AST_Constant)) return self;
// whitelist acceptable props as not all AST_Constants are true constants
if (self.key instanceof AST_String || self.key instanceof AST_Number) {
if (self.key.value == "constructor"
&& compressor.parent() instanceof AST_Class) return self;
if (self instanceof AST_ObjectKeyVal) {
self.key = self.key.value;
} else {
self.key = make_node(AST_SymbolMethod, self.key, {
name: self.key.value
});
}
}
return self;
}
OPT(AST_ObjectProperty, lift_key);
OPT(AST_ConciseMethod, function(self, compressor){
lift_key(self, compressor);
// p(){return x;} ---> p:()=>x
if (compressor.option("arrows")
&& compressor.parent() instanceof AST_Object
@@ -5362,18 +5430,7 @@ merge(Compressor.prototype, {
});
OPT(AST_ObjectKeyVal, function(self, compressor){
// ["p"]:1 ---> p:1
// [42]:1 ---> 42:1
if (compressor.option("computed_props")
&& self.key instanceof AST_Constant // save a comparison in the typical case
&& (
// whitelist acceptable props as not all AST_Constants are true constants
self.key instanceof AST_String
|| self.key instanceof AST_Number
)) {
self.key = self.key.value;
// fallthrough - `return self` not needed as transformed tree in good form
}
lift_key(self, compressor);
// p:function(){} ---> p(){}
// p:function*(){} ---> *p(){}
// p:async function(){} ---> async p(){}

View File

@@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.2.1",
"version": "3.2.2",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -166,22 +166,24 @@ cond_1: {
conditionals: true
};
input: {
var do_something; // if undeclared it's assumed to have side-effects
if (some_condition()) {
do_something(x);
} else {
do_something(y);
}
if (some_condition()) {
side_effects(x);
} else {
side_effects(y);
function foo(do_something, some_condition) {
if (some_condition) {
do_something(x);
} else {
do_something(y);
}
if (some_condition) {
side_effects(x);
} else {
side_effects(y);
}
}
}
expect: {
var do_something;
do_something(some_condition() ? x : y);
some_condition() ? side_effects(x) : side_effects(y);
function foo(do_something, some_condition) {
do_something(some_condition ? x : y);
some_condition ? side_effects(x) : side_effects(y);
}
}
}
@@ -190,16 +192,18 @@ cond_2: {
conditionals: true
};
input: {
var x, FooBar;
if (some_condition()) {
x = new FooBar(1);
} else {
x = new FooBar(2);
function foo(x, FooBar, some_condition) {
if (some_condition) {
x = new FooBar(1);
} else {
x = new FooBar(2);
}
}
}
expect: {
var x, FooBar;
x = new FooBar(some_condition() ? 1 : 2);
function foo(x, FooBar, some_condition) {
x = new FooBar(some_condition ? 1 : 2);
}
}
}
@@ -605,6 +609,42 @@ cond_8c: {
}
}
cond_9: {
options = {
conditionals: true,
}
input: {
function f(x, y) {
g() ? x(1) : x(2);
x ? (y || x)() : (y || x)();
x ? y(a, b) : y(d, b, c);
x ? y(a, b, c) : y(a, b, c);
x ? y(a, b, c) : y(a, b, f);
x ? y(a, b, c) : y(a, e, c);
x ? y(a, b, c) : y(a, e, f);
x ? y(a, b, c) : y(d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
expect: {
function f(x, y) {
g() ? x(1) : x(2);
x, (y || x)();
x ? y(a, b) : y(d, b, c);
x, y(a, b, c);
y(a, b, x ? c : f);
y(a, x ? b : e, c);
x ? y(a, b, c) : y(a, e, f);
y(x ? a : d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
}
ternary_boolean_consequent: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
@@ -1115,3 +1155,51 @@ issue_2535_2: {
"false",
]
}
issue_2560: {
options = {
conditionals: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function log(x) {
console.log(x);
}
function foo() {
return log;
}
function bar() {
if (x !== (x = foo())) {
x(1);
} else {
x(2);
}
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect: {
function log(x) {
console.log(x);
}
function bar() {
x !== (x = log) ? x(1) : x(2);
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect_stdout: [
"1",
"2",
]
}

View File

@@ -260,7 +260,9 @@ keep_fnames: {
}
drop_assign: {
options = { unused: true };
options = {
unused: true,
}
input: {
function f1() {
var a;
@@ -281,7 +283,7 @@ drop_assign: {
var a;
return function() {
a = 1;
}
};
}
}
expect: {
@@ -298,16 +300,17 @@ drop_assign: {
return 1;
}
function f5() {
var a;
return function() {
a = 1;
}
1;
};
}
}
}
keep_assign: {
options = { unused: "keep_assign" };
options = {
unused: "keep_assign",
}
input: {
function f1() {
var a;
@@ -328,7 +331,7 @@ keep_assign: {
var a;
return function() {
a = 1;
}
};
}
}
expect: {
@@ -351,19 +354,22 @@ keep_assign: {
var a;
return function() {
a = 1;
}
};
}
}
}
drop_toplevel_funcs: {
options = { toplevel: "funcs", unused: true };
options = {
toplevel: "funcs",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -379,13 +385,16 @@ drop_toplevel_funcs: {
}
drop_toplevel_vars: {
options = { toplevel: "vars", unused: true };
options = {
toplevel: "vars",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -393,11 +402,10 @@ drop_toplevel_vars: {
console.log(b = 3);
}
expect: {
var c = g;
function f(d) {
return function() {
c = 2;
}
2;
};
}
2;
function g() {}
@@ -407,13 +415,17 @@ drop_toplevel_vars: {
}
drop_toplevel_vars_fargs: {
options = { keep_fargs: false, toplevel: "vars", unused: true };
options = {
keep_fargs: false,
toplevel: "vars",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -421,11 +433,10 @@ drop_toplevel_vars_fargs: {
console.log(b = 3);
}
expect: {
var c = g;
function f() {
return function() {
c = 2;
}
2;
};
}
2;
function g() {}
@@ -435,13 +446,16 @@ drop_toplevel_vars_fargs: {
}
drop_toplevel_all: {
options = { toplevel: true, unused: true };
options = {
toplevel: true,
unused: true
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -455,13 +469,16 @@ drop_toplevel_all: {
}
drop_toplevel_retain: {
options = { top_retain: "f,a,o", unused: true };
options = {
top_retain: "f,a,o",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -469,26 +486,28 @@ drop_toplevel_retain: {
console.log(b = 3);
}
expect: {
var a, c = g;
var a;
function f(d) {
return function() {
c = 2;
}
2;
};
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_retain_array: {
options = { top_retain: [ "f", "a", "o" ], unused: true };
options = {
top_retain: [ "f", "a", "o" ],
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -496,26 +515,28 @@ drop_toplevel_retain_array: {
console.log(b = 3);
}
expect: {
var a, c = g;
var a;
function f(d) {
return function() {
c = 2;
}
2;
};
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_retain_regex: {
options = { top_retain: /^[fao]$/, unused: true };
options = {
top_retain: /^[fao]$/,
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -523,26 +544,29 @@ drop_toplevel_retain_regex: {
console.log(b = 3);
}
expect: {
var a, c = g;
var a;
function f(d) {
return function() {
c = 2;
}
2;
};
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_all_retain: {
options = { toplevel: true, top_retain: "f,a,o", unused: true };
options = {
toplevel: true,
top_retain: "f,a,o",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -550,26 +574,29 @@ drop_toplevel_all_retain: {
console.log(b = 3);
}
expect: {
var a, c = g;
var a;
function f(d) {
return function() {
c = 2;
}
2;
};
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_funcs_retain: {
options = { toplevel: "funcs", top_retain: "f,a,o", unused: true };
options = {
toplevel: "funcs",
top_retain: "f,a,o",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -581,7 +608,7 @@ drop_toplevel_funcs_retain: {
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -590,13 +617,17 @@ drop_toplevel_funcs_retain: {
}
drop_toplevel_vars_retain: {
options = { toplevel: "vars", top_retain: "f,a,o", unused: true };
options = {
toplevel: "vars",
top_retain: "f,a,o",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -604,11 +635,11 @@ drop_toplevel_vars_retain: {
console.log(b = 3);
}
expect: {
var a, c = g;
var a;
function f(d) {
return function() {
c = 2;
}
2;
};
}
a = 2;
function g() {}
@@ -618,13 +649,16 @@ drop_toplevel_vars_retain: {
}
drop_toplevel_keep_assign: {
options = { toplevel: true, unused: "keep_assign" };
options = {
toplevel: true,
unused: "keep_assign",
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
};
}
a = 2;
function g() {}
@@ -866,11 +900,11 @@ issue_1583: {
expect: {
function m(t) {
(function(e) {
t = function() {
(function() {
return (function(a) {
return function(a) {};
})();
}();
})();
})();
}
}

View File

@@ -36,19 +36,19 @@ avoid_spread_in_ternary: {
function print(...x) {
console.log(...x);
}
var a = [1, 2], b = [3, 4];
var a = [1, 2], b = [3, 4], m = Math;
if (Math)
if (m)
print(a);
else
print(b);
if (Math)
if (m)
print(...a);
else
print(b);
if (Math.no_such_property)
if (m.no_such_property)
print(a);
else
print(...b);
@@ -57,10 +57,10 @@ avoid_spread_in_ternary: {
function print(...x) {
console.log(...x);
}
var a = [ 1, 2 ], b = [ 3, 4 ];
print(Math ? a : b);
Math ? print(...a) : print(b);
Math.no_such_property ? print(a) : print(...b);
var a = [ 1, 2 ], b = [ 3, 4 ], m = Math;
print(m ? a : b);
m ? print(...a) : print(b);
m.no_such_property ? print(a) : print(...b);
}
expect_stdout: [
"[ 1, 2 ]",

View File

@@ -652,3 +652,23 @@ issue_2531_3: {
}
expect_stdout: "Greeting: Hello"
}
empty_body: {
options = {
reduce_vars: true,
side_effects: true,
}
input: {
function f() {
function noop() {}
noop();
return noop;
}
}
expect: {
function f() {
function noop() {}
return noop;
}
}
}

View File

@@ -812,3 +812,204 @@ prop_arrow_with_nested_this: {
]
node_version: ">=4"
}
issue_2554_1: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var obj = {
["x" + ""]: 1,
["method" + ""]() {
this.s = "PASS";
},
get ["g" + ""]() {
return this.x;
},
set ["s" + ""](value) {
this.x = value;
}
};
obj.method();
console.log(obj.g);
}
expect: {
var obj = {
x: 1,
method() {
this.s = "PASS";
},
get g() {
return this.x;
},
set s(value) {
this.x = value;
}
};
obj.method();
console.log(obj.g);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_2554_2: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var instance = new class {
constructor() {
this.x = 2;
}
["method" + ""]() {
this.s = "PASS";
}
get ["g" + ""]() {
return this.x;
}
set ["s" + ""](value) {
this.x = value;
}
}();
instance.method();
console.log(instance.g);
}
expect: {
var instance = new class {
constructor() {
this.x = 2;
}
method() {
this.s = "PASS";
}
get g() {
return this.x;
}
set s(value) {
this.x = value;
}
}();
instance.method();
console.log(instance.g);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2554_3: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var foo = {
[1 + 0]: 1,
[2 + 0]() {
this[4] = "PASS";
},
get [3 + 0]() {
return this[1];
},
set [4 + 0](value) {
this[1] = value;
}
};
foo[2]();
console.log(foo[3]);
}
expect: {
var foo = {
1: 1,
2() {
this[4] = "PASS";
},
get 3() {
return this[1];
},
set 4(value) {
this[1] = value;
}
};
foo[2]();
console.log(foo[3]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_2554_4: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var bar = new class {
constructor() {
this[1] = 2;
}
[2 + 0]() {
this[4] = "PASS";
}
get [3 + 0]() {
return this[1];
}
set [4 + 0](value) {
this[1] = value;
}
}();
bar[2]();
console.log(bar[3]);
}
expect: {
var bar = new class {
constructor() {
this[1] = 2;
}
2() {
this[4] = "PASS";
}
get 3() {
return this[1];
}
set 4(value) {
this[1] = value;
}
}();
bar[2]();
console.log(bar[3]);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2554_5: {
options = {
computed_props: true,
evaluate: true,
}
input: {
new class {
["constructor"]() {
console.log("FAIL");
}
"constructor"() {
console.log("PASS");
}
}();
}
expect: {
new class {
["constructor"]() {
console.log("FAIL");
}
constructor() {
console.log("PASS");
}
}();
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -4906,3 +4906,373 @@ issue_2455: {
}
}
}
issue_2560_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function baz(s) {
return s ? foo : bar;
}
function foo() {}
function bar() {}
main();
}
expect: {
function baz(s) {
return s ? foo : bar;
}
function foo() {}
function bar() {}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_2560_2: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function baz() {
return foo, bar;
}
function foo() {}
function bar() {}
main();
}
expect: {
function baz() {
return function() {}, bar;
}
function bar() {}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_2560_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function baz() {
try {
throw foo;
} catch (bar) {
return bar;
}
}
function foo() {}
main();
}
expect: {
function baz() {
try {
throw foo;
} catch (bar) {
return bar;
}
}
function foo() {}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_2560_4: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
}
function baz(s) {
function foo() {}
function bar() {}
return s ? foo : bar;
}
main();
}
expect: {
function baz(s) {
return s ? function() {} : function() {};
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
})();
}
expect_stdout: "PASS"
}
issue_2560_5: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
}
function baz() {
function foo() {}
function bar() {}
return foo, bar;
}
main();
}
expect: {
function baz() {
return function() {}, function() {};
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
})();
}
expect_stdout: "PASS"
}
issue_2560_6: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
}
function baz() {
function foo() {}
try {
throw foo;
} catch (bar) {
return bar;
}
}
main();
}
expect: {
function baz() {
// TODO: improve to match `master`
function foo() {}
try {
throw foo;
} catch (bar) {
return bar;
}
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
})();
}
expect_stdout: "PASS"
}
escape_yield: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = gen.next().value;
if (thing !== (thing = gen.next().value))
console.log("FAIL");
else
console.log("PASS");
}
function foo() {}
function* baz(s) {
for (;;) yield foo;
}
var gen = baz();
main();
}
expect: {
function foo() {}
var gen = function*(s) {
for (;;) yield foo;
}();
(function() {
var thing = gen.next().value;
if (thing !== (thing = gen.next().value))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
node_version: ">=4"
}
escape_await: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing;
baz().then(x => {
thing = x;
});
baz().then(x => {
if (thing !== (thing = x))
console.log("FAIL");
else
console.log("PASS");
});
}
function foo() {}
async function baz() {
return await foo;
}
main();
}
expect: {
function foo() {}
async function baz() {
return await foo;
}
(function() {
var thing;
baz().then(x => {
thing = x;
});
baz().then(x => {
if (thing !== (thing = x))
console.log("FAIL");
else
console.log("PASS");
});
})();
}
}
escape_expansion: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function foo() {}
function bar(...x) {
return x[0];
}
function baz() {
return bar(...[ foo ]);
}
main();
}
expect: {
function foo() {}
function baz() {
return function(...x) {
return x[0];
}(...[ foo ]);
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -122,3 +122,25 @@ return_undefined: {
}
}
}
return_void: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g() {
h();
}
return g();
}
}
expect: {
function f() {
h();
}
}
}