#430: refactor for loops from M1233249

This commit is contained in:
Cameron Kaiser 2017-08-19 21:16:16 -07:00
parent a62ee9ff96
commit b2141ff526
9 changed files with 950 additions and 607 deletions

View File

@ -609,6 +609,11 @@ class FullParseHandler
return pn;
}
ParseNode* newComprehensionBinding(ParseNode* kid) {
MOZ_ASSERT(kid->isKind(PNK_NAME));
return new_<ListNode>(PNK_LET, JSOP_NOP, kid);
}
ParseNode* newForHead(ParseNodeKind kind, ParseNode* pn1, ParseNode* pn2, ParseNode* pn3,
const TokenPos& pos)
{
@ -616,6 +621,14 @@ class FullParseHandler
return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos);
}
void initForLetBlock(ParseNode* forLetImpliedBlock, ParseNode* nestedForLoop) {
MOZ_ASSERT(forLetImpliedBlock->isKind(PNK_LEXICALSCOPE));
MOZ_ASSERT(nestedForLoop->isKind(PNK_FOR));
forLetImpliedBlock->pn_expr = nestedForLoop;
forLetImpliedBlock->pn_pos = nestedForLoop->pn_pos;
}
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
TokenPos pos(begin, caseList->pn_pos.end);
return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
@ -798,28 +811,60 @@ class FullParseHandler
return pn->pn_pos;
}
bool isDeclarationKind(ParseNodeKind kind) {
return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST;
}
ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return new_<ListNode>(kind, op, pos());
}
ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
}
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
MOZ_ASSERT(!isDeclarationKind(kind));
return new_<ListNode>(kind, op, pos());
}
/* New list with one initial child node. kid must be non-null. */
ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
MOZ_ASSERT(!isDeclarationKind(kind));
return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
}
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
MOZ_ASSERT(!isDeclarationKind(kind));
return new_<ListNode>(kind, op, kid);
}
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(isDeclarationKind(kind));
return new_<ListNode>(kind, op, pos());
}
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
MOZ_ASSERT(isDeclarationKind(kind));
return new_<ListNode>(kind, op, kid);
}
bool isDeclarationList(ParseNode* node) {
return isDeclarationKind(node->getKind());
}
bool declarationIsVar(ParseNode* node) {
MOZ_ASSERT(isDeclarationList(node));
return node->isKind(PNK_VAR);
}
bool declarationIsLet(ParseNode* node) {
MOZ_ASSERT(isDeclarationList(node));
return node->isKind(PNK_LET);
}
bool declarationIsConst(ParseNode* node) {
MOZ_ASSERT(isDeclarationList(node));
return node->isKind(PNK_CONST);
}
ParseNode* singleBindingFromDeclaration(ParseNode* decl) {
MOZ_ASSERT(isDeclarationList(decl));
MOZ_ASSERT(decl->pn_count == 1);
return decl->pn_head;
}
ParseNode* newCatchList() {
return new_<ListNode>(PNK_CATCHLIST, JSOP_NOP, pos());
}

View File

@ -775,10 +775,6 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode* opn)
return pn;
}
template <>
ParseNode*
Parser<FullParseHandler>::cloneLeftHandSide(ParseNode* opn);
/*
* Used by Parser::cloneLeftHandSide to clone a default expression
* in the form of
@ -891,6 +887,16 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode* opn)
return pn;
}
template <>
SyntaxParseHandler::Node
Parser<SyntaxParseHandler>::cloneLeftHandSide(Node node)
{
// See the comment in SyntaxParseHandler::singleBindingFromDeclaration for
// why this is okay.
MOZ_ASSERT(node == SyntaxParseHandler::NodeUnparenthesizedName);
return SyntaxParseHandler::NodeGeneric;
}
} /* namespace frontend */
} /* namespace js */

File diff suppressed because it is too large Load Diff

View File

