improve unsafe on undefined (#1548)
`unsafe` turns undefined keyword into a variable of the same name if found, but that interferes with other related optimisations. Keep track of such transformations to ensure zero information loss in the process.
This commit is contained in:
@@ -765,7 +765,7 @@ merge(Compressor.prototype, {
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
||||||
value: make_node(AST_Undefined, stat)
|
value: null
|
||||||
});
|
});
|
||||||
ret[0] = stat.transform(compressor);
|
ret[0] = stat.transform(compressor);
|
||||||
continue loop;
|
continue loop;
|
||||||
@@ -798,7 +798,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !stat.alternative) {
|
&& !stat.alternative) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
ret.push(make_node(AST_Return, ret[0], {
|
ret.push(make_node(AST_Return, ret[0], {
|
||||||
value: make_node(AST_Undefined, ret[0])
|
value: null
|
||||||
}).transform(compressor));
|
}).transform(compressor));
|
||||||
ret.unshift(stat);
|
ret.unshift(stat);
|
||||||
continue loop;
|
continue loop;
|
||||||
@@ -1055,6 +1055,10 @@ merge(Compressor.prototype, {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function is_undefined(node) {
|
||||||
|
return node instanceof AST_Undefined || node.is_undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/* -----[ boolean/negation helpers ]----- */
|
/* -----[ boolean/negation helpers ]----- */
|
||||||
|
|
||||||
// methods to determine whether an expression has a boolean result type
|
// methods to determine whether an expression has a boolean result type
|
||||||
@@ -2402,8 +2406,8 @@ merge(Compressor.prototype, {
|
|||||||
return make_node(self.body.CTOR, self, {
|
return make_node(self.body.CTOR, self, {
|
||||||
value: make_node(AST_Conditional, self, {
|
value: make_node(AST_Conditional, self, {
|
||||||
condition : self.condition,
|
condition : self.condition,
|
||||||
consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
|
consequent : self.body.value || make_node(AST_Undefined, self.body),
|
||||||
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
|
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative)
|
||||||
})
|
})
|
||||||
}).transform(compressor);
|
}).transform(compressor);
|
||||||
}
|
}
|
||||||
@@ -2834,7 +2838,7 @@ merge(Compressor.prototype, {
|
|||||||
return self.car;
|
return self.car;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.cdr instanceof AST_Undefined) {
|
if (is_undefined(self.cdr)) {
|
||||||
return make_node(AST_UnaryPrefix, self, {
|
return make_node(AST_UnaryPrefix, self, {
|
||||||
operator : "void",
|
operator : "void",
|
||||||
expression : self.car
|
expression : self.car
|
||||||
@@ -2873,7 +2877,7 @@ merge(Compressor.prototype, {
|
|||||||
self.expression = e;
|
self.expression = e;
|
||||||
return self;
|
return self;
|
||||||
} else {
|
} else {
|
||||||
return make_node(AST_Undefined, self);
|
return make_node(AST_Undefined, self).transform(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||||
@@ -3354,7 +3358,7 @@ merge(Compressor.prototype, {
|
|||||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||||
switch (self.name) {
|
switch (self.name) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
return make_node(AST_Undefined, self);
|
return make_node(AST_Undefined, self).transform(compressor);
|
||||||
case "NaN":
|
case "NaN":
|
||||||
return make_node(AST_NaN, self).transform(compressor);
|
return make_node(AST_NaN, self).transform(compressor);
|
||||||
case "Infinity":
|
case "Infinity":
|
||||||
@@ -3397,11 +3401,13 @@ merge(Compressor.prototype, {
|
|||||||
var scope = compressor.find_parent(AST_Scope);
|
var scope = compressor.find_parent(AST_Scope);
|
||||||
var undef = scope.find_variable("undefined");
|
var undef = scope.find_variable("undefined");
|
||||||
if (undef) {
|
if (undef) {
|
||||||
return make_node(AST_SymbolRef, self, {
|
var ref = make_node(AST_SymbolRef, self, {
|
||||||
name : "undefined",
|
name : "undefined",
|
||||||
scope : scope,
|
scope : scope,
|
||||||
thedef : undef
|
thedef : undef
|
||||||
});
|
});
|
||||||
|
ref.is_undefined = true;
|
||||||
|
return ref;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -3688,7 +3694,7 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_RegExp, literals_in_boolean_context);
|
OPT(AST_RegExp, literals_in_boolean_context);
|
||||||
|
|
||||||
OPT(AST_Return, function(self, compressor){
|
OPT(AST_Return, function(self, compressor){
|
||||||
if (self.value instanceof AST_Undefined) {
|
if (self.value && is_undefined(self.value)) {
|
||||||
self.value = null;
|
self.value = null;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
unsafe_undefined: {
|
unsafe_undefined: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
unsafe: true
|
unsafe: true
|
||||||
}
|
}
|
||||||
@@ -19,12 +20,7 @@ unsafe_undefined: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f(n) {
|
function f(n) {
|
||||||
return function() {
|
return function() {
|
||||||
if (a)
|
return a ? b : c ? d : n;
|
||||||
return b;
|
|
||||||
if (c)
|
|
||||||
return d;
|
|
||||||
else
|
|
||||||
return n;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,6 +28,7 @@ unsafe_undefined: {
|
|||||||
|
|
||||||
keep_fnames: {
|
keep_fnames: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
unsafe: true
|
unsafe: true
|
||||||
}
|
}
|
||||||
@@ -57,12 +54,7 @@ keep_fnames: {
|
|||||||
function n(n) {
|
function n(n) {
|
||||||
return n * n;
|
return n * n;
|
||||||
}
|
}
|
||||||
if (a)
|
return a ? b : c ? d : r;
|
||||||
return b;
|
|
||||||
if (c)
|
|
||||||
return d;
|
|
||||||
else
|
|
||||||
return r;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,3 +251,36 @@ iife: {
|
|||||||
function d() {}(), function e() {}(), function f() {}(), function g() {}();
|
function d() {}(), function e() {}(), function f() {}(), function g() {}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe_undefined: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(undefined) {
|
||||||
|
if (a)
|
||||||
|
return b;
|
||||||
|
if (c)
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
function g(undefined) {
|
||||||
|
if (a)
|
||||||
|
return b;
|
||||||
|
if (c)
|
||||||
|
return d;
|
||||||
|
e();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(undefined) {
|
||||||
|
return a ? b : c ? d : undefined;
|
||||||
|
}
|
||||||
|
function g(undefined) {
|
||||||
|
return a ? b : c ? d : void e();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user