Bug 1526031 - remove initOrStmt field from NameNode. r=jorendorff,arai

Differential Revision: https://phabricator.services.mozilla.com/D19054

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ashley Hauck 2019-02-28 01:29:19 +00:00
Родитель 7a132cc405
Коммит 83ff13eec8
13 изменённых файлов: 186 добавлений и 130 удалений

Просмотреть файл

@ -1939,8 +1939,7 @@ bool ASTSerializer::variableDeclarator(ParseNode* pn, MutableHandleValue dst) {
if (pn->isKind(ParseNodeKind::Name)) {
patternNode = pn;
initNode = pn->as<NameNode>().initializer();
MOZ_ASSERT_IF(initNode, pn->pn_pos.encloses(initNode->pn_pos));
initNode = nullptr;
} else if (pn->isKind(ParseNodeKind::AssignExpr)) {
AssignmentNode* assignNode = &pn->as<AssignmentNode>();
patternNode = assignNode->left();

Просмотреть файл

@ -2629,7 +2629,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerGetter(
ListNode* body;
MOZ_TRY(parseGetterContents(length, &params, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(method,
buildFunction(start, kind, name, params, bodyScope));
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
name, method, accessorType));
return result;
@ -2691,7 +2695,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerMethod(
ListNode* body;
MOZ_TRY(parseFunctionOrMethodContents(length, &params, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(method,
buildFunction(start, kind, name, params, bodyScope));
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
name, method, accessorType));
return result;
@ -2746,7 +2754,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerSetter(
ListNode* body;
MOZ_TRY(parseSetterContents(length, &params, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(method,
buildFunction(start, kind, name, params, bodyScope));
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
name, method, accessorType));
return result;
@ -4244,9 +4256,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceVariableDeclarator(
// `var foo [= bar]``
NameNode* bindingNameNode = &binding->template as<NameNode>();
MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
result = bindingNameNode;
if (init) {
BINJS_TRY(handler_.finishInitializerAssignment(bindingNameNode, init));
BINJS_TRY_VAR(
result, handler_.finishInitializerAssignment(bindingNameNode, init));
} else {
result = bindingNameNode;
}
} else {
// `var pattern = bar`

Просмотреть файл

@ -1006,8 +1006,12 @@ EagerMethod:
const auto accessorType = AccessorType::None;
inherits: EagerFunctionExpression
build: |
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope,
handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(method,
buildFunction(start, kind, name, params, body));
buildFunction(start, kind, name, params, bodyScope));
BINJS_TRY_DECL(result,
handler_.newObjectMethodOrPropertyDefinition(name, method,
accessorType));
@ -1603,9 +1607,11 @@ VariableDeclarator:
// `var foo [= bar]``
NameNode* bindingNameNode = &binding->template as<NameNode>();
MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
result = bindingNameNode;
if (init) {
BINJS_TRY(handler_.finishInitializerAssignment(bindingNameNode, init));
BINJS_TRY_VAR(result,
handler_.finishInitializerAssignment(bindingNameNode, init));
} else {
result = bindingNameNode;
}
} else {
// `var pattern = bar`

Просмотреть файл

@ -4039,36 +4039,49 @@ bool BytecodeEmitter::emitDeclarationList(ListNode* declList) {
MOZ_ASSERT(declList->isOp(JSOP_NOP));
for (ParseNode* decl : declList->contents()) {
if (decl->isKind(ParseNodeKind::AssignExpr)) {
ParseNode* pattern;
ParseNode* initializer;
if (decl->isKind(ParseNodeKind::Name)) {
pattern = decl;
initializer = nullptr;
} else {
MOZ_ASSERT(decl->isOp(JSOP_NOP));
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
ListNode* pattern = &assignNode->left()->as<ListNode>();
pattern = assignNode->left();
initializer = assignNode->right();
}
if (pattern->isKind(ParseNodeKind::Name)) {
// initializer can be null here.
if (!emitSingleDeclaration(declList, &pattern->as<NameNode>(),
initializer)) {
return false;
}
} else {
MOZ_ASSERT(decl->isOp(JSOP_NOP));
MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr) ||
pattern->isKind(ParseNodeKind::ObjectExpr));
MOZ_ASSERT(initializer != nullptr);
if (!updateSourceCoordNotes(assignNode->right()->pn_pos.begin)) {
if (!updateSourceCoordNotes(initializer->pn_pos.begin)) {
return false;
}
if (!markStepBreakpoint()) {
return false;
}
if (!emitTree(assignNode->right())) {
if (!emitTree(initializer)) {
return false;
}
if (!emitDestructuringOps(pattern, DestructuringDeclaration)) {
if (!emitDestructuringOps(&pattern->as<ListNode>(),
DestructuringDeclaration)) {
return false;
}
if (!emit1(JSOP_POP)) {
return false;
}
} else {
NameNode* name = &decl->as<NameNode>();
if (!emitSingleDeclaration(declList, name, name->initializer())) {
return false;
}
}
}
return true;
@ -5320,8 +5333,17 @@ bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead) {
target = parser->astGenerator().singleBindingFromDeclaration(
&target->as<ListNode>());
NameNode* nameNode = nullptr;
if (target->isKind(ParseNodeKind::Name)) {
NameNode* nameNode = &target->as<NameNode>();
nameNode = &target->as<NameNode>();
} else if (target->isKind(ParseNodeKind::AssignExpr)) {
AssignmentNode* assignNode = &target->as<AssignmentNode>();
if (assignNode->left()->is<NameNode>()) {
nameNode = &assignNode->left()->as<NameNode>();
}
}
if (nameNode) {
NameOpEmitter noe(this, nameNode->name(), NameOpEmitter::Kind::Initialize);
if (!noe.prepareForRhs()) {
return false;
@ -5454,8 +5476,11 @@ bool BytecodeEmitter::emitForIn(ForNode* forInLoop,
if (parser->astGenerator().isDeclarationList(forInTarget)) {
ParseNode* decl = parser->astGenerator().singleBindingFromDeclaration(
&forInTarget->as<ListNode>());
if (decl->isKind(ParseNodeKind::Name)) {
if (ParseNode* initializer = decl->as<NameNode>().initializer()) {
if (decl->isKind(ParseNodeKind::AssignExpr)) {
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
if (assignNode->left()->is<NameNode>()) {
NameNode* nameNode = &assignNode->left()->as<NameNode>();
ParseNode* initializer = assignNode->right();
MOZ_ASSERT(
forInTarget->isKind(ParseNodeKind::VarStmt),
"for-in initializers are only permitted for |var| declarations");
@ -5464,13 +5489,12 @@ bool BytecodeEmitter::emitForIn(ForNode* forInLoop,
return false;
}
NameNode* nameNode = &decl->as<NameNode>();
NameOpEmitter noe(this, nameNode->name(),
NameOpEmitter::Kind::Initialize);
if (!noe.prepareForRhs()) {
return false;
}
if (!emitInitializer(initializer, decl)) {
if (!emitInitializer(initializer, nameNode)) {
return false;
}
if (!noe.emitAssignment()) {

Просмотреть файл

@ -879,8 +879,15 @@ class FullParseHandler {
node->isKind(ParseNodeKind::ComputedName);
}
inline MOZ_MUST_USE bool finishInitializerAssignment(NameNodeType nameNode,
Node init);
AssignmentNodeType finishInitializerAssignment(NameNodeType nameNode,
Node init) {
MOZ_ASSERT(nameNode->isKind(ParseNodeKind::Name));
MOZ_ASSERT(!nameNode->isInParens());
checkAndSetIsDirectRHSAnonFunction(init);
return newAssignment(ParseNodeKind::AssignExpr, nameNode, init);
}
void setBeginPosition(Node pn, Node oth) {
setBeginPosition(pn, oth->pn_pos.begin);
@ -1027,21 +1034,6 @@ inline bool FullParseHandler::setLastFunctionFormalParameterDefault(
return true;
}
inline bool FullParseHandler::finishInitializerAssignment(NameNodeType nameNode,
Node init) {
MOZ_ASSERT(nameNode->isKind(ParseNodeKind::Name));
MOZ_ASSERT(!nameNode->isInParens());
checkAndSetIsDirectRHSAnonFunction(init);
nameNode->setInitializer(init);
nameNode->setOp(JSOP_SETNAME);
/* The declarator's position must include the initializer. */
nameNode->pn_pos.end = init->pn_pos.end;
return true;
}
} // namespace frontend
} // namespace js

Просмотреть файл

@ -419,9 +419,7 @@ class NameResolver : public ParseNodeVisitor<NameResolver> {
MOZ_ASSERT(spec->isKind(isImport ? ParseNodeKind::ImportSpec
: ParseNodeKind::ExportSpec));
MOZ_ASSERT(spec->left()->isKind(ParseNodeKind::Name));
MOZ_ASSERT(!spec->left()->as<NameNode>().initializer());
MOZ_ASSERT(spec->right()->isKind(ParseNodeKind::Name));
MOZ_ASSERT(!spec->right()->as<NameNode>().initializer());
}
}
#endif

Просмотреть файл

@ -311,12 +311,8 @@ void NameNode::dumpImpl(GenericPrinter& out, int indent) {
out.put("#<null name>");
} else if (getOp() == JSOP_GETARG && atom()->length() == 0) {
// Dump destructuring parameter.
static const char ZeroLengthPrefix[] = "(#<zero-length name> ";
constexpr size_t ZeroLengthPrefixLength =
ArrayLength(ZeroLengthPrefix) - 1;
out.put(ZeroLengthPrefix);
DumpParseTree(initializer(), out, indent + ZeroLengthPrefixLength);
out.printf(")");
static const char ZeroLengthName[] = "(#<zero-length name>)";
out.put(ZeroLengthName);
} else {
JS::AutoCheckCannotGC nogc;
if (atom()->hasLatin1Chars()) {
@ -328,26 +324,28 @@ void NameNode::dumpImpl(GenericPrinter& out, int indent) {
return;
case ParseNodeKind::LabelStmt: {
const char* name = parseNodeNames[size_t(getKind())];
out.printf("(%s ", name);
atom()->dumpCharsNoNewline(out);
indent += strlen(name) + atom()->length() + 2;
DumpParseTree(initializer(), out, indent);
out.printf(")");
this->as<LabeledStatement>().dump(out, indent);
return;
}
default: {
const char* name = parseNodeNames[size_t(getKind())];
out.printf("(%s ", name);
indent += strlen(name) + 2;
DumpParseTree(initializer(), out, indent);
out.printf(")");
out.printf("(%s)", name);
return;
}
}
}
void LabeledStatement::dump(GenericPrinter& out, int indent) {
const char* name = parseNodeNames[size_t(getKind())];
out.printf("(%s ", name);
atom()->dumpCharsNoNewline(out);
out.printf(" ");
indent += strlen(name) + atom()->length() + 3;
DumpParseTree(statement(), out, indent);
out.printf(")");
}
void LexicalScopeNode::dumpImpl(GenericPrinter& out, int indent) {
const char* name = parseNodeNames[size_t(getKind())];
out.printf("(%s [", name);

Просмотреть файл

@ -796,20 +796,11 @@ class NullaryNode : public ParseNode {
};
class NameNode : public ParseNode {
JSAtom* atom_; /* lexical name or label atom */
ParseNode* initOrStmt; /* var initializer, argument default, or label
statement target */
protected:
NameNode(ParseNodeKind kind, JSOp op, JSAtom* atom, ParseNode* initOrStmt,
const TokenPos& pos)
: ParseNode(kind, op, pos), atom_(atom), initOrStmt(initOrStmt) {
MOZ_ASSERT(is<NameNode>());
}
JSAtom* atom_; /* lexical name or label atom */
public:
NameNode(ParseNodeKind kind, JSOp op, JSAtom* atom, const TokenPos& pos)
: ParseNode(kind, op, pos), atom_(atom), initOrStmt(nullptr) {
: ParseNode(kind, op, pos), atom_(atom) {
MOZ_ASSERT(is<NameNode>());
}
@ -821,11 +812,6 @@ class NameNode : public ParseNode {
template <typename Visitor>
bool accept(Visitor& visitor) {
if (initOrStmt) {
if (!visitor.visit(initOrStmt)) {
return false;
}
}
return true;
}
@ -840,11 +826,7 @@ class NameNode : public ParseNode {
return atom()->asPropertyName();
}
ParseNode* initializer() const { return initOrStmt; }
void setAtom(JSAtom* atom) { atom_ = atom; }
void setInitializer(ParseNode* init) { initOrStmt = init; }
};
inline bool ParseNode::isName(PropertyName* name) const {
@ -1596,14 +1578,17 @@ class LexicalScopeNode : public ParseNode {
};
class LabeledStatement : public NameNode {
ParseNode* statement_;
public:
LabeledStatement(PropertyName* label, ParseNode* stmt, uint32_t begin)
: NameNode(ParseNodeKind::LabelStmt, JSOP_NOP, label, stmt,
TokenPos(begin, stmt->pn_pos.end)) {}
: NameNode(ParseNodeKind::LabelStmt, JSOP_NOP, label,
TokenPos(begin, stmt->pn_pos.end)),
statement_(stmt) {}
PropertyName* label() const { return atom()->asPropertyName(); }
ParseNode* statement() const { return initializer(); }
ParseNode* statement() const { return statement_; }
static bool test(const ParseNode& node) {
return node.isKind(ParseNodeKind::LabelStmt);
@ -1631,6 +1616,20 @@ class CaseClause : public BinaryNode {
MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
return match;
}
template <typename Visitor>
bool accept(Visitor& visitor) {
if (statement_) {
if (!visitor.visit(statement_)) {
return false;
}
}
return true;
}
#ifdef DEBUG
void dump(GenericPrinter& out, int indent);
#endif
};
class LoopControlStatement : public ParseNode {

Просмотреть файл

@ -4090,7 +4090,8 @@ GeneralParser<ParseHandler, Unit>::declarationPattern(
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
NameNodeType binding, DeclarationKind declKind, bool initialDeclaration,
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
Node* forInOrOfExpression) {
@ -4098,19 +4099,19 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
uint32_t initializerOffset;
if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) {
return false;
return null();
}
Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
if (!initializer) {
return false;
return null();
}
if (forHeadKind && initialDeclaration) {
bool isForIn, isForOf;
if (!matchInOrOf(&isForIn, &isForOf)) {
return false;
return null();
}
// An initialized declaration can't appear in a for-of:
@ -4118,7 +4119,7 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
// for (var/let/const x = ... of ...); // BAD
if (isForOf) {
errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL);
return false;
return null();
}
if (isForIn) {
@ -4127,7 +4128,7 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
// for (let/const x = ... in ...); // BAD
if (DeclarationKindIsLexical(declKind)) {
errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL);
return false;
return null();
}
// This leaves only initialized for-in |var| declarations. ES6
@ -4135,13 +4136,13 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
*forHeadKind = ParseNodeKind::ForIn;
if (!strictModeErrorAt(initializerOffset,
JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) {
return false;
return null();
}
*forInOrOfExpression =
expressionAfterForInOrOf(ParseNodeKind::ForIn, yieldHandling);
if (!*forInOrOfExpression) {
return false;
return null();
}
} else {
*forHeadKind = ParseNodeKind::ForHead;
@ -4152,13 +4153,10 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
}
template <class ParseHandler, typename Unit>
typename ParseHandler::NameNodeType
GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
TokenKind tt,
bool initialDeclaration,
YieldHandling yieldHandling,
ParseNodeKind* forHeadKind,
Node* forInOrOfExpression) {
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::declarationName(
DeclarationKind declKind, TokenKind tt, bool initialDeclaration,
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
Node* forInOrOfExpression) {
// Anything other than possible identifier is an error.
if (!TokenKindIsPossibleIdentifier(tt)) {
error(JSMSG_NO_VARIABLE_NAME);
@ -4190,13 +4188,17 @@ GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
return null();
}
Node declaration;
if (matched) {
if (!initializerInNameDeclaration(binding, declKind, initialDeclaration,
yieldHandling, forHeadKind,
forInOrOfExpression)) {
declaration = initializerInNameDeclaration(
binding, declKind, initialDeclaration, yieldHandling, forHeadKind,
forInOrOfExpression);
if (!declaration) {
return null();
}
} else {
declaration = binding;
if (initialDeclaration && forHeadKind) {
bool isForIn, isForOf;
if (!matchInOrOf(&isForIn, &isForOf)) {
@ -4234,7 +4236,7 @@ GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
return null();
}
return binding;
return declaration;
}
template <class ParseHandler, typename Unit>

Просмотреть файл

@ -1200,18 +1200,16 @@ class MOZ_STACK_CLASS GeneralParser : public PerHandlerParser<ParseHandler> {
bool initialDeclaration, YieldHandling yieldHandling,
ParseNodeKind* forHeadKind,
Node* forInOrOfExpression);
NameNodeType declarationName(DeclarationKind declKind, TokenKind tt,
bool initialDeclaration,
YieldHandling yieldHandling,
ParseNodeKind* forHeadKind,
Node* forInOrOfExpression);
Node declarationName(DeclarationKind declKind, TokenKind tt,
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(NameNodeType binding,
Node initializerInNameDeclaration(NameNodeType binding,
DeclarationKind declKind,
bool initialDeclaration,
YieldHandling yieldHandling,

Просмотреть файл

@ -517,9 +517,9 @@ class SyntaxParseHandler {
return NodeGeneric;
}
MOZ_MUST_USE bool finishInitializerAssignment(NameNodeType nameNode,
Node init) {
return true;
AssignmentNodeType finishInitializerAssignment(NameNodeType nameNode,
Node init) {
return NodeUnparenthesizedAssignment;
}
void setBeginPosition(Node pn, Node oth) {}

Просмотреть файл

@ -0,0 +1,14 @@
var BUGNUMBER = 1499448;
var summary = "Constant folder should fold labeled statements";
print(BUGNUMBER + ": " + summary);
if (typeof disassemble === "function") {
var code = disassemble(() => { x: 2+2; });
if (typeof reportCompare === "function")
reportCompare(true, /int8 4/.test(code));
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -609,10 +609,6 @@ static inline ParseNode* ObjectNormalFieldInitializer(ParseNode* pn) {
return BinaryRight(pn);
}
static inline ParseNode* MaybeInitializer(ParseNode* pn) {
return pn->as<NameNode>().initializer();
}
static inline bool IsUseOfName(ParseNode* pn, PropertyName* name) {
return pn->isName(name);
}
@ -3040,8 +3036,15 @@ static bool CheckGlobalDotImport(ModuleValidatorShared& m,
return m.addFFI(varName, field);
}
static bool CheckModuleGlobal(ModuleValidatorShared& m, ParseNode* var,
static bool CheckModuleGlobal(ModuleValidatorShared& m, ParseNode* decl,
bool isConst) {
if (!decl->isKind(ParseNodeKind::AssignExpr)) {
return m.fail(decl, "module import needs initializer");
}
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
ParseNode* var = assignNode->left();
if (!var->isKind(ParseNodeKind::Name)) {
return m.fail(var, "import variable is not a plain name");
}
@ -3051,10 +3054,7 @@ static bool CheckModuleGlobal(ModuleValidatorShared& m, ParseNode* var,
return false;
}
ParseNode* initNode = MaybeInitializer(var);
if (!initNode) {
return m.fail(var, "module import needs initializer");
}
ParseNode* initNode = assignNode->right();
if (IsNumericLiteral(m, initNode)) {
return CheckGlobalVariableInitConstant(m, varName, initNode, isConst);
@ -3254,8 +3254,17 @@ static bool CheckFinalReturn(FunctionValidatorShared& f,
return true;
}
static bool CheckVariable(FunctionValidatorShared& f, ParseNode* var,
static bool CheckVariable(FunctionValidatorShared& f, ParseNode* decl,
ValTypeVector* types, Vector<NumLit>* inits) {
if (!decl->isKind(ParseNodeKind::AssignExpr)) {
return f.failName(
decl, "var '%s' needs explicit type declaration via an initial value",
decl->as<NameNode>().name());
}
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
ParseNode* var = assignNode->left();
if (!var->isKind(ParseNodeKind::Name)) {
return f.fail(var, "local variable is not a plain name");
}
@ -3266,12 +3275,7 @@ static bool CheckVariable(FunctionValidatorShared& f, ParseNode* var,
return false;
}
ParseNode* initNode = MaybeInitializer(var);
if (!initNode) {
return f.failName(
var, "var '%s' needs explicit type declaration via an initial value",
name);
}
ParseNode* initNode = assignNode->right();
NumLit lit;
if (!IsLiteralOrConst(f, initNode, &lit)) {
@ -6154,13 +6158,21 @@ static bool CheckFunctions(ModuleValidator<Unit>& m) {
}
template <typename Unit>
static bool CheckFuncPtrTable(ModuleValidator<Unit>& m, ParseNode* var) {
static bool CheckFuncPtrTable(ModuleValidator<Unit>& m, ParseNode* decl) {
if (!decl->isKind(ParseNodeKind::AssignExpr)) {
return m.fail(decl, "function-pointer table must have initializer");
}
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
ParseNode* var = assignNode->left();
if (!var->isKind(ParseNodeKind::Name)) {
return m.fail(var, "function-pointer table name is not a plain name");
}
ParseNode* arrayLiteral = MaybeInitializer(var);
if (!arrayLiteral || !arrayLiteral->isKind(ParseNodeKind::ArrayExpr)) {
ParseNode* arrayLiteral = assignNode->right();
if (!arrayLiteral->isKind(ParseNodeKind::ArrayExpr)) {
return m.fail(
var, "function-pointer table's initializer must be an array literal");
}