@ -4,12 +4,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* JS parser. */
#ifndef frontend_Parser_h
#define frontend_Parser_h
/*
* JS parser definitions.
*/
#include "mozilla/Maybe.h"
#include "jspubtd.h"
@ -669,7 +669,21 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node ifStatement(YieldHandling yieldHandling);
Node doWhileStatement(YieldHandling yieldHandling);
Node whileStatement(YieldHandling yieldHandling);
Node forStatement(YieldHandling yieldHandling);
bool forHeadStart(YieldHandling yieldHandling,
ParseNodeKind* forHeadKind,
Node* forInitialPart,
mozilla::Maybe<AutoPushStmtInfoPC>& letStmt,
MutableHandle<StaticBlockObject*> blockObj,
Node* forLetImpliedBlock,
Node* forInOrOfExpression);
bool validateForInOrOfLHSExpression(Node target);
Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling);
void assertCurrentLexicalStaticBlockIs(ParseContext<ParseHandler>* pc,
Handle<StaticBlockObject*> blockObj);
Node switchStatement(YieldHandling yieldHandling);
Node continueStatement(YieldHandling yieldHandling);
Node breakStatement(YieldHandling yieldHandling);
@ -685,11 +699,59 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node exportDeclaration();
Node expressionStatement(YieldHandling yieldHandling,
InvokedPrediction invoked = PredictUninvoked);
Node variables(YieldHandling yieldHandling,
ParseNodeKind kind,
ForInitLocation location,
bool* psimple = nullptr, StaticBlockObject* blockObj = nullptr,
VarContext varContext = HoistVars);
// Declaration parsing. The main entrypoint is Parser::declarationList,
// with sub-functionality split out into the remaining methods.
// |blockObj| may be non-null only when |kind| corresponds to a lexical
// declaration (that is, PNK_LET or PNK_CONST).
//
// The for* parameters, for normal declarations, should be null/ignored.
// They should be non-null only when Parser::forHeadStart parses a
// declaration at the start of a for-loop head.
//
// In this case, on success |*forHeadKind| is PNK_FORHEAD, PNK_FORIN, or
// PNK_FOROF, corresponding to the three for-loop kinds. The precise value
// indicates what was parsed.
//
// If parsing recognized a for(;;) loop, the next token is the ';' within
// the loop-head that separates the init/test parts.
//
// Otherwise, for for-in/of loops, the next token is the ')' ending the
// loop-head. Additionally, the expression that the loop iterates over was
// parsed into |*forInOrOfExpression|.
Node declarationList(YieldHandling yieldHandling,
ParseNodeKind kind,
StaticBlockObject* blockObj = nullptr,
ParseNodeKind* forHeadKind = nullptr,
Node* forInOrOfExpression = nullptr);
// The items in a declaration list are either patterns or names, with or
// without initializers. These two methods parse a single pattern/name and
// any associated initializer -- and if parsing an |initialDeclaration|
// will, if parsing in a for-loop head (as specified by |forHeadKind| being
// non-null), consume additional tokens up to the closing ')' in a
// for-in/of loop head, returning the iterated expression in
// |*forInOrOfExpression|. (An "initial declaration" is the first
// declaration in a declaration list: |a| but not |b| in |var a, b|, |{c}|
// but not |d| in |let {c} = 3, d|.)
Node declarationPattern(Node decl, TokenKind tt, BindData<ParseHandler>* data,
bool initialDeclaration, YieldHandling yieldHandling,
ParseNodeKind* forHeadKind, Node* forInOrOfExpression);
Node declarationName(Node decl, TokenKind tt, BindData<ParseHandler>* data,
bool initialDeclaration, YieldHandling yieldHandling,
ParseNodeKind* forHeadKind, Node* forInOrOfExpression);
// Having parsed a name (not found in a destructuring pattern) declared by
// a declaration, with the current token being the '=' separating the name
// from its initializer, parse and bind that initializer -- and possibly
// consume trailing in/of and subsequent expression, if so directed by
// |forHeadKind|.
bool initializerInNameDeclaration(Node decl, Node binding, Handle<PropertyName*> name,
BindData<ParseHandler>* data, bool initialDeclaration,
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
Node* forInOrOfExpression);
Node expr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
InvokedPrediction invoked = PredictUninvoked);
@ -782,7 +844,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
CompoundAssignment,
KeyedDestructuringAssignment,
IncrementAssignment,
DecrementAssignment
DecrementAssignment,
ForInOrOfTarget
};
bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
@ -801,10 +864,6 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
bool finishFunctionDefinition(Node pn, FunctionBox* funbox, Node body);
bool addFreeVariablesFromLazyFunction(JSFunction* fun, ParseContext<ParseHandler>* pc);
bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
ParseNodeKind headKind);
bool checkForHeadConstInitializers(Node pn1);
// Use when the current token is TOK_NAME and is known to be 'let'.
bool shouldParseLetDeclaration(bool* parseDeclOut);
@ -876,8 +935,10 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
bool bindUninitialized(BindData<ParseHandler>* data, HandlePropertyName name, Node pn);
bool bindUninitialized(BindData<ParseHandler>* data, Node pn);
bool makeSetCall(Node node, unsigned errnum);
Node cloneDestructuringDefault(Node opn);
Node cloneForInOrOfDeclarationForAssignment(Node decl);
Node cloneLeftHandSide(Node opn);
Node cloneDestructuringDefault(Node opn);
Node cloneParseTree(Node opn);
Node newNumber(const Token& tok) {

View File

@ -42,11 +42,16 @@ class SyntaxParseHandler
NodeGetProp,
NodeStringExprStatement,
NodeReturn,
NodeHoistableDeclaration,
NodeBreak,
NodeThrow,
NodeEmptyStatement,
NodeVarDeclaration,
NodeLetDeclaration,
NodeConstDeclaration,
NodeFunctionDefinition,
// This is needed for proper assignment-target handling. ES6 formally
// requires function calls *not* pass IsValidSimpleAssignmentTarget,
// but at last check there were still sites with |f() = 5| and similar
@ -348,10 +353,10 @@ class SyntaxParseHandler
bool setLastFunctionArgumentDefault(Node funcpn, Node pn) { return true; }
void setLastFunctionArgumentDestructuring(Node funcpn, Node pn) {}
Node newFunctionDefinition() { return NodeHoistableDeclaration; }
Node newFunctionDefinition() { return NodeFunctionDefinition; }
void setFunctionBody(Node pn, Node kid) {}
void setFunctionBox(Node pn, FunctionBox* funbox) {}
Node newFunctionDefinitionForAnnexB(Node pn, Node assignment) { return NodeHoistableDeclaration; }
Node newFunctionDefinitionForAnnexB(Node pn, Node assignment) { return NodeFunctionDefinition; }
void addFunctionArgument(Node pn, Node argpn) {}
Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) {
@ -362,10 +367,23 @@ class SyntaxParseHandler
return NodeGeneric;
}
Node newComprehensionBinding(Node kid) {
// Careful: we're asking this well after the name was parsed, so the
// value returned may not correspond to |kid|'s actual name. But it
// *will* be truthy iff |kid| was a name, so we're safe.
MOZ_ASSERT(maybeUnparenthesizedName(kid));
return NodeGeneric;
}
Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos& pos) {
return NodeGeneric;
}
void initForLetBlock(Node forLetImpliedBlock, Node nestedForLoop) {
MOZ_ASSERT(forLetImpliedBlock == NodeGeneric); // per newForStatement
MOZ_ASSERT(nestedForLoop == NodeGeneric); // per newLexicalScope
}
Node newLexicalScope(ObjectBox* blockbox) { return NodeGeneric; }
void setLexicalScopeBody(Node block, Node body) {}
@ -391,22 +409,68 @@ class SyntaxParseHandler
Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
MOZ_ASSERT(kind != PNK_LET);
MOZ_ASSERT(kind != PNK_CONST);
return NodeGeneric;
}
Node newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
return newList(kind, op);
}
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return NodeGeneric;
return newList(kind, op);
}
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
if (kind == PNK_VAR)
return NodeVarDeclaration;
if (kind == PNK_LET)
return NodeLetDeclaration;
MOZ_ASSERT(kind == PNK_CONST);
return NodeConstDeclaration;
}
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
return newDeclarationList(kind, op);
}
bool isDeclarationList(Node node) {
return node == NodeVarDeclaration ||
node == NodeLetDeclaration ||
node == NodeConstDeclaration;
}
bool declarationIsVar(Node node) {
MOZ_ASSERT(isDeclarationList(node));
return node == NodeVarDeclaration;
}
bool declarationIsLet(Node node) {
MOZ_ASSERT(isDeclarationList(node));
return node == NodeLetDeclaration;
}
bool declarationIsConst(Node node) {
MOZ_ASSERT(isDeclarationList(node));
return node == NodeConstDeclaration;
}
Node singleBindingFromDeclaration(Node decl) {
MOZ_ASSERT(isDeclarationList(decl));
// This is, unfortunately, very dodgy. Obviously NodeVarDeclaration
// can store no info on the arbitrary number of bindings it could
// contain.
//
// But this method is called only for cloning for-in/of declarations
// as initialization targets. That context simplifies matters. If the
// binding is a single name, it'll always syntax-parse (or it would
// already have been rejected as assigning/binding a forbidden name).
// Otherwise the binding is a destructuring pattern. But syntax
// parsing would *already* have aborted when it saw a destructuring
// pattern. So we can just say any old thing here, because the only
// time we'll be wrong is a case that syntax parsing has already
// rejected. Use NodeUnparenthesizedName so the SyntaxParseHandler
// Parser::cloneLeftHandSide can assert it sees only this.
return NodeUnparenthesizedName;
}
Node newCatchList() {
@ -422,7 +486,9 @@ class SyntaxParseHandler
list == NodeUnparenthesizedArray ||
list == NodeUnparenthesizedObject ||
list == NodeUnparenthesizedCommaExpr ||
list == NodeHoistableDeclaration ||
list == NodeVarDeclaration ||
list == NodeLetDeclaration ||
list == NodeConstDeclaration ||
list == NodeFunctionCall);
}
@ -455,7 +521,9 @@ class SyntaxParseHandler
}
bool isStatementPermittedAfterReturnStatement(Node pn) {
return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow ||
return pn == NodeFunctionDefinition || pn == NodeVarDeclaration ||
pn == NodeBreak ||
pn == NodeThrow ||
pn == NodeEmptyStatement;
}

