Support private identifiers in decorators
Categories
(Core :: JavaScript Engine, enhancement, P3)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox120 | --- | fixed |
People
(Reporter: dminor, Assigned: dminor)
References
(Blocks 1 open bug)
Details
Attachments
(4 files)
Decorators can be private identifiers, so we'll need to add support for parsing and using them.
Updated•3 years ago
|
| Assignee | ||
Updated•2 years ago
|
| Assignee | ||
Comment 1•2 years ago
|
||
I think this upstream test may be mistaken: https://github.com/tc39/test262/blob/main/test/language/statements/class/decorator/syntax/class-valid/decorator-member-expr-private-identifier.js
A simplified version of this test is:
class G {
static #dec1() {}
static {
@G.#dec1 class G {}
}
}
In my current implementation, this results in a ReferenceError: can't access lexical declaration 'G' before initialization.
I think this might be the correct behaviour, because this code:
class C {
static dec() {}
static {
this.x = C.dec();
class C {}
}
}
also results in a can't access lexical declaration 'C' before initialization in Firefox, and a ReferenceError: Cannot access 'C' before initialization in Chrome.
I'm having trouble tracking down how this behaviour is defined in the specification. :arai, do you know if the test262 test above is correct or not?
Comment 2•2 years ago
|
||
Yes, the testcase looks wrong.
The inner class should use different name.
The behavior is defined in the following:
1. Creating class static block's function and calling it
- The class static block is converted into a function using:
- the class environments as
F.[[Environment]]andF.[[PrivateEnvironment]] ClassStaticBlockBodyasF.[[ECMAScriptCode]]
- the class environments as
- The enclosing lexical environment's binding is initialized to the class constructor
- The class static block's function is called
15.8.21 Runtime Semantics: Evaluation
ClassDeclaration : class BindingIdentifier ClassTail
1. If DecoratorList opt is present, then
a. Let decorators be ? DecoratorListEvaluation of DecoratorList.
2. Else, let decorators be a new empty List.
3. Perform ? BindingClassDeclarationEvaluation of this ClassDeclaration with
argument decorators.
4. Return empty.
15.7.15 Runtime Semantics: BindingClassDeclarationEvaluation
ClassDeclaration : DecoratorList opt class BindingIdentifier ClassTail
1. Let className be StringValue of BindingIdentifier .
2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments
className, className, and decorators
...
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-runtime-semantics-classdefinitionevaluation
15.7.14 Runtime Semantics: ClassDefinitionEvaluation
ClassTail : ClassHeritage opt { ClassBody opt }
1. Let env be the LexicalEnvironment of the running execution context.
2. Let classEnv be NewDeclarativeEnvironment(env).
...
4. Let outerPrivateEnvironment be the running execution context's
PrivateEnvironment.
5. Let classPrivateEnvironment be
NewPrivateEnvironment(outerPrivateEnvironment).
...
12. Set the running execution context's LexicalEnvironment to classEnv.
13. Set the running execution context's PrivateEnvironment to
classPrivateEnvironment.
...
19. If ClassBody opt is not present, let elements be a new empty List.
20. Else, let elements be NonConstructorElements of ClassBody .
...
24. Let staticElements be a new empty List.
25. For each ClassElement e of elements, do
a. If IsStatic of e is false, then
...
b. Else,
i. Let element be Completion(ClassElementEvaluation of e with
argument F).
...
d. Set element to element.[[Value]].
e. If element is a PrivateElement, then
...
f. Else if element is a ClassFieldDefinition Record, then
...
g. Else if element is a ClassStaticBlockDefinition Record, then
i. Append element to staticElements.
26. Set the running execution context's LexicalEnvironment to env.
27. If classBinding is not undefined, then
a. Perform ! classEnv.InitializeBinding(classBinding, F).
...
31. For each element elementRecord of staticElements, do
a. If elementRecord is a ClassFieldDefinition Record, then
...
b. Else,
i. Assert: elementRecord is a ClassStaticBlockDefinition Record.
ii. Let result be Completion(Call(elementRecord.[[BodyFunction]],
F)).
...
...
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-static-semantics-isstatic
15.8.4 Static Semantics: IsStatic
ClassElement : ClassStaticBlock
1. Return true.
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-static-semantics-classelementevaluation
15.8.18 Runtime Semantics: ClassElementEvaluation
ClassElement : ClassStaticBlock
1. Return ClassStaticBlockDefinitionEvaluation of ClassStaticBlock with
argument object.
15.7.11 Runtime Semantics: ClassStaticBlockDefinitionEvaluation
ClassStaticBlock : static { ClassStaticBlockBody }
1. Let lex be the running execution context's LexicalEnvironment.
2. Let privateEnv be the running execution context's PrivateEnvironment.
3. Let sourceText be the empty sequence of Unicode code points.
4. Let formalParameters be an instance of the production FormalParameters
: [empty] .
5. Let bodyFunction be OrdinaryFunctionCreate(%Function.prototype%,
sourceText, formalParameters, ClassStaticBlockBody , non-lexical-this,
lex, privateEnv).
6. Perform MakeMethod(bodyFunction, homeObject).
7. Return the ClassStaticBlockDefinition Record { [[BodyFunction]]:
bodyFunction }.
2. Bindings in class static block's function body
When the class static block's function is called at ClassDefinitionEvaluation Step 31.b.ii:
func.[[ECMAScriptCode]]isClassStaticBlockBody,- The function's lexical environemnt's bindings are created with
uninitializedfor the inner class
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-runtime-semantics-evaluatebody&secAll=true
10.2.1.3 Runtime Semantics: EvaluateBody
ClassStaticBlockBody : ClassStaticBlockStatementList
1. Assert: argumentsList is empty.
2. Return ? EvaluateClassStaticBlockBody of ClassStaticBlockBody with
argument functionObject.
15.7.12 Runtime Semantics: EvaluateClassStaticBlockBody
ClassStaticBlockBody : ClassStaticBlockStatementList
1. Perform ? FunctionDeclarationInstantiation(functionObject, « »).
2. Return ? Evaluation of ClassStaticBlockStatementList .
10.2.11 FunctionDeclarationInstantiation ( func, argumentsList )
2. Let code be func.[[ECMAScriptCode]].
...
33. Let lexDeclarations be the LexicallyScopedDeclarations of code.
34. For each element d of lexDeclarations, do
...
b. For each element dn of the BoundNames of d, do
i. If IsConstantDeclaration of d is true, then
1. Perform ! lexEnv.CreateImmutableBinding(dn, true).
ii. Else,
1. Perform ! lexEnv.CreateMutableBinding(dn, false).
...
8.2.5 Static Semantics: LexicallyScopedDeclarations
ClassStaticBlockStatementList : StatementList
1. Return the TopLevelLexicallyScopedDeclarations of StatementList .
8.2.9 Static Semantics: TopLevelLexicallyScopedDeclarations
StatementList : StatementList StatementListItem
1. Let declarations1 be TopLevelLexicallyScopedDeclarations of
StatementList .
2. Let declarations2 be TopLevelLexicallyScopedDeclarations of
StatementListItem .
3. Return the list-concatenation of declarations1 and declarations2.
StatementListItem : Declaration
1. If Declaration is Declaration : HoistableDeclaration , then
a. Return a new empty List.
2. Return « Declaration ».
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-static-semantics-boundnames
8.2.1 Static Semantics: BoundNames
ClassDeclaration : DecoratorList opt class BindingIdentifier ClassTail
1. Return the BoundNames of BindingIdentifier.
3. Evaluating class static block's function body
When inner ClassDeclaration inside the function body is evaluated:
- DecoratorList is evaluated
- The the inner class's binding for the function's lexical environemnt is initialized
So, when evaluating the DecoratorList, the function's lexical environemnt already has a mutable binding for the inner class, but the inner class's binding is initialized after DecoratorList, and the name C inside the decorator should see the uninitialized binding for the class static block's function, instead of the enclosing environment's outer class.
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-runtime-semantics-evaluatebody&secAll=true
10.2.1.3 Runtime Semantics: EvaluateBody
ClassStaticBlockBody : ClassStaticBlockStatementList
1. Assert: argumentsList is empty.
2. Return ? EvaluateClassStaticBlockBody of ClassStaticBlockBody with
argument functionObject.
15.7.12 Runtime Semantics: EvaluateClassStaticBlockBody
ClassStaticBlockBody : ClassStaticBlockStatementList
1. Perform ? FunctionDeclarationInstantiation(functionObject, « »).
2. Return ? Evaluation of ClassStaticBlockStatementList .
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-functions-and-classes
A.4 Functions and Classes
ClassStaticBlockStatementList :
StatementList[~Yield, +Await, ~Return] opt
14.2.2 Runtime Semantics: Evaluation
StatementList : StatementList StatementListItem
1. Let sl be ? Evaluation of StatementList .
2. Let s be Completion(Evaluation of StatementListItem ).
3. Return ? UpdateEmpty(s, sl).
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-statements&secAll=true
A.3 Statements
Declaration[Yield, Await] :
HoistableDeclaration[?Yield, ?Await, ~Default]
ClassDeclaration[?Yield, ?Await, ~Default]
LexicalDeclaration[+In, ?Yield, ?Await]
StatementListItem[Yield, Await, Return] :
Statement[?Yield, ?Await, ?Return]
Declaration[?Yield, ?Await]
15.8.21 Runtime Semantics: Evaluation
ClassDeclaration : DecoratorList opt class BindingIdentifier ClassTail
1. If DecoratorList opt is present, then
a. Let decorators be ? DecoratorListEvaluation of DecoratorList.
2. Else, let decorators be a new empty List.
3. Perform ? BindingClassDeclarationEvaluation of this ClassDeclaration with
argument decorators
4. Return empty.
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-decoratorlistevaluation
15.7.2 Runtime Semantics: DecoratorListEvaluation
DecoratorList : DecoratorList opt Decorator
1. If DecoratorList is present, then
a. Let leftValue be ? DecoratorListEvaluation of DecoratorList.
2. Else,
a. Let leftValue be a new empty List.
3. Let rightValue be ? DecoratorEvaluation of Decorator.
4. Prepend rightValue to leftValue.
5. Return leftValue.
https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-decoratorevaluation
15.7.1 Runtime Semantics: DecoratorEvaluation
Decorator : @ DecoratorMemberExpression
1. Let expr be the MemberExpression that is covered by DecoratorMemberExpression.
2. Let ref be ? Evaluation of expr.
3. Let value be ? GetValue(ref).
4. Return DecoratorDefinition Record { [[Decorator]]: value, [[Receiver]]: ref }.
15.8.20 Runtime Semantics: BindingClassDeclarationEvaluation
ClassDeclaration : DecoratorList opt class BindingIdentifier ClassTail
1. Let className be StringValue of BindingIdentifier .
2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments
className, className, and decorators.
3. Set value.[[SourceText]] to the source text matched by
ClassDeclaration .
4. Let env be the running execution context's LexicalEnvironment.
5. Perform ? InitializeBoundName(className, value, env).
6. Return value.
| Assignee | ||
Comment 3•2 years ago
|
||
Thank you, I've opened https://github.com/tc39/test262/pull/3907 to discuss this upstream.
| Assignee | ||
Comment 4•2 years ago
|
||
To help with debugging.
| Assignee | ||
Comment 5•2 years ago
|
||
Depends on D187124
| Assignee | ||
Comment 6•2 years ago
|
||
Depends on D187125
| Assignee | ||
Comment 7•2 years ago
|
||
Depends on D187126
Updated•2 years ago
|
Updated•2 years ago
|
Comment 9•2 years ago
|
||
| bugherder | ||
https://hg.mozilla.org/mozilla-central/rev/68a6354b17f3
https://hg.mozilla.org/mozilla-central/rev/be2f634bbd35
https://hg.mozilla.org/mozilla-central/rev/a5113ad24829
https://hg.mozilla.org/mozilla-central/rev/2faa632c12e2
Description
•