зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
7bd5e65f27
Коммит
6940ef010b
|
@ -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(() => {
|
||||
|
|
Загрузка…
Ссылка в новой задаче