diff --git a/toolchain/diagnostics/diagnostic_registry.def b/toolchain/diagnostics/diagnostic_registry.def index 43dfbb706550..4b4da600de50 100644 --- a/toolchain/diagnostics/diagnostic_registry.def +++ b/toolchain/diagnostics/diagnostic_registry.def @@ -68,19 +68,23 @@ CARBON_DIAGNOSTIC_KIND(UnexpectedTokenAfterListElement) CARBON_DIAGNOSTIC_KIND(UnexpectedTokenInCodeBlock) CARBON_DIAGNOSTIC_KIND(UnrecognizedDeclaration) -// Packaged-related diagnostics +// Package-related diagnostics. CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterPackage) CARBON_DIAGNOSTIC_KIND(ExpectedLibraryName) CARBON_DIAGNOSTIC_KIND(MissingLibraryKeyword) CARBON_DIAGNOSTIC_KIND(ExpectedApiOrImpl) CARBON_DIAGNOSTIC_KIND(ExpectedSemiToEndPackageDirective) -// For-specific diagnostics +// For-specific diagnostics. CARBON_DIAGNOSTIC_KIND(ExpectedIn) -// Interface-specific diagnostics +// Interface-specific diagnostics. CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceName) CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceOpenCurlyBrace) +CARBON_DIAGNOSTIC_KIND(MethodImplNotAllowed) + +// Class and interface diagnostics +CARBON_DIAGNOSTIC_KIND(ExpectedDeducedParam) // ============================================================================ // Semantics diagnostics diff --git a/toolchain/lexer/token_kind.def b/toolchain/lexer/token_kind.def index b8219a8e7446..3fc3121863df 100644 --- a/toolchain/lexer/token_kind.def +++ b/toolchain/lexer/token_kind.def @@ -113,56 +113,58 @@ CARBON_CLOSING_GROUP_SYMBOL_TOKEN(CloseSquareBracket, "]", OpenSquareBracket) #define CARBON_KEYWORD_TOKEN(Name, Spelling) CARBON_TOKEN(Name) #endif // clang-format off -CARBON_KEYWORD_TOKEN(Abstract, "abstract") -CARBON_KEYWORD_TOKEN(Addr, "addr") -CARBON_KEYWORD_TOKEN(Alias, "alias") -CARBON_KEYWORD_TOKEN(And, "and") -CARBON_KEYWORD_TOKEN(Api, "api") -CARBON_KEYWORD_TOKEN(As, "as") -CARBON_KEYWORD_TOKEN(Auto, "auto") -CARBON_KEYWORD_TOKEN(Base, "base") -CARBON_KEYWORD_TOKEN(Break, "break") -CARBON_KEYWORD_TOKEN(Case, "case") -CARBON_KEYWORD_TOKEN(Class, "class") -CARBON_KEYWORD_TOKEN(Constraint, "constraint") -CARBON_KEYWORD_TOKEN(Continue, "continue") -CARBON_KEYWORD_TOKEN(Default, "default") -CARBON_KEYWORD_TOKEN(Else, "else") -CARBON_KEYWORD_TOKEN(Extends, "extends") -CARBON_KEYWORD_TOKEN(External, "external") -CARBON_KEYWORD_TOKEN(Final, "final") -CARBON_KEYWORD_TOKEN(Fn, "fn") -CARBON_KEYWORD_TOKEN(For, "for") -CARBON_KEYWORD_TOKEN(In, "in") -CARBON_KEYWORD_TOKEN(Friend, "friend") -CARBON_KEYWORD_TOKEN(If, "if") -CARBON_KEYWORD_TOKEN(Impl, "impl") -CARBON_KEYWORD_TOKEN(Import, "import") -CARBON_KEYWORD_TOKEN(Interface, "interface") -CARBON_KEYWORD_TOKEN(Is, "is") -CARBON_KEYWORD_TOKEN(Let, "let") -CARBON_KEYWORD_TOKEN(Library, "library") -CARBON_KEYWORD_TOKEN(Match, "match") -CARBON_KEYWORD_TOKEN(Namespace, "namespace") -CARBON_KEYWORD_TOKEN(Not, "not") -CARBON_KEYWORD_TOKEN(Observe, "observe") -CARBON_KEYWORD_TOKEN(Or, "or") -CARBON_KEYWORD_TOKEN(Override, "override") -CARBON_KEYWORD_TOKEN(Package, "package") -CARBON_KEYWORD_TOKEN(Partial, "partial") -CARBON_KEYWORD_TOKEN(Private, "private") -CARBON_KEYWORD_TOKEN(Protected, "protected") -CARBON_KEYWORD_TOKEN(Return, "return") -CARBON_KEYWORD_TOKEN(Returned, "returned") -CARBON_KEYWORD_TOKEN(Then, "then") +CARBON_KEYWORD_TOKEN(Abstract, "abstract") +CARBON_KEYWORD_TOKEN(Addr, "addr") +CARBON_KEYWORD_TOKEN(Alias, "alias") +CARBON_KEYWORD_TOKEN(And, "and") +CARBON_KEYWORD_TOKEN(Api, "api") +CARBON_KEYWORD_TOKEN(As, "as") +CARBON_KEYWORD_TOKEN(Auto, "auto") +CARBON_KEYWORD_TOKEN(Base, "base") +CARBON_KEYWORD_TOKEN(Break, "break") +CARBON_KEYWORD_TOKEN(Case, "case") +CARBON_KEYWORD_TOKEN(Class, "class") +CARBON_KEYWORD_TOKEN(Constraint, "constraint") +CARBON_KEYWORD_TOKEN(Continue, "continue") +CARBON_KEYWORD_TOKEN(Default, "default") +CARBON_KEYWORD_TOKEN(Else, "else") +CARBON_KEYWORD_TOKEN(Extends, "extends") +CARBON_KEYWORD_TOKEN(External, "external") +CARBON_KEYWORD_TOKEN(Final, "final") +CARBON_KEYWORD_TOKEN(Fn, "fn") +CARBON_KEYWORD_TOKEN(For, "for") +CARBON_KEYWORD_TOKEN(In, "in") +CARBON_KEYWORD_TOKEN(Friend, "friend") +CARBON_KEYWORD_TOKEN(If, "if") +CARBON_KEYWORD_TOKEN(Impl, "impl") +CARBON_KEYWORD_TOKEN(Import, "import") +CARBON_KEYWORD_TOKEN(Interface, "interface") +CARBON_KEYWORD_TOKEN(Is, "is") +CARBON_KEYWORD_TOKEN(Let, "let") +CARBON_KEYWORD_TOKEN(Library, "library") +CARBON_KEYWORD_TOKEN(Match, "match") +CARBON_KEYWORD_TOKEN(Namespace, "namespace") +CARBON_KEYWORD_TOKEN(Not, "not") +CARBON_KEYWORD_TOKEN(Observe, "observe") +CARBON_KEYWORD_TOKEN(Or, "or") +CARBON_KEYWORD_TOKEN(Override, "override") +CARBON_KEYWORD_TOKEN(Package, "package") +CARBON_KEYWORD_TOKEN(Partial, "partial") +CARBON_KEYWORD_TOKEN(Private, "private") +CARBON_KEYWORD_TOKEN(Protected, "protected") +CARBON_KEYWORD_TOKEN(Return, "return") +CARBON_KEYWORD_TOKEN(Returned, "returned") +CARBON_KEYWORD_TOKEN(SelfParameter, "self") +CARBON_KEYWORD_TOKEN(SelfType, "Self") +CARBON_KEYWORD_TOKEN(Then, "then") // Underscore is tokenized as a keyword because it's part of identifiers. -CARBON_KEYWORD_TOKEN(Underscore, "_") -CARBON_KEYWORD_TOKEN(Var, "var") -CARBON_KEYWORD_TOKEN(Virtual, "virtual") -CARBON_KEYWORD_TOKEN(Where, "where") -CARBON_KEYWORD_TOKEN(While, "while") +CARBON_KEYWORD_TOKEN(Underscore, "_") +CARBON_KEYWORD_TOKEN(Var, "var") +CARBON_KEYWORD_TOKEN(Virtual, "virtual") +CARBON_KEYWORD_TOKEN(Where, "where") +CARBON_KEYWORD_TOKEN(While, "while") // TODO: In use by precedence.cpp, but not standardized. -CARBON_KEYWORD_TOKEN(Xor, "xor") +CARBON_KEYWORD_TOKEN(Xor, "xor") // clang-format on #undef CARBON_KEYWORD_TOKEN diff --git a/toolchain/lexer/token_kind_test.cpp b/toolchain/lexer/token_kind_test.cpp index 62b396aaca7f..67a3ade33279 100644 --- a/toolchain/lexer/token_kind_test.cpp +++ b/toolchain/lexer/token_kind_test.cpp @@ -21,8 +21,9 @@ using ::testing::MatchesRegex; constexpr llvm::StringLiteral SymbolRegex = R"([\[\]{}!@#%^&*()/?\\|;:.,<>=+~-]+)"; -// We restrict keywords to be lowercase ASCII letters and underscores. -constexpr llvm::StringLiteral KeywordRegex = "[a-z_]+"; +// We restrict keywords to be lowercase ASCII letters and underscores with one +// exception: `Self`. +constexpr llvm::StringLiteral KeywordRegex = "[a-z_]+|Self"; #define CARBON_TOKEN(TokenName) \ TEST(TokenKindTest, TokenName) { \ diff --git a/toolchain/parser/parse_node_kind.def b/toolchain/parser/parse_node_kind.def index 7771e6dbde3f..69488bcdf71a 100644 --- a/toolchain/parser/parse_node_kind.def +++ b/toolchain/parser/parse_node_kind.def @@ -285,6 +285,27 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(InterfaceBodyStart, 0) CARBON_PARSE_NODE_KIND_BRACKET(InterfaceBody, InterfaceBodyStart) CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDefinition, DeclaredName) +// A pattern binding for `self` deduced parameter: +// `self` +// _external_: type expression +// SelfDeducedParameter +CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfDeducedParameter, 0) + +// A pattern binding for `addr self` deduced parameter: +// `addr self` +// _external_: type expression +// SelfDeducedParameter +// CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfDeducedParameterAddress, 1) +CARBON_PARSE_NODE_KIND_CHILD_COUNT(Address, 1) +CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfType, 0) + +// Deduced parameters, such as `[self: Self]`: +// DeducedParameterListStart +// _external_: Address or PatternBinding +// DeducedParameterList +CARBON_PARSE_NODE_KIND_CHILD_COUNT(DeducedParameterListStart, 0) +CARBON_PARSE_NODE_KIND_BRACKET(DeducedParameterList, DeducedParameterListStart) + #undef CARBON_PARSE_NODE_KIND #undef CARBON_PARSE_NODE_KIND_BRACKET #undef CARBON_PARSE_NODE_KIND_CHILD_COUNT diff --git a/toolchain/parser/parser.cpp b/toolchain/parser/parser.cpp index b2aa5f7beb16..793ea8160f5c 100644 --- a/toolchain/parser/parser.cpp +++ b/toolchain/parser/parser.cpp @@ -88,7 +88,8 @@ Parser::Parser(ParseTree& tree, TokenizedBuffer& tokens, emitter_(&emitter), vlog_stream_(vlog_stream), position_(tokens_->tokens().begin()), - end_(tokens_->tokens().end()) { + end_(tokens_->tokens().end()), + stack_context_(ParseContext::File) { CARBON_CHECK(position_ != end_) << "Empty TokenizedBuffer"; --end_; CARBON_CHECK(tokens_->GetKind(*end_) == TokenKind::EndOfFile()) @@ -852,6 +853,11 @@ auto Parser::HandleExpressionInPostfixState() -> void { PushState(ParserState::ParenExpression()); break; } + case TokenKind::SelfType(): { + AddLeafNode(ParseNodeKind::SelfType(), Consume()); + PushState(state); + break; + } default: { CARBON_DIAGNOSTIC(ExpectedExpression, Error, "Expected expression."); emitter_->Emit(*position_, ExpectedExpression); @@ -1015,6 +1021,41 @@ auto Parser::HandleFunctionIntroducerState() -> void { return; } + 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()); + return; + } +} + +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, + state.has_error); +} + +auto Parser::HandleFunctionAfterDeducedParameterListState() -> void { + auto state = PopState(); + if (!PositionIs(TokenKind::OpenParen())) { CARBON_DIAGNOSTIC(ExpectedFunctionParams, Error, "Expected `(` after function name."); @@ -1029,6 +1070,7 @@ auto Parser::HandleFunctionIntroducerState() -> void { PushState(state); PushState(ParserState::FunctionParameterListFinish()); AddLeafNode(ParseNodeKind::ParameterListStart(), Consume()); + if (!PositionIs(TokenKind::CloseParen())) { PushState(ParserState::FunctionParameter()); } @@ -1096,6 +1138,15 @@ auto Parser::HandleFunctionSignatureFinishState() -> void { break; } case TokenKind::OpenCurlyBrace(): { + if (stack_context_ == ParseContext::Interface) { + CARBON_DIAGNOSTIC( + MethodImplNotAllowed, Error, + "Method implementations are not allowed in interfaces."); + emitter_->Emit(*position_, MethodImplNotAllowed); + HandleFunctionError(state, /*skip_past_likely_end=*/true); + break; + } + AddNode(ParseNodeKind::FunctionDefinitionStart(), Consume(), state.subtree_start, state.has_error); // Any error is recorded on the FunctionDefinitionStart. @@ -1307,13 +1358,78 @@ auto Parser::HandleParenExpressionFinishAsTupleState() -> void { state.has_error); } +// 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()); + // auto size = tree_->size(); + // AddLeafNode(ParseNodeKind::Address(), *position_); + AddLeafNode(ParseNodeKind::SelfDeducedParameter(), *(position_ + 1)); + // AddNode(ParseNodeKind::SelfDeducedParameterAddress(), *(position_ + 1), + // size, false); + 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::HandlePattern(PatternKind pattern_kind) -> void { auto state = PopState(); // Ensure the finish state always follows. state.state = ParserState::PatternFinish(); - // Handle an invalid pattern introducer. + // Handle an invalid pattern introducer for parameters and variables. if (!PositionIs(TokenKind::Identifier()) || tokens_->GetKind(*(position_ + 1)) != TokenKind::Colon()) { switch (pattern_kind) { @@ -1366,6 +1482,19 @@ auto Parser::HandlePatternFinishState() -> void { /*has_error=*/false); } +auto Parser::HandlePatternAddressState() -> void { + auto state = PopState(); + + // If an error was encountered, propagate it without adding a node. + if (state.has_error) { + ReturnErrorOnState(); + return; + } + + AddNode(ParseNodeKind::Address(), state.token, state.subtree_start, + /*has_error=*/false); +} + auto Parser::HandleStatementState() -> void { PopAndDiscardState(); @@ -1662,6 +1791,9 @@ auto Parser::HandleVarFinishAsForState() -> void { auto Parser::HandleInterfaceIntroducerState() -> void { auto state = PopState(); + CARBON_CHECK(stack_context_ == ParseContext::File) + << "TODO: Support nesting."; + stack_context_ = ParseContext::Interface; if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier(), ParseNodeKind::DeclaredName())) { @@ -1711,7 +1843,11 @@ auto Parser::HandleInterfaceDefinitionLoopState() -> void { break; } - // TODO: Handle possible declarations inside interface body. + case TokenKind::Fn(): { + PushState(ParserState::FunctionIntroducer()); + AddLeafNode(ParseNodeKind::FunctionIntroducer(), Consume()); + break; + } default: { CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error, "Unrecognized declaration introducer."); @@ -1731,6 +1867,7 @@ auto Parser::HandleInterfaceDefinitionFinishState() -> void { auto state = PopState(); AddNode(ParseNodeKind::InterfaceDefinition(), state.token, state.subtree_start, state.has_error); + stack_context_ = ParseContext::File; } } // namespace Carbon diff --git a/toolchain/parser/parser.h b/toolchain/parser/parser.h index 59d065250666..58573ff79088 100644 --- a/toolchain/parser/parser.h +++ b/toolchain/parser/parser.h @@ -46,6 +46,14 @@ class Parser { // Supported kinds for HandlePattern. enum class PatternKind { Parameter, Variable }; + // Gives information about the language construct/context being parsed. For + // now, a simple enum but can be extended later to provide more information as + // necessary. + enum class ParseContext { + File, // Top-level context. + Interface, + }; + // Helper class for tracing state_stack_ on crashes. class PrettyStackTraceParseState; @@ -317,6 +325,8 @@ class Parser { TokenizedBuffer::TokenIterator end_; llvm::SmallVector state_stack_; + // TODO: This can be a mini-stack of contexts rather than a simple variable. + ParseContext stack_context_; }; } // namespace Carbon diff --git a/toolchain/parser/parser_state.def b/toolchain/parser/parser_state.def index f1e9941cc639..c85b6f54b8b3 100644 --- a/toolchain/parser/parser_state.def +++ b/toolchain/parser/parser_state.def @@ -213,7 +213,7 @@ CARBON_PARSER_STATE(ExpressionStatementFinish) // If invalid: // (state done) // If parenthesized parameters: -// 1. PatternAsFunctionParameter +// 1. FunctionParameter // 2. FunctionParameterListFinish // 3. FunctionAfterParameterList // Else: @@ -557,4 +557,35 @@ CARBON_PARSER_STATE(VarAfterInitializer) 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) + +// To handle parsing deduced parameter list at the end. +// +// Always: +// (state done) +CARBON_PARSER_STATE(DeducedParameterListFinish) + +// To start parsing `self` deduced parameter. +// +// If valid: +// 1. Expression +// 2. PatternFinish +// Else: +// 1. PatternFinish +CARBON_PARSER_STATE(SelfPattern) + +CARBON_PARSER_STATE(PatternAddress) + #undef CARBON_PARSER_STATE diff --git a/toolchain/parser/testdata/generics/interface/basic.carbon b/toolchain/parser/testdata/generics/interface/basic.carbon index 27beb7ca0d17..cc8e9ad285f0 100644 --- a/toolchain/parser/testdata/generics/interface/basic.carbon +++ b/toolchain/parser/testdata/generics/interface/basic.carbon @@ -7,9 +7,87 @@ // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, // CHECK:STDOUT: {kind: 'InterfaceBodyStart', text: '{'}, -// CHECK:STDOUT: {kind: 'InterfaceBody', text: '}', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Add'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'SelfDeducedParameter', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 5}, +// 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: 15}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Add'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'SelfDeducedParameter', text: 'self'}, +// CHECK:STDOUT: {kind: 'NameReference', text: 'foo'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 5}, +// 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: 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: 'InterfaceBody', text: '}', subtree_size: 73}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', subtree_size: 75}, // 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/empty.carbon b/toolchain/parser/testdata/generics/interface/empty.carbon new file mode 100644 index 000000000000..27beb7ca0d17 --- /dev/null +++ b/toolchain/parser/testdata/generics/interface/empty.carbon @@ -0,0 +1,15 @@ +// 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: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'InterfaceBodyStart', text: '{'}, +// CHECK:STDOUT: {kind: 'InterfaceBody', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +interface foo { +} diff --git a/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon b/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon new file mode 100644 index 000000000000..858c9066e363 --- /dev/null +++ b/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon @@ -0,0 +1,34 @@ +// 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: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'InterfaceBodyStart', text: '{'}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Add'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'SelfDeducedParameter', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfType', text: 'Self'}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', subtree_size: 5}, +// 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: 'fn', has_error: yes, subtree_size: 15}, +// CHECK:STDOUT: {kind: 'InterfaceBody', text: '}', subtree_size: 17}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', 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 { + print("You can't do that."); + } +} diff --git a/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon b/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon new file mode 100644 index 000000000000..904743624fc4 --- /dev/null +++ b/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon @@ -0,0 +1,78 @@ +// 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: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {kind: 'InterfaceBodyStart', text: '{'}, +// 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: '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: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DeclaredName', text: 'Mul'}, +// CHECK:STDOUT: {kind: 'DeducedParameterListStart', text: '['}, +// CHECK:STDOUT: {kind: 'DeducedParameterList', text: ']', has_error: yes, 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: '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: 'InterfaceBody', text: '}', subtree_size: 48}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', subtree_size: 50}, +// 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 : `. + 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 : `. + 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/semantics/semantics_parse_tree_handler.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp index a75f7248cab8..69d01c63c7a6 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.cpp +++ b/toolchain/semantics/semantics_parse_tree_handler.cpp @@ -626,4 +626,28 @@ auto SemanticsParseTreeHandler::HandleWhileStatement( CARBON_FATAL() << "TODO"; } +auto SemanticsParseTreeHandler::HandleAddress(ParseTree::Node /*parse_node*/) + -> void { + CARBON_FATAL() << "TODO"; +} + +auto SemanticsParseTreeHandler::HandleSelfType(ParseTree::Node /*parse_node*/) + -> void { + CARBON_FATAL() << "TODO"; +} + +auto SemanticsParseTreeHandler::HandleDeducedParameterList( + ParseTree::Node /*parse_node*/) -> void { + CARBON_FATAL() << "TODO"; +} + +auto SemanticsParseTreeHandler::HandleSelfDeducedParameter( + ParseTree::Node /*parse_node*/) -> void { + CARBON_FATAL() << "TODO"; +} + +auto SemanticsParseTreeHandler::HandleDeducedParameterListStart( + ParseTree::Node /*parse_node*/) -> void { + CARBON_FATAL() << "TODO"; +} } // namespace Carbon