Closed Bug 1166950 Opened 5 years ago Closed 5 years ago

Generator methods incorrectly restricted from use as constructors

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla41
Tracking Status
firefox41 --- fixed

People

(Reporter: jugglinmike, Assigned: evilpie)

References

(Blocks 1 open bug)

Details

Attachments

(3 files)

Input:

    var g = { *g() {} }.g; new g();

Expected: an object is created whose [[Prototype]] internal slot is the
generator function defined in the object initializer.

Actual: TypeError

Demo:

    $ js -e "var g = { *g() {} }.g; new g();"
    -e:1:27 TypeError: g is not a constructor

"Normal" functions declared within object initializers using the
MethodDefinition syntax do not defined a [[Construct]] internal method and
cannot be used as constructors. The same is not true for generator functions:

> 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation
> 
> GeneratorMethod : * PropertyName ( StrictFormalParameters ) { GeneratorBody }
> 
> [...]
> 5. Let closure be GeneratorFunctionCreate(Method, StrictFormalParameters,
>    GeneratorBody, scope, strict).
> 6. Perform MakeMethod(closure, object).
> 7. Let prototype be ObjectCreate(%GeneratorPrototype%).
> 8. Perform MakeConstructor(closure, true, prototype).
> [...]

> 9.2.6 GeneratorFunctionCreate (kind, ParameterList, Body, Scope, Strict)
> 
> 1. Let functionPrototype be the intrinsic object %Generator%.
> 2. Let F be FunctionAllocate(functionPrototype, Strict, "generator").
> 3. Return FunctionInitialize(F, kind, ParameterList, Body, Scope).

> 9.2.3 FunctionAllocate (functionPrototype, strict [,functionKind] )
> 
> [...]
> 3. If functionKind is not present, let functionKind be "normal".
> 4. If functionKind is "non-constructor", then
>    a. Let functionKind be "normal".
>    b. Let needsConstruct be false.
> 5. Else let needsConstruct be true.
> [...]
> 9. If needsConstruct is true, then
>    a. Set F’s [[Construct]] internal method to the definition specified in
>       9.2.2.
>    b. If functionKind is "generator", set the [[ConstructorKind]] internal
>       slot of F to "derived".
>    c. Else, set the [[ConstructorKind]] internal slot of F to "base".
>    d. NOTE Generator functions are tagged as "derived" constructors to
>       prevent [[Construct]] from preallocating a generator instance.
>       Generator instance objects are allocated when EvaluateBody is applied
>       to the GeneratorBody of a generator function.

Sources:

- https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generator-function-definitions-runtime-semantics-propertydefinitionevaluation
- https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorfunctioncreate
- https://people.mozilla.org/~jorendorff/es6-draft.html#sec-functionallocate
Blocks: es6
See Also: → 1059908
And Method Definitions except for GeneratorMethod should not have a prototype property:

js> ({m(){}}).m.hasOwnProperty("prototype")
true // should be false

js> ({*g(){}}).g.hasOwnProperty("prototype")
true // √

js> (class {constructor(){} static m(){}}).m.hasOwnProperty("prototype")
true // should be false

js> (class {constructor(){} static *g(){}}).g.hasOwnProperty("prototype")
true // √

js> (new (class {constructor(){} m(){}})).m.hasOwnProperty("prototype")
true // should be false

js> (new (class {constructor(){} *g(){}})).g.hasOwnProperty("prototype")
true // √

js> Object.getOwnPropertyDescriptor({set m(_){}}, "m").set.hasOwnProperty("prototype")
true // should be false

js> Object.getOwnPropertyDescriptor({get m(){}}, "m").get.hasOwnProperty("prototype")
true // should be false
See Also: → 1069402
Assignee: nobody → evilpies
Attachment #8609835 - Flags: review?(efaustbmo)
Attachment #8609836 - Flags: review?(efaustbmo)
Comment on attachment 8609834 [details] [diff] [review]
Introduce a new FunctionKind for class-constructors

Review of attachment 8609834 [details] [diff] [review]:
-----------------------------------------------------------------

Looks fine.

::: js/src/jsfun.h
@@ +165,5 @@
>  
>      // Arrow functions store their lexical |this| in the first extended slot.
>      bool isArrow()                  const { return kind() == Arrow; }
>      // Every class-constructor is also a method.
> +    bool isMethod()                 const { return kind() == Method || kind() == ClassConstructor; }

nit: || isClassConstructor()
Attachment #8609834 - Flags: review?(efaustbmo) → review+
Comment on attachment 8609835 [details] [diff] [review]
Make generator methods constructors

Review of attachment 8609835 [details] [diff] [review]:
-----------------------------------------------------------------

Yup
Attachment #8609835 - Flags: review?(efaustbmo) → review+
Comment on attachment 8609836 [details] [diff] [review]
Only give constructor functions a prototype

Review of attachment 8609836 [details] [diff] [review]:
-----------------------------------------------------------------

Thanks for taking this, too.
Attachment #8609836 - Flags: review?(efaustbmo) → review+
You need to log in before you can comment on or make changes to this bug.