From 26381f6eaf34fbfd37b23c36f6bb6a7f55a36f0a Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 23 Oct 2025 14:34:52 -0400 Subject: [PATCH] Handle parsing of `require`...`impls` declarations (#6255) Check is not implemented yet, but some tests are added. --- toolchain/check/handle_impl.cpp | 4 +- toolchain/check/handle_require.cpp | 30 ++ toolchain/check/impl.cpp | 4 +- toolchain/check/merge.cpp | 8 +- toolchain/check/node_stack.h | 3 + .../testdata/facet/require_invalid.carbon | 54 ++++ .../check/testdata/interface/require.carbon | 275 ++++++++++++++++++ .../testdata/named_constraint/convert.carbon | 6 +- toolchain/diagnostics/diagnostic_kind.def | 1 + toolchain/parse/handle_decl_scope_loop.cpp | 3 + toolchain/parse/handle_impl.cpp | 4 +- toolchain/parse/handle_require.cpp | 48 +++ toolchain/parse/node_category.h | 27 +- toolchain/parse/node_ids.h | 1 + toolchain/parse/node_kind.def | 9 +- toolchain/parse/precedence.h | 4 + toolchain/parse/state.def | 36 ++- .../testdata/function/decl_statement.carbon | 6 +- .../parse/testdata/function/definition.carbon | 2 +- .../parse/testdata/generics/impl/basic.carbon | 2 +- .../parse/testdata/generics/impl/class.carbon | 10 +- .../testdata/generics/impl/declaration.carbon | 2 +- .../testdata/generics/impl/empty_body.carbon | 2 +- .../testdata/generics/impl/fail_impl.carbon | 8 +- .../impl/fail_out_of_line_member.carbon | 4 +- .../testdata/generics/impl/forall.carbon | 4 +- .../generics/interface/require.carbon | 240 +++++++++++++++ .../testdata/packages/package/impl.carbon | 4 +- .../testdata/where_expr/impl_where.carbon | 10 +- toolchain/parse/typed_nodes.h | 40 ++- 30 files changed, 790 insertions(+), 61 deletions(-) create mode 100644 toolchain/check/handle_require.cpp create mode 100644 toolchain/check/testdata/facet/require_invalid.carbon create mode 100644 toolchain/check/testdata/interface/require.carbon create mode 100644 toolchain/parse/handle_require.cpp create mode 100644 toolchain/parse/testdata/generics/interface/require.carbon diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index 4249ce30bf3a..a97295718f74 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -54,7 +54,7 @@ auto HandleParseNode(Context& context, Parse::ForallId /*node_id*/) -> bool { return true; } -auto HandleParseNode(Context& context, Parse::TypeImplAsId node_id) -> bool { +auto HandleParseNode(Context& context, Parse::ImplTypeAsId node_id) -> bool { auto [self_node, self_id] = context.node_stack().PopExprWithNodeId(); auto self_type_inst_id = ExprAsType(context, self_node, self_id).inst_id; context.node_stack().Push(node_id, self_type_inst_id); @@ -67,7 +67,7 @@ auto HandleParseNode(Context& context, Parse::TypeImplAsId node_id) -> bool { return true; } -auto HandleParseNode(Context& context, Parse::DefaultSelfImplAsId node_id) +auto HandleParseNode(Context& context, Parse::ImplDefaultSelfAsId node_id) -> bool { auto self_inst_id = SemIR::TypeInstId::None; diff --git a/toolchain/check/handle_require.cpp b/toolchain/check/handle_require.cpp new file mode 100644 index 000000000000..67e50c66efc7 --- /dev/null +++ b/toolchain/check/handle_require.cpp @@ -0,0 +1,30 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/check/context.h" +#include "toolchain/check/handle.h" +#include "toolchain/parse/node_ids.h" + +namespace Carbon::Check { + +auto HandleParseNode(Context& context, Parse::RequireIntroducerId node_id) + -> bool { + return context.TODO(node_id, "require"); +} + +auto HandleParseNode(Context& context, Parse::RequireDefaultSelfImplsId node_id) + -> bool { + return context.TODO(node_id, "require"); +} + +auto HandleParseNode(Context& context, Parse::RequireTypeImplsId node_id) + -> bool { + return context.TODO(node_id, "require"); +} + +auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool { + return context.TODO(node_id, "require"); +} + +} // namespace Carbon::Check diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index 93af7eec2ae6..f9db8bea0600 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -433,7 +433,7 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node, const auto& impl = context.impls().Get(impl_id); if (context.parse_tree().node_kind(self_type_node_id) == - Parse::NodeKind::TypeImplAs) { + Parse::NodeKind::ImplTypeAs) { CARBON_DIAGNOSTIC(ExtendImplSelfAs, Error, "cannot `extend` an `impl` with an explicit self type"); auto diag = context.emitter().Build(extend_node, ExtendImplSelfAs); @@ -448,7 +448,7 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node, // The explicit self type is the same as the default self type, so suggest // removing it and recover as if it were not present. if (auto self_as = - context.parse_tree_and_subtrees().ExtractAs( + context.parse_tree_and_subtrees().ExtractAs( self_type_node_id)) { CARBON_DIAGNOSTIC(ExtendImplSelfAsDefault, Note, "remove the explicit `Self` type here"); diff --git a/toolchain/check/merge.cpp b/toolchain/check/merge.cpp index e0ea4c247168..5d71e7ac62fb 100644 --- a/toolchain/check/merge.cpp +++ b/toolchain/check/merge.cpp @@ -461,17 +461,17 @@ static auto CheckRedeclParamSyntax(Context& context, // https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p3763.md#redeclarations auto new_node_kind = context.parse_tree().node_kind(new_node_id); auto prev_node_kind = context.parse_tree().node_kind(prev_node_id); - if (new_node_kind == Parse::NodeKind::DefaultSelfImplAs && + if (new_node_kind == Parse::NodeKind::ImplDefaultSelfAs && prev_node_kind == Parse::NodeKind::SelfTypeNameExpr && context.parse_tree().node_kind(prev_iter[1]) == - Parse::NodeKind::TypeImplAs) { + Parse::NodeKind::ImplTypeAs) { ++prev_iter; continue; } - if (prev_node_kind == Parse::NodeKind::DefaultSelfImplAs && + if (prev_node_kind == Parse::NodeKind::ImplDefaultSelfAs && new_node_kind == Parse::NodeKind::SelfTypeNameExpr && context.parse_tree().node_kind(new_iter[1]) == - Parse::NodeKind::TypeImplAs) { + Parse::NodeKind::ImplTypeAs) { ++new_iter; continue; } diff --git a/toolchain/check/node_stack.h b/toolchain/check/node_stack.h index 168949e78f05..1428ae19d850 100644 --- a/toolchain/check/node_stack.h +++ b/toolchain/check/node_stack.h @@ -523,6 +523,9 @@ class NodeStack { case Parse::NodeKind::ParenExprStart: case Parse::NodeKind::PatternListComma: case Parse::NodeKind::Placeholder: + case Parse::NodeKind::RequireIntroducer: + case Parse::NodeKind::RequireDefaultSelfImpls: + case Parse::NodeKind::RequireTypeImpls: case Parse::NodeKind::RequirementAnd: case Parse::NodeKind::RequirementEqual: case Parse::NodeKind::RequirementEqualEqual: diff --git a/toolchain/check/testdata/facet/require_invalid.carbon b/toolchain/check/testdata/facet/require_invalid.carbon new file mode 100644 index 000000000000..0589354e2782 --- /dev/null +++ b/toolchain/check/testdata/facet/require_invalid.carbon @@ -0,0 +1,54 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/facet/require_invalid.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/facet/require_invalid.carbon + +// --- fail_todo_require_outside_scope.carbon +library "[[@TEST_NAME]]"; + +interface Y {} + +// CHECK:STDERR: fail_todo_require_outside_scope.carbon:[[@LINE+4]]:1: error: semantics TODO: `require` [SemanticsTodo] +// CHECK:STDERR: require impls Y; +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: +require impls Y; + +// --- fail_todo_require_in_class.carbon +library "[[@TEST_NAME]]"; + +interface Y {} + +class C { + // TODO: require is not allowed outside of `interface` or `constraint`. + // CHECK:STDERR: fail_todo_require_in_class.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require impls Y; +} + +// --- fail_require_in_fn.carbon +library "[[@TEST_NAME]]"; + +interface Y {} + +fn F() { + // require is not allowed outside of `interface` or `constraint`. + // CHECK:STDERR: fail_require_in_fn.carbon:[[@LINE+8]]:3: error: expected expression [ExpectedExpr] + // CHECK:STDERR: require impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_require_in_fn.carbon:[[@LINE+4]]:3: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo] + // CHECK:STDERR: require impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require impls Y; +} diff --git a/toolchain/check/testdata/interface/require.carbon b/toolchain/check/testdata/interface/require.carbon new file mode 100644 index 000000000000..50e7efd2deb5 --- /dev/null +++ b/toolchain/check/testdata/interface/require.carbon @@ -0,0 +1,275 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/require.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/require.carbon + +// --- fail_todo_implicit_self_impls.carbon +library "[[@TEST_NAME]]"; + +interface Y { + fn YY(); +} + +//@dump-sem-ir-begin +interface Z { + // CHECK:STDERR: fail_todo_implicit_self_impls.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require impls Y; +} +//@dump-sem-ir-end + +fn F(T:! Z) { + T.(Y.YY)(); +} + +// --- fail_todo_explicit_self_impls.carbon +library "[[@TEST_NAME]]"; + +interface Y { + fn YY(); +} + +//@dump-sem-ir-begin +interface Z { + // CHECK:STDERR: fail_todo_explicit_self_impls.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require Self impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require Self impls Y; +} +//@dump-sem-ir-end + +fn F(T:! Z) { + T.(Y.YY)(); +} + +// --- fail_todo_implicit_self_no_extend_name_lookup_fails.carbon +library "[[@TEST_NAME]]"; + +interface Y { + fn YY(); +} + +interface Z { + // CHECK:STDERR: fail_todo_implicit_self_no_extend_name_lookup_fails.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require impls Y; +} + +fn F(T:! Z) { + // TODO: This should fail name lookup since Z does not extend Y. + T.YY(); +} + +// --- fail_todo_explicit_self_no_extend_name_lookup_fails.carbon +library "[[@TEST_NAME]]"; + +interface Y { + fn YY(); +} + +interface Z { + // CHECK:STDERR: fail_todo_explicit_self_no_extend_name_lookup_fails.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require Self impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require Self impls Y; +} + +fn F(T:! Z) { + // TODO: This should fail name lookup since Z does not extend Y. + T.YY(); +} + +// --- fail_todo_explicit_self_specific_impls.carbon +library "[[@TEST_NAME]]"; + +interface Y {} + +class C(T:! type); + +//@dump-sem-ir-begin +interface Z { + // CHECK:STDERR: fail_todo_explicit_self_specific_impls.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require C(Self) impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require C(Self) impls Y; +} +//@dump-sem-ir-end + +// --- fail_todo_impls_where.carbon +library "[[@TEST_NAME]]"; + +interface Y { let Y1:! type; } + +//@dump-sem-ir-begin +interface Z { + // CHECK:STDERR: fail_todo_impls_where.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require impls Y where .Y1 = (); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require impls Y where .Y1 = (); +} +//@dump-sem-ir-end + +// --- fail_todo_other_impls_with_self.carbon +library "[[@TEST_NAME]]"; + +interface Y {} + +//@dump-sem-ir-begin +interface Z(T:! type) { + // CHECK:STDERR: fail_todo_other_impls_with_self.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require T impls Z(Self); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require T impls Z(Self); +} +//@dump-sem-ir-end + +// --- fail_todo_other_impls_without_self.carbon +library "[[@TEST_NAME]]"; + +interface Y {} + +//@dump-sem-ir-begin +interface Z(T:! type) { + // TODO: Either the type `T` or the facet type `Y` must mention `Self`, but + // they don't. + // CHECK:STDERR: fail_todo_other_impls_without_self.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: require T impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + require T impls Y; +} +//@dump-sem-ir-end + +// --- fail_todo_extend.carbon +library "[[@TEST_NAME]]"; + +interface Y { + fn YY(); +} + +//@dump-sem-ir-begin +interface Z { + // CHECK:STDERR: fail_todo_extend.carbon:[[@LINE+4]]:10: error: semantics TODO: `require` [SemanticsTodo] + // CHECK:STDERR: extend require impls Y; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + extend require impls Y; +} +//@dump-sem-ir-end + +fn F(T:! Z) { + T.YY(); + T.(Y.YY)(); +} + +// CHECK:STDOUT: --- fail_todo_implicit_self_impls.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Z { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = .inst6000001D +// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_explicit_self_impls.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Z { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = .inst5000001D +// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_explicit_self_specific_impls.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Z { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = .inst68000023 +// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_impls_where.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Z { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = .inst5800001A +// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_other_impls_with_self.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic interface @Z(.inst78000017.loc6_13: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: interface { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = .inst78000021 +// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Z(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_other_impls_without_self.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic interface @Z(.inst44000017.loc6_13: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: interface { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = .inst44000021 +// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Z(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_extend.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Z { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = .inst6400001D +// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/named_constraint/convert.carbon b/toolchain/check/testdata/named_constraint/convert.carbon index d81a97db2d26..b0b23ce3ad8c 100644 --- a/toolchain/check/testdata/named_constraint/convert.carbon +++ b/toolchain/check/testdata/named_constraint/convert.carbon @@ -43,11 +43,7 @@ library "[[@TEST_NAME]]"; interface Z {} constraint E { - // CHECK:STDERR: fail_todo_unspecified.carbon:[[@LINE+8]]:3: error: unrecognized declaration introducer [UnrecognizedDecl] - // CHECK:STDERR: require impls Z; - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_unspecified.carbon:[[@LINE+4]]:3: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo] + // CHECK:STDERR: fail_todo_unspecified.carbon:[[@LINE+4]]:3: error: semantics TODO: `require` [SemanticsTodo] // CHECK:STDERR: require impls Z; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 656f1c3281b3..ab17f5f97b2c 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -162,6 +162,7 @@ CARBON_DIAGNOSTIC_KIND(ImplExpectedAfterForall) CARBON_DIAGNOSTIC_KIND(ImplExpectedAs) CARBON_DIAGNOSTIC_KIND(ExpectedAssociatedConstantIdentifier) CARBON_DIAGNOSTIC_KIND(ExpectedAssociatedConstantColonExclaim) +CARBON_DIAGNOSTIC_KIND(RequireExpectedImpls) // Alias diagnostics. CARBON_DIAGNOSTIC_KIND(ExpectedAliasInitializer) diff --git a/toolchain/parse/handle_decl_scope_loop.cpp b/toolchain/parse/handle_decl_scope_loop.cpp index 94e2b8c4e69b..dab82e216b4c 100644 --- a/toolchain/parse/handle_decl_scope_loop.cpp +++ b/toolchain/parse/handle_decl_scope_loop.cpp @@ -130,6 +130,8 @@ static constexpr auto DeclIntroducers = [] { StateKind::TypeAfterIntroducerAsInterface); set(Lex::TokenKind::Namespace, NodeKind::NamespaceStart, StateKind::Namespace); + set(Lex::TokenKind::Require, NodeKind::RequireIntroducer, + StateKind::RequireAfterIntroducer); set_contextual(Lex::TokenKind::Let, RegularContext, NodeKind::LetIntroducer, StateKind::Let); set_contextual(Lex::TokenKind::Let, ClassContext, NodeKind::LetIntroducer, @@ -225,6 +227,7 @@ static auto ResolveAmbiguousTokenAsDeclaration(Context& context, case Lex::TokenKind::Let: case Lex::TokenKind::Library: case Lex::TokenKind::Namespace: + case Lex::TokenKind::Require: case Lex::TokenKind::Var: #define CARBON_PARSE_NODE_KIND(Name) #define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name) case Lex::TokenKind::Name: diff --git a/toolchain/parse/handle_impl.cpp b/toolchain/parse/handle_impl.cpp index 3d037cf77309..f49efb88050c 100644 --- a/toolchain/parse/handle_impl.cpp +++ b/toolchain/parse/handle_impl.cpp @@ -10,7 +10,7 @@ namespace Carbon::Parse { static auto ExpectAsOrTypeExpression(Context& context) -> void { if (context.PositionIs(Lex::TokenKind::As)) { // as ... - context.AddLeafNode(NodeKind::DefaultSelfImplAs, context.Consume()); + context.AddLeafNode(NodeKind::ImplDefaultSelfAs, context.Consume()); context.PushState(StateKind::Expr); } else { // as ... @@ -62,7 +62,7 @@ auto HandleImplAfterForall(Context& context) -> void { auto HandleImplBeforeAs(Context& context) -> void { auto state = context.PopState(); if (auto as = context.ConsumeIf(Lex::TokenKind::As)) { - context.AddNode(NodeKind::TypeImplAs, *as, state.has_error); + context.AddNode(NodeKind::ImplTypeAs, *as, state.has_error); context.PushState(StateKind::Expr); } else { if (!state.has_error) { diff --git a/toolchain/parse/handle_require.cpp b/toolchain/parse/handle_require.cpp new file mode 100644 index 000000000000..93c89466b02a --- /dev/null +++ b/toolchain/parse/handle_require.cpp @@ -0,0 +1,48 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/parse/context.h" +#include "toolchain/parse/handle.h" + +namespace Carbon::Parse { + +auto HandleRequireAfterIntroducer(Context& context) -> void { + auto state = context.PopState(); + state.kind = StateKind::RequireDecl; + context.PushState(state); + + if (context.PositionIs(Lex::TokenKind::Impls)) { + // impls ... + context.AddLeafNode(NodeKind::RequireDefaultSelfImpls, context.Consume()); + context.PushState(StateKind::Expr); + } else { + // impls ... + context.PushState(StateKind::RequireBeforeImpls); + context.PushStateForExpr(PrecedenceGroup::ForRequirements()); + } +} + +auto HandleRequireBeforeImpls(Context& context) -> void { + auto state = context.PopState(); + if (auto impls = context.ConsumeIf(Lex::TokenKind::Impls)) { + context.AddNode(NodeKind::RequireTypeImpls, *impls, state.has_error); + context.PushState(StateKind::Expr); + } else { + if (!state.has_error) { + CARBON_DIAGNOSTIC(RequireExpectedImpls, Error, + "expected `impls` in `require` declaration"); + context.emitter().Emit(*context.position(), RequireExpectedImpls); + } + context.ReturnErrorOnState(); + } +} + +auto HandleRequireDecl(Context& context) -> void { + auto state = context.PopState(); + context.AddNodeExpectingDeclSemi(state, NodeKind::RequireDecl, + Lex::TokenKind::Require, + /*is_def_allowed=*/false); +} + +} // namespace Carbon::Parse diff --git a/toolchain/parse/node_category.h b/toolchain/parse/node_category.h index 1408a79eb0be..0cbc999a75db 100644 --- a/toolchain/parse/node_category.h +++ b/toolchain/parse/node_category.h @@ -15,18 +15,21 @@ namespace Carbon::Parse { // #define CARBON_NODE_CATEGORY_FOR_XYZ(Name) ... // CARBON_NODE_CATEGORY(CARBON_NODE_CATEGORY_FOR_XYZ) // #undef CARBON_NODE_CATEGORY_FOR_XYZ -#define CARBON_NODE_CATEGORY(X) \ - X(Decl) \ - X(Expr) \ - X(ImplAs) \ - X(IntConst) \ - X(MemberExpr) \ - X(MemberName) \ - X(Modifier) \ - X(NonExprName) \ - X(PackageName) \ - X(Pattern) \ - X(Requirement) \ +#define CARBON_NODE_CATEGORY(X) \ + X(Decl) \ + X(Expr) \ + /* `impl as` or just `impl as` */ \ + X(ImplAs) \ + X(IntConst) \ + X(MemberExpr) \ + X(MemberName) \ + X(Modifier) \ + X(NonExprName) \ + X(PackageName) \ + X(Pattern) \ + /* `require impls` or just `require impls` */ \ + X(RequireImpls) \ + X(Requirement) \ X(Statement) // We expect this to grow, so are using a bigger size than needed. diff --git a/toolchain/parse/node_ids.h b/toolchain/parse/node_ids.h index 1cf2255e48e8..cedea5866a77 100644 --- a/toolchain/parse/node_ids.h +++ b/toolchain/parse/node_ids.h @@ -108,6 +108,7 @@ using AnyModifierId = NodeIdInCategory; using AnyPatternId = NodeIdInCategory; using AnyStatementId = NodeIdInCategory; +using AnyRequireImplsId = NodeIdInCategory; using AnyRequirementId = NodeIdInCategory; using AnyNonExprNameId = NodeIdInCategory; using AnyPackageNameId = NodeIdInCategory; diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index 2f117bd3652d..f09f17a8e072 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -367,8 +367,13 @@ CARBON_PARSE_NODE_KIND(ImplDefinitionStart) CARBON_PARSE_NODE_KIND(ImplDefinition) CARBON_PARSE_NODE_KIND(ImplDecl) CARBON_PARSE_NODE_KIND(Forall) -CARBON_PARSE_NODE_KIND(TypeImplAs) -CARBON_PARSE_NODE_KIND(DefaultSelfImplAs) +CARBON_PARSE_NODE_KIND(ImplTypeAs) +CARBON_PARSE_NODE_KIND(ImplDefaultSelfAs) + +CARBON_PARSE_NODE_KIND(RequireIntroducer) +CARBON_PARSE_NODE_KIND(RequireTypeImpls) +CARBON_PARSE_NODE_KIND(RequireDefaultSelfImpls) +CARBON_PARSE_NODE_KIND(RequireDecl) CARBON_PARSE_NODE_KIND(NamedConstraintIntroducer) CARBON_PARSE_NODE_KIND(NamedConstraintDefinitionStart) diff --git a/toolchain/parse/precedence.h b/toolchain/parse/precedence.h index 7d4f7c609fd3..208ca32c2fa8 100644 --- a/toolchain/parse/precedence.h +++ b/toolchain/parse/precedence.h @@ -58,6 +58,10 @@ class PrecedenceGroup { // `impl` and `as`. static auto ForImplAs() -> PrecedenceGroup; + // Get the precedence level at which to parse the type expression between + // `require` and `impls`. + static auto ForRequireImpls() -> PrecedenceGroup; + // Get the precedence level at which to parse expressions in requirements // after `where` or `require`. static auto ForRequirements() -> PrecedenceGroup; diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index d39b1d6ebb03..b161007612c7 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -359,6 +359,10 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterParams) // ^~~~~~~ // 1. Package // +// require ... +// ^~~~~~~ +// 1. RequireAfterIntroducer +// // var ... (variant is Regular) // ^~~ // 1. VarAsRegular @@ -1336,7 +1340,7 @@ CARBON_PARSE_STATE(BaseDecl) // ^~ // 1. Expr // 2. DeclOrDefinitionAsImpl -// impl type_expression as ... +// impl TypeExpression as ... // ^ // 1. Expr // 2. ImplBeforeAs @@ -1349,7 +1353,7 @@ CARBON_PARSE_STATE(ImplAfterIntroducer) // impl forall [ ... ] as ... // ^~ // 1. Expr -// impl forall [ ... ] type_expression as ... +// impl forall [ ... ] TypeExpression as ... // ^ // 1. Expr // 2. ImplBeforeAs @@ -1363,6 +1367,34 @@ CARBON_PARSE_STATE(ImplAfterForall) // 1. Expr CARBON_PARSE_STATE(ImplBeforeAs) +// Handles processing of a `require...impls` declaration after the introducer. +// +// require impls ... +// ^~~~~ +// 1. Expr +// 2. RequireDecl +// require TypeExpression impls ... +// ^ +// 1. Expr +// 2. RequireBeforeImpls +// 3. RequireDecl +CARBON_PARSE_STATE(RequireAfterIntroducer) + +// Handles processing of the `impls` in a `require` declaration after the type +// expression. +// +// require TypeExpression impls ... +// ^~~~~ +// 1. Expr +CARBON_PARSE_STATE(RequireBeforeImpls) + +// Handles processing of a completed `require` declaration. +// +// require TypeExpression impls FacetTypeExpression ; +// ^ +// (state done) +CARBON_PARSE_STATE(RequireDecl) + // Handles the start of a `var` or `returned var` in a non-class context. // // var ... (variant is Regular) diff --git a/toolchain/parse/testdata/function/decl_statement.carbon b/toolchain/parse/testdata/function/decl_statement.carbon index a623e27b1cd6..8665c6ec6d3d 100644 --- a/toolchain/parse/testdata/function/decl_statement.carbon +++ b/toolchain/parse/testdata/function/decl_statement.carbon @@ -86,14 +86,14 @@ fn F() { // CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'A'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 6}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'FinalModifier', text: 'final'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'A'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 6}, // CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 7}, @@ -139,7 +139,7 @@ fn F() { // CHECK:STDOUT: {kind: 'BaseDecl', text: ';', subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, -// CHECK:STDOUT: {kind: 'DefaultSelfImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'ImplDefaultSelfAs', text: 'as'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 5}, // CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'}, diff --git a/toolchain/parse/testdata/function/definition.carbon b/toolchain/parse/testdata/function/definition.carbon index a9c12011bbb8..7eb38f07f96b 100644 --- a/toolchain/parse/testdata/function/definition.carbon +++ b/toolchain/parse/testdata/function/definition.carbon @@ -186,7 +186,7 @@ fn TestRecoveryFromSpuriousEquals(); // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, diff --git a/toolchain/parse/testdata/generics/impl/basic.carbon b/toolchain/parse/testdata/generics/impl/basic.carbon index a59eae7a681f..ff3eb742721e 100644 --- a/toolchain/parse/testdata/generics/impl/basic.carbon +++ b/toolchain/parse/testdata/generics/impl/basic.carbon @@ -17,7 +17,7 @@ impl i32 as Interface { // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, diff --git a/toolchain/parse/testdata/generics/impl/class.carbon b/toolchain/parse/testdata/generics/impl/class.carbon index 5efec6dfd37c..d971fbdba96d 100644 --- a/toolchain/parse/testdata/generics/impl/class.carbon +++ b/toolchain/parse/testdata/generics/impl/class.carbon @@ -26,23 +26,23 @@ class C { // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'C'}, // CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, -// CHECK:STDOUT: {kind: 'DefaultSelfImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'ImplDefaultSelfAs', text: 'as'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ForwardDeclared'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 4}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'C'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ExplicitType'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 6}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ExplicitSelf'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, -// CHECK:STDOUT: {kind: 'DefaultSelfImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'ImplDefaultSelfAs', text: 'as'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ExtendImpl'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, @@ -54,7 +54,7 @@ class C { // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'C'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'InvalidButDiagnosedInCheck'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 6}, // CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 36}, diff --git a/toolchain/parse/testdata/generics/impl/declaration.carbon b/toolchain/parse/testdata/generics/impl/declaration.carbon index d5d369def346..75fade94ddd7 100644 --- a/toolchain/parse/testdata/generics/impl/declaration.carbon +++ b/toolchain/parse/testdata/generics/impl/declaration.carbon @@ -15,7 +15,7 @@ impl bool as Interface; // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/generics/impl/empty_body.carbon b/toolchain/parse/testdata/generics/impl/empty_body.carbon index 637287462075..6e77f114087a 100644 --- a/toolchain/parse/testdata/generics/impl/empty_body.carbon +++ b/toolchain/parse/testdata/generics/impl/empty_body.carbon @@ -16,7 +16,7 @@ impl str as Interface { // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'str'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 6}, diff --git a/toolchain/parse/testdata/generics/impl/fail_impl.carbon b/toolchain/parse/testdata/generics/impl/fail_impl.carbon index 94b553f79b2e..27e1483295c5 100644 --- a/toolchain/parse/testdata/generics/impl/fail_impl.carbon +++ b/toolchain/parse/testdata/generics/impl/fail_impl.carbon @@ -108,12 +108,12 @@ impl // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'bar'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, @@ -146,7 +146,7 @@ impl // CHECK:STDOUT: {kind: 'Forall', text: 'forall'}, // CHECK:STDOUT: {kind: 'InvalidParse', text: 'f16', has_error: yes}, // CHECK:STDOUT: {kind: 'FloatTypeLiteral', text: 'f16'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Quux'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 7}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, @@ -178,7 +178,7 @@ impl // CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, // CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 6}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 12}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, diff --git a/toolchain/parse/testdata/generics/impl/fail_out_of_line_member.carbon b/toolchain/parse/testdata/generics/impl/fail_out_of_line_member.carbon index 64b7c5a29e23..e6d0a8cdfb92 100644 --- a/toolchain/parse/testdata/generics/impl/fail_out_of_line_member.carbon +++ b/toolchain/parse/testdata/generics/impl/fail_out_of_line_member.carbon @@ -50,7 +50,7 @@ fn C.(Self as Interface).F() {} // CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 9}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, @@ -67,7 +67,7 @@ fn C.(Self as Interface).F() {} // CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, diff --git a/toolchain/parse/testdata/generics/impl/forall.carbon b/toolchain/parse/testdata/generics/impl/forall.carbon index d8dbb3877bdb..d6cb35ae778e 100644 --- a/toolchain/parse/testdata/generics/impl/forall.carbon +++ b/toolchain/parse/testdata/generics/impl/forall.carbon @@ -25,7 +25,7 @@ impl forall [T:! type, U:! Interface] U as Interface(T) { // CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, // CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 6}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 12}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, @@ -42,7 +42,7 @@ impl forall [T:! type, U:! Interface] U as Interface(T) { // CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, // CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 11}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'U'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, diff --git a/toolchain/parse/testdata/generics/interface/require.carbon b/toolchain/parse/testdata/generics/interface/require.carbon new file mode 100644 index 000000000000..3db3d0586197 --- /dev/null +++ b/toolchain/parse/testdata/generics/interface/require.carbon @@ -0,0 +1,240 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/generics/interface/require.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/generics/interface/require.carbon + +// --- implicit_self_impls.carbon + +interface Y {} + +interface Z { + require impls Y; +} + +// --- explicit_self_impls.carbon + +interface Y {} + +interface Z { + require Self impls Y; +} + +// --- impls_where.carbon + +interface Y { let Y1:! type; } + +interface Z { + require impls Y where .Y1 = (); +} + +// --- other_impls.carbon + +interface Y {} + +interface Z(T:! type) { + require T impls Y; +} + +// --- extend.carbon + +interface Y {} + +interface Z { + extend require impls Y; +} + +// --- fail_missing_impls.carbon + +interface Y {} + +interface Z { + // CHECK:STDERR: fail_missing_impls.carbon:[[@LINE+4]]:12: error: expected `impls` in `require` declaration [RequireExpectedImpls] + // CHECK:STDERR: require Y; + // CHECK:STDERR: ^ + // CHECK:STDERR: + require Y; +} + +// --- fail_wrong_keyword.carbon + +interface Y {} + +interface Z { + // CHECK:STDERR: fail_wrong_keyword.carbon:[[@LINE+4]]:11: error: expected expression [ExpectedExpr] + // CHECK:STDERR: require as Y; + // CHECK:STDERR: ^~ + // CHECK:STDERR: + require as Y; +} + +// --- fail_as_in_self.carbon + +interface Y {} + +interface Z { + // CHECK:STDERR: fail_as_in_self.carbon:[[@LINE+4]]:16: error: expected `impls` in `require` declaration [RequireExpectedImpls] + // CHECK:STDERR: require Self as Y impls Y; + // CHECK:STDERR: ^~ + // CHECK:STDERR: + require Self as Y impls Y; +} + +// CHECK:STDOUT: - filename: implicit_self_impls.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'RequireDefaultSelfImpls', text: 'impls'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Y'}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: explicit_self_impls.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'RequireTypeImpls', text: 'impls', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Y'}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: impls_where.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'AssociatedConstantIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y1'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'AssociatedConstantNameAndType', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'AssociatedConstantDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'RequireDefaultSelfImpls', text: 'impls'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Y'}, +// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y1'}, +// CHECK:STDOUT: {kind: 'DesignatorExpr', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'RequirementEqual', text: '=', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'WhereExpr', text: 'where', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: other_impls.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'T'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':!', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'RequireTypeImpls', text: 'impls', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Y'}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: extend.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, +// CHECK:STDOUT: {kind: 'RequireDefaultSelfImpls', text: 'impls'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Y'}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_missing_impls.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Y'}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_wrong_keyword.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: 'as', has_error: yes}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_as_in_self.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Y'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Z'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'RequireIntroducer', text: 'require'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'RequireDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/package/impl.carbon b/toolchain/parse/testdata/packages/package/impl.carbon index d0a3e3da6dcf..c20fdbaad4be 100644 --- a/toolchain/parse/testdata/packages/package/impl.carbon +++ b/toolchain/parse/testdata/packages/package/impl.carbon @@ -42,7 +42,7 @@ impl package.Name as package.Interface {} // CHECK:STDOUT: {kind: 'PackageDecl', text: ';', subtree_size: 4}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, // CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 6}, @@ -59,7 +59,7 @@ impl package.Name as package.Interface {} // CHECK:STDOUT: {kind: 'PackageExpr', text: 'package'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Name'}, // CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 4}, // CHECK:STDOUT: {kind: 'PackageExpr', text: 'package'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Interface'}, // CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3}, diff --git a/toolchain/parse/testdata/where_expr/impl_where.carbon b/toolchain/parse/testdata/where_expr/impl_where.carbon index 0c05e5754bcc..c7d8924c991f 100644 --- a/toolchain/parse/testdata/where_expr/impl_where.carbon +++ b/toolchain/parse/testdata/where_expr/impl_where.carbon @@ -38,7 +38,7 @@ impl f64 as Interface where .T = (type where .Self impls type) { // CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 9}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'T'}, @@ -51,7 +51,7 @@ impl f64 as Interface where .T = (type where .Self impls type) { // CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 13}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'T'}, @@ -63,7 +63,7 @@ impl f64 as Interface where .T = (type where .Self impls type) { // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('}, // CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 3}, // CHECK:STDOUT: {kind: 'ParenExprStart', text: '('}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2}, @@ -79,7 +79,7 @@ impl f64 as Interface where .T = (type where .Self impls type) { // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'}, // CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 2}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 3}, // CHECK:STDOUT: {kind: 'ParenExprStart', text: '('}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2}, @@ -100,7 +100,7 @@ impl f64 as Interface where .T = (type where .Self impls type) { // CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 22}, // CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, // CHECK:STDOUT: {kind: 'FloatTypeLiteral', text: 'f64'}, -// CHECK:STDOUT: {kind: 'TypeImplAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, // CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'T'}, diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index d7790bdb707f..a866b4c3f8b5 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -1446,6 +1446,40 @@ struct InterfaceDefinition { Lex::CloseCurlyBraceTokenIndex token; }; +// `require`...`impls` statements +// ------------------------------ + +// `require` +using RequireIntroducer = + LeafNode; + +// `impls` with no type before it +using RequireDefaultSelfImpls = + LeafNode; + +// ` impls`. +struct RequireTypeImpls { + static constexpr auto Kind = NodeKind::RequireTypeImpls.Define( + {.category = NodeCategory::RequireImpls, .child_count = 1}); + + AnyExprId type_expr; + Lex::ImplsTokenIndex token; +}; + +// `require T impls I where...` +struct RequireDecl { + static constexpr auto Kind = + NodeKind::RequireDecl.Define({.category = NodeCategory::Decl, + .bracketed_by = RequireIntroducer::Kind}); + + RequireIntroducerId introducer; + llvm::SmallVector modifiers; + AnyRequireImplsId impls; + AnyExprId facet_type; + Lex::SemiTokenIndex token; +}; + // `impl`...`as` declarations and definitions // ------------------------------------------ @@ -1462,12 +1496,12 @@ struct ImplForall { }; // `as` with no type before it -using DefaultSelfImplAs = LeafNode; // ` as` -struct TypeImplAs { - static constexpr auto Kind = NodeKind::TypeImplAs.Define( +struct ImplTypeAs { + static constexpr auto Kind = NodeKind::ImplTypeAs.Define( {.category = NodeCategory::ImplAs, .child_count = 1}); AnyExprId type_expr;