Introduce new compress option unsafe_arrows (#2278)

* Not always safe to convert a function expression to an arrow
  function when code depends on the function prototype existing.

Fixes #2271
This commit is contained in:
kzc
2017-08-16 10:51:26 -04:00
committed by Alex Lam S.L
parent a5461e0adc
commit ae0f117da6
4 changed files with 52 additions and 10 deletions

View File

@@ -646,9 +646,16 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `evaluate` -- attempt to evaluate constant expressions
- `arrows` (default `true`) -- convert ES5 style anonymous function expressions
to arrow functions if permissible by language semantics.
Note: `arrows` requires that the `ecma` compress option is set to `6` or greater.
- `arrows` (default `true`) -- Converts `()=>{return x}` to `()=>x`. Class
and object literal methods will also be converted to arrow expressions if
the resultant code is shorter: `m(){return x}` becomes `m:()=>x`.
This transform requires that the `ecma` compress option is set to `6` or greater.
- `unsafe_arrows` (default `false`) -- Convert ES5 style anonymous function
expressions to arrow functions if the function body does not reference `this`.
Note: it is not always safe to perform this conversion if code relies on the
the function having a `prototype`, which arrow functions lack.
This transform requires that the `ecma` compress option is set to `6` or greater.
- `booleans` -- various optimizations for boolean context, for example `!!a
? b : c → a ? b : c`

View File

@@ -84,6 +84,7 @@ function Compressor(options, false_by_default) {
toplevel : !!(options && options["top_retain"]),
typeofs : !false_by_default,
unsafe : false,
unsafe_arrows : false,
unsafe_comps : false,
unsafe_Func : false,
unsafe_math : false,
@@ -4748,7 +4749,7 @@ merge(Compressor.prototype, {
OPT(AST_Function, function(self, compressor){
tighten_body(self.body, compressor);
if (compressor.option("arrows")
if (compressor.option("unsafe_arrows")
&& compressor.option("ecma") >= 6
&& !self.name
&& !self.is_generator

View File

@@ -213,7 +213,7 @@ no_leading_parentheses: {
async_identifiers: {
options = {
arrows: true,
unsafe_arrows: true,
ecma: 6,
}
input: {
@@ -237,7 +237,7 @@ async_identifiers: {
async_function_expression: {
options = {
arrows: true,
unsafe_arrows: true,
ecma: 6,
evaluate: true,
side_effects: true,
@@ -262,7 +262,7 @@ async_function_expression: {
issue_27: {
options = {
arrows: true,
unsafe_arrows: true,
collapse_vars: true,
ecma: 6,
unused: true,
@@ -283,7 +283,7 @@ issue_27: {
issue_2105_1: {
options = {
arrows: true,
unsafe_arrows: true,
collapse_vars: true,
ecma: 6,
inline: true,
@@ -501,7 +501,7 @@ issue_485_crashing_1530: {
issue_2084: {
options = {
arrows: true,
unsafe_arrows: true,
collapse_vars: true,
conditionals: true,
ecma: 6,
@@ -577,6 +577,7 @@ concise_methods_with_computed_property2: {
async_object_literal: {
options = {
arrows: true,
unsafe_arrows: true,
ecma: 6,
evaluate: true,
}
@@ -597,3 +598,35 @@ async_object_literal: {
};
}
}
issue_2271: {
options = {
arrows: true,
ecma: 6,
evaluate: true,
unsafe_arrows: false,
}
input: {
var Foo = function() {};
Foo.prototype.set = function(value) {
this.value = value;
return this;
}
Foo.prototype.print = function() {
console.log(this.value);
}
new Foo().set("PASS").print();
}
expect: {
var Foo = function() {};
Foo.prototype.set = function(value) {
this.value = value;
return this;
}
Foo.prototype.print = function() {
console.log(this.value);
}
new Foo().set("PASS").print();
}
expect_stdout: "PASS"
}

View File

@@ -36,9 +36,10 @@ compress_new_function_with_destruct: {
compress_new_function_with_destruct_arrows: {
options = {
arrows: true,
unsafe_arrows: true,
unsafe: true,
unsafe_Func: true,
ecma: 6
ecma: 6,
}
beautify = {
ecma: 6