diff --git a/lib/compress.js b/lib/compress.js index 3847015dbe..384e0e89c8 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3396,12 +3396,14 @@ merge(Compressor.prototype, { if (prop instanceof AST_Node) break; prop = "" + prop; var diff = prop == "__proto__" || compressor.has_directive("use strict") ? function(node) { - return typeof node.key == "string" && node.key != prop; + var key = node.key; + return typeof key == "string" && key != prop && key != "__proto__"; } : function(node) { + var key = node.key; if (node instanceof AST_ObjectGetter || node instanceof AST_ObjectSetter) { - return typeof node.key == "string" && node.key != prop; + return typeof key == "string" && key != prop; } - return true; + return key !== "__proto__"; }; if (!all(value.properties, diff)) break; value.properties.push(make_node(AST_ObjectKeyVal, node, { @@ -5141,12 +5143,12 @@ merge(Compressor.prototype, { return true; } def(AST_Node, return_false); - def(AST_Array, function() { - return all_constant(this.elements); + def(AST_Array, function(scope) { + return all_constant(this.elements, scope); }); - def(AST_Binary, function() { - return this.left.is_constant_expression() - && this.right.is_constant_expression() + def(AST_Binary, function(scope) { + return this.left.is_constant_expression(scope) + && this.right.is_constant_expression(scope) && (this.operator != "in" || is_object(this.right)); }); def(AST_Class, function(scope) { @@ -5198,14 +5200,14 @@ merge(Compressor.prototype, { })); return result; }); - def(AST_Object, function() { - return all_constant(this.properties); + def(AST_Object, function(scope) { + return all_constant(this.properties, scope); }); - def(AST_ObjectProperty, function() { - return typeof this.key == "string" && this.value.is_constant_expression(); + def(AST_ObjectProperty, function(scope) { + return typeof this.key == "string" && this.value.is_constant_expression(scope); }); - def(AST_Unary, function() { - return this.expression.is_constant_expression(); + def(AST_Unary, function(scope) { + return this.expression.is_constant_expression(scope); }); })(function(node, func) { node.DEFMETHOD("is_constant_expression", func); diff --git a/test/compress/join_vars.js b/test/compress/join_vars.js index 21b76aaa47..8925126663 100644 --- a/test/compress/join_vars.js +++ b/test/compress/join_vars.js @@ -1024,7 +1024,7 @@ issue_3856: { expect_stdout: "undefined" } -issue_3916: { +issue_3916_1: { options = { join_vars: true, } @@ -1044,8 +1044,8 @@ issue_3916: { var o = { p: "PASS", __proto__: 42, - q: "FAIL", }; + o.q = "FAIL"; o.__proto__ = { p: "FAIL", q: "PASS", @@ -1056,6 +1056,62 @@ issue_3916: { expect_stdout: "object PASS true PASS" } +issue_3916_2: { + options = { + join_vars: true, + } + input: { + var log = console.log, o = {}; + o.p = "FAIL 1"; + o.__proto__ = { + get p() { + return "FAIL 2"; + }, + set p(u) { + log("FAIL 3"); + }, + set q(v) { + log("PASS 1"); + }, + get q() { + return "PASS 3"; + }, + }; + o.p = "PASS 2"; + o.q = "FAIL 4"; + log(o.p); + log(o.q); + } + expect: { + var log = console.log, o = { + p: "FAIL 1", + __proto__: { + get p() { + return "FAIL 2"; + }, + set p(u) { + log("FAIL 3"); + }, + set q(v) { + log("PASS 1"); + }, + get q() { + return "PASS 3"; + }, + }, + }; + o.p = "PASS 2"; + o.q = "FAIL 4"; + log(o.p); + log(o.q); + } + expect_stdout: [ + "PASS 1", + "PASS 2", + "PASS 3", + ] +} + assign_var: { options = { join_vars: true, diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index 8ccaefe0df..b48a418a1d 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -1188,7 +1188,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) { var hadDefault = false; - var s = [""]; + var s = [ "" ]; canBreak = enableLoopControl(canBreak, CAN_BREAK); while (n-- > 0) { //hadDefault = n > 0; // disables weird `default` clause positioning (use when handling destabilizes) @@ -1619,6 +1619,10 @@ var KEYS = [ "1.5", "3", ].concat(SAFE_KEYS); +SAFE_KEYS = SAFE_KEYS.concat(SAFE_KEYS); +SAFE_KEYS = SAFE_KEYS.concat(SAFE_KEYS); +SAFE_KEYS = SAFE_KEYS.concat(SAFE_KEYS); +SAFE_KEYS.push("__proto__"); function getDotKey(assign) { var key; @@ -1736,8 +1740,9 @@ function createObjectFunction(recurmax, stmtDepth, canThrow, internal, isClazz) function createObjectLiteral(recurmax, stmtDepth, canThrow) { recurmax--; - var obj = ["({"]; + var obj = [ "({" ]; var offset = SUPPORT.spread_object ? 0 : SUPPORT.computed_key ? 2 : 4; + var has_proto = false; for (var i = rng(6); --i >= 0;) switch (offset + rng(50 - offset)) { case 0: obj.push("..." + getVarName() + ","); @@ -1753,7 +1758,12 @@ function createObjectLiteral(recurmax, stmtDepth, canThrow) { obj.push(createObjectFunction(recurmax, stmtDepth, canThrow) + ","); break; default: - obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ": " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ","); + if (has_proto || rng(200)) { + obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ": " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ","); + } else { + obj.push("__proto__: " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " || {},"); + has_proto = true; + } break; } obj.push("})");