fix delete corner cases (#1799)

- assignment
- boolean
- conditional
- sequence
This commit is contained in:
Alex Lam S.L
2017-04-08 14:25:28 +08:00
committed by GitHub
parent a1532eb076
commit cf72fe552f
5 changed files with 369 additions and 24 deletions

View File

@@ -481,15 +481,15 @@ merge(Compressor.prototype, {
// func(something) because that changes the meaning of // func(something) because that changes the meaning of
// the func (becomes lexical instead of global). // the func (becomes lexical instead of global).
function maintain_this_binding(parent, orig, val) { function maintain_this_binding(parent, orig, val) {
if (parent instanceof AST_Call && parent.expression === orig) { if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
if (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name === "eval") { || parent instanceof AST_Call && parent.expression === orig
return make_node(AST_Seq, orig, { && (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name == "eval")) {
car: make_node(AST_Number, orig, { return make_node(AST_Seq, orig, {
value: 0 car: make_node(AST_Number, orig, {
}), value: 0
cdr: val }),
}); cdr: val
} });
} }
return val; return val;
} }
@@ -3103,11 +3103,27 @@ merge(Compressor.prototype, {
}); });
OPT(AST_UnaryPrefix, function(self, compressor){ OPT(AST_UnaryPrefix, function(self, compressor){
var e = self.expression;
if (self.operator == "delete"
&& !(e instanceof AST_SymbolRef
|| e instanceof AST_PropAccess
|| e instanceof AST_NaN
|| e instanceof AST_Infinity
|| e instanceof AST_Undefined)) {
if (e instanceof AST_Seq) {
e = e.to_array();
e.push(make_node(AST_True, self));
return AST_Seq.from_array(e).optimize(compressor);
}
return make_node(AST_Seq, self, {
car: e,
cdr: make_node(AST_True, self)
}).optimize(compressor);
}
var seq = self.lift_sequences(compressor); var seq = self.lift_sequences(compressor);
if (seq !== self) { if (seq !== self) {
return seq; return seq;
} }
var e = self.expression;
if (compressor.option("side_effects") && self.operator == "void") { if (compressor.option("side_effects") && self.operator == "void") {
e = e.drop_side_effect_free(compressor); e = e.drop_side_effect_free(compressor);
if (e) { if (e) {
@@ -3606,6 +3622,14 @@ merge(Compressor.prototype, {
return self; return self;
}); });
function in_delete(parent) {
return parent instanceof AST_UnaryPrefix && parent.operator == "delete";
}
function is_atomic(parent, self) {
return parent.expression instanceof AST_SymbolRef || parent.expression.TYPE === self.TYPE;
}
OPT(AST_Undefined, function(self, compressor){ OPT(AST_Undefined, function(self, compressor){
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
var undef = find_variable(compressor, "undefined"); var undef = find_variable(compressor, "undefined");
@@ -3620,10 +3644,7 @@ merge(Compressor.prototype, {
} }
} }
var parent = compressor.parent(); var parent = compressor.parent();
if (parent instanceof AST_UnaryPrefix if (in_delete(parent) && is_atomic(parent, self)) return self;
&& parent.operator == "delete"
&& (parent.expression instanceof AST_SymbolRef
|| parent.expression.TYPE === self.TYPE)) return self;
return make_node(AST_UnaryPrefix, self, { return make_node(AST_UnaryPrefix, self, {
operator: "void", operator: "void",
expression: make_node(AST_Number, self, { expression: make_node(AST_Number, self, {
@@ -3634,12 +3655,10 @@ merge(Compressor.prototype, {
OPT(AST_Infinity, function(self, compressor){ OPT(AST_Infinity, function(self, compressor){
var parent = compressor.parent(); var parent = compressor.parent();
if (parent instanceof AST_UnaryPrefix var del = in_delete(parent);
&& parent.operator == "delete" if (del && is_atomic(parent, self)) return self;
&& (parent.expression instanceof AST_SymbolRef
|| parent.expression.TYPE === self.TYPE))
return self;
if (compressor.option("keep_infinity") if (compressor.option("keep_infinity")
&& !(del && !is_atomic(parent, self))
&& !find_variable(compressor, "Infinity")) && !find_variable(compressor, "Infinity"))
return self; return self;
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
@@ -3655,10 +3674,7 @@ merge(Compressor.prototype, {
OPT(AST_NaN, function(self, compressor){ OPT(AST_NaN, function(self, compressor){
var parent = compressor.parent(); var parent = compressor.parent();
if (parent instanceof AST_UnaryPrefix if (in_delete(parent) && !is_atomic(parent, self)
&& parent.operator == "delete"
&& !(parent.expression instanceof AST_SymbolRef
|| parent.expression.TYPE === self.TYPE)
|| find_variable(compressor, "NaN")) { || find_variable(compressor, "NaN")) {
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "/", operator: "/",

View File

@@ -962,3 +962,56 @@ condition_symbol_matches_consequent: {
} }
expect_stdout: "3 7 true 4" expect_stdout: "3 7 true 4"
} }
delete_conditional_1: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
side_effects: true,
}
input: {
console.log(delete (1 ? undefined : x));
console.log(delete (1 ? void 0 : x));
console.log(delete (1 ? Infinity : x));
console.log(delete (1 ? 1 / 0 : x));
console.log(delete (1 ? NaN : x));
console.log(delete (1 ? 0 / 0 : x));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((NaN, !0));
}
expect_stdout: true
}
delete_conditional_2: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
keep_infinity: true,
side_effects: true,
}
input: {
console.log(delete (0 ? x : undefined));
console.log(delete (0 ? x : void 0));
console.log(delete (0 ? x : Infinity));
console.log(delete (0 ? x : 1 / 0));
console.log(delete (0 ? x : NaN));
console.log(delete (0 ? x : 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((Infinity, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((NaN, !0));
}
expect_stdout: true
}

View File

@@ -974,3 +974,58 @@ issue_1715_4: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
delete_assign_1: {
options = {
booleans: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
console.log(delete (a = undefined));
console.log(delete (a = void 0));
console.log(delete (a = Infinity));
console.log(delete (a = 1 / 0));
console.log(delete (a = NaN));
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_assign_2: {
options = {
booleans: true,
keep_infinity: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
console.log(delete (a = undefined));
console.log(delete (a = void 0));
console.log(delete (a = Infinity));
console.log(delete (a = 1 / 0));
console.log(delete (a = NaN));
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((Infinity, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
}
expect_stdout: true
}

View File

@@ -858,8 +858,9 @@ issue_1760_2: {
expect_stdout: "Infinity" expect_stdout: "Infinity"
} }
delete_expr: { delete_expr_1: {
options = { options = {
booleans: true,
evaluate: true, evaluate: true,
} }
input: { input: {
@@ -871,6 +872,23 @@ delete_expr: {
console.log(delete (0 / 0)); console.log(delete (0 / 0));
} }
expect: { expect: {
console.log(delete undefined);
console.log((void 0, !0));
console.log(delete Infinity);
console.log((1 / 0, !0));
console.log(delete NaN);
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_expr_2: {
options = {
booleans: true,
evaluate: true,
keep_infinity: true,
}
input: {
console.log(delete undefined); console.log(delete undefined);
console.log(delete void 0); console.log(delete void 0);
console.log(delete Infinity); console.log(delete Infinity);
@@ -878,5 +896,64 @@ delete_expr: {
console.log(delete NaN); console.log(delete NaN);
console.log(delete (0 / 0)); console.log(delete (0 / 0));
} }
expect: {
console.log(delete undefined);
console.log((void 0, !0));
console.log(delete Infinity);
console.log((1 / 0, !0));
console.log(delete NaN);
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_binary_1: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
console.log(delete (true && undefined));
console.log(delete (true && void 0));
console.log(delete (true && Infinity));
console.log(delete (true && (1 / 0)));
console.log(delete (true && NaN));
console.log(delete (true && (0 / 0)));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((NaN, !0));
}
expect_stdout: true
}
delete_binary_2: {
options = {
booleans: true,
evaluate: true,
keep_infinity: true,
side_effects: true,
}
input: {
console.log(delete (false || undefined));
console.log(delete (false || void 0));
console.log(delete (false || Infinity));
console.log(delete (false || (1 / 0)));
console.log(delete (false || NaN));
console.log(delete (false || (0 / 0)));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((Infinity, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((NaN, !0));
}
expect_stdout: true expect_stdout: true
} }

View File

@@ -466,3 +466,147 @@ issue_1758: {
} }
expect_stdout: "undefined" expect_stdout: "undefined"
} }
delete_seq_1: {
options = {
booleans: true,
side_effects: true,
}
input: {
console.log(delete (1, undefined));
console.log(delete (1, void 0));
console.log(delete (1, Infinity));
console.log(delete (1, 1 / 0));
console.log(delete (1, NaN));
console.log(delete (1, 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_seq_2: {
options = {
booleans: true,
side_effects: true,
}
input: {
console.log(delete (1, 2, undefined));
console.log(delete (1, 2, void 0));
console.log(delete (1, 2, Infinity));
console.log(delete (1, 2, 1 / 0));
console.log(delete (1, 2, NaN));
console.log(delete (1, 2, 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_seq_3: {
options = {
booleans: true,
keep_infinity: true,
side_effects: true,
}
input: {
console.log(delete (1, 2, undefined));
console.log(delete (1, 2, void 0));
console.log(delete (1, 2, Infinity));
console.log(delete (1, 2, 1 / 0));
console.log(delete (1, 2, NaN));
console.log(delete (1, 2, 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((Infinity, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_seq_4: {
options = {
booleans: true,
sequences: true,
side_effects: true,
}
input: {
function f() {}
console.log(delete (f(), undefined));
console.log(delete (f(), void 0));
console.log(delete (f(), Infinity));
console.log(delete (f(), 1 / 0));
console.log(delete (f(), NaN));
console.log(delete (f(), 0 / 0));
}
expect: {
function f() {}
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0));
}
expect_stdout: true
}
delete_seq_5: {
options = {
booleans: true,
keep_infinity: true,
sequences: true,
side_effects: true,
}
input: {
function f() {}
console.log(delete (f(), undefined));
console.log(delete (f(), void 0));
console.log(delete (f(), Infinity));
console.log(delete (f(), 1 / 0));
console.log(delete (f(), NaN));
console.log(delete (f(), 0 / 0));
}
expect: {
function f() {}
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0));
}
expect_stdout: true
}
delete_seq_6: {
options = {
booleans: true,
side_effects: true,
}
input: {
var a;
console.log(delete (1, a));
}
expect: {
var a;
console.log((a, !0));
}
expect_stdout: true
}