diff --git a/toolchain/parse/context.cpp b/toolchain/parse/context.cpp index 82b2656dc9fac..dbcd5c6b14338 100644 --- a/toolchain/parse/context.cpp +++ b/toolchain/parse/context.cpp @@ -39,13 +39,14 @@ Context::Context(Tree& tree, Lex::TokenizedBuffer& tokens, auto Context::ReplacePlaceholderNode(int32_t position, NodeKind kind, Lex::TokenIndex token, bool has_error) -> void { + CARBON_CHECK( + kind != NodeKind::InvalidParse && kind != NodeKind::InvalidParseSubtree, + "{0} shouldn't occur in Placeholder use-cases", kind); CARBON_CHECK(position >= 0 && position < tree_->size(), "position: {0} size: {1}", position, tree_->size()); auto* node_impl = &tree_->node_impls_[position]; CARBON_CHECK(node_impl->kind == NodeKind::Placeholder); - node_impl->kind = kind; - node_impl->has_error = has_error; - node_impl->token = token; + *node_impl = {.kind = kind, .has_error = has_error, .token = token}; } auto Context::ConsumeAndAddOpenParen(Lex::TokenIndex default_token, diff --git a/toolchain/parse/context.h b/toolchain/parse/context.h index ec594adfcd50f..edd9a071fe878 100644 --- a/toolchain/parse/context.h +++ b/toolchain/parse/context.h @@ -98,12 +98,22 @@ class Context { // Adds a node to the parse tree that has no children (a leaf). auto AddLeafNode(NodeKind kind, Lex::TokenIndex token, bool has_error = false) -> void { - tree_->node_impls_.push_back(Tree::NodeImpl(kind, has_error, token)); + AddNode(kind, token, has_error); } // Adds a node to the parse tree that has children. auto AddNode(NodeKind kind, Lex::TokenIndex token, bool has_error) -> void { - tree_->node_impls_.push_back(Tree::NodeImpl(kind, has_error, token)); + CARBON_CHECK(has_error || (kind != NodeKind::InvalidParse && + kind != NodeKind::InvalidParseStart && + kind != NodeKind::InvalidParseSubtree), + "{0} nodes must always have an error", kind); + tree_->node_impls_.push_back( + {.kind = kind, .has_error = has_error, .token = token}); + } + + // Adds an invalid parse node. + auto AddInvalidParse(Lex::TokenIndex token) -> void { + AddNode(NodeKind::InvalidParse, token, /*has_error=*/true); } // Replaces the placeholder node at the indicated position with a leaf node. diff --git a/toolchain/parse/handle_binding_pattern.cpp b/toolchain/parse/handle_binding_pattern.cpp index 79556418e5482..77d08143e8ad7 100644 --- a/toolchain/parse/handle_binding_pattern.cpp +++ b/toolchain/parse/handle_binding_pattern.cpp @@ -67,9 +67,8 @@ auto HandleBindingPattern(Context& context) -> void { context.PushStateForExpr(PrecedenceGroup::ForType()); } else { on_error(/*expected_name=*/false); - // Add a placeholder for the type. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + // Add a substitute for a type node. + context.AddInvalidParse(*context.position()); context.PushState(state, State::BindingPatternFinishAsRegular); } } diff --git a/toolchain/parse/handle_decl_name_and_params.cpp b/toolchain/parse/handle_decl_name_and_params.cpp index 24cba5d5c592a..99f68823dd69f 100644 --- a/toolchain/parse/handle_decl_name_and_params.cpp +++ b/toolchain/parse/handle_decl_name_and_params.cpp @@ -30,8 +30,7 @@ auto HandleDeclNameAndParams(Context& context) -> void { context.tokens().GetKind(state.token)); } context.ReturnErrorOnState(); - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + context.AddInvalidParse(*context.position()); return; } diff --git a/toolchain/parse/handle_expr.cpp b/toolchain/parse/handle_expr.cpp index 8e22b126caf34..bf50ffc05c7d3 100644 --- a/toolchain/parse/handle_expr.cpp +++ b/toolchain/parse/handle_expr.cpp @@ -190,11 +190,9 @@ auto HandleExprInPostfix(Context& context) -> void { context.AddLeafNode(NodeKind::IdentifierName, context.Consume(), /*has_error=*/true); } else if (context.PositionIs(Lex::TokenKind::IntLiteral)) { - context.AddLeafNode(NodeKind::InvalidParse, context.Consume(), - /*has_error=*/true); + context.AddInvalidParse(context.Consume()); } else { - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + context.AddInvalidParse(*context.position()); // Indicate the error to the parent state so that it can avoid // producing more errors. We only do this on this path where we don't // consume the token after the period, where we expect further errors @@ -215,8 +213,7 @@ auto HandleExprInPostfix(Context& context) -> void { } // Add a node to keep the parse tree balanced. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + context.AddInvalidParse(*context.position()); context.ReturnErrorOnState(); break; } diff --git a/toolchain/parse/handle_if_expr.cpp b/toolchain/parse/handle_if_expr.cpp index 577c2f54251a2..0b4497bd8b26d 100644 --- a/toolchain/parse/handle_if_expr.cpp +++ b/toolchain/parse/handle_if_expr.cpp @@ -24,11 +24,9 @@ auto HandleIfExprFinishCondition(Context& context) -> void { if (!state.has_error) { context.emitter().Emit(*context.position(), ExpectedThenAfterIf); } - // Add placeholders for `IfExprThen` and final `Expr`. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + // Add invalid nodes to substitute for `IfExprThen` and the final `Expr`. + context.AddInvalidParse(*context.position()); + context.AddInvalidParse(*context.position()); context.ReturnErrorOnState(); } } @@ -49,9 +47,8 @@ auto HandleIfExprFinishThen(Context& context) -> void { if (!state.has_error) { context.emitter().Emit(*context.position(), ExpectedElseAfterIf); } - // Add placeholder for the final `Expr`. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + // Add an invalid node to substitute for the final `Expr`. + context.AddInvalidParse(*context.position()); context.ReturnErrorOnState(); } } diff --git a/toolchain/parse/handle_impl.cpp b/toolchain/parse/handle_impl.cpp index 922e39b64f884..b5d4fcbbb721a 100644 --- a/toolchain/parse/handle_impl.cpp +++ b/toolchain/parse/handle_impl.cpp @@ -38,8 +38,7 @@ auto HandleImplAfterIntroducer(Context& context) -> void { // If we aren't producing a node from the PatternListAsImplicit state, // we still need to create a node to be the child of the `ImplForall` // token created in the `ImplAfterForall` state. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + context.AddInvalidParse(*context.position()); } } else { // One of: diff --git a/toolchain/parse/handle_match.cpp b/toolchain/parse/handle_match.cpp index 345412c7eb77a..feb98912c74d0 100644 --- a/toolchain/parse/handle_match.cpp +++ b/toolchain/parse/handle_match.cpp @@ -176,8 +176,7 @@ auto HandleMatchCaseAfterPattern(Context& context) -> void { context.AddLeafNode(NodeKind::MatchCaseGuardStart, *context.position(), true); - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + context.AddInvalidParse(*context.position()); state = context.PopState(); context.AddNode(NodeKind::MatchCaseGuard, *context.position(), /*has_error=*/true); diff --git a/toolchain/parse/handle_paren_condition.cpp b/toolchain/parse/handle_paren_condition.cpp index dba288becc908..da95f952d0649 100644 --- a/toolchain/parse/handle_paren_condition.cpp +++ b/toolchain/parse/handle_paren_condition.cpp @@ -23,8 +23,7 @@ static auto HandleParenCondition(Context& context, NodeKind start_kind, // For an open curly, assume the condition was completely omitted. // Expression parsing would treat the { as a struct, but instead assume it's // a code block and just emit an invalid parse. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); + context.AddInvalidParse(*context.position()); } else { context.PushState(State::Expr); } diff --git a/toolchain/parse/tree.h b/toolchain/parse/tree.h index f68cf68ce7f35..c19031fbc622d 100644 --- a/toolchain/parse/tree.h +++ b/toolchain/parse/tree.h @@ -199,9 +199,6 @@ class Tree : public Printable { // The in-memory representation of data used for a particular node in the // tree. struct NodeImpl { - explicit NodeImpl(NodeKind kind, bool has_error, Lex::TokenIndex token) - : kind(kind), has_error(has_error), token(token) {} - // The kind of this node. Note that this is only a single byte. NodeKind kind; @@ -221,7 +218,7 @@ class Tree : public Printable { // optional (and will depend on the particular parse implementation // strategy). The goal is that you can rely on grammar-based structural // invariants *until* you encounter a node with this set. - bool has_error = false; + bool has_error; // The token root of this node. Lex::TokenIndex token;