Skip to content

Commit

Permalink
Change return of SkipPastLikelyEnd to be last consumed token (carbo…
Browse files Browse the repository at this point in the history
…n-language#3493)

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

---------

Co-authored-by: Jon Ross-Perkins <[email protected]>
  • Loading branch information
josh11b and jonmeow committed Dec 11, 2023
1 parent 1addf10 commit 6067ca3
Show file tree
Hide file tree
Showing 28 changed files with 72 additions and 94 deletions.
15 changes: 6 additions & 9 deletions toolchain/parse/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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().
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 2 additions & 3 deletions toolchain/parse/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 4 additions & 11 deletions toolchain/parse/handle_decl_scope_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
11 changes: 3 additions & 8 deletions toolchain/parse/handle_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 2 additions & 4 deletions toolchain/parse/handle_import_and_package.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions toolchain/parse/handle_let.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 1 addition & 5 deletions toolchain/parse/handle_statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
8 changes: 3 additions & 5 deletions toolchain/parse/handle_var.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
31 changes: 16 additions & 15 deletions toolchain/parse/node_kind.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -330,21 +330,22 @@ 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
// BreakStatement
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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: ]
2 changes: 1 addition & 1 deletion toolchain/parse/testdata/array/fail_syntax.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: ]
9 changes: 5 additions & 4 deletions toolchain/parse/testdata/for/fail_missing_cond.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -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: ]
Original file line number Diff line number Diff line change
Expand Up @@ -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: '('},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: '('},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: '('},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: ]
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ 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: '['},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'a'},
// 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: ]
Loading

0 comments on commit 6067ca3

Please sign in to comment.