enable collapse_vars & reduce_vars by default

- fix corner cases in `const` optimisation
- deprecate `/*@const*/`

fixes #1497
closes #1498
This commit is contained in:
alexlamsl
2017-02-24 01:46:57 +08:00
parent 1e51586996
commit 4e49302916
8 changed files with 56 additions and 25 deletions

View File

@@ -469,8 +469,6 @@ separate file and include it into the build. For example you can have a
```javascript
const DEBUG = false;
const PRODUCTION = true;
// Alternative for environments that don't support `const`
/** @const */ var STAGING = false;
// etc.
```
@@ -481,7 +479,8 @@ and build your code like this:
UglifyJS will notice the constants and, since they cannot be altered, it
will evaluate references to them to the value itself and drop unreachable
code as usual. The build will contain the `const` declarations if you use
them. If you are targeting < ES6 environments, use `/** @const */ var`.
them. If you are targeting < ES6 environments which does not support `const`,
using `var` with `reduce_vars` (enabled by default) should suffice.
<a name="codegen-options"></a>

View File

@@ -69,8 +69,8 @@ function Compressor(options, false_by_default) {
hoist_vars : false,
if_return : !false_by_default,
join_vars : !false_by_default,
collapse_vars : false,
reduce_vars : false,
collapse_vars : !false_by_default,
reduce_vars : !false_by_default,
cascade : !false_by_default,
side_effects : !false_by_default,
pure_getters : false,
@@ -1252,7 +1252,7 @@ merge(Compressor.prototype, {
this._evaluating = true;
try {
var d = this.definition();
if ((d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
if (compressor.option("reduce_vars") && !d.modified && d.init) {
if (compressor.option("unsafe")) {
if (!HOP(d.init, '_evaluated')) {
d.init._evaluated = ev(d.init, compressor);
@@ -3025,9 +3025,11 @@ merge(Compressor.prototype, {
return make_node(AST_Infinity, self).transform(compressor);
}
}
if (compressor.option("evaluate") && !isLHS(self, compressor.parent())) {
if (compressor.option("evaluate")
&& compressor.option("reduce_vars")
&& !isLHS(self, compressor.parent())) {
var d = self.definition();
if (d && d.constant && d.init && d.init.is_constant(compressor)) {
if (d.constant && !d.modified && d.init && d.init.is_constant(compressor)) {
var original_as_string = self.print_to_string();
var const_node = make_node_from_constant(compressor, d.init.constant_value(compressor), self);
var const_node_as_string = const_node.print_to_string();

View File

@@ -97,7 +97,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var scope = self.parent_scope = null;
var labels = new Dictionary();
var defun = null;
var last_var_had_const_pragma = false;
var tw = new TreeWalker(function(node, descend){
if (options.screw_ie8 && node instanceof AST_Catch) {
var save_scope = scope;
@@ -154,13 +153,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// later.
(node.scope = defun.parent_scope).def_function(node);
}
else if (node instanceof AST_Var) {
last_var_had_const_pragma = node.has_const_pragma();
}
else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) {
var def = defun.def_variable(node);
def.constant = node instanceof AST_SymbolConst || last_var_had_const_pragma;
def.constant = node instanceof AST_SymbolConst;
def.init = tw.parent().value;
}
else if (node instanceof AST_SymbolCatch) {
@@ -369,12 +365,6 @@ AST_Symbol.DEFMETHOD("global", function(){
return this.definition().global;
});
AST_Var.DEFMETHOD("has_const_pragma", function() {
var comments_before = this.start && this.start.comments_before;
var lastComment = comments_before && comments_before[comments_before.length - 1];
return lastComment && /@const\b/.test(lastComment.value);
});
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
return defaults(options, {
except : [],

View File

@@ -12,6 +12,7 @@ issue_1191: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function foo(rot) {
@@ -43,6 +44,7 @@ issue_1194: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function f1() {const a = "X"; return a + a;}
@@ -70,6 +72,7 @@ issue_1396: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function foo(a) {
@@ -140,6 +143,7 @@ regexp_literal_not_const: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
(function(){

View File

@@ -94,7 +94,8 @@ dead_code_const_declaration: {
loops : true,
booleans : true,
conditionals : true,
evaluate : true
evaluate : true,
reduce_vars : true,
};
input: {
var unused;
@@ -119,7 +120,8 @@ dead_code_const_annotation: {
loops : true,
booleans : true,
conditionals : true,
evaluate : true
evaluate : true,
reduce_vars : true,
};
input: {
var unused;
@@ -167,7 +169,8 @@ dead_code_const_annotation_complex_scope: {
loops : true,
booleans : true,
conditionals : true,
evaluate : true
evaluate : true,
reduce_vars : true,
};
input: {
var unused_var;
@@ -201,6 +204,5 @@ dead_code_const_annotation_complex_scope: {
var beef = 'good';
var meat = 'beef';
var pork = 'bad';
'good' === pork && console.log('reached, not const');
}
}

View File

@@ -648,3 +648,34 @@ drop_value: {
foo(), bar();
}
}
const_assign: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
const b = 2;
return 1 + b;
}
function g() {
const b = 2;
b = 3;
return 1 + b;
}
}
expect: {
function f() {
return 3;
}
function g() {
const b = 2;
b = 3;
return 1 + b;
}
}
}

View File

@@ -602,6 +602,7 @@ unsafe_prototype_function: {
call_args: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
const a = 1;

View File

@@ -13,7 +13,8 @@ const_declaration: {
const_pragma: {
options = {
evaluate: true
evaluate: true,
reduce_vars: true,
};
input: {
@@ -27,7 +28,8 @@ const_pragma: {
// for completeness' sake
not_const: {
options = {
evaluate: true
evaluate: true,
reduce_vars: true,
};
input: {