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 : 6aa03d31c71c0bf8634daf6aa0c349eba0058086
This commit is contained in:
Morgan Phillips 2015-09-01 09:20:11 -07:00
Родитель 7bd5e65f27
Коммит 6940ef010b
8 изменённых файлов: 26 добавлений и 42 удалений

Просмотреть файл

@ -1397,7 +1397,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
JSFunction::Flags flags;
switch (kind) {
case Expression:
flags = JSFunction::INTERPRETED_LAMBDA;
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_LAMBDA
: JSFunction::INTERPRETED_LAMBDA_GENERATOR);
break;
case Arrow:
flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
@ -1405,10 +1407,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:
@ -1425,8 +1426,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,

Просмотреть файл

@ -433,15 +433,16 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
* isBuiltin() test covers this case because bound functions are native
* (and thus built-in) functions by definition/construction.
*
* In ES6 9.2.8 MakeConstructor the .prototype property is only assigned
* to constructors.
* ES6 9.2.8 MakeConstructor defines the .prototype property on constructors.
* Generators are not constructors, but they have a .prototype property anyway,
* according to errata to ES6. See bug 1191486.
*
* Thus all of the following don't get a .prototype property:
* - Methods (that are not class-constructors or generators)
* - Arrow functions
* - Function.prototype
*/
if (fun->isBuiltin() || !fun->isConstructor())
if (fun->isBuiltin() || (!fun->isConstructor() && !fun->isGenerator()))
return true;
if (!ResolveInterpretedFunctionPrototype(cx, fun, id))

Просмотреть файл

@ -81,13 +81,15 @@ 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_LAMBDA_GENERATOR = INTERPRETED | LAMBDA,
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 |

Просмотреть файл

@ -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");

Просмотреть файл

@ -10,15 +10,5 @@ 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.
assertDeepEq([...new function*(i) { yield i; if(i > 0) yield* new new.target(i-1) }(10)],
[ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

Просмотреть файл

@ -60,9 +60,9 @@ function TestGenerator(g, expected_values_for_next,
testThrow(function*() { return yield* g(); });
if (g instanceof GeneratorFunction) {
testNext(function() { return new g(); });
testSend(function() { return new g(); });
testThrow(function() { return new g(); });
testNext(function() { return g(); });
testSend(function() { return g(); });
testThrow(function() { return g(); });
}
}

Просмотреть файл

@ -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();

Просмотреть файл

@ -68,10 +68,12 @@ for (var constructor of constructors) {
constructor.of.call(Object.getOwnPropertyDescriptor({get getter() {}}, "getter").get);
}, TypeError);
// Generators are also legal constructors.
assertEq(constructor.of.call(function*(len) {
// Generators are not legal constructors.
assertThrowsInstanceOf(() => {
constructor.of.call(function*(len) {
return len;
}, "a", "b", "c").next().value, 3);
}, "a")
}, TypeError);
// An exception might be thrown in a strict assignment to the new object's indexed properties.
assertThrowsInstanceOf(() => {