diff --git a/toolchain/check/handle_name.cpp b/toolchain/check/handle_name.cpp index 39760d7878f2..398d8f7f3aca 100644 --- a/toolchain/check/handle_name.cpp +++ b/toolchain/check/handle_name.cpp @@ -152,6 +152,16 @@ auto HandleParseNode(Context& context, Parse::IdentifierNameExprId node_id) return true; } +auto HandleParseNode(Context& context, + Parse::KeywordNameNotBeforeParamsId node_id) -> bool { + return context.TODO(node_id, "KeywordNameNotBeforeParamsId"); +} + +auto HandleParseNode(Context& context, Parse::KeywordNameBeforeParamsId node_id) + -> bool { + return context.TODO(node_id, "KeywordNameBeforeParamsId"); +} + auto HandleParseNode(Context& context, Parse::BaseNameId node_id) -> bool { context.node_stack().Push(node_id, SemIR::NameId::Base); return true; @@ -188,7 +198,8 @@ auto HandleParseNode(Context& context, } auto HandleParseNode(Context& context, - Parse::NameQualifierWithoutParamsId /*node_id*/) -> bool { + Parse::IdentifierNameQualifierWithoutParamsId /*node_id*/) + -> bool { context.decl_name_stack().ApplyNameQualifier(PopNameComponent(context)); return true; } @@ -229,6 +240,12 @@ auto HandleParseNode(Context& context, Parse::DesignatorExprId node_id) return true; } +auto HandleParseNode(Context& context, + Parse::KeywordNameQualifierWithoutParamsId node_id) + -> bool { + return context.TODO(node_id, "KeywordNameQualifierWithoutParamsId"); +} + auto HandleParseNode(Context& context, Parse::PackageExprId node_id) -> bool { AddInstAndPush( context, node_id, diff --git a/toolchain/check/name_component.cpp b/toolchain/check/name_component.cpp index 83679bc18c90..078abb798309 100644 --- a/toolchain/check/name_component.cpp +++ b/toolchain/check/name_component.cpp @@ -57,8 +57,7 @@ auto PopNameComponent(Context& context, SemIR::InstId return_slot_pattern_id) } auto [name_loc_id, name_id] = - context.node_stack() - .PopWithNodeId(); + context.node_stack().PopWithNodeId(); return { .name_loc_id = name_loc_id, diff --git a/toolchain/check/node_stack.h b/toolchain/check/node_stack.h index 0dea644ee397..025b5cc4623d 100644 --- a/toolchain/check/node_stack.h +++ b/toolchain/check/node_stack.h @@ -377,9 +377,9 @@ class NodeStack { Id::KindFor()); set_id_if_category_is(Parse::NodeCategory::Expr, Id::KindFor()); - set_id_if_category_is(Parse::NodeCategory::MemberName | - Parse::NodeCategory::NonExprIdentifierName, - Id::KindFor()); + set_id_if_category_is( + Parse::NodeCategory::MemberName | Parse::NodeCategory::NonExprName, + Id::KindFor()); set_id_if_category_is(Parse::NodeCategory::ImplAs, Id::KindFor()); set_id_if_category_is(Parse::NodeCategory::Decl | @@ -469,11 +469,13 @@ class NodeStack { case Parse::NodeKind::ForHeader: case Parse::NodeKind::ForHeaderStart: case Parse::NodeKind::ForIn: + case Parse::NodeKind::IdentifierNameQualifierWithoutParams: case Parse::NodeKind::IdentifierPackageName: case Parse::NodeKind::IfConditionStart: case Parse::NodeKind::ImportIntroducer: case Parse::NodeKind::IndexExprStart: case Parse::NodeKind::InvalidParseStart: + case Parse::NodeKind::KeywordNameQualifierWithoutParams: case Parse::NodeKind::LibraryIntroducer: case Parse::NodeKind::LibrarySpecifier: case Parse::NodeKind::MatchCase: @@ -494,7 +496,6 @@ class NodeStack { case Parse::NodeKind::NamedConstraintDefinitionStart: case Parse::NodeKind::NamedConstraintIntroducer: case Parse::NodeKind::NameQualifierWithParams: - case Parse::NodeKind::NameQualifierWithoutParams: case Parse::NodeKind::NamespaceStart: case Parse::NodeKind::PackageIntroducer: case Parse::NodeKind::ParenExprStart: diff --git a/toolchain/check/testdata/class/no_prelude/destroy.carbon b/toolchain/check/testdata/class/no_prelude/destroy.carbon new file mode 100644 index 000000000000..58ffe95a4f3e --- /dev/null +++ b/toolchain/check/testdata/class/no_prelude/destroy.carbon @@ -0,0 +1,179 @@ +// 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/check/testdata/class/no_prelude/destroy.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/no_prelude/destroy.carbon + +// --- fail_todo_basic.carbon + +library "[[@TEST_NAME]]"; + +class C { + // CHECK:STDERR: fail_todo_basic.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo] + // CHECK:STDERR: fn destroy[self: Self](); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + fn destroy[self: Self](); +} + +// --- fail_todo_addr.carbon + +library "[[@TEST_NAME]]"; + +class C { + // CHECK:STDERR: fail_todo_addr.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo] + // CHECK:STDERR: fn destroy[addr self: Self*](); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + fn destroy[addr self: Self*](); +} + +// --- fail_todo_class_function.carbon + +library "[[@TEST_NAME]]"; + +class C { + // CHECK:STDERR: fail_todo_class_function.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo] + // CHECK:STDERR: fn destroy(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + fn destroy(); +} + +// --- fail_todo_destroy_in_namespace.carbon + +library "[[@TEST_NAME]]"; + +namespace NS; + +// CHECK:STDERR: fail_todo_destroy_in_namespace.carbon:[[@LINE+4]]:7: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo] +// CHECK:STDERR: fn NS.destroy(); +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: +fn NS.destroy(); + +// --- fail_todo_missing_params.carbon + +library "[[@TEST_NAME]]"; + + +class C { + // CHECK:STDERR: fail_todo_missing_params.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameNotBeforeParamsId` [SemanticsTodo] + // CHECK:STDERR: fn destroy; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + fn destroy; +} + +fn C.destroy {} + +// --- fail_todo_wrong_scope.carbon + +library "[[@TEST_NAME]]"; + + +// CHECK:STDERR: fail_todo_wrong_scope.carbon:[[@LINE+4]]:4: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo] +// CHECK:STDERR: fn destroy(); +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: +fn destroy(); + +// --- fail_invalid_qualifier.carbon + +class C { + // CHECK:STDERR: fail_invalid_qualifier.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo] + // CHECK:STDERR: fn destroy(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + fn destroy(); +} + +fn C.destroy.destroy() {} + +// CHECK:STDOUT: --- fail_todo_basic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: complete_type_witness = invalid +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_addr.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: complete_type_witness = invalid +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_class_function.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: complete_type_witness = invalid +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_destroy_in_namespace.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_missing_params.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: complete_type_witness = invalid +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_wrong_scope.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_invalid_qualifier.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: complete_type_witness = invalid +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/lex/token_kind.def b/toolchain/lex/token_kind.def index 4699203a7562..b8752e7e81d6 100644 --- a/toolchain/lex/token_kind.def +++ b/toolchain/lex/token_kind.def @@ -179,7 +179,7 @@ CARBON_KEYWORD_TOKEN(Const, "const") CARBON_KEYWORD_TOKEN(Continue, "continue") CARBON_KEYWORD_TOKEN(Core, "Core") CARBON_KEYWORD_TOKEN(Default, "default") -CARBON_KEYWORD_TOKEN(Destructor, "destructor") +CARBON_KEYWORD_TOKEN(Destroy, "destroy") CARBON_KEYWORD_TOKEN(Else, "else") CARBON_KEYWORD_TOKEN(Extend, "extend") CARBON_KEYWORD_TOKEN(Extern, "extern") diff --git a/toolchain/parse/BUILD b/toolchain/parse/BUILD index 6f6e1cd3a100..3b10e24fc7c2 100644 --- a/toolchain/parse/BUILD +++ b/toolchain/parse/BUILD @@ -110,6 +110,7 @@ cc_library( "//toolchain/base:shared_value_stores", "//toolchain/diagnostics:diagnostic_emitter", "//toolchain/diagnostics:format_providers", + "//toolchain/lex:token_index", "//toolchain/lex:token_kind", "//toolchain/lex:tokenized_buffer", ], diff --git a/toolchain/parse/handle_decl_name_and_params.cpp b/toolchain/parse/handle_decl_name_and_params.cpp index 9f8ec8010db0..4fde242e4f01 100644 --- a/toolchain/parse/handle_decl_name_and_params.cpp +++ b/toolchain/parse/handle_decl_name_and_params.cpp @@ -2,67 +2,87 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include "toolchain/lex/token_index.h" #include "toolchain/parse/context.h" #include "toolchain/parse/handle.h" namespace Carbon::Parse { -auto HandleDeclNameAndParams(Context& context) -> void { - auto state = context.PopState(); - - auto identifier = context.ConsumeIf(Lex::TokenKind::Identifier); - if (!identifier) { - Lex::TokenIndex token = *context.position(); - if (context.tokens().GetKind(token) == Lex::TokenKind::FileEnd) { - // The end of file is an unhelpful diagnostic location. Instead, use the - // introducer token. - token = state.token; - } - if (state.token == *context.position()) { - CARBON_DIAGNOSTIC(ExpectedDeclNameAfterPeriod, Error, - "`.` should be followed by a name"); - context.emitter().Emit(token, ExpectedDeclNameAfterPeriod); - } else { - CARBON_DIAGNOSTIC(ExpectedDeclName, Error, - "`{0}` introducer should be followed by a name", - Lex::TokenKind); - context.emitter().Emit(token, ExpectedDeclName, - context.tokens().GetKind(state.token)); - } - context.ReturnErrorOnState(); - context.AddInvalidParse(*context.position()); - return; - } - +// Adds a leaf node for the name, and updates the state stack for parameter +// handling. +static auto HandleName(Context& context, Context::StateStackEntry state, + Lex::TokenIndex name_token, + NodeKind not_before_params_kind, + NodeKind not_before_params_qualifier_kind, + NodeKind before_params_kind) -> void { switch (context.PositionKind()) { case Lex::TokenKind::Period: - context.AddLeafNode(NodeKind::IdentifierNameNotBeforeParams, *identifier); - context.AddNode(NodeKind::NameQualifierWithoutParams, + context.AddLeafNode(not_before_params_kind, name_token); + context.AddNode(not_before_params_qualifier_kind, context.ConsumeChecked(Lex::TokenKind::Period), state.has_error); context.PushState(State::DeclNameAndParams); break; case Lex::TokenKind::OpenSquareBracket: - context.AddLeafNode(NodeKind::IdentifierNameBeforeParams, *identifier); + context.AddLeafNode(before_params_kind, name_token); state.state = State::DeclNameAndParamsAfterImplicit; context.PushState(state); context.PushState(State::PatternListAsImplicit); break; case Lex::TokenKind::OpenParen: - context.AddLeafNode(NodeKind::IdentifierNameBeforeParams, *identifier); + context.AddLeafNode(before_params_kind, name_token); state.state = State::DeclNameAndParamsAfterParams; context.PushState(state); context.PushState(State::PatternListAsExplicit); break; default: - context.AddLeafNode(NodeKind::IdentifierNameNotBeforeParams, *identifier); + context.AddLeafNode(not_before_params_kind, name_token); break; } } +auto HandleDeclNameAndParams(Context& context) -> void { + auto state = context.PopState(); + + if (auto identifier = context.ConsumeIf(Lex::TokenKind::Identifier)) { + HandleName(context, state, *identifier, + NodeKind::IdentifierNameNotBeforeParams, + NodeKind::IdentifierNameQualifierWithoutParams, + NodeKind::IdentifierNameBeforeParams); + return; + } + + if (auto keyword = context.ConsumeIf(Lex::TokenKind::Destroy)) { + HandleName(context, state, *keyword, NodeKind::KeywordNameNotBeforeParams, + NodeKind::KeywordNameQualifierWithoutParams, + NodeKind::KeywordNameBeforeParams); + return; + } + + Lex::TokenIndex token = *context.position(); + if (context.tokens().GetKind(token) == Lex::TokenKind::FileEnd) { + // The end of file is an unhelpful diagnostic location. Instead, use the + // introducer token. + token = state.token; + } + if (state.token == *context.position()) { + CARBON_DIAGNOSTIC(ExpectedDeclNameAfterPeriod, Error, + "`.` should be followed by a name"); + context.emitter().Emit(token, ExpectedDeclNameAfterPeriod); + } else { + CARBON_DIAGNOSTIC(ExpectedDeclName, Error, + "`{0}` introducer should be followed by a name", + Lex::TokenKind); + context.emitter().Emit(token, ExpectedDeclName, + context.tokens().GetKind(state.token)); + } + context.ReturnErrorOnState(); + context.AddInvalidParse(*context.position()); +} + auto HandleDeclNameAndParamsAfterImplicit(Context& context) -> void { auto state = context.PopState(); diff --git a/toolchain/parse/node_category.h b/toolchain/parse/node_category.h index fb67a4691cef..cc6d3d7d6f3d 100644 --- a/toolchain/parse/node_category.h +++ b/toolchain/parse/node_category.h @@ -25,7 +25,7 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); X(MemberExpr) \ X(MemberName) \ X(Modifier) \ - X(NonExprIdentifierName) \ + X(NonExprName) \ X(PackageName) \ X(Pattern) \ X(Requirement) \ diff --git a/toolchain/parse/node_ids.h b/toolchain/parse/node_ids.h index 54977bc4849f..b66349ae3ef5 100644 --- a/toolchain/parse/node_ids.h +++ b/toolchain/parse/node_ids.h @@ -79,8 +79,7 @@ using AnyPatternId = NodeIdInCategory; using AnyStatementId = NodeIdInCategory; using AnyRequirementId = NodeIdInCategory; -using AnyNonExprIdentifierNameId = - NodeIdInCategory; +using AnyNonExprNameId = NodeIdInCategory; using AnyPackageNameId = NodeIdInCategory; // NodeId with kind that matches one of the `T::Kind`s. diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index bf54e99969a2..00e5d7cf9e1d 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -98,6 +98,9 @@ CARBON_PARSE_NODE_KIND(EmptyDecl) CARBON_PARSE_NODE_KIND(IdentifierNameNotBeforeParams) CARBON_PARSE_NODE_KIND(IdentifierNameBeforeParams) +CARBON_PARSE_NODE_KIND(KeywordNameNotBeforeParams) +CARBON_PARSE_NODE_KIND(KeywordNameBeforeParams) + CARBON_PARSE_NODE_KIND(IdentifierNameExpr) CARBON_PARSE_NODE_KIND(SelfValueName) @@ -124,7 +127,8 @@ CARBON_PARSE_NODE_KIND(LibraryDecl) CARBON_PARSE_NODE_KIND(LibrarySpecifier) CARBON_PARSE_NODE_KIND(NameQualifierWithParams) -CARBON_PARSE_NODE_KIND(NameQualifierWithoutParams) +CARBON_PARSE_NODE_KIND(IdentifierNameQualifierWithoutParams) +CARBON_PARSE_NODE_KIND(KeywordNameQualifierWithoutParams) CARBON_PARSE_NODE_KIND(ExportIntroducer) CARBON_PARSE_NODE_KIND(ExportDecl) diff --git a/toolchain/parse/testdata/alias/basic.carbon b/toolchain/parse/testdata/alias/basic.carbon index 9ad0d6812cee..b4b51ca49cdf 100644 --- a/toolchain/parse/testdata/alias/basic.carbon +++ b/toolchain/parse/testdata/alias/basic.carbon @@ -44,7 +44,7 @@ fn F() { // CHECK:STDOUT: {kind: 'Alias', text: ';', subtree_size: 7}, // CHECK:STDOUT: {kind: 'AliasIntroducer', text: 'alias'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'NS'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'ns'}, // CHECK:STDOUT: {kind: 'AliasInitializer', text: '='}, // CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'foo'}, diff --git a/toolchain/parse/testdata/class/local.carbon b/toolchain/parse/testdata/class/local.carbon index 95d45a9fcbc4..8235a63b5953 100644 --- a/toolchain/parse/testdata/class/local.carbon +++ b/toolchain/parse/testdata/class/local.carbon @@ -41,7 +41,7 @@ fn F() { // CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 15}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'C'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'H'}, // CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, // CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2}, diff --git a/toolchain/parse/testdata/function/declaration.carbon b/toolchain/parse/testdata/function/declaration.carbon index 6eb8ce089e7b..3a8306458f98 100644 --- a/toolchain/parse/testdata/function/declaration.carbon +++ b/toolchain/parse/testdata/function/declaration.carbon @@ -36,6 +36,22 @@ fn foo(a: i32, b: i32); fn foo() -> u32; +// --- keyword.carbon + +fn destroy() {} + +// --- keyword_no_params.carbon + +fn destroy {} + +// --- keyword_in_qualified.carbon + +fn MyClass.destroy() {} + +// --- keyword_decl.carbon + +fn destroy.destroy() {} + // --- impl_fn.carbon impl fn F(); @@ -256,6 +272,52 @@ fn (a tokens c d e f g h i j k l m n o p q r s t u v w x y z); // CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 7}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: keyword.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: keyword_no_params.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'KeywordNameNotBeforeParams', text: 'destroy'}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: keyword_in_qualified.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'MyClass'}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: keyword_decl.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'KeywordNameNotBeforeParams', text: 'destroy'}, +// CHECK:STDOUT: {kind: 'KeywordNameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] // CHECK:STDOUT: - filename: impl_fn.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, 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 4855c95564bb..64b7c5a29e23 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 @@ -79,7 +79,7 @@ fn C.(Self as Interface).F() {} // CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 15}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'C'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'InvalidParse', text: '(', has_error: yes}, // CHECK:STDOUT: {kind: 'FunctionDecl', text: '}', has_error: yes, subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/namespace/fail_incomplete_name.carbon b/toolchain/parse/testdata/namespace/fail_incomplete_name.carbon index bb1be72e9a3b..c448468e7bca 100644 --- a/toolchain/parse/testdata/namespace/fail_incomplete_name.carbon +++ b/toolchain/parse/testdata/namespace/fail_incomplete_name.carbon @@ -19,7 +19,7 @@ namespace Foo.; // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes}, // CHECK:STDOUT: {kind: 'Namespace', text: ';', has_error: yes, subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/namespace/nested.carbon b/toolchain/parse/testdata/namespace/nested.carbon index b370fbcb294e..5ecd562b0668 100644 --- a/toolchain/parse/testdata/namespace/nested.carbon +++ b/toolchain/parse/testdata/namespace/nested.carbon @@ -23,14 +23,14 @@ fn Foo.Bar.Baz() { // CHECK:STDOUT: {kind: 'Namespace', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Bar'}, // CHECK:STDOUT: {kind: 'Namespace', text: ';', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Bar'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Baz'}, // CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, // CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2}, diff --git a/toolchain/parse/testdata/packages/export.carbon b/toolchain/parse/testdata/packages/export.carbon index c3f712a31117..4f9b17b5ab44 100644 --- a/toolchain/parse/testdata/packages/export.carbon +++ b/toolchain/parse/testdata/packages/export.carbon @@ -162,7 +162,7 @@ export Foo; // CHECK:STDOUT: {kind: 'PackageDecl', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Bar'}, // CHECK:STDOUT: {kind: 'ExportDecl', text: ';', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, @@ -230,7 +230,7 @@ export Foo; // CHECK:STDOUT: {kind: 'PackageDecl', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'}, // CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2}, // CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes}, // CHECK:STDOUT: {kind: 'ExportDecl', text: ';', has_error: yes, subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index 915ffc395c73..9ceddcfd327e 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -131,13 +131,19 @@ using EmptyDecl = // to be followed by parameters. using IdentifierNameBeforeParams = LeafNode; + NodeCategory::MemberName | NodeCategory::NonExprName>; +using KeywordNameBeforeParams = + LeafNode; // A name in a non-expression context, such as a declaration, that is known // to not be followed by parameters. using IdentifierNameNotBeforeParams = LeafNode; + NodeCategory::MemberName | NodeCategory::NonExprName>; +using KeywordNameNotBeforeParams = + LeafNode; // A name in an expression context. using IdentifierNameExpr = @@ -174,21 +180,31 @@ struct NameQualifierWithParams { }; // A name qualifier without parameters, such as `A.`. -struct NameQualifierWithoutParams { - static constexpr auto Kind = NodeKind::NameQualifierWithoutParams.Define( - {.bracketed_by = IdentifierNameNotBeforeParams::Kind}); +struct IdentifierNameQualifierWithoutParams { + static constexpr auto Kind = + NodeKind::IdentifierNameQualifierWithoutParams.Define( + {.bracketed_by = IdentifierNameNotBeforeParams::Kind}); IdentifierNameNotBeforeParamsId name; Lex::PeriodTokenIndex token; }; +struct KeywordNameQualifierWithoutParams { + static constexpr auto Kind = + NodeKind::KeywordNameQualifierWithoutParams.Define( + {.bracketed_by = KeywordNameNotBeforeParams::Kind}); + + KeywordNameNotBeforeParamsId name; + Lex::PeriodTokenIndex token; +}; // A complete name in a declaration: `A.C(T:! type).F(n: i32)`. // Note that this includes the parameters of the entity itself. struct DeclName { llvm::SmallVector< - NodeIdOneOf> + NodeIdOneOf> qualifiers; - AnyNonExprIdentifierNameId name; + AnyNonExprNameId name; std::optional implicit_params; std::optional params; }; @@ -1157,7 +1173,7 @@ struct ChoiceDefinition { ChoiceDefinitionStartId signature; struct Alternative { - AnyNonExprIdentifierNameId name; + AnyNonExprNameId name; std::optional parameters; }; CommaSeparatedList alternatives; diff --git a/toolchain/parse/typed_nodes_test.cpp b/toolchain/parse/typed_nodes_test.cpp index daf7570401cb..e9f3445d2103 100644 --- a/toolchain/parse/typed_nodes_test.cpp +++ b/toolchain/parse/typed_nodes_test.cpp @@ -290,10 +290,10 @@ Optional [^:]*: found Optional [^:]*: begin NodeIdForKind error: wrong kind IdentifierNameBeforeParams, expected ImplicitParamList Optional [^:]*: missing -NodeIdInCategory NonExprIdentifierName: kind IdentifierNameBeforeParams consumed +NodeIdInCategory NonExprName: kind IdentifierNameBeforeParams consumed Vector: begin -NodeIdOneOf NameQualifierWithParams or NameQualifierWithoutParams: NameQualifierWithoutParams consumed -NodeIdOneOf error: wrong kind AbstractModifier, expected NameQualifierWithParams or NameQualifierWithoutParams +NodeIdOneOf NameQualifierWithParams or IdentifierNameQualifierWithoutParams or KeywordNameQualifierWithoutParams: IdentifierNameQualifierWithoutParams consumed +NodeIdOneOf error: wrong kind AbstractModifier, expected NameQualifierWithParams or IdentifierNameQualifierWithoutParams or KeywordNameQualifierWithoutParams Vector: end Aggregate [^:]*: success Vector: begin