View File

@ -16,14 +16,95 @@ eval(`[...let] = [];`);
eval(`function let() { return 42; } assertEq(let(), 42);`)
eval(`let {x:x} = {x:42}; assertEq(x, 42);`);
eval(`let [x] = [42]; assertEq(x, 42);`);
eval(`for (let x in [1]) { assertEq(x, "0"); }`);
expectError(`for (const x in [1]) { assertEq(x, "0"); }`); // XXX bug 449811
eval(`for (let x of [1]) { assertEq(x, 1); }`);
expectError(`for (const x of [1]) { assertEq(x, 1); }`); // XXX bug 449811
eval(`for (let i = 0; i < 1; i++) { assertEq(i, 0); }`);
eval(`for (let in [1]) { assertEq(let, "0"); }`);
eval(`var done = false; for (const i = 0; !done; done = true) { assertEq(i, 0); }`);
eval(`for (let of of [1]) { assertEq(of, 1); }`);
eval(`for (let/1;;) { break; }`);
expectError(`for (const of of [1]) { assertEq(of, 1); }`); // XXX bug 449811
eval(`try { throw 17; } catch (let) { assertEq(let, 17); }`);
eval(`try { throw [17]; } catch ([let]) { assertEq(let, 17); }`);
eval(`try { throw { x: 17 }; } catch ({ x: let }) { assertEq(let, 17); }`);
eval(`try { throw {}; } catch ({ x: let = 17 }) { assertEq(let, 17); }`);
expectError(`try { throw [17, 42]; } catch ([let, let]) {}`);
eval(`for (let in [1]) { assertEq(let, "0"); }`);
eval(`for (let / 1; ; ) { break; }`);
expectError(`let = {}; for (let.x of;;);`);
expectError(`for (let of [1]) { }`);
expectError(`let let = 42;`);
expectError(`for (let let in [1]) { }`);
expectError(`for (const let in [1]) { }`);
expectError(`for (let let of [1]) { }`);
expectError(`for (const let of [1]) { }`);
expectError(`for (let let = 17; false; ) { }`);
expectError(`for (const let = 17; false; ) { }`);
expectError(`for (let [let] = 17; false; ) { }`);
expectError(`for (const [let] = 17; false; ) { }`);
expectError(`for (let [let = 42] = 17; false; ) { }`);
expectError(`for (const [let = 42] = 17; false; ) { }`);
expectError(`for (let { x: let } = 17; false; ) { }`);
expectError(`for (const { x: let } = 17; false; ) { }`);
expectError(`for (let { x: let = 42 } = 17; false; ) { }`);
expectError(`for (const { x: let = 42 } = 17; false; ) { }`);
expectError("let\nlet;");
expectError("const\nlet;");
expectError(`let let = 17;`);
expectError(`const let = 17;`);
expectError(`let [let] = 17;`);
expectError(`const [let] = 17;`);
expectError(`let [let = 42] = 17;`);
expectError(`const [let = 42] = 17;`);
expectError(`let {let} = 17;`);
expectError(`const {let} = 17;`);
expectError(`let { let = 42 } = 17;`);
expectError(`const { let = 42 } = 17;`);
expectError(`let { x: let } = 17;`);
expectError(`const { x: let } = 17;`);
expectError(`let { x: let = 42 } = 17;`);
expectError(`const { x: let = 42 } = 17;`);
expectError(`let { ['y']: let } = 17;`);
expectError(`const { ['y']: let } = 17;`);
expectError(`let { ['y']: let = 42 } = 17;`);
expectError(`const { ['y']: let = 42 } = 17;`);
expectError(`let { x: [let] } = { x: 17 };`);
expectError(`const { x: [let] } = { x: 17 };`);
expectError(`let { x: [let = 42] } = { x: 17 };`);
expectError(`const { x: [let = 42] } = { x: 17 };`);
expectError(`let [foo, let] = 42;`);
expectError(`const [foo, let] = 42;`);
expectError(`let [foo, { let }] = [17, {}];`);
expectError(`const [foo, { let }] = [17, {}];`);
expectError(`"use strict"; var let = 42;`);
expectError(`"use strict"; function let() {}`);
expectError(`"use strict"; for (let of [1]) {}`);
expectError(`"use strict"; try {} catch (let) {}`);

