mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-04 23:08:39 +09:00
Issue #2142 - Fix several scoping issues in field initializers
Based-on: m-c 1540789, 1547130, 1547467
This commit is contained in:
parent
8c6750014c
commit
bcb6203e4f
11 changed files with 156 additions and 176 deletions
|
|
@ -2701,6 +2701,8 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
|
|||
return false;
|
||||
|
||||
for (ParseNode* item : memberList->contents()) {
|
||||
if (item->is<LexicalScopeNode>())
|
||||
item = item->as<LexicalScopeNode>().scopeBody();
|
||||
if (item->is<ClassField>()) {
|
||||
ClassField* field = &item->as<ClassField>();
|
||||
MOZ_ASSERT(memberList->pn_pos.encloses(field->pn_pos));
|
||||
|
|
|
|||
|
|
@ -2324,7 +2324,7 @@ BytecodeEmitter::emitSetThis(BinaryNode* setThisNode)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!emitInitializeInstanceFields(true)) {
|
||||
if (!emitInitializeInstanceFields()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -7623,6 +7623,13 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
continue;
|
||||
}
|
||||
|
||||
if (propdef->is<LexicalScopeNode>()) {
|
||||
// Constructors are sometimes wrapped in LexicalScopeNodes. As we already
|
||||
// handled emitting the constructor, skip it.
|
||||
MOZ_ASSERT(propdef->as<LexicalScopeNode>().scopeBody()->isKind(PNK_CLASSMETHOD));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle __proto__: v specially because *only* this form, and no other
|
||||
// involving "__proto__", performs [[Prototype]] mutation.
|
||||
if (propdef->isKind(PNK_MUTATEPROTO)) {
|
||||
|
|
@ -7854,14 +7861,7 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
}
|
||||
}
|
||||
|
||||
if (obj->getKind() == PNK_CLASSMEMBERLIST) {
|
||||
if (!emitCreateFieldKeys(obj))
|
||||
return false;
|
||||
if (!emitCreateFieldInitializers(obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
FieldInitializers
|
||||
|
|
@ -8063,38 +8063,7 @@ BytecodeEmitter::findFieldInitializersForCall()
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitCopyInitializersToLocalInitializers()
|
||||
{
|
||||
MOZ_ASSERT(sc->asFunctionBox()->isDerivedClassConstructor());
|
||||
if (getFieldInitializers().numFieldInitializers == 0)
|
||||
return true;
|
||||
|
||||
NameOpEmitter noe(this, cx->names().dotLocalInitializers, NameOpEmitter::Kind::Initialize);
|
||||
if (!noe.prepareForRhs()) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitGetName(cx->names().dotInitializers)) {
|
||||
// [stack] .initializers
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!noe.emitAssignment()) {
|
||||
// [stack] .initializers
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emit1(JSOP_POP)) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitInitializeInstanceFields(bool isSuperCall)
|
||||
BytecodeEmitter::emitInitializeInstanceFields()
|
||||
{
|
||||
const FieldInitializers& fieldInitializers = findFieldInitializersForCall();
|
||||
size_t numFields = fieldInitializers.numFieldInitializers;
|
||||
|
|
@ -8103,16 +8072,9 @@ BytecodeEmitter::emitInitializeInstanceFields(bool isSuperCall)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (isSuperCall) {
|
||||
if (!emitGetName(cx->names().dotLocalInitializers)) {
|
||||
// [stack] ARRAY
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!emitGetName(cx->names().dotInitializers)) {
|
||||
// [stack] ARRAY
|
||||
return false;
|
||||
}
|
||||
if (!emitGetName(cx->names().dotInitializers)) {
|
||||
// [stack] ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
|
||||
|
|
@ -8625,16 +8587,19 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
ParseNode* heritageExpression = classNode->heritage();
|
||||
ListNode* classMembers = classNode->memberList();
|
||||
|
||||
FunctionNode* constructor = nullptr;
|
||||
for (ParseNode* mn : classMembers->contents()) {
|
||||
if (mn->is<ClassMethod>()) {
|
||||
ClassMethod& method = mn->as<ClassMethod>();
|
||||
ParseNode* constructor = nullptr;
|
||||
for (ParseNode* classElement : classMembers->contents()) {
|
||||
ParseNode* unwrappedElement = classElement;
|
||||
if (unwrappedElement->is<LexicalScopeNode>())
|
||||
unwrappedElement = unwrappedElement->as<LexicalScopeNode>().scopeBody();
|
||||
if (unwrappedElement->is<ClassMethod>()) {
|
||||
ClassMethod& method = unwrappedElement->as<ClassMethod>();
|
||||
ParseNode& methodName = method.name();
|
||||
if (!method.isStatic() &&
|
||||
(methodName.isKind(PNK_OBJECT_PROPERTY_NAME) || methodName.isKind(PNK_STRING)) &&
|
||||
methodName.as<NameNode>().atom() == cx->names().constructor)
|
||||
{
|
||||
constructor = &method.method();
|
||||
constructor = classElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -8656,8 +8621,8 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
}
|
||||
}
|
||||
|
||||
if (!classNode->isEmptyScope()) {
|
||||
if (!ce.emitScope(classNode->scopeBindings(), classNode->names() != nullptr)) {
|
||||
if (LexicalScopeNode* scopeBindings = classNode->scopeBindings()) {
|
||||
if (!ce.emitScope(scopeBindings->scopeBindings())) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
|
|
@ -8685,12 +8650,35 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
}
|
||||
|
||||
if (constructor) {
|
||||
bool needsHomeObject = constructor->funbox()->needsHomeObject();
|
||||
FunctionNode* ctor;
|
||||
// .fieldKeys must be declared outside the scope .initializers is declared
|
||||
// in, hence this extra scope.
|
||||
Maybe<LexicalScopeEmitter> lse;
|
||||
if (constructor->is<LexicalScopeNode>()) {
|
||||
lse.emplace(this);
|
||||
if (!lse->emitScope(ScopeKind::Lexical, constructor->as<LexicalScopeNode>().scopeBindings()))
|
||||
return false;
|
||||
|
||||
// Any class with field initializers will have a constructor
|
||||
if (!emitCreateFieldInitializers(classMembers))
|
||||
return false;
|
||||
ctor = &constructor->as<LexicalScopeNode>().scopeBody()->as<ClassMethod>().method();
|
||||
} else {
|
||||
ctor = &constructor->as<ClassMethod>().method();
|
||||
}
|
||||
|
||||
bool needsHomeObject = ctor->funbox()->needsHomeObject();
|
||||
// HERITAGE is consumed inside emitFunction.
|
||||
if (!emitFunction(constructor, isDerived, classMembers)) {
|
||||
if (!emitFunction(ctor, isDerived, classMembers)) {
|
||||
// [stack] HOMEOBJ CTOR
|
||||
return false;
|
||||
}
|
||||
if (lse.isSome()) {
|
||||
if (!lse->emitEnd()) {
|
||||
return false;
|
||||
}
|
||||
lse.reset();
|
||||
}
|
||||
if (!ce.emitInitConstructor(needsHomeObject)) {
|
||||
// [stack] CTOR HOMEOBJ
|
||||
return false;
|
||||
|
|
@ -8706,6 +8694,10 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
// [stack] CTOR HOMEOBJ
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitCreateFieldKeys(classMembers))
|
||||
return false;
|
||||
|
||||
if (!ce.emitEnd(kind)) {
|
||||
// [stack] # class declaration
|
||||
// [stack]
|
||||
|
|
|
|||
|
|
@ -533,8 +533,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj);
|
||||
MOZ_MUST_USE bool emitCreateFieldInitializers(ListNode* obj);
|
||||
const FieldInitializers& findFieldInitializersForCall();
|
||||
MOZ_MUST_USE bool emitCopyInitializersToLocalInitializers();
|
||||
MOZ_MUST_USE bool emitInitializeInstanceFields(bool isSuperCall);
|
||||
MOZ_MUST_USE bool emitInitializeInstanceFields();
|
||||
|
||||
// To catch accidental misuse, emitUint16Operand/emit3 assert that they are
|
||||
// not used to unconditionally emit JSOP_GETLOCAL. Variable access should
|
||||
|
|
|
|||
|
|
@ -459,31 +459,35 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
|||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType memberList, Node key, FunctionNodeType funNode,
|
||||
JSOp op, bool isStatic)
|
||||
MOZ_MUST_USE ClassMethod* newClassMethodDefinition(Node key, FunctionNodeType funNode,
|
||||
JSOp op, bool isStatic)
|
||||
{
|
||||
MOZ_ASSERT(memberList->isKind(PNK_CLASSMEMBERLIST));
|
||||
MOZ_ASSERT(isUsableAsObjectPropertyName(key));
|
||||
|
||||
ClassMethod* classMethod = new_<ClassMethod>(key, funNode, op, isStatic);
|
||||
if (!classMethod)
|
||||
return false;
|
||||
memberList->append(classMethod);
|
||||
return true;
|
||||
return new_<ClassMethod>(key, funNode, op, isStatic);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addClassFieldDefinition(ListNodeType memberList, Node name, FunctionNodeType initializer)
|
||||
MOZ_MUST_USE ClassField* newClassFieldDefinition(Node name, FunctionNodeType initializer)
|
||||
{
|
||||
MOZ_ASSERT(memberList->isKind(PNK_CLASSMEMBERLIST));
|
||||
MOZ_ASSERT(isUsableAsObjectPropertyName(name));
|
||||
|
||||
ParseNode* classField = new_<ClassField>(name, initializer);
|
||||
if (!classField)
|
||||
return false;
|
||||
memberList->append(classField);
|
||||
return new_<ClassField>(name, initializer);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member)
|
||||
{
|
||||
MOZ_ASSERT(memberList->isKind(PNK_CLASSMEMBERLIST));
|
||||
// Constructors can be surrounded by LexicalScopes.
|
||||
MOZ_ASSERT(member->isKind(PNK_CLASSMETHOD) ||
|
||||
member->isKind(PNK_CLASSFIELD) ||
|
||||
(member->isKind(PNK_LEXICALSCOPE) &&
|
||||
member->as<LexicalScopeNode>().scopeBody()->isKind(PNK_CLASSMETHOD)));
|
||||
|
||||
addList(/* list = */ memberList, /* kid = */ member);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
UnaryNodeType newInitialYieldExpression(uint32_t begin, Node gen) {
|
||||
TokenPos pos(begin, begin + 1);
|
||||
return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
|
||||
|
|
|
|||
|
|
@ -477,13 +477,8 @@ bool FunctionScriptEmitter::prepareForBody()
|
|||
}
|
||||
|
||||
if (funbox_->function()->kind() == JSFunction::FunctionKind::ClassConstructor) {
|
||||
if (funbox_->isDerivedClassConstructor()) {
|
||||
if (!bce_->emitCopyInitializersToLocalInitializers()) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!bce_->emitInitializeInstanceFields(false)) {
|
||||
if (!funbox_->isDerivedClassConstructor()) {
|
||||
if (!bce_->emitInitializeInstanceFields()) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -531,13 +531,12 @@ ClassEmitter::ClassEmitter(BytecodeEmitter* bce)
|
|||
isClass_ = true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::emitScope(JS::Handle<LexicalScope::Data*> scopeBindings, bool hasName)
|
||||
bool ClassEmitter::emitScope(JS::Handle<LexicalScope::Data*> scopeBindings)
|
||||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start);
|
||||
MOZ_ASSERT(classState_ == ClassState::Start);
|
||||
|
||||
if (hasName)
|
||||
tdzCacheForInnerName_.emplace(bce_);
|
||||
tdzCache_.emplace(bce_);
|
||||
|
||||
innerScope_.emplace(bce_);
|
||||
if (!innerScope_->enterLexical(bce_, ScopeKind::Lexical, scopeBindings))
|
||||
|
|
@ -717,7 +716,7 @@ bool ClassEmitter::emitEnd(Kind kind)
|
|||
}
|
||||
|
||||
if (name_ != bce_->cx->names().empty) {
|
||||
MOZ_ASSERT(tdzCacheForInnerName_.isSome());
|
||||
MOZ_ASSERT(tdzCache_.isSome());
|
||||
MOZ_ASSERT(innerScope_.isSome());
|
||||
|
||||
if (!bce_->emitLexicalInitialization(name_)) {
|
||||
|
|
@ -743,20 +742,21 @@ bool ClassEmitter::emitEnd(Kind kind)
|
|||
}
|
||||
}
|
||||
|
||||
tdzCacheForInnerName_.reset();
|
||||
tdzCache_.reset();
|
||||
} else if (innerScope_.isSome()) {
|
||||
// [stack] CTOR
|
||||
MOZ_ASSERT(kind == Kind::Expression);
|
||||
MOZ_ASSERT(tdzCacheForInnerName_.isNothing());
|
||||
MOZ_ASSERT(tdzCache_.isSome());
|
||||
|
||||
if (!innerScope_->leave(bce_))
|
||||
return false;
|
||||
innerScope_.reset();
|
||||
tdzCache_.reset();
|
||||
}else {
|
||||
// [stack] CTOR
|
||||
|
||||
MOZ_ASSERT(kind == Kind::Expression);
|
||||
MOZ_ASSERT(tdzCacheForInnerName_.isNothing());
|
||||
MOZ_ASSERT(tdzCache_.isNothing());
|
||||
}
|
||||
|
||||
// [stack] # class declaration
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
|
|||
//
|
||||
// `class {}`
|
||||
// ClassEmitter ce(this);
|
||||
// ce.emitScope(scopeBindings, false);
|
||||
// ce.emitScope(scopeBindings);
|
||||
// ce.emitClass();
|
||||
//
|
||||
// ce.emitInitDefaultConstructor(Some(offset_of_class),
|
||||
|
|
@ -474,7 +474,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
|
|||
//
|
||||
// `class { constructor() { ... } }`
|
||||
// ClassEmitter ce(this);
|
||||
// ce.emitScope(scopeBindings, false);
|
||||
// ce.emitScope(scopeBindings);
|
||||
// ce.emitClass();
|
||||
//
|
||||
// emit(function_for_constructor);
|
||||
|
|
@ -484,7 +484,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
|
|||
//
|
||||
// `class X { constructor() { ... } }`
|
||||
// ClassEmitter ce(this);
|
||||
// ce.emitScope(scopeBindings, true);
|
||||
// ce.emitScope(scopeBindings);
|
||||
// ce.emitClass(atom_of_X);
|
||||
//
|
||||
// ce.emitInitDefaultConstructor(Some(offset_of_class),
|
||||
|
|
@ -494,7 +494,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
|
|||
//
|
||||
// `class X { constructor() { ... } }`
|
||||
// ClassEmitter ce(this);
|
||||
// ce.emitScope(scopeBindings, true);
|
||||
// ce.emitScope(scopeBindings);
|
||||
// ce.emitClass(atom_of_X);
|
||||
//
|
||||
// emit(function_for_constructor);
|
||||
|
|
@ -504,7 +504,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
|
|||
//
|
||||
// `class X extends Y { constructor() { ... } }`
|
||||
// ClassEmitter ce(this);
|
||||
// ce.emitScope(scopeBindings, true);
|
||||
// ce.emitScope(scopeBindings);
|
||||
//
|
||||
// emit(Y);
|
||||
// ce.emitDerivedClass(atom_of_X);
|
||||
|
|
@ -516,7 +516,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
|
|||
//
|
||||
// `class X extends Y { constructor() { ... super.f(); ... } }`
|
||||
// ClassEmitter ce(this);
|
||||
// ce.emitScope(scopeBindings, true);
|
||||
// ce.emitScope(scopeBindings);
|
||||
//
|
||||
// emit(Y);
|
||||
// ce.emitDerivedClass(atom_of_X);
|
||||
|
|
@ -630,7 +630,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
|
||||
bool isDerived_ = false;
|
||||
|
||||
mozilla::Maybe<TDZCheckCache> tdzCacheForInnerName_;
|
||||
mozilla::Maybe<TDZCheckCache> tdzCache_;
|
||||
mozilla::Maybe<EmitterScope> innerScope_;
|
||||
AutoSaveLocalStrictMode strictMode_;
|
||||
|
||||
|
|
@ -691,7 +691,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
public:
|
||||
explicit ClassEmitter(BytecodeEmitter* bce);
|
||||
|
||||
MOZ_MUST_USE bool emitScope(JS::Handle<LexicalScope::Data*> scopeBindings, bool hasName);
|
||||
MOZ_MUST_USE bool emitScope(JS::Handle<LexicalScope::Data*> scopeBindings);
|
||||
|
||||
// @param name
|
||||
// Name of the class (nullptr if this is anonymous class)
|
||||
|
|
|
|||
|
|
@ -2268,13 +2268,9 @@ class ClassNode : public TernaryNode
|
|||
MOZ_ASSERT(list->isKind(PNK_CLASSMEMBERLIST));
|
||||
return list;
|
||||
}
|
||||
bool isEmptyScope() const {
|
||||
ParseNode* scope = kid3();
|
||||
return scope->as<LexicalScopeNode>().isEmptyScope();
|
||||
}
|
||||
Handle<LexicalScope::Data*> scopeBindings() const {
|
||||
ParseNode* scope = kid3();
|
||||
return scope->as<LexicalScopeNode>().scopeBindings();
|
||||
LexicalScopeNode* scopeBindings() const {
|
||||
LexicalScopeNode* scope = &kid3()->as<LexicalScopeNode>();
|
||||
return scope->isEmptyScope() ? nullptr : scope;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2791,12 +2791,6 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
|
|||
return null();
|
||||
}
|
||||
|
||||
if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
|
||||
if (!noteDeclaredName(context->names().dotLocalInitializers,
|
||||
DeclarationKind::Var, pos()))
|
||||
return null();
|
||||
}
|
||||
|
||||
return finishLexicalScope(pc->varScope(), body);
|
||||
}
|
||||
|
||||
|
|
@ -3689,6 +3683,12 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
|||
FunctionBox* funbox = pc->functionBox();
|
||||
RootedFunction fun(context, funbox->function());
|
||||
|
||||
if (kind == FunctionSyntaxKind::ClassConstructor ||
|
||||
kind == FunctionSyntaxKind::DerivedClassConstructor) {
|
||||
if (!noteUsedName(context->names().dotInitializers))
|
||||
return false;
|
||||
}
|
||||
|
||||
// See below for an explanation why arrow function parameters and arrow
|
||||
// function bodies are parsed with different yield/await settings.
|
||||
{
|
||||
|
|
@ -7501,7 +7501,11 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d
|
|||
return false;
|
||||
}
|
||||
|
||||
return handler.addClassFieldDefinition(classMembers, propName, initializer);
|
||||
ClassFieldType field = handler.newClassFieldDefinition(propName, initializer);
|
||||
if (!field)
|
||||
return false;
|
||||
|
||||
return handler.addClassMemberDefinition(classMembers, field);
|
||||
}
|
||||
|
||||
if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
|
||||
|
|
@ -7554,6 +7558,19 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d
|
|||
funName = propAtom;
|
||||
}
|
||||
|
||||
// .fieldKeys must be declared outside the scope .initializers is declared in,
|
||||
// hence this extra scope.
|
||||
Maybe<ParseContext::Scope> dotInitializersScope;
|
||||
if (isConstructor && !options().selfHostingMode) {
|
||||
dotInitializersScope.emplace(this);
|
||||
if (!dotInitializersScope->init(pc))
|
||||
return false;
|
||||
|
||||
if (!noteDeclaredName(context->names().dotInitializers, DeclarationKind::Let, pos()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Calling toString on constructors need to return the source text for
|
||||
// the entire class. The end offset is unknown at this point in
|
||||
// parsing and will be amended when class parsing finishes below.
|
||||
|
|
@ -7565,7 +7582,18 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d
|
|||
handler.checkAndSetIsDirectRHSAnonFunction(funNode);
|
||||
|
||||
JSOp op = JSOpFromPropertyType(propType);
|
||||
return handler.addClassMethodDefinition(classMembers, propName, funNode, op, isStatic);
|
||||
Node method = handler.newClassMethodDefinition(propName, funNode, op, isStatic);
|
||||
if (!method)
|
||||
return false;
|
||||
|
||||
if (dotInitializersScope.isSome()) {
|
||||
method = finishLexicalScope(*dotInitializersScope, method);
|
||||
if (!method)
|
||||
return false;
|
||||
dotInitializersScope.reset();
|
||||
}
|
||||
|
||||
return handler.addClassMemberDefinition(classMembers, method);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
|
@ -7580,6 +7608,16 @@ Parser<ParseHandler>::finishClassConstructor(const ParseContext::ClassStatement&
|
|||
// JSOP_DERIVEDCONSTRUCTOR due to needing to emit calls to the field
|
||||
// initializers in the constructor. So, synthesize a new one.
|
||||
if (classStmt.constructorBox == nullptr && numFields > 0) {
|
||||
MOZ_ASSERT(!options().selfHostingMode);
|
||||
// Unconditionally create the scope here, because it's always the
|
||||
// constructor.
|
||||
ParseContext::Scope dotInitializersScope(this);
|
||||
if (!dotInitializersScope.init(pc))
|
||||
return false;
|
||||
|
||||
if (!noteDeclaredName(context->names().dotInitializers, DeclarationKind::Let, pos()))
|
||||
return false;
|
||||
|
||||
// synthesizeConstructor assigns to classStmt.constructorBox
|
||||
FunctionNodeType synthesizedCtor = synthesizeConstructor(className, classStartOffset, hasHeritage);
|
||||
if (!synthesizedCtor) {
|
||||
|
|
@ -7595,9 +7633,14 @@ Parser<ParseHandler>::finishClassConstructor(const ParseContext::ClassStatement&
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!handler.addClassMethodDefinition(classMembers, constructorNameNode,
|
||||
synthesizedCtor, JSOP_INITPROP,
|
||||
/* isStatic = */ false)) {
|
||||
ClassMethodType method = handler.newClassMethodDefinition(constructorNameNode, synthesizedCtor,
|
||||
JSOP_INITPROP, /* isStatic = */ false);
|
||||
if (!method)
|
||||
return false;
|
||||
|
||||
LexicalScopeNodeType scope = finishLexicalScope(dotInitializersScope, method);
|
||||
|
||||
if (!handler.addClassMemberDefinition(classMembers, scope)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -7712,35 +7755,6 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
|||
break;
|
||||
}
|
||||
|
||||
if (numFields > 0) {
|
||||
// .initializers is always closed over by the constructor when there are
|
||||
// fields with initializers. However, there's some strange circumstances
|
||||
// which prevents us from using the normal noteUsedName() system. We
|
||||
// cannot call noteUsedName(".initializers") when parsing the constructor,
|
||||
// because .initializers should be marked as used *only if* there are
|
||||
// fields with initializers. Even if we haven't seen any fields yet,
|
||||
// there may be fields after the constructor.
|
||||
// Consider the following class:
|
||||
//
|
||||
// class C {
|
||||
// constructor() {
|
||||
// // do we noteUsedName(".initializers") here?
|
||||
// }
|
||||
// // ... because there might be some fields down here.
|
||||
// }
|
||||
//
|
||||
// So, instead, at the end of class parsing (where we are now), we do some
|
||||
// tricks to pretend that noteUsedName(".initializers") was called in the
|
||||
// constructor.
|
||||
if (!usedNames.markAsAlwaysClosedOver(context, context->names().dotInitializers,
|
||||
pc->scriptId(),
|
||||
pc->innermostScope()->id()))
|
||||
return null();
|
||||
if (!noteDeclaredName(context->names().dotInitializers,
|
||||
DeclarationKind::Let, namePos))
|
||||
return null();
|
||||
}
|
||||
|
||||
if (numFieldKeys > 0) {
|
||||
if (!noteDeclaredName(context->names().dotFieldKeys, DeclarationKind::Let, namePos))
|
||||
return null();
|
||||
|
|
@ -7836,11 +7850,6 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
|
|||
|
||||
pc->functionScope().useAsVarScope(pc);
|
||||
|
||||
// Push a LexicalScope on to the stack.
|
||||
ParseContext::Scope lexicalScope(this);
|
||||
if (!lexicalScope.init(pc))
|
||||
return null();
|
||||
|
||||
auto stmtList = handler.newStatementList(synthesizedBodyPos);
|
||||
if (!stmtList)
|
||||
return null();
|
||||
|
|
@ -7848,14 +7857,8 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
|
|||
if (!noteUsedName(context->names().dotThis))
|
||||
return null();
|
||||
|
||||
// One might expect a noteUsedName(".initializers") here. See comment in
|
||||
// GeneralParser<ParseHandler, Unit>::classDefinition on why it's not here.
|
||||
|
||||
if (hasHeritage) {
|
||||
if (!noteDeclaredName(context->names().dotLocalInitializers,
|
||||
DeclarationKind::Var, synthesizedBodyPos))
|
||||
return null();
|
||||
}
|
||||
if (!noteUsedName(context->names().dotInitializers))
|
||||
return null();
|
||||
|
||||
bool canSkipLazyClosedOverBindings = handler.canSkipLazyClosedOverBindings();
|
||||
if (!declareFunctionThis(canSkipLazyClosedOverBindings))
|
||||
|
|
@ -7890,9 +7893,6 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
|
|||
if (!setThis)
|
||||
return null();
|
||||
|
||||
if (!noteUsedName(context->names().dotLocalInitializers))
|
||||
return null();
|
||||
|
||||
UnaryNodeType exprStatement = handler.newExprStatement(setThis, synthesizedBodyPos.end);
|
||||
if (!exprStatement)
|
||||
return null();
|
||||
|
|
@ -7900,7 +7900,7 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
|
|||
handler.addStatementToList(stmtList, exprStatement);
|
||||
}
|
||||
|
||||
auto initializerBody = finishLexicalScope(lexicalScope, stmtList);
|
||||
auto initializerBody = finishLexicalScope(pc->varScope(), stmtList);
|
||||
if (!initializerBody)
|
||||
return null();
|
||||
handler.setBeginPosition(initializerBody, stmtList);
|
||||
|
|
@ -7969,15 +7969,7 @@ Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH
|
|||
if (!funpc.init())
|
||||
return null();
|
||||
|
||||
// Push a VarScope on to the stack.
|
||||
ParseContext::VarScope varScope(this);
|
||||
if (!varScope.init(pc))
|
||||
return null();
|
||||
|
||||
// Push a LexicalScope on to the stack.
|
||||
ParseContext::Scope lexicalScope(this);
|
||||
if (!lexicalScope.init(pc))
|
||||
return null();
|
||||
pc->functionScope().useAsVarScope(pc);
|
||||
|
||||
Node initializerExpr;
|
||||
TokenPos wholeInitializerPos;
|
||||
|
|
@ -8081,7 +8073,7 @@ Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH
|
|||
handler.addStatementToList(statementList, exprStatement);
|
||||
|
||||
// Set the function's body to the field assignment.
|
||||
LexicalScopeNodeType initializerBody = finishLexicalScope(lexicalScope, statementList);
|
||||
LexicalScopeNodeType initializerBody = finishLexicalScope(pc->varScope(), statementList);
|
||||
if (!initializerBody) {
|
||||
return null();
|
||||
}
|
||||
|
|
@ -9975,7 +9967,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
|
|||
if (!nextMember)
|
||||
return null();
|
||||
|
||||
if (!noteUsedName(context->names().dotLocalInitializers))
|
||||
if (!noteUsedName(context->names().dotInitializers))
|
||||
return null();
|
||||
} else {
|
||||
nextMember = memberCall(tt, lhs, yieldHandling, possibleError);
|
||||
|
|
|
|||
|
|
@ -331,8 +331,9 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
|||
MOZ_MUST_USE bool addShorthand(ListNodeType literal, NameNodeType name, NameNodeType expr) { return true; }
|
||||
MOZ_MUST_USE bool addSpreadProperty(ListNodeType literal, uint32_t begin, Node inner) { return true; }
|
||||
MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node name, FunctionNodeType funNode, JSOp op) { return true; }
|
||||
MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType memberList, Node key, FunctionNodeType funNode, JSOp op, bool isStatic) { return true; }
|
||||
MOZ_MUST_USE bool addClassFieldDefinition(ListNodeType memberList, Node name, FunctionNodeType initializer) { return true; }
|
||||
MOZ_MUST_USE Node newClassMethodDefinition(Node key, FunctionNodeType funNode, JSOp op, bool isStatic) { return NodeGeneric; }
|
||||
MOZ_MUST_USE Node newClassFieldDefinition(Node name, FunctionNodeType initializer) { return NodeGeneric; }
|
||||
MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member) { return true; }
|
||||
UnaryNodeType newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
UnaryNodeType newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@
|
|||
macro(dotGenerator, dotGenerator, ".generator") \
|
||||
macro(dotThis, dotThis, ".this") \
|
||||
macro(dotInitializers, dotInitializers, ".initializers") \
|
||||
macro(dotLocalInitializers, dotLocalInitializers, ".localInitializers") \
|
||||
macro(dotFieldKeys, dotFieldKeys, ".fieldKeys") \
|
||||
macro(each, each, "each") \
|
||||
macro(elementType, elementType, "elementType") \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue