Просмотр исходного кода

Change return of `SkipPastLikelyEnd` to be last consumed token (#3493)

This approach means the parse subtree includes the full token range
consumed.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
josh11b 2 лет назад
Родитель
Сommit
6067ca3f49
28 измененных файлов с 72 добавлено и 94 удалено
  1. 6 9
      toolchain/parse/context.cpp
  2. 2 3
      toolchain/parse/context.h
  3. 4 11
      toolchain/parse/handle_decl_scope_loop.cpp
  4. 3 8
      toolchain/parse/handle_expr.cpp
  5. 2 4
      toolchain/parse/handle_import_and_package.cpp
  6. 1 3
      toolchain/parse/handle_let.cpp
  7. 1 5
      toolchain/parse/handle_statement.cpp
  8. 3 5
      toolchain/parse/handle_var.cpp
  9. 16 15
      toolchain/parse/node_kind.def
  10. 1 1
      toolchain/parse/testdata/array/fail_require_close_bracket.carbon
  11. 1 1
      toolchain/parse/testdata/array/fail_syntax.carbon
  12. 1 1
      toolchain/parse/testdata/basics/fail_paren_match_regression.carbon
  13. 5 4
      toolchain/parse/testdata/for/fail_missing_cond.carbon
  14. 1 1
      toolchain/parse/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon
  15. 1 1
      toolchain/parse/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon
  16. 1 1
      toolchain/parse/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon
  17. 3 2
      toolchain/parse/testdata/function/definition/fail_identifier_in_statements.carbon
  18. 2 2
      toolchain/parse/testdata/generics/deduced_params/fail_no_parens.carbon
  19. 1 1
      toolchain/parse/testdata/generics/interface/fail_missing_name.carbon
  20. 2 2
      toolchain/parse/testdata/generics/interface/fail_missing_open_curly.carbon
  21. 5 4
      toolchain/parse/testdata/if/fail_errors.carbon
  22. 4 4
      toolchain/parse/testdata/namespace/fail_incomplete.carbon
  23. 1 1
      toolchain/parse/testdata/package_expr/fail_in_name.carbon
  24. 1 1
      toolchain/parse/testdata/packages/import/fail_no_semi.carbon
  25. 1 1
      toolchain/parse/testdata/packages/library/fail_invalid_name.carbon
  26. 1 1
      toolchain/parse/testdata/packages/package/fail_no_semi.carbon
  27. 1 1
      toolchain/parse/testdata/return/fail_expr_no_semi.carbon
  28. 1 1
      toolchain/parse/testdata/return/fail_var_no_semi.carbon

+ 6 - 9
toolchain/parse/context.cpp

@@ -200,10 +200,9 @@ auto Context::SkipMatchingGroup() -> bool {
   return true;
 }
 
-auto Context::SkipPastLikelyEnd(Lex::TokenIndex skip_root)
-    -> std::optional<Lex::TokenIndex> {
+auto Context::SkipPastLikelyEnd(Lex::TokenIndex skip_root) -> Lex::TokenIndex {
   if (position_ == end_) {
-    return std::nullopt;
+    return *(position_ - 1);
   }
 
   Lex::LineIndex root_line = tokens().GetLine(skip_root);
@@ -224,13 +223,13 @@ auto Context::SkipPastLikelyEnd(Lex::TokenIndex skip_root)
     if (PositionIs(Lex::TokenKind::CloseCurlyBrace)) {
       // Immediately bail out if we hit an unmatched close curly, this will
       // pop us up a level of the syntax grouping.
-      return std::nullopt;
+      return *(position_ - 1);
     }
 
     // We assume that a semicolon is always intended to be the end of the
     // current construct.
     if (auto semi = ConsumeIf(Lex::TokenKind::Semi)) {
-      return semi;
+      return *semi;
     }
 
     // Skip over any matching group of tokens().
@@ -243,7 +242,7 @@ auto Context::SkipPastLikelyEnd(Lex::TokenIndex skip_root)
   } while (position_ != end_ &&
            is_same_line_or_indent_greater_than_root(*position_));
 
-  return std::nullopt;
+  return *(position_ - 1);
 }
 
 auto Context::SkipTo(Lex::TokenIndex t) -> void {
@@ -412,9 +411,7 @@ auto Context::RecoverFromDeclError(StateStackEntry state,
                                    bool skip_past_likely_end) -> void {
   auto token = state.token;
   if (skip_past_likely_end) {
-    if (auto semi = SkipPastLikelyEnd(token)) {
-      token = *semi;
-    }
+    token = SkipPastLikelyEnd(token);
   }
   AddNode(parse_node_kind, token, state.subtree_start,
           /*has_error=*/true);

+ 2 - 3
toolchain/parse/context.h

@@ -181,9 +181,8 @@ class Context {
   //   less indentation, there is likely a missing semicolon. Continued
   //   declarations or statements across multiple lines should be indented.
   //
-  // Returns a semicolon token if one is the likely end.
-  auto SkipPastLikelyEnd(Lex::TokenIndex skip_root)
-      -> std::optional<Lex::TokenIndex>;
+  // Returns the last token consumed.
+  auto SkipPastLikelyEnd(Lex::TokenIndex skip_root) -> Lex::TokenIndex;
 
   // Skip forward to the given token. Verifies that it is actually forward.
   auto SkipTo(Lex::TokenIndex t) -> void;

+ 4 - 11
toolchain/parse/handle_decl_scope_loop.cpp

@@ -52,19 +52,12 @@ static auto TryHandleEndOrPackagingDecl(Context& context) -> bool {
 static auto FinishAndSkipInvalidDecl(Context& context, int32_t subtree_start)
     -> void {
   auto cursor = *context.position();
-  // Consume to the next `;` or end of line. We ignore the return value since
-  // we only care how much was consumed, not whether it ended with a `;`.
-  // TODO: adjust the return of SkipPastLikelyEnd or create a new function
-  // to avoid going through these hoops.
-  context.SkipPastLikelyEnd(cursor);
-  // Set `iter` to the last token consumed, one before the current position.
-  auto iter = context.position();
-  --iter;
-  // Output an invalid parse subtree including everything up to the last token
-  // consumed.
+  // Output an invalid parse subtree including everything up to the next `;`
+  // or end of line.
   context.ReplacePlaceholderNode(subtree_start, NodeKind::InvalidParseStart,
                                  cursor, /*has_error=*/true);
-  context.AddNode(NodeKind::InvalidParseSubtree, *iter, subtree_start,
+  context.AddNode(NodeKind::InvalidParseSubtree,
+                  context.SkipPastLikelyEnd(cursor), subtree_start,
                   /*has_error=*/true);
 }
 

+ 3 - 8
toolchain/parse/handle_expr.cpp

@@ -401,14 +401,9 @@ auto HandleExprStatementFinish(Context& context) -> void {
     context.emitter().Emit(*context.position(), ExpectedExprSemi);
   }
 
-  if (auto semi_token = context.SkipPastLikelyEnd(state.token)) {
-    context.AddNode(NodeKind::ExprStatement, *semi_token, state.subtree_start,
-                    /*has_error=*/true);
-    return;
-  }
-
-  // Found junk not even followed by a `;`, no node to add.
-  context.ReturnErrorOnState();
+  context.AddNode(NodeKind::ExprStatement,
+                  context.SkipPastLikelyEnd(state.token), state.subtree_start,
+                  /*has_error=*/true);
 }
 
 }  // namespace Carbon::Parse

+ 2 - 4
toolchain/parse/handle_import_and_package.cpp

@@ -12,10 +12,8 @@ namespace Carbon::Parse {
 // Provides common error exiting logic that skips to the semi, if present.
 static auto OnParseError(Context& context, Context::StateStackEntry state,
                          NodeKind directive) -> void {
-  auto semi_token = context.SkipPastLikelyEnd(state.token);
-  return context.AddNode(directive, semi_token ? *semi_token : state.token,
-                         state.subtree_start,
-                         /*has_error=*/true);
+  return context.AddNode(directive, context.SkipPastLikelyEnd(state.token),
+                         state.subtree_start, /*has_error=*/true);
 }
 
 // Handles parsing of the library name. Returns the name's ID on success, which

+ 1 - 3
toolchain/parse/handle_let.cpp

@@ -48,9 +48,7 @@ auto HandleLetFinish(Context& context) -> void {
   } else {
     context.EmitExpectedDeclSemi(Lex::TokenKind::Let);
     state.has_error = true;
-    if (auto semi_token = context.SkipPastLikelyEnd(state.token)) {
-      end_token = *semi_token;
-    }
+    end_token = context.SkipPastLikelyEnd(state.token);
   }
   context.AddNode(NodeKind::LetDecl, end_token, state.subtree_start,
                   state.has_error);

+ 1 - 5
toolchain/parse/handle_statement.cpp

@@ -72,12 +72,8 @@ static auto HandleStatementKeywordFinish(Context& context, NodeKind node_kind)
     context.emitter().Emit(*context.position(), ExpectedStatementSemi,
                            context.tokens().GetKind(state.token));
     state.has_error = true;
-    // Recover to the next semicolon if possible, otherwise indicate the
-    // keyword for the error.
+    // Recover to the next semicolon if possible.
     semi = context.SkipPastLikelyEnd(state.token);
-    if (!semi) {
-      semi = state.token;
-    }
   }
   context.AddNode(node_kind, *semi, state.subtree_start, state.has_error);
 }

+ 3 - 5
toolchain/parse/handle_var.cpp

@@ -35,8 +35,8 @@ auto HandleVarAsReturned(Context& context) -> void {
     CARBON_DIAGNOSTIC(ExpectedVarAfterReturned, Error,
                       "Expected `var` after `returned`.");
     context.emitter().Emit(*context.position(), ExpectedVarAfterReturned);
-    auto semi = context.SkipPastLikelyEnd(returned_token);
-    context.AddLeafNode(NodeKind::EmptyDecl, semi ? *semi : returned_token,
+    context.AddLeafNode(NodeKind::EmptyDecl,
+                        context.SkipPastLikelyEnd(returned_token),
                         /*has_error=*/true);
     context.PopAndDiscardState();
     return;
@@ -76,9 +76,7 @@ auto HandleVarFinishAsDecl(Context& context) -> void {
     // TODO: Disambiguate between statement and member declaration.
     context.EmitExpectedDeclSemi(Lex::TokenKind::Var);
     state.has_error = true;
-    if (auto semi_token = context.SkipPastLikelyEnd(state.token)) {
-      end_token = *semi_token;
-    }
+    end_token = context.SkipPastLikelyEnd(state.token);
   }
   context.AddNode(NodeKind::VariableDecl, end_token, state.subtree_start,
                   state.has_error);

+ 16 - 15
toolchain/parse/node_kind.def

@@ -165,7 +165,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageApi, 0, CARBON_TOKEN(Api))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageImpl, 0, CARBON_TOKEN(Impl))
 CARBON_PARSE_NODE_KIND_BRACKET(PackageDirective, PackageIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Package)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `import`:
 //   ImportIntroducer
@@ -175,7 +175,7 @@ CARBON_PARSE_NODE_KIND_BRACKET(PackageDirective, PackageIntroducer,
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImportIntroducer, 0, CARBON_TOKEN(Import))
 CARBON_PARSE_NODE_KIND_BRACKET(ImportDirective, ImportIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Import)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 // `library` as directive:
 //   LibraryIntroducer
 //   DefaultLibrary or _external_: LibraryName
@@ -184,7 +184,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(DefaultLibrary, 0, CARBON_TOKEN(Default))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryIntroducer, 0, CARBON_TOKEN(Library))
 CARBON_PARSE_NODE_KIND_BRACKET(LibraryDirective, LibraryIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Library)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `library` in `package` or `import`:
 //   _external_: LibraryName
@@ -199,7 +199,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibrarySpecifier, 1, CARBON_TOKEN(Library))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(NamespaceStart, 0, CARBON_TOKEN(Namespace))
 CARBON_PARSE_NODE_KIND_BRACKET(Namespace, NamespaceStart,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Namespace)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // A code block:
 //   CodeBlockStart
@@ -234,7 +234,7 @@ CARBON_PARSE_NODE_KIND_BRACKET(FunctionDefinition, FunctionDefinitionStart,
                                CARBON_TOKEN(CloseCurlyBrace))
 CARBON_PARSE_NODE_KIND_BRACKET(FunctionDecl, FunctionIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Fn)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // A tuple pattern:
 //   TuplePatternStart
@@ -307,7 +307,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(LetIntroducer, 0, CARBON_TOKEN(Let))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(LetInitializer, 0, CARBON_TOKEN(Equal))
 CARBON_PARSE_NODE_KIND_BRACKET(LetDecl, LetIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Let)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `var` and `returned var`:
 //   VariableIntroducer
@@ -330,13 +330,14 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnedModifier, 0, CARBON_TOKEN(Returned))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(VariableInitializer, 0, CARBON_TOKEN(Equal))
 CARBON_PARSE_NODE_KIND_BRACKET(VariableDecl, VariableIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Var)
-                                                       CARBON_TOKEN(Returned)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // An expression statement:
 //   _external_: expression
 // ExprStatement
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExprStatement, 1, CARBON_TOKEN(Semi))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExprStatement, 1,
+                                   CARBON_TOKEN(Semi)
+                                       CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `break`:
 //   BreakStatementStart
@@ -344,7 +345,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExprStatement, 1, CARBON_TOKEN(Semi))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(BreakStatementStart, 0, CARBON_TOKEN(Break))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(BreakStatement, 1,
                                    CARBON_TOKEN(Semi)
-                                       CARBON_IF_ERROR(CARBON_TOKEN(Break)))
+                                       CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `continue`:
 //   ContinueStatementStart
@@ -353,7 +354,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(ContinueStatementStart, 0,
                                    CARBON_TOKEN(Continue))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(ContinueStatement, 1,
                                    CARBON_TOKEN(Semi)
-                                       CARBON_IF_ERROR(CARBON_TOKEN(Continue)))
+                                       CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `return`:
 //   ReturnStatementStart
@@ -364,7 +365,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnStatementStart, 0,
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnVarModifier, 0, CARBON_TOKEN(Var))
 CARBON_PARSE_NODE_KIND_BRACKET(ReturnStatement, ReturnStatementStart,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Return)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `for`:
 //     ForHeaderStart
@@ -658,7 +659,7 @@ CARBON_PARSE_NODE_KIND_BRACKET(ClassDefinition, ClassDefinitionStart,
                                CARBON_TOKEN(CloseCurlyBrace))
 CARBON_PARSE_NODE_KIND_BRACKET(ClassDecl, ClassIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Class)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `base`:
 //   BaseIntroducer
@@ -670,7 +671,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseIntroducer, 0, CARBON_TOKEN(Base))
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseColon, 0, CARBON_TOKEN(Colon))
 CARBON_PARSE_NODE_KIND_BRACKET(BaseDecl, BaseIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Base)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `interface`:
 //     InterfaceIntroducer
@@ -691,7 +692,7 @@ CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDefinition, InterfaceDefinitionStart,
                                CARBON_TOKEN(CloseCurlyBrace))
 CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDecl, InterfaceIntroducer,
                                CARBON_TOKEN(Semi)
-                                   CARBON_IF_ERROR(CARBON_TOKEN(Interface)))
+                                   CARBON_IF_ERROR(CARBON_ANY_TOKEN))
 
 // `impl ... as`:
 //     ImplIntroducer

+ 1 - 1
toolchain/parse/testdata/array/fail_require_close_bracket.carbon

@@ -30,6 +30,6 @@ var x: [i32;;
 // CHECK:STDOUT:           {kind: 'InvalidParse', text: ';', has_error: yes},
 // CHECK:STDOUT:         {kind: 'ArrayExpr', text: ']', has_error: yes, subtree_size: 5},
 // CHECK:STDOUT:       {kind: 'BindingPattern', text: ':', subtree_size: 7},
-// CHECK:STDOUT:     {kind: 'VariableDecl', text: 'var', has_error: yes, subtree_size: 9},
+// CHECK:STDOUT:     {kind: 'VariableDecl', text: ']', has_error: yes, subtree_size: 9},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/array/fail_syntax.carbon

@@ -123,7 +123,7 @@ var x: [i32];
 // CHECK:STDOUT:           {kind: 'InvalidParse', text: ';', has_error: yes},
 // CHECK:STDOUT:         {kind: 'ArrayExpr', text: ']', has_error: yes, subtree_size: 5},
 // CHECK:STDOUT:       {kind: 'BindingPattern', text: ':', subtree_size: 7},
-// CHECK:STDOUT:     {kind: 'VariableDecl', text: 'var', has_error: yes, subtree_size: 9},
+// CHECK:STDOUT:     {kind: 'VariableDecl', text: ']', has_error: yes, subtree_size: 9},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]
 // CHECK:STDOUT: - filename: no_semi.carbon

+ 1 - 1
toolchain/parse/testdata/basics/fail_paren_match_regression.carbon

@@ -26,6 +26,6 @@ var = (foo {})
 // CHECK:STDOUT:         {kind: 'ExprOpenParen', text: '('},
 // CHECK:STDOUT:         {kind: 'IdentifierNameExpr', text: 'foo'},
 // CHECK:STDOUT:       {kind: 'ParenExpr', text: ')', has_error: yes, subtree_size: 3},
-// CHECK:STDOUT:     {kind: 'VariableDecl', text: 'var', has_error: yes, subtree_size: 9},
+// CHECK:STDOUT:     {kind: 'VariableDecl', text: ')', has_error: yes, subtree_size: 9},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 5 - 4
toolchain/parse/testdata/for/fail_missing_cond.carbon

@@ -34,9 +34,10 @@ fn F() {
 // CHECK:STDOUT:           {kind: 'StructLiteral', text: '}', subtree_size: 2},
 // CHECK:STDOUT:         {kind: 'ForHeader', text: 'for', has_error: yes, subtree_size: 4},
 // CHECK:STDOUT:           {kind: 'CodeBlockStart', text: '}', has_error: yes},
-// CHECK:STDOUT:           {kind: 'InvalidParse', text: '}', has_error: yes},
-// CHECK:STDOUT:         {kind: 'CodeBlock', text: '}', has_error: yes, subtree_size: 3},
-// CHECK:STDOUT:       {kind: 'ForStatement', text: 'for', subtree_size: 8},
-// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 14},
+// CHECK:STDOUT:             {kind: 'InvalidParse', text: '}', has_error: yes},
+// CHECK:STDOUT:           {kind: 'ExprStatement', text: '}', has_error: yes, subtree_size: 2},
+// CHECK:STDOUT:         {kind: 'CodeBlock', text: '}', has_error: yes, subtree_size: 4},
+// CHECK:STDOUT:       {kind: 'ForStatement', text: 'for', subtree_size: 9},
+// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 15},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon

@@ -17,7 +17,7 @@ fn F();
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: '(', has_error: yes},
-// CHECK:STDOUT:     {kind: 'FunctionDecl', text: 'fn', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'FunctionDecl', text: ')', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'IdentifierName', text: 'F'},
 // CHECK:STDOUT:         {kind: 'TuplePatternStart', text: '('},

+ 1 - 1
toolchain/parse/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon

@@ -17,7 +17,7 @@ fn F();
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: '(', has_error: yes},
-// CHECK:STDOUT:     {kind: 'FunctionDecl', text: 'fn', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'FunctionDecl', text: ')', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'IdentifierName', text: 'F'},
 // CHECK:STDOUT:         {kind: 'TuplePatternStart', text: '('},