View File

@ -199,8 +199,10 @@ MSG_DEF(JSMSG_BAD_DESTRUCT_PARENS, 0, JSEXN_SYNTAXERR, "destructuring patter
MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context")
MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop")
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side")
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
MSG_DEF(JSMSG_BAD_YIELD_SYNTAX, 0, JSEXN_SYNTAXERR, "yield expression must be parenthesized")
MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 0, JSEXN_SYNTAXERR, "generator expression must be parenthesized")
MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
@ -265,7 +267,7 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage a
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character")
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
MSG_DEF(JSMSG_INVALID_FOR_INOF_DECL_WITH_INIT,1,JSEXN_SYNTAXERR,"for-{0} loop head declarations may not have initializers")
MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class")
@ -312,7 +314,7 @@ MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 0, JSEXN_SYNTAXERR, "missing ( before wit
MSG_DEF(JSMSG_PAREN_IN_PAREN, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch")
MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_SYNTAXERR, "redeclaration of identifier '{0}' in catch")
MSG_DEF(JSMSG_REDECLARED_PARAM, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
MSG_DEF(JSMSG_RESERVED_ID, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
MSG_DEF(JSMSG_REST_WITH_DEFAULT, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")

View File

@ -20,7 +20,7 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);
expect = 'SyntaxError: invalid for/in left-hand side';
expect = 'SyntaxError: invalid for-in/of left-hand side';
actual = '';
try
{

View File

@ -29,11 +29,11 @@ namespace js {
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 336;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 337;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 434,
static_assert(JSErr_Limit == 436,
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
"removed MSG_DEFs from js.msg, you should increment "
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "