Issue #2142 - Fix several scoping issues in field initializers

Based-on: m-c 1540789, 1547130, 1547467
This commit is contained in:
Martok 2023-04-09 19:54:45 +02:00 committed by roytam1
commit bcb6203e4f
11 changed files with 156 additions and 176 deletions

View file

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

View file

@ -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]

View file

@ -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

View file

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

View file

@ -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;
}

View file

@ -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

View file

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

View file

@ -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;
}
};

View file

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

View file

@ -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; }

View file

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