Skip to content

Commit d42128e

Browse files
authored
Parse all kinds of declarations at function scope. (#4779)
These don't fully work in check and beyond yet, because they're not added into lexical lookup, but already mostly do the right thing. Per #3407, disallow namespace declarations anywhere other than at file scope for now. We don't treat statements starting with a packaging introducer keyword (`package`, `library`, `import`) as declarations because they're sufficiently unlikely to occur that the error recovery doesn't seem important, and this avoids needing to disambiguate `package.` at the start of an expression.
1 parent 1e5e2bc commit d42128e

25 files changed

+1223
-116
lines changed

toolchain/check/handle_namespace.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "toolchain/sem_ir/ids.h"
1111
#include "toolchain/sem_ir/inst.h"
1212
#include "toolchain/sem_ir/name_scope.h"
13+
#include "toolchain/sem_ir/typed_insts.h"
1314

1415
namespace Carbon::Check {
1516

@@ -26,6 +27,12 @@ auto HandleParseNode(Context& context, Parse::NamespaceStartId /*node_id*/)
2627
return true;
2728
}
2829

30+
static auto IsNamespaceScope(Context& context, SemIR::NameScopeId name_scope_id)
31+
-> bool {
32+
auto [_, inst] = context.name_scopes().GetInstIfValid(name_scope_id);
33+
return inst && inst->Is<SemIR::Namespace>();
34+
}
35+
2936
auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool {
3037
auto name_context = context.decl_name_stack().FinishName(
3138
PopNameComponentWithoutParams(context, Lex::TokenKind::Namespace));
@@ -83,6 +90,11 @@ auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool {
8390
namespace_inst.name_scope_id = context.name_scopes().Add(
8491
namespace_id, name_context.name_id_for_new_inst(),
8592
name_context.parent_scope_id);
93+
if (!IsNamespaceScope(context, name_context.parent_scope_id)) {
94+
CARBON_DIAGNOSTIC(NamespaceDeclNotAtTopLevel, Error,
95+
"`namespace` declaration not at top level");
96+
context.emitter().Emit(node_id, NamespaceDeclNotAtTopLevel);
97+
}
8698
}
8799

88100
context.ReplaceInstBeforeConstantUse(namespace_id, namespace_inst);

toolchain/check/testdata/class/adapter/adapt.carbon

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,30 @@ class AdaptNotExtend {
3939

4040
fn F(a: AdaptNotExtend) {
4141
// `Adapted` is not extended, so lookup for `F` finds nothing.
42-
// CHECK:STDERR: fail_not_extend.carbon:[[@LINE+3]]:3: error: member name `F` not found in `AdaptNotExtend` [MemberNameNotFoundInScope]
42+
// CHECK:STDERR: fail_not_extend.carbon:[[@LINE+4]]:3: error: member name `F` not found in `AdaptNotExtend` [MemberNameNotFoundInScope]
4343
// CHECK:STDERR: a.F();
4444
// CHECK:STDERR: ^~~
45+
// CHECK:STDERR:
4546
a.F();
4647
}
4748

49+
// --- fail_misplaced.carbon
50+
51+
fn F() {
52+
// CHECK:STDERR: fail_misplaced.carbon:[[@LINE+4]]:3: error: `adapt` declaration outside class [ClassSpecificDeclOutsideClass]
53+
// CHECK:STDERR: adapt i32;
54+
// CHECK:STDERR: ^~~~~~~~~~
55+
// CHECK:STDERR:
56+
adapt i32;
57+
}
58+
59+
interface I {
60+
// CHECK:STDERR: fail_misplaced.carbon:[[@LINE+3]]:3: error: `adapt` declaration outside class [ClassSpecificDeclOutsideClass]
61+
// CHECK:STDERR: adapt i32;
62+
// CHECK:STDERR: ^~~~~~~~~~
63+
adapt i32;
64+
}
65+
4866
// CHECK:STDOUT: --- basic.carbon
4967
// CHECK:STDOUT:
5068
// CHECK:STDOUT: constants {
@@ -184,3 +202,50 @@ fn F(a: AdaptNotExtend) {
184202
// CHECK:STDOUT: return
185203
// CHECK:STDOUT: }
186204
// CHECK:STDOUT:
205+
// CHECK:STDOUT: --- fail_misplaced.carbon
206+
// CHECK:STDOUT:
207+
// CHECK:STDOUT: constants {
208+
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
209+
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
210+
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template]
211+
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template]
212+
// CHECK:STDOUT: %I.type: type = facet_type <@I> [template]
213+
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
214+
// CHECK:STDOUT: }
215+
// CHECK:STDOUT:
216+
// CHECK:STDOUT: imports {
217+
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
218+
// CHECK:STDOUT: .Int = %import_ref.187
219+
// CHECK:STDOUT: import Core//prelude
220+
// CHECK:STDOUT: import Core//prelude/...
221+
// CHECK:STDOUT: }
222+
// CHECK:STDOUT: }
223+
// CHECK:STDOUT:
224+
// CHECK:STDOUT: file {
225+
// CHECK:STDOUT: package: <namespace> = namespace [template] {
226+
// CHECK:STDOUT: .Core = imports.%Core
227+
// CHECK:STDOUT: .F = %F.decl
228+
// CHECK:STDOUT: .I = %I.decl
229+
// CHECK:STDOUT: }
230+
// CHECK:STDOUT: %Core.import = import Core
231+
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
232+
// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type] {} {}
233+
// CHECK:STDOUT: }
234+
// CHECK:STDOUT:
235+
// CHECK:STDOUT: interface @I {
236+
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
237+
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32]
238+
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
239+
// CHECK:STDOUT:
240+
// CHECK:STDOUT: !members:
241+
// CHECK:STDOUT: .Self = %Self
242+
// CHECK:STDOUT: witness = ()
243+
// CHECK:STDOUT: }
244+
// CHECK:STDOUT:
245+
// CHECK:STDOUT: fn @F() {
246+
// CHECK:STDOUT: !entry:
247+
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32]
248+
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
249+
// CHECK:STDOUT: return
250+
// CHECK:STDOUT: }
251+
// CHECK:STDOUT:

