fix delete corner cases (#1799)
- assignment - boolean - conditional - sequence
This commit is contained in:
@@ -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: "/",
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user