+ 1 - 1
toolchain/parse/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon

@@ -15,7 +15,7 @@ fn F();
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: '(', has_error: yes},
-// CHECK:STDOUT:     {kind: 'FunctionDecl', text: 'fn', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'FunctionDecl', text: ')', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'IdentifierName', text: 'F'},
 // CHECK:STDOUT:         {kind: 'TuplePatternStart', text: '('},

+ 3 - 2
toolchain/parse/testdata/function/definition/fail_identifier_in_statements.carbon

@@ -21,7 +21,8 @@ fn F() {
 // CHECK:STDOUT:           {kind: 'TuplePatternStart', text: '('},
 // CHECK:STDOUT:         {kind: 'TuplePattern', text: ')', subtree_size: 2},
 // CHECK:STDOUT:       {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
-// CHECK:STDOUT:       {kind: 'IdentifierNameExpr', text: 'bar'},
-// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', has_error: yes, subtree_size: 7},
+// CHECK:STDOUT:         {kind: 'IdentifierNameExpr', text: 'bar'},
+// CHECK:STDOUT:       {kind: 'ExprStatement', text: 'bar', has_error: yes, subtree_size: 2},
+// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 8},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 2 - 2
toolchain/parse/testdata/generics/deduced_params/fail_no_parens.carbon

@@ -44,7 +44,7 @@ interface Bar[a: i32] {}
 // CHECK:STDOUT:       {kind: 'IdentifierName', text: 'Bar'},
 // CHECK:STDOUT:         {kind: 'ImplicitParamListStart', text: '['},
 // CHECK:STDOUT:       {kind: 'ImplicitParamList', text: ']', subtree_size: 2},
-// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: 'interface', has_error: yes, subtree_size: 5},
+// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: '}', has_error: yes, subtree_size: 5},
 // CHECK:STDOUT:       {kind: 'InterfaceIntroducer', text: 'interface'},
 // CHECK:STDOUT:       {kind: 'IdentifierName', text: 'Bar'},
 // CHECK:STDOUT:         {kind: 'ImplicitParamListStart', text: '['},
@@ -52,6 +52,6 @@ interface Bar[a: i32] {}
 // CHECK:STDOUT:           {kind: 'IntTypeLiteral', text: 'i32'},
 // CHECK:STDOUT:         {kind: 'BindingPattern', text: ':', subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'ImplicitParamList', text: ']', subtree_size: 5},
-// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: 'interface', has_error: yes, subtree_size: 8},
+// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: '}', has_error: yes, subtree_size: 8},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/generics/interface/fail_missing_name.carbon

@@ -15,6 +15,6 @@ interface {
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'InterfaceIntroducer', text: 'interface'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: '{', has_error: yes},
-// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: 'interface', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: '}', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 2 - 2
toolchain/parse/testdata/generics/interface/fail_missing_open_curly.carbon

@@ -19,9 +19,9 @@ interface Foo
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'InterfaceIntroducer', text: 'interface'},
 // CHECK:STDOUT:       {kind: 'IdentifierName', text: 'Bar'},
-// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: 'interface', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: '}', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'InterfaceIntroducer', text: 'interface'},
 // CHECK:STDOUT:       {kind: 'IdentifierName', text: 'Foo'},
-// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: 'interface', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'InterfaceDecl', text: 'Foo', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 5 - 4
toolchain/parse/testdata/if/fail_errors.carbon

@@ -56,9 +56,10 @@ fn F() {
 // CHECK:STDOUT:           {kind: 'IdentifierNameExpr', text: 'd'},
 // CHECK:STDOUT:         {kind: 'IfCondition', text: ')', subtree_size: 3},
 // CHECK:STDOUT:           {kind: 'CodeBlockStart', text: '}', has_error: yes},
-// CHECK:STDOUT:           {kind: 'InvalidParse', text: '}', has_error: yes},
-// CHECK:STDOUT:         {kind: 'CodeBlock', text: '}', has_error: yes, subtree_size: 3},
-// CHECK:STDOUT:       {kind: 'IfStatement', text: 'if', subtree_size: 7},
-// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 31},
+// CHECK:STDOUT:             {kind: 'InvalidParse', text: '}', has_error: yes},
+// CHECK:STDOUT:           {kind: 'ExprStatement', text: ')', has_error: yes, subtree_size: 2},
+// CHECK:STDOUT:         {kind: 'CodeBlock', text: '}', has_error: yes, subtree_size: 4},
+// CHECK:STDOUT:       {kind: 'IfStatement', text: 'if', subtree_size: 8},
+// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 32},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 4 - 4
toolchain/parse/testdata/namespace/fail_incomplete.carbon

@@ -39,16 +39,16 @@ namespace
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'NamespaceStart', text: 'namespace'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: '123', has_error: yes},
-// CHECK:STDOUT:     {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'Namespace', text: '123', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'NamespaceStart', text: 'namespace'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: '""', has_error: yes},
-// CHECK:STDOUT:     {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'Namespace', text: '""', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'NamespaceStart', text: 'namespace'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: '+', has_error: yes},
-// CHECK:STDOUT:     {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'Namespace', text: '+', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'NamespaceStart', text: 'namespace'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: 'bool', has_error: yes},
-// CHECK:STDOUT:     {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'Namespace', text: 'bool', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'NamespaceStart', text: 'namespace'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: 'namespace', has_error: yes},
 // CHECK:STDOUT:     {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},

+ 1 - 1
toolchain/parse/testdata/package_expr/fail_in_name.carbon

@@ -33,6 +33,6 @@ class package.C {
 // CHECK:STDOUT:     {kind: 'Namespace', text: ';', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'ClassIntroducer', text: 'class'},
 // CHECK:STDOUT:       {kind: 'InvalidParse', text: 'package', has_error: yes},
-// CHECK:STDOUT:     {kind: 'ClassDecl', text: 'class', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'ClassDecl', text: '}', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/packages/import/fail_no_semi.carbon

@@ -14,6 +14,6 @@ import Geometry
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'ImportIntroducer', text: 'import'},
 // CHECK:STDOUT:       {kind: 'PackageName', text: 'Geometry'},
-// CHECK:STDOUT:     {kind: 'ImportDirective', text: 'import', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:     {kind: 'ImportDirective', text: 'Geometry', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/packages/library/fail_invalid_name.carbon

@@ -73,6 +73,6 @@ library "NoSemi" api
 // CHECK:STDOUT:       {kind: 'LibraryIntroducer', text: 'library'},
 // CHECK:STDOUT:       {kind: 'LibraryName', text: '"NoSemi"'},
 // CHECK:STDOUT:       {kind: 'PackageApi', text: 'api'},
-// CHECK:STDOUT:     {kind: 'LibraryDirective', text: 'library', has_error: yes, subtree_size: 4},
+// CHECK:STDOUT:     {kind: 'LibraryDirective', text: 'api', has_error: yes, subtree_size: 4},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/packages/package/fail_no_semi.carbon

@@ -15,6 +15,6 @@ package Geometry api
 // CHECK:STDOUT:       {kind: 'PackageIntroducer', text: 'package'},
 // CHECK:STDOUT:       {kind: 'PackageName', text: 'Geometry'},
 // CHECK:STDOUT:       {kind: 'PackageApi', text: 'api'},
-// CHECK:STDOUT:     {kind: 'PackageDirective', text: 'package', has_error: yes, subtree_size: 4},
+// CHECK:STDOUT:     {kind: 'PackageDirective', text: 'api', has_error: yes, subtree_size: 4},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/return/fail_expr_no_semi.carbon

@@ -21,7 +21,7 @@ fn F() {
 // CHECK:STDOUT:       {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
 // CHECK:STDOUT:         {kind: 'ReturnStatementStart', text: 'return'},
 // CHECK:STDOUT:         {kind: 'IdentifierNameExpr', text: 'x'},
-// CHECK:STDOUT:       {kind: 'ReturnStatement', text: 'return', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:       {kind: 'ReturnStatement', text: 'x', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 9},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 1 - 1
toolchain/parse/testdata/return/fail_var_no_semi.carbon

@@ -21,7 +21,7 @@ fn F() {
 // CHECK:STDOUT:       {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
 // CHECK:STDOUT:         {kind: 'ReturnStatementStart', text: 'return'},
 // CHECK:STDOUT:         {kind: 'ReturnVarModifier', text: 'var'},
-// CHECK:STDOUT:       {kind: 'ReturnStatement', text: 'return', has_error: yes, subtree_size: 3},
+// CHECK:STDOUT:       {kind: 'ReturnStatement', text: 'var', has_error: yes, subtree_size: 3},
 // CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 9},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]