toolchain/check/testdata/class/fail_base_misplaced.carbon

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,55 @@ base class B {}
1717
extend base: B;
1818

1919
fn F() {
20-
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+7]]:3: error: expected expression [ExpectedExpr]
20+
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+4]]:3: error: `base` declaration outside class [ClassSpecificDeclOutsideClass]
2121
// CHECK:STDERR: extend base: B;
22-
// CHECK:STDERR: ^~~~~~
22+
// CHECK:STDERR: ^~~~~~~~~~~~~~~
2323
// CHECK:STDERR:
24-
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:3: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
25-
// CHECK:STDERR: extend base: B;
26-
// CHECK:STDERR: ^~~~~~
2724
extend base: B;
2825
}
2926

27+
class C {
28+
fn F() {
29+
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:5: error: `base` declaration outside class [ClassSpecificDeclOutsideClass]
30+
// CHECK:STDERR: extend base: B;
31+
// CHECK:STDERR: ^~~~~~~~~~~~~~~
32+
extend base: B;
33+
}
34+
}
35+
3036
// CHECK:STDOUT: --- fail_base_misplaced.carbon
3137
// CHECK:STDOUT:
3238
// CHECK:STDOUT: constants {
3339
// CHECK:STDOUT: %B: type = class_type @B [template]
3440
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template]
3541
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template]
42+
// CHECK:STDOUT: %F.type.b25: type = fn_type @F.1 [template]
43+
// CHECK:STDOUT: %F.c41: %F.type.b25 = struct_value () [template]
44+
// CHECK:STDOUT: %C: type = class_type @C [template]
45+
// CHECK:STDOUT: %F.type.675: type = fn_type @F.2 [template]
46+
// CHECK:STDOUT: %F.2c9: %F.type.675 = struct_value () [template]
47+
// CHECK:STDOUT: }
48+
// CHECK:STDOUT:
49+
// CHECK:STDOUT: imports {
50+
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
51+
// CHECK:STDOUT: import Core//prelude
52+
// CHECK:STDOUT: import Core//prelude/...
53+
// CHECK:STDOUT: }
3654
// CHECK:STDOUT: }
3755
// CHECK:STDOUT:
38-
// CHECK:STDOUT: file {}
56+
// CHECK:STDOUT: file {
57+
// CHECK:STDOUT: package: <namespace> = namespace [template] {
58+
// CHECK:STDOUT: .Core = imports.%Core
59+
// CHECK:STDOUT: .B = %B.decl
60+
// CHECK:STDOUT: .F = %F.decl
61+
// CHECK:STDOUT: .C = %C.decl
62+
// CHECK:STDOUT: }
63+
// CHECK:STDOUT: %Core.import = import Core
64+
// CHECK:STDOUT: %B.decl: type = class_decl @B [template = constants.%B] {} {}
65+
// CHECK:STDOUT: %B.ref: type = name_ref B, %B.decl [template = constants.%B]
66+
// CHECK:STDOUT: %F.decl: %F.type.b25 = fn_decl @F.1 [template = constants.%F.c41] {} {}
67+
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {}
68+
// CHECK:STDOUT: }
3969
// CHECK:STDOUT:
4070
// CHECK:STDOUT: class @B {
4171
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template = constants.%complete_type]
@@ -45,5 +75,25 @@ fn F() {
4575
// CHECK:STDOUT: complete_type_witness = %complete_type
4676
// CHECK:STDOUT: }
4777
// CHECK:STDOUT:
48-
// CHECK:STDOUT: fn @F();
78+
// CHECK:STDOUT: class @C {
79+
// CHECK:STDOUT: %F.decl: %F.type.675 = fn_decl @F.2 [template = constants.%F.2c9] {} {}
80+
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template = constants.%complete_type]
81+
// CHECK:STDOUT:
82+
// CHECK:STDOUT: !members:
83+
// CHECK:STDOUT: .Self = constants.%C
84+
// CHECK:STDOUT: .F = %F.decl
85+
// CHECK:STDOUT: complete_type_witness = %complete_type
86+
// CHECK:STDOUT: }
87+
// CHECK:STDOUT:
88+
// CHECK:STDOUT: fn @F.1() {
89+
// CHECK:STDOUT: !entry:
90+
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
91+
// CHECK:STDOUT: return
92+
// CHECK:STDOUT: }
93+
// CHECK:STDOUT:
94+
// CHECK:STDOUT: fn @F.2() {
95+
// CHECK:STDOUT: !entry:
96+
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
97+
// CHECK:STDOUT: return
98+
// CHECK:STDOUT: }
4999
// CHECK:STDOUT:

