Просмотр исходного кода

[parser] More support for `interface`s: methods and `self` deduced param. (#2427)

Summary:

Extends the current support for parsing `interface`s. In particular, adds support for parsing functions and `me` params.
Kareem Ergawy 3 лет назад
Родитель
Сommit
c74e39dbb3

+ 7 - 3
toolchain/diagnostics/diagnostic_registry.def

@@ -68,19 +68,23 @@ CARBON_DIAGNOSTIC_KIND(UnexpectedTokenAfterListElement)
 CARBON_DIAGNOSTIC_KIND(UnexpectedTokenInCodeBlock)
 CARBON_DIAGNOSTIC_KIND(UnexpectedTokenInCodeBlock)
 CARBON_DIAGNOSTIC_KIND(UnrecognizedDeclaration)
 CARBON_DIAGNOSTIC_KIND(UnrecognizedDeclaration)
 
 
-// Packaged-related diagnostics
+// Package-related diagnostics.
 CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterPackage)
 CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterPackage)
 CARBON_DIAGNOSTIC_KIND(ExpectedLibraryName)
 CARBON_DIAGNOSTIC_KIND(ExpectedLibraryName)
 CARBON_DIAGNOSTIC_KIND(MissingLibraryKeyword)
 CARBON_DIAGNOSTIC_KIND(MissingLibraryKeyword)
 CARBON_DIAGNOSTIC_KIND(ExpectedApiOrImpl)
 CARBON_DIAGNOSTIC_KIND(ExpectedApiOrImpl)
 CARBON_DIAGNOSTIC_KIND(ExpectedSemiToEndPackageDirective)
 CARBON_DIAGNOSTIC_KIND(ExpectedSemiToEndPackageDirective)
 
 
-// For-specific diagnostics
+// For-specific diagnostics.
 CARBON_DIAGNOSTIC_KIND(ExpectedIn)
 CARBON_DIAGNOSTIC_KIND(ExpectedIn)
 
 
-// Interface-specific diagnostics
+// Interface-specific diagnostics.
 CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceName)
 CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceName)
 CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceOpenCurlyBrace)
 CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceOpenCurlyBrace)
+CARBON_DIAGNOSTIC_KIND(MethodImplNotAllowed)
+
+// Class and interface diagnostics
+CARBON_DIAGNOSTIC_KIND(ExpectedDeducedParam)
 
 
 // ============================================================================
 // ============================================================================
 // Semantics diagnostics
 // Semantics diagnostics

+ 50 - 48
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)
 #define CARBON_KEYWORD_TOKEN(Name, Spelling) CARBON_TOKEN(Name)
 #endif
 #endif
 // clang-format off
 // 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.
 // 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.
 // TODO: In use by precedence.cpp, but not standardized.
-CARBON_KEYWORD_TOKEN(Xor,        "xor")
+CARBON_KEYWORD_TOKEN(Xor,           "xor")
 // clang-format on
 // clang-format on
 #undef CARBON_KEYWORD_TOKEN
 #undef CARBON_KEYWORD_TOKEN
 
 

+ 3 - 2
toolchain/lexer/token_kind_test.cpp

