Bug 1191486 - Generators should not have [[Construct]]; r=jorendorff

generator function do not have a [[construct]] trap, so `new` throws called a
generator. This is unexpected behavior, so a TypeError is preferred.

--HG--
extra : rebase_source : 200c1a59db9dd2a0559de3aa52c8f2c466f76289
This commit is contained in:
Morgan Phillips 2015-08-19 10:52:52 -07:00
parent c3ccaf7607
commit dfe5b037ca
7 changed files with 19 additions and 49 deletions

View File

@ -1292,10 +1292,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
break;
case Method:
MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator);
if (generatorKind == NotGenerator)
flags = JSFunction::INTERPRETED_METHOD;
else
flags = JSFunction::INTERPRETED_METHOD_GENERATOR;
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_METHOD
: JSFunction::INTERPRETED_METHOD_GENERATOR);
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case ClassConstructor:
@ -1312,8 +1311,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
default:
flags = JSFunction::INTERPRETED_NORMAL;
break;
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_NORMAL
: JSFunction::INTERPRETED_GENERATOR);
}
fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,

View File

@ -81,13 +81,14 @@ class JSFunction : public js::NativeObject
ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND | CONSTRUCTOR,
INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND,
INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
INTERPRETED_GENERATOR = INTERPRETED,
NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
STABLE_ACROSS_CLONES = IS_FUN_PROTO | CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM |

View File

@ -67,7 +67,7 @@ assertEq(next.value.hello, 2);
assertEq(next.value.world, 3);
// prototype property
assertEq(b.g.hasOwnProperty("prototype"), true);
assertEq(b.g.hasOwnProperty("prototype"), false);
// Strict mode
a = {*b(c){"use strict";yield c;}};
@ -75,13 +75,8 @@ assertEq(a.b(1).next().value, 1);
a = {*["b"](c){"use strict";return c;}};
assertEq(a.b(1).next().value, 1);
// Constructing
// Generators should not have [[Construct]]
a = {*g() { yield 1; }}
it = new a.g;
next = it.next();
assertEq(next.done, false);
assertEq(next.value, 1);
next = it.next();
assertEq(next.done, true);
assertThrowsInstanceOf(() => { new a.g }, TypeError);
reportCompare(0, 0, "ok");

View File

@ -13,23 +13,17 @@ class TestClass {
var test = new TestClass();
var hasPrototype = [
test.constructor,
test.generator,
TestClass.staticGenerator
]
for (var fun of hasPrototype) {
assertEq(fun.hasOwnProperty('prototype'), true);
}
assertEq(test.constructor.hasOwnProperty('prototype'), true);
var hasNoPrototype = [
test.method,
test.generator,
TestClass.staticGenerator,
Object.getOwnPropertyDescriptor(test.__proto__, 'getter').get,
Object.getOwnPropertyDescriptor(test.__proto__, 'setter').set,
TestClass.staticMethod,
Object.getOwnPropertyDescriptor(TestClass, 'staticGetter').get,
Object.getOwnPropertyDescriptor(TestClass, 'staticSetter').set,
Object.getOwnPropertyDescriptor(TestClass, 'staticSetter').set
]
for (var fun of hasNoPrototype) {

View File

@ -10,10 +10,6 @@ const ITERATIONS = 25;
for (let i = 0; i < ITERATIONS; i++)
assertEq(generatorNewTarget(undefined).next().value(), undefined);
for (let i = 0; i < ITERATIONS; i++)
assertEq(new generatorNewTarget(generatorNewTarget).next().value(),
generatorNewTarget);
// also check to make sure it's useful in yield inside generators.
// Plus, this code is so ugly, how could it not be a test? ;)
// Thanks to anba for supplying this ludicrous expression.

View File

@ -15,14 +15,6 @@ function TestGeneratorObject() {
assertEq(String(iter), "[object Generator]");
assertDeepEq(Object.getOwnPropertyNames(iter), []);
assertNotEq(g(), iter);
// g() is the same as new g().
iter = new g();
assertEq(Object.getPrototypeOf(iter), g.prototype);
assertTrue(iter instanceof g);
assertEq(String(iter), "[object Generator]");
assertDeepEq(Object.getOwnPropertyNames(iter), []);
assertNotEq(new g(), iter);
}
TestGeneratorObject();

View File

@ -18,11 +18,12 @@ var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
var GeneratorFunction = GeneratorFunctionPrototype.constructor;
var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
// A generator function should have the same set of properties as any
// other function.
// other function, minus a prototype.
function TestGeneratorFunctionInstance() {
var f_own_property_names = Object.getOwnPropertyNames(f);
f_own_property_names.splice(f_own_property_names.indexOf("prototype"), 1);
var g_own_property_names = Object.getOwnPropertyNames(g);
f_own_property_names.sort();
@ -41,7 +42,6 @@ function TestGeneratorFunctionInstance() {
}
TestGeneratorFunctionInstance();
// Generators have an additional object interposed in the chain between
// themselves and Function.prototype.
function TestGeneratorFunctionPrototype() {
@ -112,15 +112,7 @@ TestGeneratorFunction();
function TestPerGeneratorPrototype() {
assertNotEq((function*(){}).prototype, (function*(){}).prototype);
assertNotEq((function*(){}).prototype, g.prototype);
assertEq(typeof GeneratorFunctionPrototype, "object");
assertEq(g.prototype.__proto__.constructor, GeneratorFunctionPrototype, "object");
assertEq(Object.getPrototypeOf(g.prototype), GeneratorObjectPrototype);
assertFalse(g.prototype instanceof Function);
assertEq(typeof (g.prototype), "object");
assertDeepEq(Object.getOwnPropertyNames(g.prototype), []);
assertEq(g.hasOwnProperty("prototype"), false);
}
TestPerGeneratorPrototype();