From 39750b9925269141a31a99b4e39f3dc84983b10b Mon Sep 17 00:00:00 2001 From: Geoff Romer Date: Thu, 7 Dec 2023 17:16:03 -0800 Subject: [PATCH] Parse support for tuple patterns in `var` and `let` (#3448) Co-authored-by: Richard Smith --- toolchain/check/handle_binding_pattern.cpp | 1 + toolchain/check/handle_let.cpp | 3 + toolchain/check/handle_variable.cpp | 14 ++++- toolchain/diagnostics/diagnostic_kind.def | 4 +- toolchain/parse/context.cpp | 10 --- toolchain/parse/context.h | 13 ---- toolchain/parse/handle_binding_pattern.cpp | 62 +++++-------------- toolchain/parse/handle_let.cpp | 2 +- toolchain/parse/handle_param.cpp | 6 +- toolchain/parse/handle_pattern.cpp | 18 ++++++ toolchain/parse/handle_var.cpp | 2 +- toolchain/parse/node_kind.def | 6 +- toolchain/parse/state.def | 42 +++++++++++-- .../basics/fail_paren_match_regression.carbon | 2 +- .../fail_missing_implicit_close.carbon | 2 +- .../fail_with_identifier_as_param.carbon | 2 +- .../interface/fail_self_param_syntax.carbon | 4 +- .../parse/testdata/let/fail_bad_name.carbon | 2 +- .../parse/testdata/let/fail_empty.carbon | 2 +- .../testdata/let/fail_missing_type.carbon | 2 +- .../parse/testdata/let/fail_no_semi.carbon | 2 +- toolchain/parse/testdata/let/let_tuple.carbon | 38 ++++++++++++ .../testdata/package_expr/fail_in_name.carbon | 2 +- .../parse/testdata/var/fail_bad_name.carbon | 2 +- .../parse/testdata/var/fail_empty.carbon | 2 +- .../parse/testdata/var/fail_no_semi.carbon | 2 +- toolchain/parse/testdata/var/var_tuple.carbon | 38 ++++++++++++ 27 files changed, 181 insertions(+), 104 deletions(-) create mode 100644 toolchain/parse/handle_pattern.cpp create mode 100644 toolchain/parse/testdata/let/let_tuple.carbon create mode 100644 toolchain/parse/testdata/var/var_tuple.carbon diff --git a/toolchain/check/handle_binding_pattern.cpp b/toolchain/check/handle_binding_pattern.cpp index 27fde6128b87..1c5f525e8abc 100644 --- a/toolchain/check/handle_binding_pattern.cpp +++ b/toolchain/check/handle_binding_pattern.cpp @@ -150,6 +150,7 @@ auto HandleBindingPattern(Context& context, Parse::NodeId parse_node) -> bool { } auto HandleTemplate(Context& context, Parse::NodeId parse_node) -> bool { + // TODO: diagnose if this occurs in a `var` context. return context.TODO(parse_node, "HandleTemplate"); } diff --git a/toolchain/check/handle_let.cpp b/toolchain/check/handle_let.cpp index e42cc29a0f4f..16353a68d786 100644 --- a/toolchain/check/handle_let.cpp +++ b/toolchain/check/handle_let.cpp @@ -11,6 +11,9 @@ namespace Carbon::Check { auto HandleLetDecl(Context& context, Parse::NodeId parse_node) -> bool { auto value_id = context.node_stack().PopExpr(); + if (context.node_stack().PeekIs()) { + return context.TODO(parse_node, "tuple pattern in let"); + } SemIR::InstId pattern_id = context.node_stack().Pop(); context.node_stack() diff --git a/toolchain/check/handle_variable.cpp b/toolchain/check/handle_variable.cpp index c6c48da25ee8..bd0268e973f8 100644 --- a/toolchain/check/handle_variable.cpp +++ b/toolchain/check/handle_variable.cpp @@ -34,15 +34,23 @@ auto HandleVariableInitializer(Context& context, Parse::NodeId parse_node) auto HandleVariableDecl(Context& context, Parse::NodeId parse_node) -> bool { // Handle the optional initializer. auto init_id = SemIR::InstId::Invalid; - bool has_init = - context.parse_tree().node_kind(context.node_stack().PeekParseNode()) != - Parse::NodeKind::BindingPattern; + Parse::NodeKind next_kind = + context.parse_tree().node_kind(context.node_stack().PeekParseNode()); + if (next_kind == Parse::NodeKind::ParamList) { + return context.TODO(parse_node, "tuple pattern in var"); + } + // TODO: find a more robust way to determine if there was an initializer. + bool has_init = next_kind != Parse::NodeKind::BindingPattern; if (has_init) { init_id = context.node_stack().PopExpr(); context.node_stack() .PopAndDiscardSoloParseNode(); } + if (context.node_stack().PeekIs()) { + return context.TODO(parse_node, "tuple pattern in var"); + } + // Extract the name binding. auto value_id = context.node_stack().Pop(); if (auto bind_name = context.insts().Get(value_id).TryAs()) { diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index a9833de36b55..fe45df9fc923 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -64,15 +64,13 @@ CARBON_DIAGNOSTIC_KIND(ExpectedCloseSymbol) CARBON_DIAGNOSTIC_KIND(ExpectedCodeBlock) CARBON_DIAGNOSTIC_KIND(ExpectedExpr) CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterDotOrArrow) -CARBON_DIAGNOSTIC_KIND(ExpectedLetBindingName) -CARBON_DIAGNOSTIC_KIND(ExpectedParamName) +CARBON_DIAGNOSTIC_KIND(ExpectedBindingPattern) CARBON_DIAGNOSTIC_KIND(ExpectedParenAfter) CARBON_DIAGNOSTIC_KIND(ExpectedExprSemi) CARBON_DIAGNOSTIC_KIND(ExpectedStatementSemi) CARBON_DIAGNOSTIC_KIND(ExpectedStructLiteralField) CARBON_DIAGNOSTIC_KIND(ExpectedVarAfterReturned) CARBON_DIAGNOSTIC_KIND(ExpectedVariableDecl) -CARBON_DIAGNOSTIC_KIND(ExpectedVariableName) CARBON_DIAGNOSTIC_KIND(OperatorRequiresParentheses) CARBON_DIAGNOSTIC_KIND(StatementOperatorAsSubExpr) CARBON_DIAGNOSTIC_KIND(UnaryOperatorRequiresParentheses) diff --git a/toolchain/parse/context.cpp b/toolchain/parse/context.cpp index aabc91f05838..f17a2c8d7fcb 100644 --- a/toolchain/parse/context.cpp +++ b/toolchain/parse/context.cpp @@ -166,16 +166,6 @@ auto Context::ConsumeIf(Lex::TokenKind kind) -> std::optional { return Consume(); } -auto Context::ConsumeIfBindingPatternKeyword(Lex::TokenKind keyword_token, - State keyword_state, - int subtree_start) -> void { - if (auto token = ConsumeIf(keyword_token)) { - PushState(Context::StateStackEntry( - keyword_state, PrecedenceGroup::ForTopLevelExpr(), - PrecedenceGroup::ForTopLevelExpr(), *token, subtree_start)); - } -} - auto Context::FindNextOf(std::initializer_list desired_kinds) -> std::optional { auto new_position = position_; diff --git a/toolchain/parse/context.h b/toolchain/parse/context.h index 227938b3fc92..2774674d9366 100644 --- a/toolchain/parse/context.h +++ b/toolchain/parse/context.h @@ -39,14 +39,6 @@ class Context { // Possible return values for FindListToken. enum class ListTokenKind : int8_t { Comma, Close, CommaClose }; - // Supported kinds for HandleBindingPattern. - enum class BindingPatternKind : int8_t { - ImplicitParam, - Param, - Variable, - Let - }; - // Used for restricting ordering of `package` and `import` directives. enum class PackagingState : int8_t { FileStart, @@ -295,11 +287,6 @@ class Context { // Propagates an error up the state stack, to the parent state. auto ReturnErrorOnState() -> void { state_stack_.back().has_error = true; } - // For HandleBindingPattern, tries to consume a wrapping keyword. - auto ConsumeIfBindingPatternKeyword(Lex::TokenKind keyword_token, - State keyword_state, int subtree_start) - -> void; - // Emits a diagnostic for a declaration missing a semi. auto EmitExpectedDeclSemi(Lex::TokenKind expected_kind) -> void; diff --git a/toolchain/parse/handle_binding_pattern.cpp b/toolchain/parse/handle_binding_pattern.cpp index c5236df0ba22..eeb8dd8273cf 100644 --- a/toolchain/parse/handle_binding_pattern.cpp +++ b/toolchain/parse/handle_binding_pattern.cpp @@ -6,46 +6,28 @@ namespace Carbon::Parse { -// Handles BindingPatternAs(ImplicitParam|FunctionParam|Variable|Let). -static auto HandleBindingPattern(Context& context, - Context::BindingPatternKind pattern_kind) - -> void { +auto HandleBindingPattern(Context& context) -> void { auto state = context.PopState(); // Parameters may have keywords prefixing the pattern. They become the parent // for the full BindingPattern. - if (pattern_kind != Context::BindingPatternKind::Variable) { - context.ConsumeIfBindingPatternKeyword(Lex::TokenKind::Template, - State::BindingPatternTemplate, - state.subtree_start); - context.ConsumeIfBindingPatternKeyword(Lex::TokenKind::Addr, - State::BindingPatternAddress, - state.subtree_start); + if (auto token = context.ConsumeIf(Lex::TokenKind::Template)) { + context.PushState(Context::StateStackEntry( + State::BindingPatternTemplate, PrecedenceGroup::ForTopLevelExpr(), + PrecedenceGroup::ForTopLevelExpr(), *token, state.subtree_start)); + } + + if (auto token = context.ConsumeIf(Lex::TokenKind::Addr)) { + context.PushState(Context::StateStackEntry( + State::BindingPatternAddress, PrecedenceGroup::ForTopLevelExpr(), + PrecedenceGroup::ForTopLevelExpr(), *token, state.subtree_start)); } // Handle an invalid pattern introducer for parameters and variables. auto on_error = [&]() { - switch (pattern_kind) { - case Context::BindingPatternKind::ImplicitParam: - case Context::BindingPatternKind::Param: { - CARBON_DIAGNOSTIC(ExpectedParamName, Error, - "Expected parameter declaration."); - context.emitter().Emit(*context.position(), ExpectedParamName); - break; - } - case Context::BindingPatternKind::Variable: { - CARBON_DIAGNOSTIC(ExpectedVariableName, Error, - "Expected pattern in `var` declaration."); - context.emitter().Emit(*context.position(), ExpectedVariableName); - break; - } - case Context::BindingPatternKind::Let: { - CARBON_DIAGNOSTIC(ExpectedLetBindingName, Error, - "Expected pattern in `let` declaration."); - context.emitter().Emit(*context.position(), ExpectedLetBindingName); - break; - } - } + CARBON_DIAGNOSTIC(ExpectedBindingPattern, Error, + "Expected binding pattern."); + context.emitter().Emit(*context.position(), ExpectedBindingPattern); // Add a placeholder for the type. context.AddLeafNode(NodeKind::InvalidParse, *context.position(), /*has_error=*/true); @@ -89,22 +71,6 @@ static auto HandleBindingPattern(Context& context, } } -auto HandleBindingPatternAsImplicitParam(Context& context) -> void { - HandleBindingPattern(context, Context::BindingPatternKind::ImplicitParam); -} - -auto HandleBindingPatternAsParam(Context& context) -> void { - HandleBindingPattern(context, Context::BindingPatternKind::Param); -} - -auto HandleBindingPatternAsVariable(Context& context) -> void { - HandleBindingPattern(context, Context::BindingPatternKind::Variable); -} - -auto HandleBindingPatternAsLet(Context& context) -> void { - HandleBindingPattern(context, Context::BindingPatternKind::Let); -} - // Handles BindingPatternFinishAs(Generic|Regular). static auto HandleBindingPatternFinish(Context& context, NodeKind node_kind) -> void { diff --git a/toolchain/parse/handle_let.cpp b/toolchain/parse/handle_let.cpp index 201af005d6e9..73db9a8408ec 100644 --- a/toolchain/parse/handle_let.cpp +++ b/toolchain/parse/handle_let.cpp @@ -16,7 +16,7 @@ auto HandleLet(Context& context) -> void { context.PushState(state); // This will start at the pattern. - context.PushState(State::BindingPatternAsLet); + context.PushState(State::Pattern); } auto HandleLetAfterPattern(Context& context) -> void { diff --git a/toolchain/parse/handle_param.cpp b/toolchain/parse/handle_param.cpp index ee31f23e9470..dc27932e3b3e 100644 --- a/toolchain/parse/handle_param.cpp +++ b/toolchain/parse/handle_param.cpp @@ -16,13 +16,11 @@ static auto HandleParam(Context& context, State pattern_state, } auto HandleParamAsImplicit(Context& context) -> void { - HandleParam(context, State::BindingPatternAsImplicitParam, - State::ParamFinishAsImplicit); + HandleParam(context, State::BindingPattern, State::ParamFinishAsImplicit); } auto HandleParamAsRegular(Context& context) -> void { - HandleParam(context, State::BindingPatternAsParam, - State::ParamFinishAsRegular); + HandleParam(context, State::BindingPattern, State::ParamFinishAsRegular); } // Handles ParamFinishAs(Implicit|Regular). diff --git a/toolchain/parse/handle_pattern.cpp b/toolchain/parse/handle_pattern.cpp new file mode 100644 index 000000000000..49ccafbd1489 --- /dev/null +++ b/toolchain/parse/handle_pattern.cpp @@ -0,0 +1,18 @@ +// 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 + +#include "toolchain/parse/context.h" + +namespace Carbon::Parse { + +auto HandlePattern(Context& context) -> void { + context.PopAndDiscardState(); + if (context.PositionKind() == Lex::TokenKind::OpenParen) { + context.PushState(State::ParamListAsRegular); + } else { + context.PushState(State::BindingPattern); + } +} + +} // namespace Carbon::Parse diff --git a/toolchain/parse/handle_var.cpp b/toolchain/parse/handle_var.cpp index 0897b4df8655..e3de77dd8503 100644 --- a/toolchain/parse/handle_var.cpp +++ b/toolchain/parse/handle_var.cpp @@ -23,7 +23,7 @@ static auto HandleVar(Context& context, State finish_state, context.AddLeafNode(NodeKind::ReturnedModifier, returned_token); } - context.PushState(State::BindingPatternAsVariable); + context.PushState(State::Pattern); } auto HandleVarAsDecl(Context& context) -> void { diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index f5f07757a162..c92260600c71 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -245,6 +245,8 @@ CARBON_PARSE_NODE_KIND_BRACKET(FunctionDecl, FunctionIntroducer, // // [Generic]PatternBinding and ParamListComma may repeat with ParamListComma // as a separator. +// +// TODO: rename ParamList to TuplePattern to reflect wider usage. CARBON_PARSE_NODE_KIND_CHILD_COUNT(ParamListStart, 0, CARBON_TOKEN(OpenParen)) CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplicitParamListStart, 0, CARBON_TOKEN(OpenSquareBracket)) @@ -285,7 +287,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(Template, 1, CARBON_TOKEN(Template)) // `let`: // LetIntroducer // _repeated_ _external_: modifier -// _external_: BindingPattern +// _external_: BindingPattern or ParamList // LetInitializer // _external_: expression // LetDecl @@ -301,7 +303,7 @@ CARBON_PARSE_NODE_KIND_BRACKET(LetDecl, LetIntroducer, // VariableIntroducer // _repeated_ _external_: modifier // _optional_ ReturnedModifier -// _external_: BindingPattern +// _external_: BindingPattern or ParamList // VariableInitializer // _external_: expression // _optional_ diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index e9a8e0789d63..e3e020447a9b 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -649,7 +649,7 @@ CARBON_PARSE_STATE(Package) // // ... // ^ -// 1. BindingPatternAs(ImplicitParam|Param) +// 1. BindingPattern // 2. ParamFinishAs(Implicit|Regular) CARBON_PARSE_STATE_VARIANTS2(Param, Implicit, Regular) @@ -671,6 +671,8 @@ CARBON_PARSE_STATE_VARIANTS2(ParamFinish, Implicit, Regular) // Handles processing of a parameter list `[` or `(`. // +// TODO: Rename this to TuplePattern to reflect wider usage. +// // ( ) (variant is Regular) // ^ // [ ] (variant is Implicit) @@ -759,6 +761,17 @@ CARBON_PARSE_STATE_VARIANTS2(ParenExprParamFinish, Unknown, Tuple) // (state done) CARBON_PARSE_STATE_VARIANTS2(ParenExprFinish, Normal, Tuple) +// Handles processing of a pattern. +// +// ( ... ) +// ^ +// 1. ParamListAsRegular +// +// ... +// ^ +// 1. BindingPattern +CARBON_PARSE_STATE(Pattern) + // Handles the initial part of a binding pattern, enqueuing type expression // processing. // @@ -791,8 +804,7 @@ CARBON_PARSE_STATE_VARIANTS2(ParenExprFinish, Normal, Tuple) // ??? // ^ // 1. BindingPatternFinishAsRegular -CARBON_PARSE_STATE_VARIANTS4(BindingPattern, ImplicitParam, Param, Variable, - Let) +CARBON_PARSE_STATE(BindingPattern) // Handles `addr` in a binding pattern. // @@ -1056,13 +1068,25 @@ CARBON_PARSE_STATE(BaseDecl) // // var ... (variant is not Returned) // ^ -// 1. BindingPatternAsVariable +// 1. BindingPattern +// 2. VarAfterPattern +// 3. VarFinishAs(Decl|For) +// +// var (...) +// ^ +// 1. ParamListAsRegular // 2. VarAfterPattern // 3. VarFinishAs(Decl|For) // // returned var ... (variant is Returned) // ^~~~~~~~~~~~ -// 1. BindingPatternAsVariable +// 1. BindingPattern +// 2. VarAfterPattern +// 3. VarFinishAsDecl +// +// returned var ... (variant is Returned) +// ^~~~~~~~~~~~ +// 1. ParamListAsRegular // 2. VarAfterPattern // 3. VarFinishAsDecl // @@ -1102,9 +1126,15 @@ CARBON_PARSE_STATE_VARIANTS2(VarFinish, Decl, For) // Handles the start of a `let`. // +// let (...) +// ^~~ +// 1. ParamListAsRegular +// 2. LetAfterPattern +// 3. LetFinish +// // let ... // ^ -// 1. BindingPatternAsLet +// 1. BindingPattern // 2. LetAfterPattern // 3. LetFinish CARBON_PARSE_STATE(Let) diff --git a/toolchain/parse/testdata/basics/fail_paren_match_regression.carbon b/toolchain/parse/testdata/basics/fail_paren_match_regression.carbon index 9d2f9a191b7f..eabff1fb4b15 100644 --- a/toolchain/parse/testdata/basics/fail_paren_match_regression.carbon +++ b/toolchain/parse/testdata/basics/fail_paren_match_regression.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_paren_match_regression.carbon:[[@LINE+6]]:5: ERROR: Expected pattern in `var` declaration. +// CHECK:STDERR: fail_paren_match_regression.carbon:[[@LINE+6]]:5: ERROR: Expected binding pattern. // CHECK:STDERR: var = (foo {}) // CHECK:STDERR: ^ // CHECK:STDERR: fail_paren_match_regression.carbon:[[@LINE+3]]:12: ERROR: Expected `,` or `)`. diff --git a/toolchain/parse/testdata/function/declaration/fail_missing_implicit_close.carbon b/toolchain/parse/testdata/function/declaration/fail_missing_implicit_close.carbon index 16659baf95b1..a2457beb33b8 100644 --- a/toolchain/parse/testdata/function/declaration/fail_missing_implicit_close.carbon +++ b/toolchain/parse/testdata/function/declaration/fail_missing_implicit_close.carbon @@ -8,7 +8,7 @@ // CHECK:STDERR: fail_missing_implicit_close.carbon:[[@LINE+6]]:7: ERROR: Closing symbol does not match most recent opening symbol. // CHECK:STDERR: fn Div[(); // CHECK:STDERR: ^ -// CHECK:STDERR: fail_missing_implicit_close.carbon:[[@LINE+3]]:8: ERROR: Expected parameter declaration. +// CHECK:STDERR: fail_missing_implicit_close.carbon:[[@LINE+3]]:8: ERROR: Expected binding pattern. // CHECK:STDERR: fn Div[(); // CHECK:STDERR: ^ fn Div[(); diff --git a/toolchain/parse/testdata/function/declaration/fail_with_identifier_as_param.carbon b/toolchain/parse/testdata/function/declaration/fail_with_identifier_as_param.carbon index 45aff362356b..b2a4df1d728c 100644 --- a/toolchain/parse/testdata/function/declaration/fail_with_identifier_as_param.carbon +++ b/toolchain/parse/testdata/function/declaration/fail_with_identifier_as_param.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_with_identifier_as_param.carbon:[[@LINE+3]]:11: ERROR: Expected parameter declaration. +// CHECK:STDERR: fail_with_identifier_as_param.carbon:[[@LINE+3]]:11: ERROR: Expected binding pattern. // CHECK:STDERR: fn foo(bar); // CHECK:STDERR: ^ fn foo(bar); diff --git a/toolchain/parse/testdata/generics/interface/fail_self_param_syntax.carbon b/toolchain/parse/testdata/generics/interface/fail_self_param_syntax.carbon index 9d1c8b25689e..bf79fc2934cf 100644 --- a/toolchain/parse/testdata/generics/interface/fail_self_param_syntax.carbon +++ b/toolchain/parse/testdata/generics/interface/fail_self_param_syntax.carbon @@ -5,12 +5,12 @@ // AUTOUPDATE interface Foo { - // CHECK:STDERR: fail_self_param_syntax.carbon:[[@LINE+3]]:13: ERROR: Expected parameter declaration. + // CHECK:STDERR: fail_self_param_syntax.carbon:[[@LINE+3]]:13: ERROR: Expected binding pattern. // CHECK:STDERR: fn Sub[me Self](b: Self) -> Self; // CHECK:STDERR: ^~~~ fn Sub[me Self](b: Self) -> Self; - // CHECK:STDERR: fail_self_param_syntax.carbon:[[@LINE+3]]:10: ERROR: Expected parameter declaration. + // CHECK:STDERR: fail_self_param_syntax.carbon:[[@LINE+3]]:10: ERROR: Expected binding pattern. // CHECK:STDERR: fn Mul[Self](b: Self) -> Self; // CHECK:STDERR: ^~~~ fn Mul[Self](b: Self) -> Self; diff --git a/toolchain/parse/testdata/let/fail_bad_name.carbon b/toolchain/parse/testdata/let/fail_bad_name.carbon index 546da52f1ca0..52815a63201d 100644 --- a/toolchain/parse/testdata/let/fail_bad_name.carbon +++ b/toolchain/parse/testdata/let/fail_bad_name.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_bad_name.carbon:[[@LINE+3]]:5: ERROR: Expected pattern in `let` declaration. +// CHECK:STDERR: fail_bad_name.carbon:[[@LINE+3]]:5: ERROR: Expected binding pattern. // CHECK:STDERR: let ? = 4; // CHECK:STDERR: ^ let ? = 4; diff --git a/toolchain/parse/testdata/let/fail_empty.carbon b/toolchain/parse/testdata/let/fail_empty.carbon index 7a560e149057..8ed75545887f 100644 --- a/toolchain/parse/testdata/let/fail_empty.carbon +++ b/toolchain/parse/testdata/let/fail_empty.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_empty.carbon:[[@LINE+3]]:4: ERROR: Expected pattern in `let` declaration. +// CHECK:STDERR: fail_empty.carbon:[[@LINE+3]]:4: ERROR: Expected binding pattern. // CHECK:STDERR: let; // CHECK:STDERR: ^ let; diff --git a/toolchain/parse/testdata/let/fail_missing_type.carbon b/toolchain/parse/testdata/let/fail_missing_type.carbon index 5bba7b2e0faf..39e53fb7dadd 100644 --- a/toolchain/parse/testdata/let/fail_missing_type.carbon +++ b/toolchain/parse/testdata/let/fail_missing_type.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_missing_type.carbon:[[@LINE+3]]:7: ERROR: Expected pattern in `let` declaration. +// CHECK:STDERR: fail_missing_type.carbon:[[@LINE+3]]:7: ERROR: Expected binding pattern. // CHECK:STDERR: let a = 4; // CHECK:STDERR: ^ let a = 4; diff --git a/toolchain/parse/testdata/let/fail_no_semi.carbon b/toolchain/parse/testdata/let/fail_no_semi.carbon index 8990e97ea183..cc8243fef400 100644 --- a/toolchain/parse/testdata/let/fail_no_semi.carbon +++ b/toolchain/parse/testdata/let/fail_no_semi.carbon @@ -6,7 +6,7 @@ let -// CHECK:STDERR: fail_no_semi.carbon:[[@LINE+15]]:21: ERROR: Expected pattern in `let` declaration. +// CHECK:STDERR: fail_no_semi.carbon:[[@LINE+15]]:21: ERROR: Expected binding pattern. // CHECK:STDERR: // CHECK:STDOUT: ] // CHECK:STDERR: ^ // CHECK:STDERR: fail_no_semi.carbon:[[@LINE+12]]:21: ERROR: `let` declarations must end with a `;`. diff --git a/toolchain/parse/testdata/let/let_tuple.carbon b/toolchain/parse/testdata/let/let_tuple.carbon new file mode 100644 index 000000000000..1f717f9ba55d --- /dev/null +++ b/toolchain/parse/testdata/let/let_tuple.carbon @@ -0,0 +1,38 @@ +// 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 + +fn F() { + let (s: String, i: i32) = ("hello", 0); +} + +// CHECK:STDOUT: - filename: let_tuple.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'ParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParamList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'ParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 's'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'String'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParamListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'i'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParamList', text: ')', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'ParenExprOrTupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello"'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '0'}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 23}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/package_expr/fail_in_name.carbon b/toolchain/parse/testdata/package_expr/fail_in_name.carbon index e4a38d0772c4..189952af63c5 100644 --- a/toolchain/parse/testdata/package_expr/fail_in_name.carbon +++ b/toolchain/parse/testdata/package_expr/fail_in_name.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_in_name.carbon:[[@LINE+3]]:5: ERROR: Expected pattern in `var` declaration. +// CHECK:STDERR: fail_in_name.carbon:[[@LINE+3]]:5: ERROR: Expected binding pattern. // CHECK:STDERR: var package.val: i32; // CHECK:STDERR: ^~~~~~~ var package.val: i32; diff --git a/toolchain/parse/testdata/var/fail_bad_name.carbon b/toolchain/parse/testdata/var/fail_bad_name.carbon index 47d9fdc99c33..798f73bbddd6 100644 --- a/toolchain/parse/testdata/var/fail_bad_name.carbon +++ b/toolchain/parse/testdata/var/fail_bad_name.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_bad_name.carbon:[[@LINE+3]]:5: ERROR: Expected pattern in `var` declaration. +// CHECK:STDERR: fail_bad_name.carbon:[[@LINE+3]]:5: ERROR: Expected binding pattern. // CHECK:STDERR: var *; // CHECK:STDERR: ^ var *; diff --git a/toolchain/parse/testdata/var/fail_empty.carbon b/toolchain/parse/testdata/var/fail_empty.carbon index 88a61f8a768f..c1a57894632a 100644 --- a/toolchain/parse/testdata/var/fail_empty.carbon +++ b/toolchain/parse/testdata/var/fail_empty.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_empty.carbon:[[@LINE+3]]:4: ERROR: Expected pattern in `var` declaration. +// CHECK:STDERR: fail_empty.carbon:[[@LINE+3]]:4: ERROR: Expected binding pattern. // CHECK:STDERR: var; // CHECK:STDERR: ^ var; diff --git a/toolchain/parse/testdata/var/fail_no_semi.carbon b/toolchain/parse/testdata/var/fail_no_semi.carbon index 2a4b297f23a5..ece7a9cca181 100644 --- a/toolchain/parse/testdata/var/fail_no_semi.carbon +++ b/toolchain/parse/testdata/var/fail_no_semi.carbon @@ -6,7 +6,7 @@ var -// CHECK:STDERR: fail_no_semi.carbon:[[@LINE+15]]:21: ERROR: Expected pattern in `var` declaration. +// CHECK:STDERR: fail_no_semi.carbon:[[@LINE+15]]:21: ERROR: Expected binding pattern. // CHECK:STDERR: // CHECK:STDOUT: ] // CHECK:STDERR: ^ // CHECK:STDERR: fail_no_semi.carbon:[[@LINE+12]]:21: ERROR: `var` declarations must end with a `;`. diff --git a/toolchain/parse/testdata/var/var_tuple.carbon b/toolchain/parse/testdata/var/var_tuple.carbon new file mode 100644 index 000000000000..7ab81f140a63 --- /dev/null +++ b/toolchain/parse/testdata/var/var_tuple.carbon @@ -0,0 +1,38 @@ +// 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 + +fn F() { + var (s: String, i: 32) = ("hello", 0); +} + +// CHECK:STDOUT: - filename: var_tuple.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'ParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParamList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'ParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 's'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'String'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParamListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'i'}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '32'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParamList', text: ')', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'ParenExprOrTupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'StringLiteral', text: '"hello"'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '0'}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 23}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ]