diff --git a/toolchain/check/handle_pattern_list.cpp b/toolchain/check/handle_pattern_list.cpp index d7a7991b30b2..152ac2fdfbe2 100644 --- a/toolchain/check/handle_pattern_list.cpp +++ b/toolchain/check/handle_pattern_list.cpp @@ -35,6 +35,11 @@ auto HandleParseNode(Context& context, Parse::TuplePatternStartId node_id) return HandlePatternListStart(context, node_id); } +auto HandleParseNode(Context& context, Parse::StructPatternStartId node_id) + -> bool { + return context.TODO(node_id, "struct pattern start"); +} + auto HandleParseNode(Context& context, Parse::ExplicitParamListStartId node_id) -> bool { context.full_pattern_stack().StartExplicitParamList(); @@ -129,6 +134,15 @@ auto HandleParseNode(Context& context, Parse::TuplePatternId node_id) -> bool { return true; } +auto HandleParseNode(Context& context, Parse::StructPatternId node_id) -> bool { + return context.TODO(node_id, "struct pattern"); +} + +auto HandleParseNode(Context& context, + Parse::StructPatternDesignatedFieldId node_id) -> bool { + return context.TODO(node_id, "struct pattern field"); +} + auto HandleParseNode(Context& context, Parse::PatternListCommaId /*node_id*/) -> bool { EndExprRegionForPattern(context, context.node_stack()); diff --git a/toolchain/check/node_stack.h b/toolchain/check/node_stack.h index b499b48f5de3..e1e065691d82 100644 --- a/toolchain/check/node_stack.h +++ b/toolchain/check/node_stack.h @@ -472,6 +472,8 @@ class NodeStack { case Parse::NodeKind::RuntimeBindingName: case Parse::NodeKind::ReturnStatementStart: case Parse::NodeKind::StructLiteralStart: + case Parse::NodeKind::StructPatternStart: + case Parse::NodeKind::StructPatternDesignatedField: case Parse::NodeKind::StructTypeLiteralField: case Parse::NodeKind::StructTypeLiteralStart: case Parse::NodeKind::TemplateBindingName: diff --git a/toolchain/diagnostics/kind.def b/toolchain/diagnostics/kind.def index 23aa58ec1c76..3ffbb8faa4b9 100644 --- a/toolchain/diagnostics/kind.def +++ b/toolchain/diagnostics/kind.def @@ -125,16 +125,21 @@ CARBON_DIAGNOSTIC_KIND(RedundantRuntimeModifier) CARBON_DIAGNOSTIC_KIND(ExpectedExprSemi) CARBON_DIAGNOSTIC_KIND(ExpectedStatementSemi) CARBON_DIAGNOSTIC_KIND(ExpectedStructLiteralField) +CARBON_DIAGNOSTIC_KIND(ExpectedStructPatternDesignatedField) +CARBON_DIAGNOSTIC_KIND(ExpectedCloseAfterUnderscore) CARBON_DIAGNOSTIC_KIND(ExpectedVarAfterReturned) CARBON_DIAGNOSTIC_KIND(ExpectedChoiceDefinition) CARBON_DIAGNOSTIC_KIND(ExpectedChoiceAlternativeName) CARBON_DIAGNOSTIC_KIND(ExpectedObserveOperator) +CARBON_DIAGNOSTIC_KIND(NestedTuplePatternInStructPatternShortField) +CARBON_DIAGNOSTIC_KIND(NestedStructPatternStructPatternShortField) CARBON_DIAGNOSTIC_KIND(NestedVar) CARBON_DIAGNOSTIC_KIND(NestedUnused) CARBON_DIAGNOSTIC_KIND(UnusedAfterBindingModifier) CARBON_DIAGNOSTIC_KIND(OperatorRequiresParentheses) CARBON_DIAGNOSTIC_KIND(RefInsideVar) CARBON_DIAGNOSTIC_KIND(StatementOperatorAsSubExpr) +CARBON_DIAGNOSTIC_KIND(AnonymousBindingInStructPattern) CARBON_DIAGNOSTIC_KIND(UnaryOperatorRequiresParentheses) CARBON_DIAGNOSTIC_KIND(UnaryOperatorHasWhitespace) CARBON_DIAGNOSTIC_KIND(UnaryOperatorRequiresWhitespace) diff --git a/toolchain/parse/context.h b/toolchain/parse/context.h index 3c197abebdd9..6a60db105d91 100644 --- a/toolchain/parse/context.h +++ b/toolchain/parse/context.h @@ -116,6 +116,13 @@ class Context { // could help catch errors. bool in_unused_pattern : 1 = false; + // Set to true to indicate that this state is handling a shorthand pattern + // inside a struct pattern such as `{var a: T}` + // TODO: This is meaningful only for patterns, and the precedence fields + // are meaningful only for expressions, so expressing them as a union + // could help catch errors. + bool in_field_shorthand_pattern : 1 = false; + // The binding context governing this state, used to pick the default phase // of its bindings. Meaningful for pattern states, and for the // declaration-name states that carry an enclosing declaration's default @@ -139,7 +146,8 @@ class Context { // We expect State to fit into 12 bytes: // state = 1 byte - // has_error, in_var_pattern, in_unused_pattern, binding_context = 1 byte + // has_error, in_var_pattern, in_unused_pattern, in_field_shorthand_pattern, + // binding_context = 1 byte // ambient_precedence = 1 byte // lhs_precedence = 1 byte // token = 4 bytes @@ -368,16 +376,19 @@ class Context { } // Pushes a new state for handling a pattern. `in_var_pattern` and - // `in_unused_pattern` indicate whether that pattern is nested inside a `var` - // or `unused` pattern. `binding_context` is the binding context that - // determines the default phase of bindings in this pattern. + // `in_unused_pattern` and `in_field_shorthand_pattern` indicate whether that + // pattern is nested inside a `var`, `unused` or a struct shorthand field + // pattern.. `binding_context` is the binding context that determines the + // default phase of bindings in this pattern. auto PushStateForPattern(StateKind kind, bool in_var_pattern, bool in_unused_pattern, + bool in_field_shorthand_pattern, BindingContext binding_context, PrecedenceGroup precedence) -> void { PushState({.kind = kind, .in_var_pattern = in_var_pattern, .in_unused_pattern = in_unused_pattern, + .in_field_shorthand_pattern = in_field_shorthand_pattern, .binding_context = binding_context, .ambient_precedence = precedence, .token = *position_, diff --git a/toolchain/parse/handle_binding_pattern.cpp b/toolchain/parse/handle_binding_pattern.cpp index 0322679be0f3..a5ef270811ed 100644 --- a/toolchain/parse/handle_binding_pattern.cpp +++ b/toolchain/parse/handle_binding_pattern.cpp @@ -125,6 +125,15 @@ auto HandleBindingPattern(Context& context) -> void { self_token = *self; context.AddLeafNode(NodeKind::SelfValueName, *self); } else if (auto underscore = context.ConsumeIf(Lex::TokenKind::Underscore)) { + if (state.in_field_shorthand_pattern) { + CARBON_DIAGNOSTIC( + AnonymousBindingInStructPattern, Error, + "Anonymous binding found in struct pattern. Use `.field = " + "_: field_type` or `unused field: field_type`"); + context.emitter().Emit(*context.position(), + AnonymousBindingInStructPattern); + state.has_error = true; + } context.AddLeafNode(NodeKind::UnderscoreName, *underscore); } else if (context.PositionKind().is_word() && context.PositionKind(Lookahead::NextToken) diff --git a/toolchain/parse/handle_let.cpp b/toolchain/parse/handle_let.cpp index a8609cde23a3..413a08d2d842 100644 --- a/toolchain/parse/handle_let.cpp +++ b/toolchain/parse/handle_let.cpp @@ -19,6 +19,7 @@ auto HandleLet(Context& context) -> void { context.PushStateForPattern(StateKind::Pattern, /*in_var_pattern=*/false, /*in_unused_pattern=*/false, + /*in_field_shorthand_pattern=*/false, BindingContext::ExplicitParam, PrecedenceGroup::ForTopLevelPattern()); } diff --git a/toolchain/parse/handle_match.cpp b/toolchain/parse/handle_match.cpp index 75066ede1d2f..2e9aa23d4b81 100644 --- a/toolchain/parse/handle_match.cpp +++ b/toolchain/parse/handle_match.cpp @@ -144,6 +144,7 @@ auto HandleMatchCaseIntroducer(Context& context) -> void { context.PushState(state, StateKind::MatchCaseAfterPattern); context.PushStateForPattern(StateKind::Pattern, /*in_var_pattern=*/false, /*in_unused_pattern=*/false, + /*in_field_shorthand_pattern=*/false, BindingContext::ExplicitParam, PrecedenceGroup::ForTopLevelPattern()); } diff --git a/toolchain/parse/handle_pattern.cpp b/toolchain/parse/handle_pattern.cpp index 560682d6c664..904d5df0b851 100644 --- a/toolchain/parse/handle_pattern.cpp +++ b/toolchain/parse/handle_pattern.cpp @@ -11,22 +11,28 @@ auto HandlePattern(Context& context) -> void { auto state = context.PopState(); switch (context.PositionKind()) { case Lex::TokenKind::OpenParen: - context.PushStateForPattern(StateKind::PatternListAsTuple, - state.in_var_pattern, state.in_unused_pattern, - state.binding_context, - state.ambient_precedence); + context.PushStateForPattern( + StateKind::PatternListAsTuple, state.in_var_pattern, + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); + break; + case Lex::TokenKind::OpenCurlyBrace: + context.PushStateForPattern( + StateKind::PatternListAsStruct, state.in_var_pattern, + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); break; case Lex::TokenKind::Var: - context.PushStateForPattern(StateKind::VariablePattern, - state.in_var_pattern, state.in_unused_pattern, - state.binding_context, - state.ambient_precedence); + context.PushStateForPattern( + StateKind::VariablePattern, state.in_var_pattern, + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); break; case Lex::TokenKind::Unused: - context.PushStateForPattern(StateKind::UnusedPattern, - state.in_var_pattern, state.in_unused_pattern, - state.binding_context, - state.ambient_precedence); + context.PushStateForPattern( + StateKind::UnusedPattern, state.in_var_pattern, + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); break; case Lex::TokenKind::Template: case Lex::TokenKind::Generic: @@ -35,10 +41,10 @@ auto HandlePattern(Context& context) -> void { // `self` is always a binding, even when its type is omitted (and so is not // followed by a `:`). case Lex::TokenKind::SelfValueIdentifier: - context.PushStateForPattern(StateKind::BindingPattern, - state.in_var_pattern, state.in_unused_pattern, - state.binding_context, - state.ambient_precedence); + context.PushStateForPattern( + StateKind::BindingPattern, state.in_var_pattern, + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); break; default: if (context.PositionKind().is_word() && @@ -46,11 +52,14 @@ auto HandlePattern(Context& context) -> void { .is_binding_pattern_operator()) { context.PushStateForPattern( StateKind::BindingPattern, state.in_var_pattern, - state.in_unused_pattern, state.binding_context, - state.ambient_precedence); + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); break; } - context.PushState(StateKind::ExprPattern); + context.PushStateForPattern( + StateKind::ExprPattern, state.in_var_pattern, state.in_unused_pattern, + state.in_field_shorthand_pattern, state.binding_context, + state.ambient_precedence); context.PushStateForExpr(state.ambient_precedence); break; } diff --git a/toolchain/parse/handle_pattern_list.cpp b/toolchain/parse/handle_pattern_list.cpp index 51064b304a28..2a9d0857e0a9 100644 --- a/toolchain/parse/handle_pattern_list.cpp +++ b/toolchain/parse/handle_pattern_list.cpp @@ -13,11 +13,13 @@ static auto HandlePatternListElement(Context& context, StateKind pattern_state, auto state = context.PopState(); context.PushStateForPattern(finish_state_kind, state.in_var_pattern, - state.in_unused_pattern, state.binding_context, - state.ambient_precedence); + state.in_unused_pattern, + state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); context.PushStateForPattern(pattern_state, state.in_var_pattern, - state.in_unused_pattern, state.binding_context, - state.ambient_precedence); + state.in_unused_pattern, + state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); } auto HandlePatternListElementAsTuple(Context& context) -> void { @@ -25,6 +27,31 @@ auto HandlePatternListElementAsTuple(Context& context) -> void { StateKind::PatternListElementFinishAsTuple); } +auto HandlePatternListElementAsStruct(Context& context) -> void { + switch (context.PositionKind()) { + case Lex::TokenKind::Period: + HandlePatternListElement(context, + StateKind::StructPatternFieldAfterDesignator, + StateKind::PatternListElementFinishAsStruct); + context.PushState(StateKind::PeriodAsStruct); + break; + case Lex::TokenKind::Underscore: + // If this ends up as part of a binding pattern, it will look like a + // shorthand pattern such as `{_: i32}`. + // Set flag on state which will be popped in HandlePatternListElement. + context.state_stack().back().in_field_shorthand_pattern = true; + HandlePatternListElement(context, StateKind::StructPatternUnderscore, + StateKind::PatternListElementFinishAsStruct); + break; + default: + // Set flag on state which will be popped in HandlePatternListElement. + context.state_stack().back().in_field_shorthand_pattern = true; + HandlePatternListElement(context, StateKind::Pattern, + StateKind::PatternListElementFinishAsStruct); + break; + } +} + auto HandlePatternListElementAsExplicit(Context& context) -> void { HandlePatternListElement(context, StateKind::Pattern, StateKind::PatternListElementFinishAsExplicit); @@ -35,7 +62,95 @@ auto HandlePatternListElementAsImplicit(Context& context) -> void { StateKind::PatternListElementFinishAsImplicit); } -// Handles PatternListElementFinishAs(Tuple|Explicit|Implicit). +auto HandleStructPatternDesignatedFieldFinish(Context& context) -> void { + auto state = context.PopState(); + context.AddNode(NodeKind::StructPatternDesignatedField, state.token, + state.has_error); +} + +auto HandleStructPatternFieldAfterDesignator(Context& context) -> void { + auto state = context.PopState(); + + auto skip_to_recovery_position = [&](bool add_invalid_parse) { + auto recovery_pos = + context.FindNextOf({Lex::TokenKind::Equal, Lex::TokenKind::Comma, + Lex::TokenKind::CloseCurlyBrace}); + + if (add_invalid_parse) { + if (context.tokens().GetKind(*recovery_pos) != Lex::TokenKind::Equal) { + context.AddInvalidParse(*context.position()); + } + } + context.SkipTo(*recovery_pos); + }; + + if (state.has_error) { + // recover from error returned when parsing designator + skip_to_recovery_position(/*add_invalid_parse=*/false); + } + + if (!context.PositionIs(Lex::TokenKind::Equal)) { + if (!state.has_error) { + state.has_error = true; + + CARBON_DIAGNOSTIC(ExpectedStructPatternDesignatedField, Error, + "expected `= value` after `.field`"); + context.emitter().Emit(*context.position(), + ExpectedStructPatternDesignatedField); + } + skip_to_recovery_position(/*add_invalid_parse=*/true); + + if (context.PositionIs(Lex::TokenKind::Comma) || + context.PositionIs(Lex::TokenKind::CloseCurlyBrace)) { + context.PushState(state, StateKind::StructPatternDesignatedFieldFinish); + return; + } + } + + state.token = context.ConsumeChecked(Lex::TokenKind::Equal); + + context.PushState(state, StateKind::StructPatternDesignatedFieldFinish); + context.PushStateForPattern(StateKind::Pattern, state.in_var_pattern, + state.in_unused_pattern, + state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); +} + +auto HandleStructPatternUnderscore(Context& context) -> void { + auto state = context.PopState(); + + if (context.PositionKind(Lookahead::NextToken) + .is_binding_pattern_operator()) { + context.PushStateForPattern( + StateKind::BindingPattern, state.in_var_pattern, + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); + + return; + } + + auto underscore = context.ConsumeChecked(Lex::TokenKind::Underscore); + + bool is_last = context.PositionIs(Lex::TokenKind::CloseCurlyBrace); + + if (!is_last) { + CARBON_DIAGNOSTIC( + ExpectedCloseAfterUnderscore, Error, + "unexpected token `{0}` after `_` in struct pattern, expected `}`", + Lex::TokenKind); + context.emitter().Emit(*context.position(), ExpectedCloseAfterUnderscore, + context.PositionKind()); + state.has_error = true; + } + + context.AddNode(NodeKind::UnderscoreName, underscore, state.has_error); + + if (state.has_error) { + context.ReturnErrorOnState(); + } +} + +// Handles PatternListElementFinishAs(Tuple|Struct|Explicit|Implicit). static auto HandlePatternListElementFinish(Context& context, Lex::TokenKind close_token, StateKind param_state_kind) -> void { @@ -59,9 +174,10 @@ static auto HandlePatternListElementFinish(Context& context, } if (list_token_kind == Context::ListTokenKind::Comma) { - context.PushStateForPattern(param_state_kind, state.in_var_pattern, - state.in_unused_pattern, state.binding_context, - state.ambient_precedence); + context.PushStateForPattern( + param_state_kind, state.in_var_pattern, state.in_unused_pattern, + /*in_field_shorthand_pattern=*/false, state.binding_context, + state.ambient_precedence); } } @@ -70,6 +186,11 @@ auto HandlePatternListElementFinishAsTuple(Context& context) -> void { StateKind::PatternListElementAsTuple); } +auto HandlePatternListElementFinishAsStruct(Context& context) -> void { + HandlePatternListElementFinish(context, Lex::TokenKind::CloseCurlyBrace, + StateKind::PatternListElementAsStruct); +} + auto HandlePatternListElementFinishAsExplicit(Context& context) -> void { HandlePatternListElementFinish(context, Lex::TokenKind::CloseParen, StateKind::PatternListElementAsExplicit); @@ -80,7 +201,7 @@ auto HandlePatternListElementFinishAsImplicit(Context& context) -> void { StateKind::PatternListElementAsImplicit); } -// Handles PatternListAs(Tuple|Explicit|Implicit). +// Handles PatternListAs(Tuple|Struct|Explicit|Implicit). static auto HandlePatternList(Context& context, NodeKind node_kind, Lex::TokenKind open_token_kind, Lex::TokenKind close_token_kind, @@ -88,18 +209,41 @@ static auto HandlePatternList(Context& context, NodeKind node_kind, StateKind finish_state_empty, StateKind finish_state_nonempty) -> void { auto state = context.PopState(); + + if (state.in_field_shorthand_pattern) { + if (node_kind == NodeKind::TuplePatternStart) { + CARBON_DIAGNOSTIC(NestedTuplePatternInStructPatternShortField, Error, + "Tuple pattern in shorthand struct pattern field. Use " + "`.field = (...)` instead"); + context.emitter().Emit(*context.position(), + NestedTuplePatternInStructPatternShortField); + + context.ReturnErrorOnState(); + } else if (node_kind == NodeKind::StructPatternStart) { + CARBON_DIAGNOSTIC(NestedStructPatternStructPatternShortField, Error, + "Struct pattern in shorthand struct pattern field. Use " + "`.field = {{...}` instead"); + context.emitter().Emit(*context.position(), + NestedStructPatternStructPatternShortField); + + context.ReturnErrorOnState(); + } + } + auto open_token = context.ConsumeChecked(open_token_kind); bool empty = context.PositionIs(close_token_kind); context.PushStateForPattern( empty ? finish_state_empty : finish_state_nonempty, state.in_var_pattern, - state.in_unused_pattern, state.binding_context, state.ambient_precedence); + state.in_unused_pattern, state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); context.AddLeafNode(node_kind, open_token); if (!empty) { - context.PushStateForPattern(param_state, state.in_var_pattern, - state.in_unused_pattern, state.binding_context, - PrecedenceGroup::ForTopLevelExpr()); + context.PushStateForPattern( + param_state, state.in_var_pattern, state.in_unused_pattern, + state.in_field_shorthand_pattern, state.binding_context, + PrecedenceGroup::ForTopLevelExpr()); } } @@ -112,6 +256,14 @@ auto HandlePatternListAsTuple(Context& context) -> void { StateKind::PatternListFinishAsTuple, StateKind::PatternListFinishAsParen); } +auto HandlePatternListAsStruct(Context& context) -> void { + HandlePatternList( + context, NodeKind::StructPatternStart, Lex::TokenKind::OpenCurlyBrace, + Lex::TokenKind::CloseCurlyBrace, StateKind::PatternListElementAsStruct, + StateKind::PatternListFinishAsStruct, + StateKind::PatternListFinishAsStruct); +} + auto HandlePatternListAsExplicit(Context& context) -> void { HandlePatternList(context, NodeKind::ExplicitParamListStart, Lex::TokenKind::OpenParen, Lex::TokenKind::CloseParen, @@ -148,6 +300,11 @@ auto HandlePatternListFinishAsTuple(Context& context) -> void { Lex::TokenKind::CloseParen); } +auto HandlePatternListFinishAsStruct(Context& context) -> void { + HandlePatternListFinish(context, NodeKind::StructPattern, + Lex::TokenKind::CloseCurlyBrace); +} + auto HandlePatternListFinishAsExplicit(Context& context) -> void { HandlePatternListFinish(context, NodeKind::ExplicitParamList, Lex::TokenKind::CloseParen); diff --git a/toolchain/parse/handle_statement.cpp b/toolchain/parse/handle_statement.cpp index 1e65f95b06da..6605ff8269b4 100644 --- a/toolchain/parse/handle_statement.cpp +++ b/toolchain/parse/handle_statement.cpp @@ -118,10 +118,10 @@ auto HandleStatementForHeader(Context& context) -> void { state.kind = StateKind::StatementForHeaderIn; context.PushState(state); - context.PushStateForPattern(StateKind::Pattern, /*in_var_pattern=*/false, - /*in_unused_pattern=*/false, - BindingContext::ExplicitParam, - PrecedenceGroup::ForTopLevelPattern()); + context.PushStateForPattern( + StateKind::Pattern, /*in_var_pattern=*/false, + /*in_unused_pattern=*/false, /*in_field_shorthand_pattern=*/false, + BindingContext::ExplicitParam, PrecedenceGroup::ForTopLevelPattern()); } auto HandleStatementForHeaderIn(Context& context) -> void { diff --git a/toolchain/parse/handle_unused.cpp b/toolchain/parse/handle_unused.cpp index a7e5f15f2b28..87073f82da5c 100644 --- a/toolchain/parse/handle_unused.cpp +++ b/toolchain/parse/handle_unused.cpp @@ -19,8 +19,9 @@ auto HandleUnusedPattern(Context& context) -> void { context.ConsumeChecked(Lex::TokenKind::Unused); context.PushStateForPattern(StateKind::Pattern, state.in_var_pattern, - /*in_unused_pattern=*/true, state.binding_context, - state.ambient_precedence); + /*in_unused_pattern=*/true, + state.in_field_shorthand_pattern, + state.binding_context, state.ambient_precedence); } auto HandleFinishUnusedPattern(Context& context) -> void { diff --git a/toolchain/parse/handle_var.cpp b/toolchain/parse/handle_var.cpp index f6deb7d1a46e..dc4e07560a00 100644 --- a/toolchain/parse/handle_var.cpp +++ b/toolchain/parse/handle_var.cpp @@ -27,6 +27,7 @@ static auto HandleVar(Context& context, StateKind finish_state_kind, context.PushStateForPattern(StateKind::Pattern, /*in_var_pattern=*/true, /*in_unused_pattern=*/false, + /*in_field_shorthand_pattern=*/false, BindingContext::ExplicitParam, PrecedenceGroup::ForTopLevelPattern()); } @@ -101,7 +102,8 @@ auto HandleVariablePattern(Context& context) -> void { // A `var` binding is always runtime, regardless of the enclosing context. context.PushStateForPattern( StateKind::Pattern, /*in_var_pattern=*/true, state.in_unused_pattern, - BindingContext::ExplicitParam, state.ambient_precedence); + state.in_field_shorthand_pattern, BindingContext::ExplicitParam, + state.ambient_precedence); } auto HandleFinishVariablePattern(Context& context) -> void { diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index 4ec6732c3c42..320d3af476a3 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -172,6 +172,10 @@ CARBON_PARSE_NODE_KIND(PatternListComma) CARBON_PARSE_NODE_KIND(ParenPattern) CARBON_PARSE_NODE_KIND(TuplePattern) +CARBON_PARSE_NODE_KIND(StructPatternStart) +CARBON_PARSE_NODE_KIND(StructPatternDesignatedField) +CARBON_PARSE_NODE_KIND(StructPattern) + CARBON_PARSE_NODE_KIND(ExplicitParamListStart) CARBON_PARSE_NODE_KIND(ExplicitParamList) CARBON_PARSE_NODE_KIND(ImplicitParamListStart) diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index c33260d05a14..e7583162ee39 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -53,7 +53,10 @@ Variant4) \ CARBON_PARSE_STATE_VARIANT(Kind, Variant1) \ CARBON_PARSE_STATE_VARIANTS3(Kind, Variant2, Variant3, Variant4) - +#define CARBON_PARSE_STATE_VARIANTS5(Kind, Variant1, Variant2, Variant3, \ + Variant4, Variant5) \ + CARBON_PARSE_STATE_VARIANT(Kind, Variant1) \ + CARBON_PARSE_STATE_VARIANTS4(Kind, Variant2, Variant3, Variant4, Variant5) // Used as a default for State initialization in some cases. Should // not be put on the state stack. CARBON_PARSE_STATE(Invalid) @@ -994,13 +997,26 @@ CARBON_PARSE_STATE(AliasAfterName) CARBON_PARSE_STATE(AliasFinish) // Starts parsing a pattern in a comma-separated list. The variants mark -// whether it is part of an implicit parameter list or a tuple pattern. +// whether it is part of an implicit parameter list, struct pattern or a tuple +// pattern. // // ... // ^ // 1. Pattern -// 2. PatternListElementFinishAs(Tuple|Explicit|Implicit) -CARBON_PARSE_STATE_VARIANTS3(PatternListElement, Tuple, Explicit, Implicit) +// 2. PatternListElementFinishAs(Tuple|Struct|Explicit|Implicit) +// +// .foo = ... (variant is Struct) +// ^ +// 1. PeriodAsStruct +// 2. StructPatternFieldAfterDesignator +// 3 PatternListElementFinishAsStruct +// +// _ ... (variant is Struct) +// ^ +// 1. StructPatternUnderscore +// 2. PatternListElementFinishAsStruct +CARBON_PARSE_STATE_VARIANTS4(PatternListElement, Tuple, Struct, Explicit, + Implicit) // Finishes parsing a pattern in a comma-separated list, including the // optional trailing `,`. If there are more patterns, enqueues another @@ -1011,29 +1027,35 @@ CARBON_PARSE_STATE_VARIANTS3(PatternListElement, Tuple, Explicit, Implicit) // (state done) // SPECIAL: parent becomes PatternListFinishAsTuple // +// ... , } (variant is Struct) +// ^ +// (state done) +// // ... , ] (variant is Implicit) // ^ // (state done) // // ... , ... // ^ -// 1. PatternListElementAs(Tuple|Explicit|Implicit) +// 1. PatternListElementAs(Tuple|Struct|Explicit|Implicit) // SPECIAL (variant is Tuple): parent becomes PatternListFinishAsTuple // // ... // ^ // (state done) -CARBON_PARSE_STATE_VARIANTS3(PatternListElementFinish, Tuple, Explicit, +CARBON_PARSE_STATE_VARIANTS4(PatternListElementFinish, Tuple, Struct, Explicit, Implicit) -// Handles processing of a tuple pattern (parentheses) or implicit parameter -// list (square brackets). +// Handles processing of a tuple pattern (parentheses), implicit parameter +// list (square brackets) or struct pattern (braces). // // ( ) (variant is Tuple or Explicit) // ^ // [ ] (variant is Implicit) // ^ -// 1. PatternListFinishAs(Tuple|Explicit|Implicit) +// { } (variant is Struct) +// ^ +// 1. PatternListFinishAs(Tuple|Struct|Explicit|Implicit) // // ( ... ) (variant is Explicit) // ^ @@ -1046,18 +1068,69 @@ CARBON_PARSE_STATE_VARIANTS3(PatternListElementFinish, Tuple, Explicit, // ^ // 1. PatternListElementAsTuple // 2. PatternListFinishAsParen (SPECIAL: may be replaced) -CARBON_PARSE_STATE_VARIANTS3(PatternList, Tuple, Explicit, Implicit) +// +// { ... } (variant is Struct) +// ^ +// 1. PatternListElementAsStruct +// 2. PatternListFinishAsStruct +CARBON_PARSE_STATE_VARIANTS4(PatternList, Tuple, Struct, Explicit, Implicit) -// Handles processing of a parameter list `]` or `)`. +// Handles processing of a parameter list `]`, `)` or `}`. // // ( ... ) (variant is Paren, Tuple or Explicit) // ^ // [ ... ] (variant is Implicit) // ^ +// { ... } (variant is Struct) +// ^ // (state done) -CARBON_PARSE_STATE_VARIANTS4(PatternListFinish, Paren, Tuple, Explicit, +CARBON_PARSE_STATE_VARIANTS5(PatternListFinish, Paren, Tuple, Struct, Explicit, Implicit) +// +// ... , +// ^ +// (state done) +// +// ... } +// ^ +// (state done) +CARBON_PARSE_STATE(StructPatternDesignatedFieldFinish) + +// Handles a struct pattern parameter after the initial designator. +// .foo = ... +// ^ +// 1. Pattern +// 2. StructPatternDesignatedFieldFinish +// +// .foo ??? = ... +// ^~~~~ +// 1. Pattern +// 2. StructPatternDesignatedFieldFinish +// +// .foo ??? , ... +// ^~~~ +// 1. StructPatternDesignatedFieldFinish +// +// .foo ??? } ... +// ^~~~ +// 1. StructPatternDesignatedFieldFinish +CARBON_PARSE_STATE(StructPatternFieldAfterDesignator) + +// Handles the processing of an '_' element in a struct pattern +// _ } +// ^ +// (state done) +// +// _ : ??? +// ^ +// 1. BindingPattern +// +// _ :? ??? +// ^ +// 1. BindingPattern +CARBON_PARSE_STATE(StructPatternUnderscore) + // Handles the processing of a `(condition)` up through the expression. // // if/while/match { (invalid) diff --git a/toolchain/parse/testdata/for/fail_missing_cond.carbon b/toolchain/parse/testdata/for/fail_missing_cond.carbon index 7c613ec3f9a3..30be0408ff4a 100644 --- a/toolchain/parse/testdata/for/fail_missing_cond.carbon +++ b/toolchain/parse/testdata/for/fail_missing_cond.carbon @@ -42,8 +42,8 @@ fn F() { // CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2}, // CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'ForHeaderStart', text: 'for', has_error: yes}, -// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, -// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 2}, // CHECK:STDOUT: {kind: 'ForIn', text: 'for', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'InvalidParse', text: '}', has_error: yes}, // CHECK:STDOUT: {kind: 'ForHeader', text: 'for', has_error: yes, subtree_size: 6}, diff --git a/toolchain/parse/testdata/let/let_struct.carbon b/toolchain/parse/testdata/let/let_struct.carbon new file mode 100644 index 000000000000..68daf6f271cb --- /dev/null +++ b/toolchain/parse/testdata/let/let_struct.carbon @@ -0,0 +1,197 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/let/let_struct.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/let/let_struct.carbon + +// --- let_struct.carbon + +let {.s = s: str, .i = i: i32} = {.s = "hello", .i = 1}; + +// --- let_struct_shorthand.carbon + +let {s: str, i: i32} = {.s = "hello shorthand", .i = 2}; + +// --- let_struct_mixed.carbon + +let {.s = s: str, i: i32} = {.s = "hello mixed", .i = 2}; + +// --- let_ref_struct.carbon + +let {.s = ref s: str, .i = i: i32} = {.s = "hello ref", .i = 3}; + +// --- let_ref_struct_shorthand.carbon + +let {ref s: str, i: i32} = {.s = "hello ref shorthand", .i = 4}; + +// CHECK:STDOUT: - filename: let_struct.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '1'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 31}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: let_struct_shorthand.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello shorthand"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '2'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 25}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: let_struct_mixed.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello mixed"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '2'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 28}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: let_ref_struct.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'RefBindingName', text: 'ref', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello ref"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '3'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 32}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: let_ref_struct_shorthand.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'RefBindingName', text: 'ref', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello ref shorthand"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '4'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/struct/struct_pattern.carbon b/toolchain/parse/testdata/struct/struct_pattern.carbon new file mode 100644 index 000000000000..e771673cf24b --- /dev/null +++ b/toolchain/parse/testdata/struct/struct_pattern.carbon @@ -0,0 +1,1134 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/struct/struct_pattern.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/struct/struct_pattern.carbon + +// --- struct_pattern_empty.carbon + +let {} = {}; + +// --- struct_pattern_one_entry.carbon + +let {.x = y: i32} = {}; + +// --- struct_pattern_trailing_comma.carbon + +let {.x = y: i32,} = {}; + +// --- struct_pattern_two_entries.carbon + +let {.x = y: i32, .m = n: i32} = {}; + +// --- struct_value_literal_as_pattern.carbon + +let {.x = 1, .y = 2}; + +// --- struct_pattern_discard.carbon + +let {.x = y: i32, _} = {}; + +// --- struct_pattern_unnamed.carbon + +let {.x = _: i32} = {}; + +// --- struct_pattern_shorthand.carbon + +let {x: i32, y: i32} = {}; + +// --- struct_pattern_shorthand_ref.carbon + +let {ref x: i32, y: i32} = {}; + +// --- struct_pattern_shorthand_mixed.carbon + +let {.x = y: i32, m: i32} = {}; + +// --- struct_pattern_designated_tuple.carbon + +let{x: i32, .y = (a: i32, b: i32)} = {}; + +// --- struct_pattern_designated_struct.carbon + +let{x: i32, .y = {a: i32, b: i32}} = {}; + +// --- fail_struct_pattern_comma_only.carbon + +// CHECK:STDERR: fail_struct_pattern_comma_only.carbon:[[@LINE+4]]:6: error: expected pattern [ExpectedPattern] +// CHECK:STDERR: let {,} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {,} = {}; + +// --- fail_struct_pattern_missing_designator.carbon + +// CHECK:STDERR: fail_struct_pattern_missing_designator.carbon:[[@LINE+4]]:6: error: expected pattern [ExpectedPattern] +// CHECK:STDERR: let {= y: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {= y: i32} = {}; + +// --- fail_struct_pattern_invalid_designator.carbon + +// CHECK:STDERR: fail_struct_pattern_invalid_designator.carbon:[[@LINE+4]]:7: error: expected identifier after `.` [ExpectedIdentifierAfterPeriodOrArrow] +// CHECK:STDERR: let {.7 = y: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.7 = y: i32} = {}; + +// --- fail_struct_pattern_designator_only.carbon + +// CHECK:STDERR: fail_struct_pattern_designator_only.carbon:[[@LINE+4]]:8: error: expected `= value` after `.field` [ExpectedStructPatternDesignatedField] +// CHECK:STDERR: let {.x} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x} = {}; + +// --- fail_struct_type_literal_as_pattern.carbon + +// CHECK:STDERR: fail_struct_type_literal_as_pattern.carbon:[[@LINE+4]]:8: error: expected `= value` after `.field` [ExpectedStructPatternDesignatedField] +// CHECK:STDERR: let {.x: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x: i32} = {}; + +// --- fail_struct_pattern_period_only.carbon + +// CHECK:STDERR: fail_struct_pattern_period_only.carbon:[[@LINE+4]]:7: error: expected identifier after `.` [ExpectedIdentifierAfterPeriodOrArrow] +// CHECK:STDERR: let {.} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.} = {}; + +// --- fail_struct_pattern_repeated_comma.carbon + +// CHECK:STDERR: fail_struct_pattern_repeated_comma.carbon:[[@LINE+4]]:18: error: expected pattern [ExpectedPattern] +// CHECK:STDERR: let {.x = x: i32,,} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x = x: i32,,} = {}; + +// --- fail_struct_pattern_missing_comma.carbon + +// CHECK:STDERR: fail_struct_pattern_missing_comma.carbon:[[@LINE+4]]:21: error: expected `,` or `}` [UnexpectedTokenAfterListElement] +// CHECK:STDERR: let {.x = x: i32 .y = y: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x = x: i32 .y = y: i32} = {}; + +// --- fail_struct_pattern_missing_pattern.carbon + +// CHECK:STDERR: fail_struct_pattern_missing_pattern.carbon:[[@LINE+4]]:11: error: expected pattern [ExpectedPattern] +// CHECK:STDERR: let {.x = } = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x = } = {}; + +// --- fail_struct_pattern_shorthand_missing_identifier.carbon + +// CHECK:STDERR: fail_struct_pattern_shorthand_missing_identifier.carbon:[[@LINE+4]]:6: error: expected pattern [ExpectedPattern] +// CHECK:STDERR: let {:i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {:i32} = {}; + +// --- fail_struct_pattern_shorthand_missing_expression.carbon + +// CHECK:STDERR: fail_struct_pattern_shorthand_missing_expression.carbon:[[@LINE+4]]:9: error: expected expression [ExpectedExpr] +// CHECK:STDERR: let {x: } = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {x: } = {}; + +// --- fail_struct_pattern_shorthand_missing_comma.carbon + +// CHECK:STDERR: fail_struct_pattern_shorthand_missing_comma.carbon:[[@LINE+4]]:13: error: expected `,` or `}` [UnexpectedTokenAfterListElement] +// CHECK:STDERR: let {x: i32 y: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {x: i32 y: i32} = {}; + +// --- fail_struct_pattern_missing_equals.carbon + +// CHECK:STDERR: fail_struct_pattern_missing_equals.carbon:[[@LINE+4]]:9: error: expected `= value` after `.field` [ExpectedStructPatternDesignatedField] +// CHECK:STDERR: let {.x x:i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x x:i32} = {}; + +// --- fail_struct_pattern_token_after_underscore.carbon + +// CHECK:STDERR: fail_struct_pattern_token_after_underscore.carbon:[[@LINE+4]]:20: error: unexpected token `,` after `_` in struct pattern, expected `}` [ExpectedCloseAfterUnderscore] +// CHECK:STDERR: let {.x = x: i32, _,} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x = x: i32, _,} = {}; + +// --- fail_struct_pattern_underscore_not_last.carbon + +// CHECK:STDERR: fail_struct_pattern_underscore_not_last.carbon:[[@LINE+4]]:6: error: unexpected token `,` after `_` in struct pattern, expected `}` [ExpectedCloseAfterUnderscore] +// CHECK:STDERR: let{_, .x = x: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let{_, .x = x: i32} = {}; + +// --- fail_struct_pattern_extra_token_end.carbon + +// CHECK:STDERR: fail_struct_pattern_extra_token_end.carbon:[[@LINE+4]]:18: error: expected `,` or `}` [UnexpectedTokenAfterListElement] +// CHECK:STDERR: let {.x = x: i32 foo, .y = y: i32} = {}; +// CHECK:STDERR: ^~~ +// CHECK:STDERR: +let {.x = x: i32 foo, .y = y: i32} = {}; + +// --- fail_struct_pattern_extra_token_start.carbon + +// CHECK:STDERR: fail_struct_pattern_extra_token_start.carbon:[[@LINE+4]]:26: error: expected `,` or `}` [UnexpectedTokenAfterListElement] +// CHECK:STDERR: let {.x = x: i32, foo .y = y: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {.x = x: i32, foo .y = y: i32} = {}; + +// --- fail_struct_pattern_shorthand_extra_token_end.carbon + +// CHECK:STDERR: fail_struct_pattern_shorthand_extra_token_end.carbon:[[@LINE+4]]:13: error: expected `,` or `}` [UnexpectedTokenAfterListElement] +// CHECK:STDERR: let {x: i32 foo, y: i32} = {}; +// CHECK:STDERR: ^~~ +// CHECK:STDERR: +let {x: i32 foo, y: i32} = {}; + +// --- fail_struct_pattern_shorthand_extra_token_start.carbon + +// CHECK:STDERR: fail_struct_pattern_shorthand_extra_token_start.carbon:[[@LINE+4]]:18: error: expected `,` or `}` [UnexpectedTokenAfterListElement] +// CHECK:STDERR: let {x: i32, foo y: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {x: i32, foo y: i32} = {}; + +// --- fail_struct_pattern_invalid_introducer.carbon + +// CHECK:STDERR: fail_struct_pattern_invalid_introducer.carbon:[[@LINE+4]]:6: error: expected pattern [ExpectedPattern] +// CHECK:STDERR: let {!x = x: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {!x = x: i32} = {}; + +// --- fail_struct_pattern_extra_token_middle.carbon + +// recover on `=` +// CHECK:STDERR: fail_struct_pattern_extra_token_middle.carbon:[[@LINE+4]]:9: error: expected `= value` after `.field` [ExpectedStructPatternDesignatedField] +// CHECK:STDERR: let {.x foo = x: ()} = {}; +// CHECK:STDERR: ^~~ +// CHECK:STDERR: +let {.x foo = x: ()} = {}; + +// no equals or comma - recover on `}` +// CHECK:STDERR: fail_struct_pattern_extra_token_middle.carbon:[[@LINE+4]]:9: error: expected `= value` after `.field` [ExpectedStructPatternDesignatedField] +// CHECK:STDERR: let {.x foo x: ()} = {}; +// CHECK:STDERR: ^~~ +// CHECK:STDERR: +let {.x foo x: ()} = {}; + +// no equals, trailing comma - recover on `,` +// CHECK:STDERR: fail_struct_pattern_extra_token_middle.carbon:[[@LINE+4]]:9: error: expected `= value` after `.field` [ExpectedStructPatternDesignatedField] +// CHECK:STDERR: let {.x foo x: (),} = {}; +// CHECK:STDERR: ^~~ +// CHECK:STDERR: +let {.x foo x: (),} = {}; + +// no equals, second field - recover on `,` +// CHECK:STDERR: fail_struct_pattern_extra_token_middle.carbon:[[@LINE+4]]:9: error: expected `= value` after `.field` [ExpectedStructPatternDesignatedField] +// CHECK:STDERR: let {.x foo x: (), .y = y: ()} = {}; +// CHECK:STDERR: ^~~ +// CHECK:STDERR: +let {.x foo x: (), .y = y: ()} = {}; + +// --- fail_struct_pattern_invalid_field.carbon + +// CHECK:STDERR: fail_struct_pattern_invalid_field.carbon:[[@LINE+4]]:12: error: expected `,` or `}` [UnexpectedTokenAfterListElement] +// CHECK:STDERR: let {"foo" = , .x = x:()} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {"foo" = , .x = x:()} = {}; + +// --- fail_struct_pattern_nested_tuple_pattern.carbon + +// CHECK:STDERR: fail_struct_pattern_nested_tuple_pattern.carbon:[[@LINE+4]]:14: error: Tuple pattern in shorthand struct pattern field. Use `.field = (...)` instead [NestedTuplePatternInStructPatternShortField] +// CHECK:STDERR: var {x: i32, (y: i32, z: i32)} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +var {x: i32, (y: i32, z: i32)} = {}; + +// --- fail_struct_pattern_nested_var_tuple_pattern.carbon + +// CHECK:STDERR: fail_struct_pattern_nested_var_tuple_pattern.carbon:[[@LINE+4]]:18: error: Tuple pattern in shorthand struct pattern field. Use `.field = (...)` instead [NestedTuplePatternInStructPatternShortField] +// CHECK:STDERR: let {x: i32, var (y: i32, z: i32)} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {x: i32, var (y: i32, z: i32)} = {}; + +// --- fail_struct_pattern_nested_struct_pattern.carbon + +// CHECK:STDERR: fail_struct_pattern_nested_struct_pattern.carbon:[[@LINE+4]]:13: error: Struct pattern in shorthand struct pattern field. Use `.field = {...}` instead [NestedStructPatternStructPatternShortField] +// CHECK:STDERR: let{x: i32, {y: i32, z: i32}} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let{x: i32, {y: i32, z: i32}} = {}; + +// --- fail_struct_pattern_unused_shorthand.carbon + +// CHECK:STDERR: fail_struct_pattern_unused_shorthand.carbon:[[@LINE+4]]:7: error: Anonymous binding found in struct pattern. Use `.field = _: field_type` or `unused field: field_type` [AnonymousBindingInStructPattern] +// CHECK:STDERR: var {_: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +var {_: i32} = {}; +// CHECK:STDERR: fail_struct_pattern_unused_shorthand.carbon:[[@LINE+4]]:11: error: Anonymous binding found in struct pattern. Use `.field = _: field_type` or `unused field: field_type` [AnonymousBindingInStructPattern] +// CHECK:STDERR: let {ref _: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {ref _: i32} = {}; +// CHECK:STDERR: fail_struct_pattern_unused_shorthand.carbon:[[@LINE+4]]:11: error: Anonymous binding found in struct pattern. Use `.field = _: field_type` or `unused field: field_type` [AnonymousBindingInStructPattern] +// CHECK:STDERR: let {var _: i32} = {}; +// CHECK:STDERR: ^ +// CHECK:STDERR: +let {var _: i32} = {}; + +// CHECK:STDOUT: - filename: struct_pattern_empty.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_one_entry.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_trailing_comma.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 10}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_two_entries.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'm'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'n'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 22}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_value_literal_as_pattern.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '1'}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '2'}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_discard.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_'}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_unnamed.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_shorthand.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_shorthand_ref.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'RefBindingName', text: 'ref', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_shorthand_mixed.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'm'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 19}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_designated_tuple.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'a'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'b'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 21}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_pattern_designated_struct.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'a'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'b'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 21}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_comma_only.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: ',', has_error: yes}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_missing_designator.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: '=', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_invalid_designator.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: '7', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', has_error: yes, subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_designator_only.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: '}', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '.', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_type_literal_as_pattern.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: ':', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '.', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_period_only.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: '}', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: '}', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '.', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_repeated_comma.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: ',', has_error: yes}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_missing_comma.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_missing_pattern.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: '}', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_shorthand_missing_identifier.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: ':', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_shorthand_missing_expression.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: '}', has_error: yes}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_shorthand_missing_comma.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_missing_equals.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: 'x', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '.', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_token_after_underscore.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_', has_error: yes}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_underscore_not_last.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_', has_error: yes}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_extra_token_end.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 17}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 22}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_extra_token_start.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'foo'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 13}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_shorthand_extra_token_end.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_shorthand_extra_token_start.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'foo'}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 8}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_invalid_introducer.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: '!', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_extra_token_middle.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', has_error: yes, subtree_size: 8}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 10}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: 'foo', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '.', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: 'foo', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '.', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: 'foo', has_error: yes}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '.', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 20}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_invalid_field.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"foo"'}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_nested_tuple_pattern.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'z'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 18}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 19}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 24}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_nested_var_tuple_pattern.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'z'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', has_error: yes, subtree_size: 12}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 19}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 24}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_nested_struct_pattern.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'z'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 18}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 23}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_struct_pattern_unused_shorthand.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':', has_error: yes}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 6}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_'}, +// CHECK:STDOUT: {kind: 'RefBindingName', text: 'ref', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':', has_error: yes}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 7}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':', has_error: yes}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', has_error: yes, subtree_size: 7}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/var/unused.carbon b/toolchain/parse/testdata/var/unused.carbon index 90bbed7fd281..a5e5efe9e4b1 100644 --- a/toolchain/parse/testdata/var/unused.carbon +++ b/toolchain/parse/testdata/var/unused.carbon @@ -36,6 +36,14 @@ let unused (x: (), y: ()) = ((), ()); let var (x: (), unused y: ()) = ((), ()); let var unused (x: (), y: ()) = ((), ()); +// --- unused_struct.carbon +let {.x = x: i32, var unused y: i32} = {}; +let {.x = x: i32, unused var y: i32} = {}; + +let unused {x: i32, y: i32} = {}; +let var {x: i32, unused y: i32} = {}; +let var unused {x: i32, y: i32} = {}; + // --- var_unused_function.carbon fn F(x: (), var unused y: ()); @@ -304,6 +312,106 @@ var unused (unused y: i32) = (0,); // CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 25}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: unused_struct.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'UnusedPattern', text: 'unused', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 21}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'UnusedPattern', text: 'unused', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 21}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'UnusedPattern', text: 'unused', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'UnusedPattern', text: 'unused', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'UnusedPattern', text: 'unused', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] // CHECK:STDOUT: - filename: var_unused_function.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, diff --git a/toolchain/parse/testdata/var/var_pattern.carbon b/toolchain/parse/testdata/var/var_pattern.carbon index 9578788efc2d..b7ffd7becdb3 100644 --- a/toolchain/parse/testdata/var/var_pattern.carbon +++ b/toolchain/parse/testdata/var/var_pattern.carbon @@ -20,6 +20,14 @@ let (x: (), var y: ()) = ((), ()); fn F(x: (), var y: ()); +// --- struct.carbon + +let {.x = var x: ()} = {.x = ()}; + +// --- struct_shorthand.carbon + +let {var y: ()} = {.y = ()}; + // --- fail_nested.carbon // CHECK:STDERR: fail_nested.carbon:[[@LINE+4]]:25: error: `var` nested within another `var` [NestedVar] @@ -95,6 +103,55 @@ let (x: (), var (y: (), var z: ())) = ((), ((), ())); // CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 17}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 21}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: struct_shorthand.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'y'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] // CHECK:STDOUT: - filename: fail_nested.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, diff --git a/toolchain/parse/testdata/var/var_struct.carbon b/toolchain/parse/testdata/var/var_struct.carbon new file mode 100644 index 000000000000..91e944c51f85 --- /dev/null +++ b/toolchain/parse/testdata/var/var_struct.carbon @@ -0,0 +1,124 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/var/var_struct.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/var/var_struct.carbon + +// --- var_struct.carbon + +var {.s = s: str, .i = i: 32} = {.s = "hello", .i = 0}; + +// --- var_struct_shorthand.carbon + +var {s: str, i: 32} = {.s = "hello shorthand", .i = 1}; + +// --- var_struct_mixed.carbon + +var {.s = s: str, i: 32} = {.s = "hello mixed", .i = 1}; + +// CHECK:STDOUT: - filename: var_struct.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '0'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 32}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: var_struct_shorthand.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello shorthand"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '1'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: var_struct_mixed.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'StructPatternStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPatternDesignatedField', text: '=', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '32'}, +// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructPattern', text: '}', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 's'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello mixed"'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'i'}, +// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '1'}, +// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 29}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index cc3145cf7e9d..bcdc9674974b 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -1498,6 +1498,39 @@ struct StructTypeLiteral { Lex::CloseCurlyBraceTokenIndex token; }; +// Struct Patterns +// ---------------------------------------- + +using StructPatternStart = + LeafNode; + +// `.a = pattern` +struct StructPatternDesignatedField { + static constexpr auto Kind = NodeKind::StructPatternDesignatedField.Define( + {.bracketed_by = StructFieldDesignator::Kind, .child_count = 2}); + + StructFieldDesignatorId name; + Lex::EqualTokenIndex token; + AnyPatternId pattern; +}; + +using StructPatternFieldId = + NodeIdOneOf; + +struct StructPattern { + static constexpr auto Kind = NodeKind::StructPattern.Define( + {.category = NodeCategory::Pattern, + .bracketed_by = StructPatternStart::Kind}); + + StructPatternStartId left_brace; + + CommaSeparatedList fields; + + Lex::CloseCurlyBraceTokenIndex token; +}; + // `class` declarations and definitions // ------------------------------------