diff --git a/toolchain/check/handle_namespace.cpp b/toolchain/check/handle_namespace.cpp index 52edf82c20f50..bb0be005a0c7d 100644 --- a/toolchain/check/handle_namespace.cpp +++ b/toolchain/check/handle_namespace.cpp @@ -10,6 +10,7 @@ #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/name_scope.h" +#include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { @@ -26,6 +27,12 @@ auto HandleParseNode(Context& context, Parse::NamespaceStartId /*node_id*/) return true; } +static auto IsNamespaceScope(Context& context, SemIR::NameScopeId name_scope_id) + -> bool { + auto [_, inst] = context.name_scopes().GetInstIfValid(name_scope_id); + return inst && inst->Is(); +} + auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool { auto name_context = context.decl_name_stack().FinishName( PopNameComponentWithoutParams(context, Lex::TokenKind::Namespace)); @@ -83,6 +90,11 @@ auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool { namespace_inst.name_scope_id = context.name_scopes().Add( namespace_id, name_context.name_id_for_new_inst(), name_context.parent_scope_id); + if (!IsNamespaceScope(context, name_context.parent_scope_id)) { + CARBON_DIAGNOSTIC(NamespaceDeclNotAtTopLevel, Error, + "`namespace` declaration not at top level"); + context.emitter().Emit(node_id, NamespaceDeclNotAtTopLevel); + } } context.ReplaceInstBeforeConstantUse(namespace_id, namespace_inst); diff --git a/toolchain/check/testdata/class/adapter/adapt.carbon b/toolchain/check/testdata/class/adapter/adapt.carbon index ca314127c279e..0a168a991cd7d 100644 --- a/toolchain/check/testdata/class/adapter/adapt.carbon +++ b/toolchain/check/testdata/class/adapter/adapt.carbon @@ -39,12 +39,30 @@ class AdaptNotExtend { fn F(a: AdaptNotExtend) { // `Adapted` is not extended, so lookup for `F` finds nothing. - // CHECK:STDERR: fail_not_extend.carbon:[[@LINE+3]]:3: error: member name `F` not found in `AdaptNotExtend` [MemberNameNotFoundInScope] + // CHECK:STDERR: fail_not_extend.carbon:[[@LINE+4]]:3: error: member name `F` not found in `AdaptNotExtend` [MemberNameNotFoundInScope] // CHECK:STDERR: a.F(); // CHECK:STDERR: ^~~ + // CHECK:STDERR: a.F(); } +// --- fail_misplaced.carbon + +fn F() { + // CHECK:STDERR: fail_misplaced.carbon:[[@LINE+4]]:3: error: `adapt` declaration outside class [ClassSpecificDeclOutsideClass] + // CHECK:STDERR: adapt i32; + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + adapt i32; +} + +interface I { + // CHECK:STDERR: fail_misplaced.carbon:[[@LINE+3]]:3: error: `adapt` declaration outside class [ClassSpecificDeclOutsideClass] + // CHECK:STDERR: adapt i32; + // CHECK:STDERR: ^~~~~~~~~~ + adapt i32; +} + // CHECK:STDOUT: --- basic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -184,3 +202,50 @@ fn F(a: AdaptNotExtend) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_misplaced.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template] +// CHECK:STDOUT: %I.type: type = facet_type <@I> [template] +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: .Int = %import_ref.187 +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/fail_base_misplaced.carbon b/toolchain/check/testdata/class/fail_base_misplaced.carbon index cab8006aab9b4..8b725380b709b 100644 --- a/toolchain/check/testdata/class/fail_base_misplaced.carbon +++ b/toolchain/check/testdata/class/fail_base_misplaced.carbon @@ -17,25 +17,55 @@ base class B {} extend base: B; fn F() { - // CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+7]]:3: error: expected expression [ExpectedExpr] + // CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+4]]:3: error: `base` declaration outside class [ClassSpecificDeclOutsideClass] // CHECK:STDERR: extend base: B; - // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: ^~~~~~~~~~~~~~~ // CHECK:STDERR: - // CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:3: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo] - // CHECK:STDERR: extend base: B; - // CHECK:STDERR: ^~~~~~ extend base: B; } +class C { + fn F() { + // CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:5: error: `base` declaration outside class [ClassSpecificDeclOutsideClass] + // CHECK:STDERR: extend base: B; + // CHECK:STDERR: ^~~~~~~~~~~~~~~ + extend base: B; + } +} + // CHECK:STDOUT: --- fail_base_misplaced.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %B: type = class_type @B [template] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template] // CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template] +// CHECK:STDOUT: %F.type.b25: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.c41: %F.type.b25 = struct_value () [template] +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %F.type.675: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.2c9: %F.type.675 = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .B = %B.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %B.decl: type = class_decl @B [template = constants.%B] {} {} +// CHECK:STDOUT: %B.ref: type = name_ref B, %B.decl [template = constants.%B] +// CHECK:STDOUT: %F.decl: %F.type.b25 = fn_decl @F.1 [template = constants.%F.c41] {} {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @B { // CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type] @@ -45,5 +75,25 @@ fn F() { // CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: %F.decl: %F.type.675 = fn_decl @F.2 [template = constants.%F.2c9] {} {} +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B] +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/fail_todo_local_class.carbon b/toolchain/check/testdata/class/fail_todo_local_class.carbon index 7b246ca8fe424..a6a875bb71c90 100644 --- a/toolchain/check/testdata/class/fail_todo_local_class.carbon +++ b/toolchain/check/testdata/class/fail_todo_local_class.carbon @@ -8,21 +8,22 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_todo_local_class.carbon -// TODO: Support parsing classes at function scope. class A { - fn F() { - // CHECK:STDERR: fail_todo_local_class.carbon:[[@LINE+7]]:5: error: expected expression [ExpectedExpr] - // CHECK:STDERR: class B { - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_local_class.carbon:[[@LINE+3]]:5: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo] - // CHECK:STDERR: class B { - // CHECK:STDERR: ^~~~~ + fn F() -> i32 { class B { - fn G() { - var b: B = {}; + fn Make() -> Self { + returned var b: Self = {.n = 1}; + return var; } + + var n: i32; } + + // TODO: Add the name `B` to the lexical scope. + // CHECK:STDERR: fail_todo_local_class.carbon:[[@LINE+3]]:12: error: name `B` not found [NameNotFound] + // CHECK:STDERR: return B.Make().n; + // CHECK:STDERR: ^ + return B.Make().n; } } @@ -30,17 +31,59 @@ class A { // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %A: type = class_type @A [template] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template] -// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template] +// CHECK:STDOUT: %complete_type.357: = complete_type_witness %empty_struct_type [template] +// CHECK:STDOUT: %B: type = class_type @B [template] +// CHECK:STDOUT: %Make.type: type = fn_type @Make [template] +// CHECK:STDOUT: %Make: %Make.type = struct_value () [template] +// CHECK:STDOUT: %B.elem: type = unbound_element_type %B, %i32 [template] +// CHECK:STDOUT: %struct_type.n.5cd: type = struct_type {.n: %i32} [template] +// CHECK:STDOUT: %complete_type.9b7: = complete_type_witness %struct_type.n.5cd [template] +// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [template] +// CHECK:STDOUT: %struct_type.n.44a: type = struct_type {.n: Core.IntLiteral} [template] +// CHECK:STDOUT: %Convert.type.cd1: type = fn_type @Convert.1, @ImplicitAs(%i32) [template] +// CHECK:STDOUT: %impl_witness.5b0: = impl_witness (imports.%import_ref.723), @impl.1(%int_32) [template] +// CHECK:STDOUT: %Convert.type.466: type = fn_type @Convert.2, @impl.1(%int_32) [template] +// CHECK:STDOUT: %Convert.925: %Convert.type.466 = struct_value () [template] +// CHECK:STDOUT: %Convert.bound: = bound_method %int_1.5b8, %Convert.925 [template] +// CHECK:STDOUT: %Convert.specific_fn: = specific_function %Convert.bound, @Convert.2(%int_32) [template] +// CHECK:STDOUT: %int_1.c60: %i32 = int_value 1 [template] +// CHECK:STDOUT: %B.val: %B = struct_value (%int_1.c60) [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: .Int = %import_ref.187 +// CHECK:STDOUT: .ImplicitAs = %import_ref.a69 +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %A.decl: type = class_decl @A [template = constants.%A] {} {} +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @A { -// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} -// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %return.patt: %i32 = return_slot_pattern +// CHECK:STDOUT: %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32] +// CHECK:STDOUT: %return.param: ref %i32 = out_param runtime_param0 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type.357] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%A @@ -48,5 +91,49 @@ class A { // CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: class @B { +// CHECK:STDOUT: %Make.decl: %Make.type = fn_decl @Make [template = constants.%Make] { +// CHECK:STDOUT: %return.patt: %B = return_slot_pattern +// CHECK:STDOUT: %return.param_patt: %B = out_param_pattern %return.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B [template = constants.%B] +// CHECK:STDOUT: %return.param: ref %B = out_param runtime_param0 +// CHECK:STDOUT: %return: ref %B = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc19: %B.elem = field_decl n, element0 [template] +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.n.5cd [template = constants.%complete_type.9b7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%B +// CHECK:STDOUT: .Make = %Make.decl +// CHECK:STDOUT: .n = %.loc19 +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %B.decl: type = class_decl @B [template = constants.%B] {} {} +// CHECK:STDOUT: %B.ref: = name_ref B, [template = ] +// CHECK:STDOUT: %Make.ref: = name_ref Make, [template = ] +// CHECK:STDOUT: %n.ref: = name_ref n, [template = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Make() -> %return.param_patt: %B { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %b: ref %B = bind_name b, %return +// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [template = constants.%int_1.5b8] +// CHECK:STDOUT: %.loc15_39.1: %struct_type.n.44a = struct_literal (%int_1) +// CHECK:STDOUT: %impl.elem0: %Convert.type.cd1 = impl_witness_access constants.%impl_witness.5b0, element0 [template = constants.%Convert.925] +// CHECK:STDOUT: %Convert.bound: = bound_method %int_1, %impl.elem0 [template = constants.%Convert.bound] +// CHECK:STDOUT: %Convert.specific_fn: = specific_function %Convert.bound, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn] +// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_1) [template = constants.%int_1.c60] +// CHECK:STDOUT: %.loc15_39.2: init %i32 = converted %int_1, %int.convert_checked [template = constants.%int_1.c60] +// CHECK:STDOUT: %.loc15_39.3: ref %i32 = class_element_access %return, element0 +// CHECK:STDOUT: %.loc15_39.4: init %i32 = initialize_from %.loc15_39.2 to %.loc15_39.3 [template = constants.%int_1.c60] +// CHECK:STDOUT: %.loc15_39.5: init %B = class_init (%.loc15_39.4), %return [template = constants.%B.val] +// CHECK:STDOUT: %.loc15_40: init %B = converted %.loc15_39.1, %.loc15_39.5 [template = constants.%B.val] +// CHECK:STDOUT: assign %return, %.loc15_40 +// CHECK:STDOUT: return %b to %return +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/definition/no_prelude/fail_local_decl.carbon b/toolchain/check/testdata/function/definition/no_prelude/fail_local_decl.carbon new file mode 100644 index 0000000000000..dc4f234a23d6d --- /dev/null +++ b/toolchain/check/testdata/function/definition/no_prelude/fail_local_decl.carbon @@ -0,0 +1,106 @@ +// 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/function/definition/no_prelude/fail_local_decl.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/definition/no_prelude/fail_local_decl.carbon + +// --- fail_virtual.carbon + +library "[[@TEST_NAME]]"; + +fn F() { + // CHECK:STDERR: fail_virtual.carbon:[[@LINE+4]]:3: error: `default` not allowed; requires interface scope [ModifierRequiresInterface] + // CHECK:STDERR: default fn F(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + default fn F(); + // CHECK:STDERR: fail_virtual.carbon:[[@LINE+4]]:3: error: `impl` not allowed; requires class scope [ModifierRequiresClass] + // CHECK:STDERR: impl fn G(); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: + impl fn G(); + // CHECK:STDERR: fail_virtual.carbon:[[@LINE+4]]:3: error: `virtual` not allowed; requires class scope [ModifierRequiresClass] + // CHECK:STDERR: virtual fn H(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + virtual fn H(); +} + +// --- fail_access.carbon + +library "[[@TEST_NAME]]"; + +fn F() { + // CHECK:STDERR: fail_access.carbon:[[@LINE+4]]:3: error: `private` not allowed; requires class or file scope [ModifierPrivateNotAllowed] + // CHECK:STDERR: private var v: {}; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + private var v: {}; + // CHECK:STDERR: fail_access.carbon:[[@LINE+3]]:3: error: `protected` not allowed; requires class scope [ModifierProtectedNotAllowed] + // CHECK:STDERR: protected var w: {}; + // CHECK:STDERR: ^~~~~~~~~ + protected var w: {}; +} + +// CHECK:STDOUT: --- fail_virtual.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %F.type.b25: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.c41: %F.type.b25 = struct_value () [template] +// CHECK:STDOUT: %F.type.21a: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.c14: %F.type.21a = struct_value () [template] +// CHECK:STDOUT: %G.type: type = fn_type @G [template] +// CHECK:STDOUT: %G: %G.type = struct_value () [template] +// CHECK:STDOUT: %H.type: type = fn_type @H [template] +// CHECK:STDOUT: %H: %H.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type.b25 = fn_decl @F.1 [template = constants.%F.c41] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.decl: %F.type.21a = fn_decl @F.2 [template = constants.%F.c14] {} {} +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] {} {} +// CHECK:STDOUT: %H.decl: %H.type = fn_decl @H [template = constants.%H] {} {} +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @H(); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_access.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %v.var: ref %empty_struct_type = var v +// CHECK:STDOUT: %v: ref %empty_struct_type = bind_name v, %v.var +// CHECK:STDOUT: %w.var: ref %empty_struct_type = var w +// CHECK:STDOUT: %w: ref %empty_struct_type = bind_name w, %w.var +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon index 6de910c368fab..95e0ee7752f99 100644 --- a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon +++ b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon @@ -8,18 +8,40 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/fail_impl_as_scope.carbon +// --- fail_global.carbon + +library "[[@TEST_NAME]]"; + interface Simple { fn F(); } -// CHECK:STDERR: fail_impl_as_scope.carbon:[[@LINE+3]]:6: error: `impl as` can only be used in a class [ImplAsOutsideClass] +// CHECK:STDERR: fail_global.carbon:[[@LINE+4]]:6: error: `impl as` can only be used in a class [ImplAsOutsideClass] // CHECK:STDERR: impl as Simple { // CHECK:STDERR: ^~ +// CHECK:STDERR: impl as Simple { fn F() {} } -// CHECK:STDOUT: --- fail_impl_as_scope.carbon +// --- fail_function.carbon + +library "[[@TEST_NAME]]"; + +interface Simple { + fn F(); +} + +fn Function() { + // CHECK:STDERR: fail_function.carbon:[[@LINE+3]]:8: error: `impl as` can only be used in a class [ImplAsOutsideClass] + // CHECK:STDERR: impl as Simple { + // CHECK:STDERR: ^~ + impl as Simple { + fn F() {} + } +} + +// CHECK:STDOUT: --- fail_global.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Simple.type: type = facet_type <@Simple> [template] @@ -50,3 +72,36 @@ impl as Simple { // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%Self) {} // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_function.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Simple.type: type = facet_type <@Simple> [template] +// CHECK:STDOUT: %Self: %Simple.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %F.assoc_type: type = assoc_entity_type %Simple.type, %F.type [template] +// CHECK:STDOUT: %assoc0: %F.assoc_type = assoc_entity element0, @Simple.%F.decl [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Simple { +// CHECK:STDOUT: %Self: %Simple.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: %assoc0: %F.assoc_type = assoc_entity element0, %F.decl [template = constants.%assoc0] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %assoc0 +// CHECK:STDOUT: witness = (%F.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(@Simple.%Self: %Simple.type) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Function(); +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%Self) {} +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/namespace/fail_not_top_level.carbon b/toolchain/check/testdata/namespace/fail_not_top_level.carbon new file mode 100644 index 0000000000000..30979998eb061 --- /dev/null +++ b/toolchain/check/testdata/namespace/fail_not_top_level.carbon @@ -0,0 +1,132 @@ +// 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/namespace/fail_not_top_level.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/namespace/fail_not_top_level.carbon + +fn F() { + // CHECK:STDERR: fail_not_top_level.carbon:[[@LINE+4]]:3: error: `namespace` declaration not at top level [NamespaceDeclNotAtTopLevel] + // CHECK:STDERR: namespace N; + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: + namespace N; + // CHECK:STDERR: fail_not_top_level.carbon:[[@LINE+4]]:6: error: name `N` not found [NameNotFound] + // CHECK:STDERR: fn N.F() {} + // CHECK:STDERR: ^ + // CHECK:STDERR: + fn N.F() {} +} + +class C { + // CHECK:STDERR: fail_not_top_level.carbon:[[@LINE+4]]:3: error: `namespace` declaration not at top level [NamespaceDeclNotAtTopLevel] + // CHECK:STDERR: namespace N; + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: + namespace N; + fn N.F() {} +} + +interface I { + // CHECK:STDERR: fail_not_top_level.carbon:[[@LINE+3]]:3: error: `namespace` declaration not at top level [NamespaceDeclNotAtTopLevel] + // CHECK:STDERR: namespace N; + // CHECK:STDERR: ^~~~~~~~~~~~ + namespace N; + fn N.I() {} +} + +// CHECK:STDOUT: --- fail_not_top_level.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %F.type.b25: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.c41: %F.type.b25 = struct_value () [template] +// CHECK:STDOUT: %.type: type = fn_type @.1 [template] +// CHECK:STDOUT: %.3ad: %.type = struct_value () [template] +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %F.type.2e2: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.5e0: %F.type.2e2 = struct_value () [template] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template] +// CHECK:STDOUT: %I.type.733: type = facet_type <@I.2> [template] +// CHECK:STDOUT: %Self: %I.type.733 = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %I.type.ad2: type = fn_type @I.1 [template] +// CHECK:STDOUT: %I: %I.type.ad2 = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %F.decl: %F.type.b25 = fn_decl @F.1 [template = constants.%F.c41] {} {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} +// CHECK:STDOUT: %I.decl: type = interface_decl @I.2 [template = constants.%I.type.733] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I.2 { +// CHECK:STDOUT: %Self: %I.type.733 = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %N: = namespace [template] { +// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.decl: %I.type.ad2 = fn_decl @I.1 [template = constants.%I] {} {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .N = %N +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: %N: = namespace [template] { +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type.2e2 = fn_decl @F.2 [template = constants.%F.5e0] {} {} +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: .N = %N +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %N: = namespace [template] {} +// CHECK:STDOUT: %.decl: %.type = fn_decl @.1 [template = constants.%.3ad] {} {} +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @I.1(@I.2.%Self: %I.type.733) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.1(constants.%Self) {} +// CHECK:STDOUT: diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index be2bf5657e2b0..3d029708bf29b 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -106,6 +106,7 @@ CARBON_DIAGNOSTIC_KIND(ExpectedLibraryName) CARBON_DIAGNOSTIC_KIND(ExpectedLibraryNameOrDefault) CARBON_DIAGNOSTIC_KIND(MissingLibraryKeyword) CARBON_DIAGNOSTIC_KIND(ExportImportPackage) +CARBON_DIAGNOSTIC_KIND(ExpectedPeriodAfterPackage) // For-specific diagnostics. CARBON_DIAGNOSTIC_KIND(ExpectedIn) @@ -187,6 +188,9 @@ CARBON_DIAGNOSTIC_KIND(ExternLibraryIncorrect) CARBON_DIAGNOSTIC_KIND(ExternLibraryExpected) CARBON_DIAGNOSTIC_KIND(ExternRequiresDeclInApiFile) +// Namespace checking. +CARBON_DIAGNOSTIC_KIND(NamespaceDeclNotAtTopLevel) + // Function call checking. CARBON_DIAGNOSTIC_KIND(AddrSelfIsNonRef) CARBON_DIAGNOSTIC_KIND(CallArgCountMismatch) diff --git a/toolchain/parse/handle_decl_scope_loop.cpp b/toolchain/parse/handle_decl_scope_loop.cpp index 81b16ae55b34d..184656fb63d73 100644 --- a/toolchain/parse/handle_decl_scope_loop.cpp +++ b/toolchain/parse/handle_decl_scope_loop.cpp @@ -242,21 +242,8 @@ static auto TryHandleAsModifier(Context& context) -> bool { } } -auto HandleDeclScopeLoop(Context& context) -> void { - // This maintains the current state unless we're at the end of the scope. - - if (context.PositionIs(Lex::TokenKind::CloseCurlyBrace) || - context.PositionIs(Lex::TokenKind::FileEnd)) { - // This is the end of the scope, so the loop state ends. - context.PopAndDiscardState(); - return; - } - - // Create a state with the correct starting position, with a dummy kind - // until we see the declaration's introducer. - Context::StateStackEntry state{.state = State::Invalid, - .token = *context.position(), - .subtree_start = context.tree().size()}; +auto HandleDecl(Context& context) -> void { + auto state = context.PopState(); // Add a placeholder node, to be replaced by the declaration introducer once // it is found. @@ -271,4 +258,16 @@ auto HandleDeclScopeLoop(Context& context) -> void { } } +auto HandleDeclScopeLoop(Context& context) -> void { + // This maintains the current state unless we're at the end of the scope. + if (context.PositionIs(Lex::TokenKind::CloseCurlyBrace) || + context.PositionIs(Lex::TokenKind::FileEnd)) { + // This is the end of the scope, so the loop state ends. + context.PopAndDiscardState(); + return; + } + + context.PushState(State::Decl); +} + } // namespace Carbon::Parse diff --git a/toolchain/parse/handle_expr.cpp b/toolchain/parse/handle_expr.cpp index bf50ffc05c7d3..739ce8df6d52a 100644 --- a/toolchain/parse/handle_expr.cpp +++ b/toolchain/parse/handle_expr.cpp @@ -156,6 +156,12 @@ auto HandleExprInPostfix(Context& context) -> void { } case Lex::TokenKind::Package: { context.AddLeafNode(NodeKind::PackageExpr, context.Consume()); + if (context.PositionKind() != Lex::TokenKind::Period) { + CARBON_DIAGNOSTIC(ExpectedPeriodAfterPackage, Error, + "expected `.` after `package` expression"); + context.emitter().Emit(*context.position(), ExpectedPeriodAfterPackage); + state.has_error = true; + } context.PushState(state); break; } diff --git a/toolchain/parse/handle_statement.cpp b/toolchain/parse/handle_statement.cpp index 4243d3e5a10fc..be11593dfac3c 100644 --- a/toolchain/parse/handle_statement.cpp +++ b/toolchain/parse/handle_statement.cpp @@ -11,11 +11,6 @@ auto HandleStatement(Context& context) -> void { context.PopAndDiscardState(); switch (context.PositionKind()) { - case Lex::TokenKind::Alias: { - context.PushState(State::Alias); - context.AddLeafNode(NodeKind::AliasIntroducer, context.Consume()); - break; - } case Lex::TokenKind::Break: { context.PushState(State::StatementBreakFinish); context.AddLeafNode(NodeKind::BreakStatementStart, context.Consume()); @@ -36,24 +31,15 @@ auto HandleStatement(Context& context) -> void { context.PushState(State::StatementIf); break; } - case Lex::TokenKind::Let: { - context.PushState(State::Let); - context.AddLeafNode(NodeKind::LetIntroducer, context.Consume()); - break; - } case Lex::TokenKind::Return: { context.PushState(State::StatementReturn); break; } case Lex::TokenKind::Returned: { + // TODO: Consider handling this as a modifier. context.PushState(State::VarAsReturned); break; } - case Lex::TokenKind::Var: { - context.PushState(State::VarAsDecl); - context.AddLeafNode(NodeKind::VariableIntroducer, context.Consume()); - break; - } case Lex::TokenKind::While: { context.PushState(State::StatementWhile); break; @@ -62,6 +48,27 @@ auto HandleStatement(Context& context) -> void { context.PushState(State::MatchIntroducer); break; } +#define CARBON_PARSE_NODE_KIND(...) +#define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name, ...) \ + case Lex::TokenKind::Name: +#include "toolchain/parse/node_kind.def" + case Lex::TokenKind::Adapt: + case Lex::TokenKind::Alias: + case Lex::TokenKind::Choice: + case Lex::TokenKind::Class: + case Lex::TokenKind::Constraint: + case Lex::TokenKind::Fn: + case Lex::TokenKind::Import: + case Lex::TokenKind::Interface: + case Lex::TokenKind::Let: + case Lex::TokenKind::Library: + case Lex::TokenKind::Namespace: + // We intentionally don't handle Package here, because `package.` can be + // used at the start of an expression, and it's not worth disambiguating it. + case Lex::TokenKind::Var: { + context.PushState(State::Decl); + break; + } default: { context.PushState(State::ExprStatementFinish); context.PushStateForExpr(PrecedenceGroup::ForExprStatement()); diff --git a/toolchain/parse/node_ids.h b/toolchain/parse/node_ids.h index 9f877a93575c5..cba0c4693be74 100644 --- a/toolchain/parse/node_ids.h +++ b/toolchain/parse/node_ids.h @@ -78,7 +78,8 @@ using AnyMemberAccessId = NodeCategory::IntConst>; using AnyModifierId = NodeIdInCategory; using AnyPatternId = NodeIdInCategory; -using AnyStatementId = NodeIdInCategory; +using AnyStatementId = + NodeIdInCategory; using AnyRequirementId = NodeIdInCategory; // NodeId with kind that matches one of the `T::Kind`s. diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index 5ea5d1afe1c1e..a2df47d3f703b 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -275,8 +275,8 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterImplicit) // (state done) CARBON_PARSE_STATE(DeclNameAndParamsAfterParams) -// Handles processing of a declaration scope. Things like fn, class, interface, -// and so on. +// Handles processing of a declaration. Things like fn, class, interface, and so +// on. // // abstract // ^~~~~~~~ @@ -298,95 +298,95 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterParams) // ^~~~~~~~~ // virtual // ^~~~~~~ -// 1. DeclScopeLoop +// 1. Decl // // adapt ... // ^~~~~ // 1. AdaptAfterIntroducer -// 2. DeclScopeLoop // // alias ... // ^~~~~ // 1. Alias -// 2. DeclScopeLoop // // base : ... // ^~~~ // 1. BaseAfterIntroducer -// 2. DeclScopeLoop // // choice ... // ^~~~~~ // 1. ChoiceIntroducer -// 2. DeclScopeLoop // // class ... // ^~~~~ // 1. TypeAfterIntroducerAsClass -// 2. DeclScopeLoop // // constraint ... // ^~~~~~~~~~ // 1. TypeAfterIntroducerAsNamedConstraint -// 2. DeclScopeLoop // // export ... // ^~~~~~ // 1. ExportName -// 2. DeclScopeLoop // // fn ... // ^~ // 1. FunctionIntroducer -// 2. DeclScopeLoop // // impl ... // ^~~~ // 1. ImplAfterIntroducer -// 2. DeclScopeLoop // // import ... (in packaging directives) // ^~~~~~ // 1. Import -// 2. DeclScopeLoop // // interface ... // ^~~~~~~~~ // 1. TypeAfterIntroducerAsInterface -// 2. DeclScopeLoop // // let ... // ^~~ // 1. Let -// 2. DeclScopeLoop // // library ... (in packaging directives) // ^~~~~~~ // 1. Library -// 2. DeclScopeLoop // // namespace ... // ^~~~~~~~~ // 1. Namespace -// 2. DeclScopeLoop // // package ... (in packaging directives) // ^~~~~~~ // 1. Package -// 2. DeclScopeLoop // // var ... // ^~~ // 1. VarAsDecl -// 2. DeclScopeLoop // // ; // ^ -// 1. DeclScopeLoop +// (state done) // // ??? ; // ^~~~~ // (state done) +CARBON_PARSE_STATE(Decl) + +// Handles processing of a declaration scope, which contains a sequence of +// declarations. +// +// } +// ^ +// +// ^ +// (state done) +// +// ... +// ^ +// 1. Decl +// 2. DeclScopeLoop +// CARBON_PARSE_STATE(DeclScopeLoop) // Handles periods. Only does one `.` segment; the source is @@ -1069,10 +1069,6 @@ CARBON_PARSE_STATE_VARIANTS2(BindingPatternFinish, Generic, Regular) // ^ // 1. StatementReturn // -// var ... -// ^ -// 1. VarAsDecl -// // returned ... // ^ // 1. VarAsReturned @@ -1089,6 +1085,10 @@ CARBON_PARSE_STATE_VARIANTS2(BindingPatternFinish, Generic, Regular) // match ... // ^ // 1. MatchIntroducer +// +// +// ^ +// 1. Decl CARBON_PARSE_STATE(Statement) // Handles `break` processing at the `;`. diff --git a/toolchain/parse/testdata/choice/local.carbon b/toolchain/parse/testdata/choice/local.carbon new file mode 100644 index 0000000000000..0e0d9f499960a --- /dev/null +++ b/toolchain/parse/testdata/choice/local.carbon @@ -0,0 +1,35 @@ +// 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/choice/local.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/choice/local.carbon + +fn F() { + choice C { + X, + Y + } +} + +// CHECK:STDOUT: - filename: local.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'X'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Y'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/class/adapt.carbon b/toolchain/parse/testdata/class/adapt.carbon index 4fddc6bf0fd44..f75df418337d8 100644 --- a/toolchain/parse/testdata/class/adapt.carbon +++ b/toolchain/parse/testdata/class/adapt.carbon @@ -60,17 +60,13 @@ class C { } class D { - // CHECK:STDERR: fail_bad_syntax.carbon:[[@LINE+4]]:9: error: expected expression [ExpectedExpr] + // CHECK:STDERR: fail_bad_syntax.carbon:[[@LINE+3]]:9: error: expected expression [ExpectedExpr] // CHECK:STDERR: adapt class; // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: adapt class; } fn F() { - // CHECK:STDERR: fail_bad_syntax.carbon:[[@LINE+3]]:3: error: expected expression [ExpectedExpr] - // CHECK:STDERR: adapt i32; - // CHECK:STDERR: ^~~~~ adapt i32; } @@ -168,8 +164,9 @@ fn F() { // CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, // CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, // CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'InvalidParse', text: 'adapt', has_error: yes}, -// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', has_error: yes, subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'AdaptIntroducer', text: 'adapt'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'AdaptDecl', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 9}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/class/base_misplaced.carbon b/toolchain/parse/testdata/class/base_misplaced.carbon index 749eca717e753..f8e495ebe14d1 100644 --- a/toolchain/parse/testdata/class/base_misplaced.carbon +++ b/toolchain/parse/testdata/class/base_misplaced.carbon @@ -8,15 +8,37 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/class/base_misplaced.carbon -// This is rejected by check. -base: i32; +base class B {} + +// These are rejected by check. +base: B; + +fn F() { + base: B; +} + // CHECK:STDOUT: - filename: base_misplaced.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'BaseModifier', text: 'base'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'B'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 5}, // CHECK:STDOUT: {kind: 'BaseIntroducer', text: 'base'}, // CHECK:STDOUT: {kind: 'BaseColon', text: ':'}, -// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'B'}, // CHECK:STDOUT: {kind: 'BaseDecl', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'BaseIntroducer', text: 'base'}, +// CHECK:STDOUT: {kind: 'BaseColon', text: ':'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'B'}, +// CHECK:STDOUT: {kind: 'BaseDecl', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 10}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/class/local.carbon b/toolchain/parse/testdata/class/local.carbon new file mode 100644 index 0000000000000..128e8049687f8 --- /dev/null +++ b/toolchain/parse/testdata/class/local.carbon @@ -0,0 +1,52 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/class/local.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/class/local.carbon + +fn F() { + class C { + fn G() {} + fn H(); + } + fn C.H() {} +} + +// CHECK:STDOUT: - filename: local.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'G'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'H'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'NameQualifier', text: '.', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'H'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 29}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/function/definition/decl_statement.carbon b/toolchain/parse/testdata/function/definition/decl_statement.carbon new file mode 100644 index 0000000000000..044fab4b796e8 --- /dev/null +++ b/toolchain/parse/testdata/function/definition/decl_statement.carbon @@ -0,0 +1,178 @@ +// 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/function/definition/decl_statement.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/function/definition/decl_statement.carbon + +// --- valid.carbon + +// These are expected to work. +fn F() { + alias A = i32; + class A {} + base class B {} + abstract class Abstract {} + fn F() {} + constraint C {} + interface I {} + impl A as I {} + final impl A as I {} + choice C {} + let n: i32 = 0; + var v: i32; +} + +// --- syntactically_valid.carbon + +// These parse but should not type-check. +fn F() { + adapt A; + extend adapt A; + extend base: B; + extend impl as I; + namespace N; + default fn F(); + impl fn G(); + virtual fn H(); + private var v: i32; + protected var v: i32; +} + +// CHECK:STDOUT: - filename: valid.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'AliasIntroducer', text: 'alias'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'A'}, +// CHECK:STDOUT: {kind: 'AliasInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'Alias', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'A'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'BaseModifier', text: 'base'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'B'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'AbstractModifier', text: 'abstract'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Abstract'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'NamedConstraintIntroducer', text: 'constraint'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'NamedConstraintDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'NamedConstraintDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'I'}, +// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3}, +// 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: '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: 'IdentifierNameExpr', text: 'I'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'n'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LetInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '0'}, +// CHECK:STDOUT: {kind: 'LetDecl', text: ';', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'v'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 68}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: syntactically_valid.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'AdaptIntroducer', text: 'adapt'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'A'}, +// CHECK:STDOUT: {kind: 'AdaptDecl', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'AdaptIntroducer', text: 'adapt'}, +// CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'A'}, +// CHECK:STDOUT: {kind: 'AdaptDecl', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'BaseIntroducer', text: 'base'}, +// CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, +// CHECK:STDOUT: {kind: 'BaseColon', text: ':'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'B'}, +// 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: 'IdentifierNameExpr', text: 'I'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'N'}, +// CHECK:STDOUT: {kind: 'Namespace', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'DefaultModifier', text: 'default'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'G'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'VirtualModifier', text: 'virtual'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'H'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'PrivateModifier', text: 'private'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'v'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'ProtectedModifier', text: 'protected'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'v'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 56}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/function/definition/nested.carbon b/toolchain/parse/testdata/function/definition/nested.carbon new file mode 100644 index 0000000000000..5a2c87459e016 --- /dev/null +++ b/toolchain/parse/testdata/function/definition/nested.carbon @@ -0,0 +1,39 @@ +// 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/function/definition/nested.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/function/definition/nested.carbon + +fn F() { + fn NamedParams(a: i32) {} + fn PositionalParams {} +} + +// CHECK:STDOUT: - filename: nested.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'NamedParams'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'a'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'PositionalParams'}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 19}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/namespace/local.carbon b/toolchain/parse/testdata/namespace/local.carbon new file mode 100644 index 0000000000000..357d1345c1c92 --- /dev/null +++ b/toolchain/parse/testdata/namespace/local.carbon @@ -0,0 +1,29 @@ +// 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/namespace/local.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/namespace/local.carbon + +fn F() { + // This is rejected by check. + namespace N; +} + +// CHECK:STDOUT: - filename: local.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'N'}, +// CHECK:STDOUT: {kind: 'Namespace', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/class/fail_base_misplaced.carbon b/toolchain/parse/testdata/package_expr/fail_standalone.carbon similarity index 57% rename from toolchain/parse/testdata/class/fail_base_misplaced.carbon rename to toolchain/parse/testdata/package_expr/fail_standalone.carbon index c5eb24cca152f..2995863efd641 100644 --- a/toolchain/parse/testdata/class/fail_base_misplaced.carbon +++ b/toolchain/parse/testdata/package_expr/fail_standalone.carbon @@ -4,33 +4,26 @@ // // AUTOUPDATE // TIP: To test this file alone, run: -// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/class/fail_base_misplaced.carbon +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/package_expr/fail_standalone.carbon // TIP: To dump output, run: -// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/class/fail_base_misplaced.carbon - -base class B {} +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/package_expr/fail_standalone.carbon fn F() { - // CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:3: error: expected expression [ExpectedExpr] - // CHECK:STDERR: base: B; - // CHECK:STDERR: ^~~~ - base: B; + // CHECK:STDERR: fail_standalone.carbon:[[@LINE+3]]:10: error: expected `.` after `package` expression [ExpectedPeriodAfterPackage] + // CHECK:STDERR: package; + // CHECK:STDERR: ^ + package; } -// CHECK:STDOUT: - filename: fail_base_misplaced.carbon +// CHECK:STDOUT: - filename: fail_standalone.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, -// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, -// CHECK:STDOUT: {kind: 'BaseModifier', text: 'base'}, -// CHECK:STDOUT: {kind: 'IdentifierName', text: 'B'}, -// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 4}, -// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, // CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, // CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, // CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, -// CHECK:STDOUT: {kind: 'InvalidParse', text: 'base', has_error: yes}, +// CHECK:STDOUT: {kind: 'PackageExpr', text: 'package'}, // CHECK:STDOUT: {kind: 'ExprStatement', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/packages/import/fail_in_nested_scope.carbon b/toolchain/parse/testdata/packages/import/fail_in_nested_scope.carbon new file mode 100644 index 0000000000000..98b469ae3e0df --- /dev/null +++ b/toolchain/parse/testdata/packages/import/fail_in_nested_scope.carbon @@ -0,0 +1,50 @@ +// 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/packages/import/fail_in_nested_scope.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/packages/import/fail_in_nested_scope.carbon + +class A { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+7]]:3: error: `import` declarations must come after the `package` declaration (if present) and before any other entities in the file [ImportTooLate] + // CHECK:STDERR: import B; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-4]]:1: note: first declaration is here [FirstDecl] + // CHECK:STDERR: class A { + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + import B; +} + +fn F() { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+6]]:3: error: `import` declarations must come after the `package` declaration (if present) and before any other entities in the file [ImportTooLate] + // CHECK:STDERR: import C; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-15]]:1: note: first declaration is here [FirstDecl] + // CHECK:STDERR: class A { + // CHECK:STDERR: ^~~~~ + import C; +} + +// CHECK:STDOUT: - filename: fail_in_nested_scope.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'A'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'ImportDecl', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'ImportDecl', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/library/fail_in_nested_scope.carbon b/toolchain/parse/testdata/packages/library/fail_in_nested_scope.carbon new file mode 100644 index 0000000000000..2c6395d389510 --- /dev/null +++ b/toolchain/parse/testdata/packages/library/fail_in_nested_scope.carbon @@ -0,0 +1,92 @@ +// 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/packages/library/fail_in_nested_scope.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/packages/library/fail_in_nested_scope.carbon + +// api.carbon + +class C { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+7]]:3: error: the `library` declaration must be the first non-comment line [PackageTooLate] + // CHECK:STDERR: library "foo"; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-4]]:1: note: first non-comment line is here [FirstNonCommentLine] + // CHECK:STDERR: class C { + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + library "foo"; +} + +fn F() { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+7]]:3: error: the `library` declaration must be the first non-comment line [PackageTooLate] + // CHECK:STDERR: library "foo"; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-15]]:1: note: first non-comment line is here [FirstNonCommentLine] + // CHECK:STDERR: class C { + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + library "foo"; +} + +// impl.carbon + +class C { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+7]]:3: error: the `library` declaration must be the first non-comment line [PackageTooLate] + // CHECK:STDERR: impl library "foo"; + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-28]]:1: note: first non-comment line is here [FirstNonCommentLine] + // CHECK:STDERR: class C { + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + impl library "foo"; +} + +fn F() { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+6]]:3: error: the `library` declaration must be the first non-comment line [PackageTooLate] + // CHECK:STDERR: impl library "foo"; + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-39]]:1: note: first non-comment line is here [FirstNonCommentLine] + // CHECK:STDERR: class C { + // CHECK:STDERR: ^~~~~ + impl library "foo"; +} + +// CHECK:STDOUT: - filename: fail_in_nested_scope.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryDecl', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryDecl', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'}, +// CHECK:STDOUT: {kind: 'LibraryDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'}, +// CHECK:STDOUT: {kind: 'LibraryDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/package/fail_in_nested_scope.carbon b/toolchain/parse/testdata/packages/package/fail_in_nested_scope.carbon new file mode 100644 index 0000000000000..fca605ee2dc08 --- /dev/null +++ b/toolchain/parse/testdata/packages/package/fail_in_nested_scope.carbon @@ -0,0 +1,98 @@ +// 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/packages/package/fail_in_nested_scope.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/packages/package/fail_in_nested_scope.carbon + +// api.carbon + +class C { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+7]]:3: error: the `package` declaration must be the first non-comment line [PackageTooLate] + // CHECK:STDERR: package P; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-4]]:1: note: first non-comment line is here [FirstNonCommentLine] + // CHECK:STDERR: class C { + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + package P; +} + +fn F() { + // `package` here is an expression naming the package scope. + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+4]]:11: error: expected `.` after `package` expression [ExpectedPeriodAfterPackage] + // CHECK:STDERR: package P; + // CHECK:STDERR: ^ + // CHECK:STDERR: + package P; + + // OK + package.P; +} + +// impl.carbon + +class C { + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+7]]:3: error: the `package` declaration must be the first non-comment line [PackageTooLate] + // CHECK:STDERR: impl package P; + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-29]]:1: note: first non-comment line is here [FirstNonCommentLine] + // CHECK:STDERR: class C { + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + impl package P; +} + +fn F() { + // This reaches decl parsing because `impl` is a valid modifier or introducer. + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE+6]]:3: error: the `package` declaration must be the first non-comment line [PackageTooLate] + // CHECK:STDERR: impl package P; + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_in_nested_scope.carbon:[[@LINE-41]]:1: note: first non-comment line is here [FirstNonCommentLine] + // CHECK:STDERR: class C { + // CHECK:STDERR: ^~~~~ + impl package P; +} + +// CHECK:STDOUT: - filename: fail_in_nested_scope.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, +// CHECK:STDOUT: {kind: 'PackageDecl', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'PackageExpr', text: 'package'}, +// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PackageExpr', text: 'package'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'P'}, +// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, +// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'}, +// CHECK:STDOUT: {kind: 'PackageDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, +// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'}, +// CHECK:STDOUT: {kind: 'PackageDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index 6b08c2ef88b37..83d9e37e8df07 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -124,8 +124,8 @@ using FileEnd = LeafNode; // --------------------- // An empty declaration, such as `;`. -using EmptyDecl = LeafNode; +using EmptyDecl = + LeafNode; // A name in a non-expression context, such as a declaration. using IdentifierName = @@ -421,8 +421,7 @@ using AliasInitializer = // An `alias` declaration: `alias a = b;`. struct Alias { static constexpr auto Kind = NodeKind::Alias.Define( - {.category = NodeCategory::Decl | NodeCategory::Statement, - .bracketed_by = AliasIntroducer::Kind}); + {.category = NodeCategory::Decl, .bracketed_by = AliasIntroducer::Kind}); AliasIntroducerId introducer; llvm::SmallVector modifiers; @@ -441,8 +440,7 @@ using LetInitializer = LeafNode; // A `let` declaration: `let a: i32 = 5;`. struct LetDecl { static constexpr auto Kind = NodeKind::LetDecl.Define( - {.category = NodeCategory::Decl | NodeCategory::Statement, - .bracketed_by = LetIntroducer::Kind}); + {.category = NodeCategory::Decl, .bracketed_by = LetIntroducer::Kind}); LetIntroducerId introducer; llvm::SmallVector modifiers; @@ -468,9 +466,9 @@ using VariableInitializer = // A `var` declaration: `var a: i32;` or `var a: i32 = 5;`. struct VariableDecl { - static constexpr auto Kind = NodeKind::VariableDecl.Define( - {.category = NodeCategory::Decl | NodeCategory::Statement, - .bracketed_by = VariableIntroducer::Kind}); + static constexpr auto Kind = + NodeKind::VariableDecl.Define({.category = NodeCategory::Decl, + .bracketed_by = VariableIntroducer::Kind}); VariableIntroducerId introducer; llvm::SmallVector modifiers;