diff --git a/toolchain/parser/parser.cpp b/toolchain/parser/parser.cpp index 4ca8687b2470..3d13c3821dd6 100644 --- a/toolchain/parser/parser.cpp +++ b/toolchain/parser/parser.cpp @@ -778,13 +778,32 @@ auto Parser::HandleDeclarationLoopState() -> void { } } +auto Parser::HandleDeducedParameterState() -> void { + PopAndDiscardState(); + + PushState(ParserState::DeducedParameterFinish); + PushState(ParserState::PatternAsDeducedParameter); +} + +auto Parser::HandleDeducedParameterFinishState() -> void { + auto state = PopState(); + + if (state.has_error) { + ReturnErrorOnState(); + } + + if (ConsumeListToken(ParseNodeKind::ParameterListComma, + TokenKind::CloseSquareBracket, + state.has_error) == ListTokenKind::Comma) { + PushState(ParserState::DeducedParameter); + } +} + auto Parser::HandleDeducedParameterListFinishState() -> void { auto state = PopState(); - CARBON_CHECK(tokens_->GetKind(*position_) == TokenKind::CloseSquareBracket) - << "Expected current token to be: `]`, found: " - << tokens_->GetKind(state.token); - AddNode(ParseNodeKind::DeducedParameterList, Consume(), state.subtree_start, + AddNode(ParseNodeKind::DeducedParameterList, + ConsumeChecked(TokenKind::CloseSquareBracket), state.subtree_start, state.has_error); } @@ -1049,26 +1068,22 @@ auto Parser::HandleFunctionIntroducerState() -> void { return; } + // Proceed to the same state regardless of whether there's a deduced + // parameter list. state.state = ParserState::FunctionAfterDeducedParameterList; PushState(state); - // If there are deduced params handle them next. - if (PositionIs(TokenKind::OpenSquareBracket)) { - PushState(ParserState::DeducedParameterListFinish); - // This is for sure a `[`, we can safely create the corresponding node. - AddLeafNode(ParseNodeKind::DeducedParameterListStart, Consume()); - - if (PositionIs(TokenKind::CloseSquareBracket)) { - return; - } - - // TODO: For now only `self` is supported. When other types of deduced - // parameters need to be added, we will probably need to push a more - // general state. - // Push state to handle `self`'s pattern binding. - PushState(ParserState::SelfPattern); + if (!PositionIs(TokenKind::OpenSquareBracket)) { return; } + + // Parse the deduced parameter list as its own subtree. + PushState(ParserState::DeducedParameterListFinish); + AddLeafNode(ParseNodeKind::DeducedParameterListStart, Consume()); + + if (!PositionIs(TokenKind::CloseSquareBracket)) { + PushState(ParserState::DeducedParameter); + } } auto Parser::HandleFunctionAfterDeducedParameterListState() -> void { @@ -1437,13 +1452,26 @@ auto Parser::HandleParenExpressionFinishAsTupleState() -> void { auto Parser::HandlePattern(PatternKind pattern_kind) -> void { auto state = PopState(); - // Ensure the finish state always follows. + // Ensure the finish state always follows, including for errors. state.state = ParserState::PatternFinish; + // Parameters may have an `addr` keyword prefixing the pattern. This becomes + // the parent for the full PatternBinding. + if (pattern_kind != PatternKind::Variable) { + if (auto addr = ConsumeIf(TokenKind::Addr)) { + // Mirror information including subtree_size, but we need to change a copy + // to avoid affecting the token. + auto addr_state = state; + addr_state.state = ParserState::PatternAddress; + addr_state.token = *addr; + PushState(addr_state); + } + } + // Handle an invalid pattern introducer for parameters and variables. - if (!PositionIs(TokenKind::Identifier) || - tokens_->GetKind(*(position_ + 1)) != TokenKind::Colon) { + auto on_error = [&]() { switch (pattern_kind) { + case PatternKind::DeducedParameter: case PatternKind::Parameter: { CARBON_DIAGNOSTIC(ExpectedParameterName, Error, "Expected parameter declaration."); @@ -1459,16 +1487,36 @@ auto Parser::HandlePattern(PatternKind pattern_kind) -> void { } state.has_error = true; PushState(state); + }; + + // The first item should be an identifier or, for deduced parameters, `self`. + if (auto identifier = ConsumeIf(TokenKind::Identifier)) { + AddLeafNode(ParseNodeKind::DeclaredName, *identifier); + } else if (pattern_kind == PatternKind::DeducedParameter) { + if (auto self = ConsumeIf(TokenKind::SelfParameter)) { + AddLeafNode(ParseNodeKind::SelfDeducedParameter, *self); + } else { + on_error(); + return; + } + } else { + on_error(); return; } - // Switch the context token to the colon, so that it'll be used for the root - // node. - state.token = *(position_ + 1); - PushState(state); - PushStateForExpression(PrecedenceGroup::ForType()); - AddLeafNode(ParseNodeKind::DeclaredName, *position_); - position_ += 2; + if (auto colon = ConsumeIf(TokenKind::Colon)) { + // Use the colon for the root node. + state.token = *colon; + PushState(state); + PushStateForExpression(PrecedenceGroup::ForType()); + } else { + on_error(); + return; + } +} + +auto Parser::HandlePatternAsDeducedParameterState() -> void { + HandlePattern(PatternKind::DeducedParameter); } auto Parser::HandlePatternAsFunctionParameterState() -> void { @@ -1496,75 +1544,13 @@ auto Parser::HandlePatternFinishState() -> void { auto Parser::HandlePatternAddressState() -> void { auto state = PopState(); - // If an error was encountered, propagate it without adding a node. + AddNode(ParseNodeKind::Address, state.token, state.subtree_start, + state.has_error); + + // If an error was encountered, propagate it while adding a node. if (state.has_error) { ReturnErrorOnState(); - return; } - - AddNode(ParseNodeKind::Address, state.token, state.subtree_start, - /*has_error=*/false); -} - -// TODO: This can possibly be merged with `HandlePattern`. Regular function -// parameters support `addr` as well but it is not implemented yet. -auto Parser::HandleSelfPatternState() -> void { - auto state = PopState(); - - // self `:` type - auto possible_self_param = - (PositionIs(TokenKind::SelfParameter) && - tokens_->GetKind(*(position_ + 1)) == TokenKind::Colon); - - if (possible_self_param) { - // Ensure the finish state always follows. - state.state = ParserState::PatternFinish; - - // Switch the context token to the colon, so that it'll be used for the root - // node. - state.token = *(position_ + 1); - PushState(state); - PushStateForExpression(PrecedenceGroup::ForType()); - AddLeafNode(ParseNodeKind::SelfDeducedParameter, *position_); - position_ += 2; - return; - } - - // addr self `:` type - auto possible_addr_self_param = - (PositionIs(TokenKind::Addr) && - tokens_->GetKind(*(position_ + 1)) == TokenKind::SelfParameter && - tokens_->GetKind(*(position_ + 2)) == TokenKind::Colon); - - if (possible_addr_self_param) { - // Ensure the finish state always follows. - state.state = ParserState::PatternAddress; - state.token = Consume(); - PushState(state); - - PushState(ParserState::PatternFinish); - - PushStateForExpression(PrecedenceGroup::ForType()); - AddLeafNode(ParseNodeKind::SelfDeducedParameter, *(position_ + 1)); - position_ += 2; - return; - } - - CARBON_DIAGNOSTIC(ExpectedDeducedParam, Error, - "Deduced parameters must be of the form: `: ` " - "or `addr : `."); - emitter_->Emit(*position_, ExpectedDeducedParam); - state.state = ParserState::PatternFinish; - state.has_error = true; - - // Try to recover by skipping to the next `]`. - if (auto next_close_square_bracket = - FindNextOf({TokenKind::CloseSquareBracket}); - next_close_square_bracket) { - SkipTo(*next_close_square_bracket); - } - - PushState(state); } auto Parser::HandleStatementState() -> void { diff --git a/toolchain/parser/parser.h b/toolchain/parser/parser.h index a3a8f90e2511..680db42dbd2c 100644 --- a/toolchain/parser/parser.h +++ b/toolchain/parser/parser.h @@ -44,7 +44,7 @@ class Parser { enum class BraceExpressionKind { Unknown, Value, Type }; // Supported kinds for HandlePattern. - enum class PatternKind { Parameter, Variable }; + enum class PatternKind { DeducedParameter, Parameter, Variable }; // Supported return values for GetDeclarationContext. enum class DeclarationContext { @@ -310,7 +310,7 @@ class Parser { // Handles ParenExpressionParameterFinishAs(Unknown|Tuple). auto HandleParenExpressionParameterFinish(bool as_tuple) -> void; - // Handles PatternAs(FunctionParameter|Variable). + // Handles PatternAs(DeducedParameter|FunctionParameter|Variable). auto HandlePattern(PatternKind pattern_kind) -> void; // Handles the `;` after a keyword statement. diff --git a/toolchain/parser/parser_state.def b/toolchain/parser/parser_state.def index bf83e378b22f..3675db8e2d2f 100644 --- a/toolchain/parser/parser_state.def +++ b/toolchain/parser/parser_state.def @@ -145,7 +145,23 @@ CARBON_PARSER_STATE(CodeBlockFinish) // 1. DeclarationLoop CARBON_PARSER_STATE(DeclarationLoop) -// To handle parsing deduced parameter list at the end. +// Starts deduced parameter processing. +// +// Always: +// 1. PatternAsDeducedParameter +// 2. DeducedParameterFinish +CARBON_PARSER_STATE(DeducedParameter) + +// Finishes deduced parameter processing, including `,`. If there are more +// parameters, enqueues another parameter processing state. +// +// If `Comma` without `CloseSquareBracket`: +// 1. DeducedParameter +// Else: +// (state done) +CARBON_PARSER_STATE(DeducedParameterFinish) + +// Handles processing of a deduced parameter list `]`. // // Always: // (state done) @@ -233,6 +249,19 @@ CARBON_PARSER_STATE(ExpressionStatementFinish) // // If invalid: // (state done) +// If deduced parameters: +// 1. DeducedParameter +// 2. DeducedParameterListFinish +// 3. FunctionAfterDeducedParameterList +// Else: +// 1. FunctionAfterDeducedParameterList +CARBON_PARSER_STATE(FunctionIntroducer) + +// Handles processing of a functions' syntax after the deduced parameter lists's +// `]`. This applies only to interfaces and classes. +// +// If invalid: +// (state done) // If parenthesized parameters: // 1. FunctionParameter // 2. FunctionParameterListFinish @@ -240,7 +269,7 @@ CARBON_PARSER_STATE(ExpressionStatementFinish) // Else: // 1. FunctionParameterListFinish // 2. FunctionAfterParameterList -CARBON_PARSER_STATE(FunctionIntroducer) +CARBON_PARSER_STATE(FunctionAfterDeducedParameterList) // Starts function parameter processing. // @@ -373,13 +402,14 @@ CARBON_PARSER_STATE(ParenExpressionFinish) CARBON_PARSER_STATE(ParenExpressionFinishAsTuple) // Handles pattern parsing for a pattern, enqueuing type expression processing. -// This covers function parameter and `var` support. +// This covers parameter and `var` support. // // If valid: // 1. Expression // 2. PatternFinish // Else: // 1. PatternFinish +CARBON_PARSER_STATE(PatternAsDeducedParameter) CARBON_PARSER_STATE(PatternAsFunctionParameter) CARBON_PARSER_STATE(PatternAsVariable) @@ -395,15 +425,6 @@ CARBON_PARSER_STATE(PatternAddress) // (state done) CARBON_PARSER_STATE(PatternFinish) -// To start parsing `self` deduced parameter. -// -// If valid: -// 1. Expression -// 2. PatternFinish -// Else: -// 1. PatternFinish -CARBON_PARSER_STATE(SelfPattern) - // Handles a single statement. While typically within a statement block, this // can also be used for error recovery where we expect a statement block and // are missing braces. @@ -579,18 +600,4 @@ CARBON_PARSER_STATE(VarAfterPattern) CARBON_PARSER_STATE(VarFinishAsSemicolon) CARBON_PARSER_STATE(VarFinishAsFor) -// Handles processing of a functions' syntax after the deduced parameter lists's -// `]`. This applies only to interfaces and classes. -// -// If invalid: -// (state done) -// If parenthesized parameters: -// 1. FunctionParameter -// 2. FunctionParameterListFinish -// 3. FunctionAfterParameterList -// Else: -// 1. FunctionParameterListFinish -// 2. FunctionAfterParameterList -CARBON_PARSER_STATE(FunctionAfterDeducedParameterList) - #undef CARBON_PARSER_STATE diff --git a/toolchain/parser/testdata/function/declaration/addr.carbon b/toolchain/parser/testdata/function/declaration/addr.carbon new file mode 100644 index 000000000000..8ca84ed9fcd6 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/addr.carbon @@ -0,0 +1,21 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PostfixOperator', text: '*', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'Address', text: 'addr', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 10}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo(addr a: i32*); diff --git a/toolchain/parser/testdata/function/declaration/deduced_one.carbon b/toolchain/parser/testdata/function/declaration/deduced_one.carbon new file mode 100644 index 000000000000..b7534ee18659 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/deduced_one.carbon @@ -0,0 +1,21 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 10}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo[a: i32](); diff --git a/toolchain/parser/testdata/function/declaration/deduced_one_suffix_comma.carbon b/toolchain/parser/testdata/function/declaration/deduced_one_suffix_comma.carbon new file mode 100644 index 000000000000..01e130ca7929 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/deduced_one_suffix_comma.carbon @@ -0,0 +1,22 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo[a: i32,](); diff --git a/toolchain/parser/testdata/function/declaration/deduced_six.carbon b/toolchain/parser/testdata/function/declaration/deduced_six.carbon new file mode 100644 index 000000000000..306c5271ca2c --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/deduced_six.carbon @@ -0,0 +1,41 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'c'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'd'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'e'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'f'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 25}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 30}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo[a: i32, b: i32, c: i32, d: i32, e: i32, f: i32](); diff --git a/toolchain/parser/testdata/function/declaration/deduced_two.carbon b/toolchain/parser/testdata/function/declaration/deduced_two.carbon new file mode 100644 index 000000000000..df9726332fb1 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/deduced_two.carbon @@ -0,0 +1,25 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 14}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo[a: i32, b: i32](); diff --git a/toolchain/parser/testdata/function/declaration/deduced_two_suffix_comma.carbon b/toolchain/parser/testdata/function/declaration/deduced_two_suffix_comma.carbon new file mode 100644 index 000000000000..30bebd69cb8a --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/deduced_two_suffix_comma.carbon @@ -0,0 +1,26 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 10}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo[a: i32, b: i32,](); diff --git a/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon b/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon new file mode 100644 index 000000000000..0f79c7e73646 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon @@ -0,0 +1,20 @@ +// 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 +// RUN: %{not} %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Div'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// Fix and uncomment this to test error handling. +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+2]]:7: Closing symbol does not match most recent opening symbol. +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+1]]:8: Expected parameter declaration. +fn Div[(); +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+0]]:156: Expected `(` after function name. diff --git a/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon b/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon index 74aca5b2360d..7ea5f6a8d279 100644 --- a/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon @@ -8,10 +8,11 @@ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, // CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, -// CHECK:STDOUT: {kind: 'ParameterList', text: ')', has_error: yes, subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'bar'}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 6}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon:[[@LINE+1]]:8: Expected parameter declaration. +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon:[[@LINE+1]]:11: Expected parameter declaration. fn foo(bar); diff --git a/toolchain/parser/testdata/generics/interface/basic.carbon b/toolchain/parser/testdata/generics/interface/basic.carbon index 6ebf323e705a..bb9fc4f05980 100644 --- a/toolchain/parser/testdata/generics/interface/basic.carbon +++ b/toolchain/parser/testdata/generics/interface/basic.carbon @@ -38,56 +38,11 @@ // CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, // CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 15}, -// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Sub'}, -// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, -// CHECK:STDOUT: {kind: 'SelfDeducedParameter', text: ':'}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'PostfixOperator', text: '*', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'PatternBinding', text: 'self', subtree_size: 4}, -// CHECK:STDOUT: {kind: 'Address', text: 'addr', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 7}, -// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, -// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 17}, -// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Sub'}, -// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, -// CHECK:STDOUT: {kind: 'SelfDeducedParameter', text: ':'}, -// CHECK:STDOUT: {kind: 'NameReference', text: 'foo'}, -// CHECK:STDOUT: {kind: 'PostfixOperator', text: '*', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'PatternBinding', text: 'self', subtree_size: 4}, -// CHECK:STDOUT: {kind: 'Address', text: 'addr', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 7}, -// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, -// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 17}, -// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'FooFactory'}, -// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, -// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 7}, -// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 75}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 34}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] + interface Foo { fn Add[self: Self](b: Self) -> Self; fn Add[self: foo](b: Self) -> Self; - - fn Sub[addr self: Self*](b: Self) -> Self; - fn Sub[addr self: foo*](b: Self) -> Self; - - fn FooFactory() -> Self; } diff --git a/toolchain/parser/testdata/generics/interface/declaration.carbon b/toolchain/parser/testdata/generics/interface/declaration.carbon index 5e7ba8165d34..f8f405f2f672 100644 --- a/toolchain/parser/testdata/generics/interface/declaration.carbon +++ b/toolchain/parser/testdata/generics/interface/declaration.carbon @@ -5,9 +5,12 @@ // AUTOUPDATE // RUN: %{carbon-run-parser} // CHECK:STDOUT: [ -// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'InterfaceDeclaration', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -interface Foo; + +interface Foo { +} diff --git a/toolchain/parser/testdata/generics/interface/empty.carbon b/toolchain/parser/testdata/generics/interface/empty_body.carbon similarity index 100% rename from toolchain/parser/testdata/generics/interface/empty.carbon rename to toolchain/parser/testdata/generics/interface/empty_body.carbon diff --git a/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon b/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon index 5ead4add9238..4ca80fe00dd6 100644 --- a/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon +++ b/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon @@ -26,6 +26,7 @@ // CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 19}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] + interface Foo { // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon:[[@LINE+1]]:39: Method implementations are not allowed in interfaces. fn Add[self: Self](b: Self) -> Self { diff --git a/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon b/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon index c18cd69948b8..9bbb9055fc24 100644 --- a/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon +++ b/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon @@ -9,19 +9,10 @@ // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, // CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Add'}, -// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, -// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 10}, -// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Sub'}, // CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, -// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'me'}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, // CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, @@ -29,7 +20,7 @@ // CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5}, // CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, // CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 13}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Mul'}, // CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, @@ -42,37 +33,14 @@ // CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, // CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 12}, -// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Rem'}, -// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, -// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, -// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, -// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, -// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 12}, -// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 50}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 29}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -interface Foo { - fn Add(b: Self) -> Self; - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:10: Deduced parameters must be of the form: `: ` or `addr : `. +interface Foo { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:13: Expected parameter declaration. fn Sub[me Self](b: Self) -> Self; - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:10: Deduced parameters must be of the form: `: ` or `addr : `. + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:10: Expected parameter declaration. fn Mul[Self](b: Self) -> Self; - - // TODO: The recovery token is currently inserted after the `;`: - // ``` - // fn Div[me: Self(b: Self) -> Self;] - // ``` - // Fix and uncomment this to test error handling. - // fn Div[me: Self(b: Self) -> Self; - - // It is fine to have an empty deduced parameter list. - fn Rem[](b: Self) -> Self; } diff --git a/toolchain/parser/testdata/generics/interface/non_instance_fn.carbon b/toolchain/parser/testdata/generics/interface/non_instance_fn.carbon new file mode 100644 index 000000000000..12ababbba5a4 --- /dev/null +++ b/toolchain/parser/testdata/generics/interface/non_instance_fn.carbon @@ -0,0 +1,24 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'FooFactory'}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +interface Foo { + fn FooFactory() -> Self; +} diff --git a/toolchain/parser/testdata/generics/interface/self_pointer.carbon b/toolchain/parser/testdata/generics/interface/self_pointer.carbon new file mode 100644 index 000000000000..71d09420cb26 --- /dev/null +++ b/toolchain/parser/testdata/generics/interface/self_pointer.carbon @@ -0,0 +1,52 @@ +// 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 +// RUN: %{carbon-run-parser} +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Sub'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'SelfDeducedParameter', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'PostfixOperator', text: '*', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'Address', text: 'addr', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Sub'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'SelfDeducedParameter', text: 'self'}, +// CHECK:STDOUT: {kind: 'NameReference', text: 'foo'}, +// CHECK:STDOUT: {kind: 'PostfixOperator', text: '*', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'Address', text: 'addr', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 38}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +interface Foo { + fn Sub[addr self: Self*](b: Self) -> Self; + fn Sub[addr self: foo*](b: Self) -> Self; +}