@@ -21,8 +21,9 @@ using ::testing::MatchesRegex;
 constexpr llvm::StringLiteral SymbolRegex =
 constexpr llvm::StringLiteral SymbolRegex =
     R"([\[\]{}!@#%^&*()/?\\|;:.,<>=+~-]+)";
     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)                             \
 #define CARBON_TOKEN(TokenName)                             \
   TEST(TokenKindTest, TokenName) {                          \
   TEST(TokenKindTest, TokenName) {                          \

+ 21 - 0
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(InterfaceBody, InterfaceBodyStart)
 CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDefinition, DeclaredName)
 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
 #undef CARBON_PARSE_NODE_KIND_BRACKET
 #undef CARBON_PARSE_NODE_KIND_BRACKET
 #undef CARBON_PARSE_NODE_KIND_CHILD_COUNT
 #undef CARBON_PARSE_NODE_KIND_CHILD_COUNT

+ 140 - 3
toolchain/parser/parser.cpp

@@ -88,7 +88,8 @@ Parser::Parser(ParseTree& tree, TokenizedBuffer& tokens,
       emitter_(&emitter),
       emitter_(&emitter),
       vlog_stream_(vlog_stream),
       vlog_stream_(vlog_stream),
       position_(tokens_->tokens().begin()),
       position_(tokens_->tokens().begin()),
-      end_(tokens_->tokens().end()) {
+      end_(tokens_->tokens().end()),
+      stack_context_(ParseContext::File) {
   CARBON_CHECK(position_ != end_) << "Empty TokenizedBuffer";
   CARBON_CHECK(position_ != end_) << "Empty TokenizedBuffer";
   --end_;
   --end_;
   CARBON_CHECK(tokens_->GetKind(*end_) == TokenKind::EndOfFile())
   CARBON_CHECK(tokens_->GetKind(*end_) == TokenKind::EndOfFile())
@@ -852,6 +853,11 @@ auto Parser::HandleExpressionInPostfixState() -> void {
       PushState(ParserState::ParenExpression());
       PushState(ParserState::ParenExpression());
       break;
       break;
     }
     }
+    case TokenKind::SelfType(): {
+      AddLeafNode(ParseNodeKind::SelfType(), Consume());
+      PushState(state);
+      break;
+    }
     default: {
     default: {
       CARBON_DIAGNOSTIC(ExpectedExpression, Error, "Expected expression.");
       CARBON_DIAGNOSTIC(ExpectedExpression, Error, "Expected expression.");
       emitter_->Emit(*position_, ExpectedExpression);
       emitter_->Emit(*position_, ExpectedExpression);
@@ -1015,6 +1021,41 @@ auto Parser::HandleFunctionIntroducerState() -> void {
     return;
     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())) {
   if (!PositionIs(TokenKind::OpenParen())) {
     CARBON_DIAGNOSTIC(ExpectedFunctionParams, Error,
     CARBON_DIAGNOSTIC(ExpectedFunctionParams, Error,
                       "Expected `(` after function name.");
                       "Expected `(` after function name.");
@@ -1029,6 +1070,7 @@ auto Parser::HandleFunctionIntroducerState() -> void {
   PushState(state);
   PushState(state);
   PushState(ParserState::FunctionParameterListFinish());
   PushState(ParserState::FunctionParameterListFinish());
   AddLeafNode(ParseNodeKind::ParameterListStart(), Consume());
   AddLeafNode(ParseNodeKind::ParameterListStart(), Consume());
+
   if (!PositionIs(TokenKind::CloseParen())) {
   if (!PositionIs(TokenKind::CloseParen())) {
     PushState(ParserState::FunctionParameter());
     PushState(ParserState::FunctionParameter());
   }
   }
@@ -1096,6 +1138,15 @@ auto Parser::HandleFunctionSignatureFinishState() -> void {
       break;
       break;
     }
     }
     case TokenKind::OpenCurlyBrace(): {
     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(),
       AddNode(ParseNodeKind::FunctionDefinitionStart(), Consume(),
               state.subtree_start, state.has_error);
               state.subtree_start, state.has_error);
       // Any error is recorded on the FunctionDefinitionStart.
       // Any error is recorded on the FunctionDefinitionStart.
@@ -1307,13 +1358,78 @@ auto Parser::HandleParenExpressionFinishAsTupleState() -> void {
           state.has_error);
           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: `<name>: <Type>` "
+                    "or `addr <name>: <Type>`.");
+  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 Parser::HandlePattern(PatternKind pattern_kind) -> void {
   auto state = PopState();
   auto state = PopState();
 
 
   // Ensure the finish state always follows.
   // Ensure the finish state always follows.
   state.state = ParserState::PatternFinish();
   state.state = ParserState::PatternFinish();
 
 
-  // Handle an invalid pattern introducer.
+  // Handle an invalid pattern introducer for parameters and variables.
   if (!PositionIs(TokenKind::Identifier()) ||
   if (!PositionIs(TokenKind::Identifier()) ||
       tokens_->GetKind(*(position_ + 1)) != TokenKind::Colon()) {
       tokens_->GetKind(*(position_ + 1)) != TokenKind::Colon()) {
     switch (pattern_kind) {
     switch (pattern_kind) {
@@ -1366,6 +1482,19 @@ auto Parser::HandlePatternFinishState() -> void {
           /*has_error=*/false);
           /*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 {
 auto Parser::HandleStatementState() -> void {
   PopAndDiscardState();
   PopAndDiscardState();
 
 
@@ -1662,6 +1791,9 @@ auto Parser::HandleVarFinishAsForState() -> void {
 
 
 auto Parser::HandleInterfaceIntroducerState() -> void {
 auto Parser::HandleInterfaceIntroducerState() -> void {
   auto state = PopState();
   auto state = PopState();
+  CARBON_CHECK(stack_context_ == ParseContext::File)
+      << "TODO: Support nesting.";
+  stack_context_ = ParseContext::Interface;
 
 
   if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier(),
   if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier(),
                                ParseNodeKind::DeclaredName())) {
                                ParseNodeKind::DeclaredName())) {
@@ -1711,7 +1843,11 @@ auto Parser::HandleInterfaceDefinitionLoopState() -> void {
 
 
       break;
       break;
     }
     }
-      // TODO: Handle possible declarations inside interface body.
+    case TokenKind::Fn(): {
+      PushState(ParserState::FunctionIntroducer());
+      AddLeafNode(ParseNodeKind::FunctionIntroducer(), Consume());
+      break;
+    }
     default: {
     default: {
       CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error,
       CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error,
                         "Unrecognized declaration introducer.");
                         "Unrecognized declaration introducer.");
@@ -1731,6 +1867,7 @@ auto Parser::HandleInterfaceDefinitionFinishState() -> void {
   auto state = PopState();
   auto state = PopState();
   AddNode(ParseNodeKind::InterfaceDefinition(), state.token,
   AddNode(ParseNodeKind::InterfaceDefinition(), state.token,
           state.subtree_start, state.has_error);
           state.subtree_start, state.has_error);
+  stack_context_ = ParseContext::File;
 }
 }
 
 
 }  // namespace Carbon
 }  // namespace Carbon

+ 10 - 0
toolchain/parser/parser.h

@@ -46,6 +46,14 @@ class Parser {
   // Supported kinds for HandlePattern.
   // Supported kinds for HandlePattern.
   enum class PatternKind { Parameter, Variable };
   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.
   // Helper class for tracing state_stack_ on crashes.
   class PrettyStackTraceParseState;
   class PrettyStackTraceParseState;
 
 
@@ -317,6 +325,8 @@ class Parser {
   TokenizedBuffer::TokenIterator end_;
   TokenizedBuffer::TokenIterator end_;
 
 
   llvm::SmallVector<StateStackEntry> state_stack_;
   llvm::SmallVector<StateStackEntry> state_stack_;
+  // TODO: This can be a mini-stack of contexts rather than a simple variable.
+  ParseContext stack_context_;
 };
 };
 
 
 }  // namespace Carbon
 }  // namespace Carbon

+ 32 - 1
toolchain/parser/parser_state.def

@@ -213,7 +213,7 @@ CARBON_PARSER_STATE(ExpressionStatementFinish)
 // If invalid:
 // If invalid:
 //   (state done)
 //   (state done)
 // If parenthesized parameters:
 // If parenthesized parameters:
-//   1. PatternAsFunctionParameter
+//   1. FunctionParameter
 //   2. FunctionParameterListFinish
 //   2. FunctionParameterListFinish
 //   3. FunctionAfterParameterList
 //   3. FunctionAfterParameterList
 // Else:
 // Else:
@@ -557,4 +557,35 @@ CARBON_PARSER_STATE(VarAfterInitializer)
 CARBON_PARSER_STATE(VarFinishAsSemicolon)
 CARBON_PARSER_STATE(VarFinishAsSemicolon)
 CARBON_PARSER_STATE(VarFinishAsFor)
 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
 #undef CARBON_PARSER_STATE

+ 80 - 2
toolchain/parser/testdata/generics/interface/basic.carbon

@@ -7,9 +7,87 @@
 // CHECK:STDOUT: [
 // CHECK:STDOUT: [
 // CHECK:STDOUT:   {kind: 'DeclaredName', text: 'foo'},
 // CHECK:STDOUT:   {kind: 'DeclaredName', text: 'foo'},
 // CHECK:STDOUT:     {kind: 'InterfaceBodyStart', text: '{'},
 // 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: {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 interface foo {
 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;
 }
 }

+ 15 - 0
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 {
+}

+ 34 - 0
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.");
+  }
+}

+ 78 - 0
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: `<name>: <Type>` or `addr <name>: <Type>`.
+  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: `<name>: <Type>` or `addr <name>: <Type>`.
+  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;
+}

+ 24 - 0
toolchain/semantics/semantics_parse_tree_handler.cpp

@@ -626,4 +626,28 @@ auto SemanticsParseTreeHandler::HandleWhileStatement(
   CARBON_FATAL() << "TODO";
   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
 }  // namespace Carbon