toolchain/check/testdata/class/fail_todo_local_class.carbon

Lines changed: 103 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,132 @@
88
// TIP: To dump output, run:
99
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_todo_local_class.carbon
1010

11-
// TODO: Support parsing classes at function scope.
1211
class A {
13-
fn F() {
14-
// CHECK:STDERR: fail_todo_local_class.carbon:[[@LINE+7]]:5: error: expected expression [ExpectedExpr]
15-
// CHECK:STDERR: class B {
16-
// CHECK:STDERR: ^~~~~
17-
// CHECK:STDERR:
18-
// CHECK:STDERR: fail_todo_local_class.carbon:[[@LINE+3]]:5: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
19-
// CHECK:STDERR: class B {
20-
// CHECK:STDERR: ^~~~~
12+
fn F() -> i32 {
2113
class B {
22-
fn G() {
23-
var b: B = {};
14+
fn Make() -> Self {
15+
returned var b: Self = {.n = 1};
16+
return var;
2417
}
18+
19+
var n: i32;
2520
}
21+
22+
// TODO: Add the name `B` to the lexical scope.
23+
// CHECK:STDERR: fail_todo_local_class.carbon:[[@LINE+3]]:12: error: name `B` not found [NameNotFound]
24+
// CHECK:STDERR: return B.Make().n;
25+
// CHECK:STDERR: ^
26+
return B.Make().n;
2627
}
2728
}
2829

2930
// CHECK:STDOUT: --- fail_todo_local_class.carbon
3031
// CHECK:STDOUT:
3132
// CHECK:STDOUT: constants {
3233
// CHECK:STDOUT: %A: type = class_type @A [template]
34+
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template]
35+
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template]
3336
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
3437
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
3538
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template]
36-
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template]
39+
// CHECK:STDOUT: %complete_type.357: <witness> = complete_type_witness %empty_struct_type [template]
40+
// CHECK:STDOUT: %B: type = class_type @B [template]
41+
// CHECK:STDOUT: %Make.type: type = fn_type @Make [template]
42+
// CHECK:STDOUT: %Make: %Make.type = struct_value () [template]
43+
// CHECK:STDOUT: %B.elem: type = unbound_element_type %B, %i32 [template]
44+
// CHECK:STDOUT: %struct_type.n.5cd: type = struct_type {.n: %i32} [template]
45+
// CHECK:STDOUT: %complete_type.9b7: <witness> = complete_type_witness %struct_type.n.5cd [template]
46+
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [template]
47+
// CHECK:STDOUT: %struct_type.n.44a: type = struct_type {.n: Core.IntLiteral} [template]
48+
// CHECK:STDOUT: %Convert.type.cd1: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
49+
// CHECK:STDOUT: %impl_witness.5b0: <witness> = impl_witness (imports.%import_ref.723), @impl.1(%int_32) [template]
50+
// CHECK:STDOUT: %Convert.type.466: type = fn_type @Convert.2, @impl.1(%int_32) [template]
51+
// CHECK:STDOUT: %Convert.925: %Convert.type.466 = struct_value () [template]
52+
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_1.5b8, %Convert.925 [template]
53+
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(%int_32) [template]
54+
// CHECK:STDOUT: %int_1.c60: %i32 = int_value 1 [template]
55+
// CHECK:STDOUT: %B.val: %B = struct_value (%int_1.c60) [template]
3756
// CHECK:STDOUT: }
3857
// CHECK:STDOUT:
39-
// CHECK:STDOUT: file {}
58+
// CHECK:STDOUT: imports {
59+
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
60+
// CHECK:STDOUT: .Int = %import_ref.187
61+
// CHECK:STDOUT: .ImplicitAs = %import_ref.a69
62+
// CHECK:STDOUT: import Core//prelude
63+
// CHECK:STDOUT: import Core//prelude/...
64+
// CHECK:STDOUT: }
65+
// CHECK:STDOUT: }
66+
// CHECK:STDOUT:
67+
// CHECK:STDOUT: file {
68+
// CHECK:STDOUT: package: <namespace> = namespace [template] {
69+
// CHECK:STDOUT: .Core = imports.%Core
70+
// CHECK:STDOUT: .A = %A.decl
71+
// CHECK:STDOUT: }
72+
// CHECK:STDOUT: %Core.import = import Core
73+
// CHECK:STDOUT: %A.decl: type = class_decl @A [template = constants.%A] {} {}
74+
// CHECK:STDOUT: }
4075
// CHECK:STDOUT:
4176
// CHECK:STDOUT: class @A {
42-
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
43-
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template = constants.%complete_type]
77+
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {
78+
// CHECK:STDOUT: %return.patt: %i32 = return_slot_pattern
79+
// CHECK:STDOUT: %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param0
80+
// CHECK:STDOUT: } {
81+
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32]
82+
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
83+
// CHECK:STDOUT: %return.param: ref %i32 = out_param runtime_param0
84+
// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param
85+
// CHECK:STDOUT: }
86+
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template = constants.%complete_type.357]
4487
// CHECK:STDOUT:
4588
// CHECK:STDOUT: !members:
4689
// CHECK:STDOUT: .Self = constants.%A
4790
// CHECK:STDOUT: .F = %F.decl
4891
// CHECK:STDOUT: complete_type_witness = %complete_type
4992
// CHECK:STDOUT: }
5093
// CHECK:STDOUT:
51-
// CHECK:STDOUT: fn @F();
94+
// CHECK:STDOUT: class @B {
95+
// CHECK:STDOUT: %Make.decl: %Make.type = fn_decl @Make [template = constants.%Make] {
96+
// CHECK:STDOUT: %return.patt: %B = return_slot_pattern
97+
// CHECK:STDOUT: %return.param_patt: %B = out_param_pattern %return.patt, runtime_param0
98+
// CHECK:STDOUT: } {
99+
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B [template = constants.%B]
100+
// CHECK:STDOUT: %return.param: ref %B = out_param runtime_param0
101+
// CHECK:STDOUT: %return: ref %B = return_slot %return.param
102+
// CHECK:STDOUT: }
103+
// CHECK:STDOUT: %.loc19: %B.elem = field_decl n, element0 [template]
104+
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %struct_type.n.5cd [template = constants.%complete_type.9b7]
105+
// CHECK:STDOUT:
106+
// CHECK:STDOUT: !members:
107+
// CHECK:STDOUT: .Self = constants.%B
108+
// CHECK:STDOUT: .Make = %Make.decl
109+
// CHECK:STDOUT: .n = %.loc19
110+
// CHECK:STDOUT: complete_type_witness = %complete_type
111+
// CHECK:STDOUT: }
112+
// CHECK:STDOUT:
113+
// CHECK:STDOUT: fn @F() -> %i32 {
114+
// CHECK:STDOUT: !entry:
115+
// CHECK:STDOUT: %B.decl: type = class_decl @B [template = constants.%B] {} {}
116+
// CHECK:STDOUT: %B.ref: <error> = name_ref B, <error> [template = <error>]
117+
// CHECK:STDOUT: %Make.ref: <error> = name_ref Make, <error> [template = <error>]
118+
// CHECK:STDOUT: %n.ref: <error> = name_ref n, <error> [template = <error>]
119+
// CHECK:STDOUT: return <error>
120+
// CHECK:STDOUT: }
121+
// CHECK:STDOUT:
122+
// CHECK:STDOUT: fn @Make() -> %return.param_patt: %B {
123+
// CHECK:STDOUT: !entry:
124+
// CHECK:STDOUT: %b: ref %B = bind_name b, %return
125+
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [template = constants.%int_1.5b8]
126+
// CHECK:STDOUT: %.loc15_39.1: %struct_type.n.44a = struct_literal (%int_1)
127+
// CHECK:STDOUT: %impl.elem0: %Convert.type.cd1 = impl_witness_access constants.%impl_witness.5b0, element0 [template = constants.%Convert.925]
128+
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_1, %impl.elem0 [template = constants.%Convert.bound]
129+
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
130+
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_1) [template = constants.%int_1.c60]
131+
// CHECK:STDOUT: %.loc15_39.2: init %i32 = converted %int_1, %int.convert_checked [template = constants.%int_1.c60]
132+
// CHECK:STDOUT: %.loc15_39.3: ref %i32 = class_element_access %return, element0
133+
// CHECK:STDOUT: %.loc15_39.4: init %i32 = initialize_from %.loc15_39.2 to %.loc15_39.3 [template = constants.%int_1.c60]
134+
// CHECK:STDOUT: %.loc15_39.5: init %B = class_init (%.loc15_39.4), %return [template = constants.%B.val]
135+
// CHECK:STDOUT: %.loc15_40: init %B = converted %.loc15_39.1, %.loc15_39.5 [template = constants.%B.val]
136+
// CHECK:STDOUT: assign %return, %.loc15_40
137+
// CHECK:STDOUT: return %b to %return
138+
// CHECK:STDOUT: }
52139
// CHECK:STDOUT:

0 commit comments

Comments
 (0)