Implement data property creation for assignments to super.x.
authordslomov@chromium.org <dslomov@chromium.org>
Tue, 30 Sep 2014 13:19:47 +0000 (13:19 +0000)
committerdslomov@chromium.org <dslomov@chromium.org>
Tue, 30 Sep 2014 13:19:47 +0000 (13:19 +0000)
R=rossberg@chromium.org, arv@chromium.org
BUG=v8:3330
LOG=N

Review URL: https://codereview.chromium.org/618643003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24331 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/objects.cc
test/mjsunit/harmony/super.js

index 12a54b2..f6ec456 100644 (file)
@@ -2906,13 +2906,11 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
   }
 
   if (data_store_mode == SUPER_PROPERTY) {
-    if (strict_mode == STRICT) {
-      Handle<Object> args[1] = {it->name()};
-      THROW_NEW_ERROR(it->isolate(),
-                      NewReferenceError("not_defined", HandleVector(args, 1)),
-                      Object);
-    }
-    return value;
+    LookupIterator own_lookup(it->GetReceiver(), it->name(),
+                              LookupIterator::OWN);
+
+    return JSObject::SetProperty(&own_lookup, value, strict_mode, store_mode,
+                                 NORMAL_PROPERTY);
   }
 
   return AddDataProperty(it, value, NONE, strict_mode, store_mode);
index e8d3c9d..5d3ee2b 100644 (file)
 }());
 
 
+(function TestSetterDataProperties() {
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    x : "x from Base"
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testSetter = function() {
+    assertEquals("x from Base", super.x);
+    super.x = "data property";
+    assertEquals("x from Base", super.x);
+    assertEquals("data property", this.x);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testSetter();
+}());
+
+
 (function TestAccessorsOnPrimitives() {
   var getCalled = 0;
   var setCalled = 0;
     assertEquals(6, super.x += 5);
     assertEquals(2, getCalled);
     assertEquals(2, setCalled);
+
+    super.newProperty = 15;
+    assertEquals(15, this.newProperty);
+    assertEquals(undefined, super.newProperty);
   }.toMethod(Derived.prototype);
 
   Derived.prototype.testSetterStrict = function() {
     assertEquals(6, super.x += 5);
     assertEquals(2, getCalled);
     assertEquals(2, setCalled);
+
+    var ex;
+    try {
+      super.newProperty = 15;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
   }.toMethod(Derived.prototype);
 
   Derived.prototype.testSetter.call(42);
 }());
 
 
-(function TestSetterFailures() {
+(function TestSetterUndefinedProperties() {
   function Base() {}
   function Derived() {}
   Derived.prototype = { __proto__ : Base.prototype };
   Derived.prototype.mSloppy = function () {
+    assertEquals(undefined, super.x);
+    assertEquals(undefined, this.x);
     super.x = 10;
+    assertEquals(10, this.x);
     assertEquals(undefined, super.x);
   }.toMethod(Derived.prototype);
 
   Derived.prototype.mStrict = function () {
     'use strict';
+    assertEquals(undefined, super.x);
+    assertEquals(undefined, this.x);
     super.x = 10;
+    assertEquals(10, this.x);
+    assertEquals(undefined, super.x);
   }.toMethod(Derived.prototype);
   var d = new Derived();
   d.mSloppy();
-  assertEquals(undefined, d.x);
+  assertEquals(10, d.x);
   var d1 = new Derived();
-  assertThrows(function() { d.mStrict(); }, ReferenceError);
-  assertEquals(undefined, d.x);
+  d1.mStrict();
+  assertEquals(10, d.x);
+}());
+
+
+(function TestSetterCreatingOwnProperties() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  var setterCalled;
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(42, this.ownReadOnly);
+    super.ownReadOnly = 55;
+    assertEquals(42, this.ownReadOnly);
+
+    assertEquals(15, this.ownReadonlyAccessor);
+    super.ownReadonlyAccessor = 55;
+    assertEquals(15, this.ownReadonlyAccessor);
+
+    setterCalled = 0;
+    super.ownSetter = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(42, this.ownReadOnly);
+    var ex;
+    try {
+      super.ownReadOnly = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(42, this.ownReadOnly);
+
+    assertEquals(15, this.ownReadonlyAccessor);
+    ex = null;
+    try {
+      super.ownReadonlyAccessor = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(15, this.ownReadonlyAccessor);
+
+    setterCalled = 0;
+    super.ownSetter = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false });
+  Object.defineProperty(d, 'ownSetter',
+      { set : function() { setterCalled++; } });
+  Object.defineProperty(d, 'ownReadonlyAccessor',
+      { get : function() { return 15; }});
+  d.mSloppy();
+  d.mStrict();
+}());
+
+
+(function TestSetterNoProtoWalk() {
+  function Base() {}
+  function Derived() {}
+  var getCalled;
+  var setCalled;
+  Derived.prototype = {
+    __proto__ : Base.prototype,
+    get x() { getCalled++; return 42; },
+    set x(v) { setCalled++; }
+  };
+
+  Derived.prototype.mSloppy = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this.x = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super.x = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this.x);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this.x = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super.x = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this.x);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestSetterDoesNotReconfigure() {
+  function Base() {}
+  function Derived() {}
+
+  Derived.prototype.mStrict = function (){
+    'use strict';
+    super.nonEnumConfig = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+    assertEquals(5, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super.nonEnumNonConfig = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+    assertEquals(5, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mSloppy = function (){
+    super.nonEnumConfig = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+    assertEquals(42, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super.nonEnumNonConfig = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+    assertEquals(42, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'nonEnumConfig',
+      { value : 0, enumerable : false, configurable : true, writable : true });
+  Object.defineProperty(d, 'nonEnumNonConfig',
+      { value : 0, enumerable : false, configurable : false, writable : true });
+  d.mStrict();
+  d.mSloppy();
 }());