1515#include " toolchain/check/import_ref.h"
1616#include " toolchain/check/inst.h"
1717#include " toolchain/check/interface.h"
18+ #include " toolchain/check/keyword_modifier_set.h"
1819#include " toolchain/check/literal.h"
1920#include " toolchain/check/merge.h"
2021#include " toolchain/check/modifiers.h"
2122#include " toolchain/check/name_component.h"
2223#include " toolchain/check/name_lookup.h"
2324#include " toolchain/check/type.h"
2425#include " toolchain/check/type_completion.h"
26+ #include " toolchain/parse/node_ids.h"
2527#include " toolchain/sem_ir/builtin_function_kind.h"
2628#include " toolchain/sem_ir/entry_point.h"
2729#include " toolchain/sem_ir/function.h"
@@ -75,11 +77,33 @@ auto HandleParseNode(Context& context, Parse::ReturnTypeId node_id) -> bool {
7577 return true ;
7678}
7779
78- static auto DiagnoseModifiers (Context& context, DeclIntroducerState& introducer,
80+ // Returns the ID of the self parameter pattern, or None.
81+ // TODO: Do this during initial traversal of implicit params.
82+ static auto FindSelfPattern (Context& context,
83+ SemIR::InstBlockId implicit_param_patterns_id)
84+ -> SemIR::InstId {
85+ auto implicit_param_patterns =
86+ context.inst_blocks ().GetOrEmpty (implicit_param_patterns_id);
87+ if (const auto * i = llvm::find_if (implicit_param_patterns,
88+ [&](auto implicit_param_id) {
89+ return SemIR::IsSelfPattern (
90+ context.sem_ir (), implicit_param_id);
91+ });
92+ i != implicit_param_patterns.end ()) {
93+ return *i;
94+ }
95+ return SemIR::InstId::None;
96+ }
97+
98+ // Diagnoses issues with the modifiers, removing modifiers that shouldn't be
99+ // present.
100+ static auto DiagnoseModifiers (Context& context,
101+ Parse::AnyFunctionDeclId node_id,
102+ DeclIntroducerState& introducer,
79103 bool is_definition,
80104 SemIR::InstId parent_scope_inst_id,
81- std::optional<SemIR::Inst> parent_scope_inst)
82- -> void {
105+ std::optional<SemIR::Inst> parent_scope_inst,
106+ SemIR::InstId self_param_id) -> void {
83107 CheckAccessModifiersOnDecl (context, introducer, parent_scope_inst);
84108 LimitModifiersOnDecl (context, introducer,
85109 KeywordModifierSet::Access | KeywordModifierSet::Extern |
@@ -90,6 +114,33 @@ static auto DiagnoseModifiers(Context& context, DeclIntroducerState& introducer,
90114 CheckMethodModifiersOnFunction (context, introducer, parent_scope_inst_id,
91115 parent_scope_inst);
92116 RequireDefaultFinalOnlyInInterfaces (context, introducer, parent_scope_inst);
117+
118+ if (introducer.modifier_set .HasAnyOf (KeywordModifierSet::Interface)) {
119+ // TODO: Once we are saving the modifiers for a function, add check that
120+ // the function may only be defined if it is marked `default` or `final`.
121+ context.TODO (introducer.modifier_node_id (ModifierOrder::Decl),
122+ " interface modifier" );
123+ }
124+
125+ if (!self_param_id.has_value () &&
126+ introducer.modifier_set .HasAnyOf (KeywordModifierSet::Method)) {
127+ CARBON_DIAGNOSTIC (VirtualWithoutSelf, Error, " virtual class function" );
128+ context.emitter ().Build (node_id, VirtualWithoutSelf).Emit ();
129+ // TODO: Remove the incorrect modifier.
130+ // introducer.modifier_set.Remove(KeywordModifierSet::Method);
131+ }
132+ }
133+
134+ // Returns the virtual-family modifier as an enum.
135+ static auto GetVirtualModifier (const KeywordModifierSet& modifier_set)
136+ -> SemIR::Function::VirtualModifier {
137+ return modifier_set.ToEnum <SemIR::Function::VirtualModifier>()
138+ .Case (KeywordModifierSet::Virtual,
139+ SemIR::Function::VirtualModifier::Virtual)
140+ .Case (KeywordModifierSet::Abstract,
141+ SemIR::Function::VirtualModifier::Abstract)
142+ .Case (KeywordModifierSet::Impl, SemIR::Function::VirtualModifier::Impl)
143+ .Default (SemIR::Function::VirtualModifier::None);
93144}
94145
95146// Tries to merge new_function into prev_function_id. Since new_function won't
@@ -140,11 +191,17 @@ static auto MergeFunctionRedecl(Context& context,
140191
141192// Check whether this is a redeclaration, merging if needed.
142193static auto TryMergeRedecl (Context& context, Parse::AnyFunctionDeclId node_id,
143- SemIR::NameId name_id, SemIR::InstId prev_id,
144- SemIR::LocId name_loc_id,
194+ const DeclNameStack::NameContext& name_context,
145195 SemIR::FunctionDecl& function_decl,
146196 SemIR::Function& function_info, bool is_definition)
147197 -> void {
198+ if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
199+ DiagnosePoisonedName (context, name_context.name_id_for_new_inst (),
200+ name_context.poisoning_loc_id , name_context.loc_id );
201+ return ;
202+ }
203+
204+ auto prev_id = name_context.prev_inst_id ();
148205 if (!prev_id.has_value ()) {
149206 return ;
150207 }
@@ -185,7 +242,8 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
185242 }
186243
187244 if (!prev_function_id.has_value ()) {
188- DiagnoseDuplicateName (context, name_id, name_loc_id, prev_id);
245+ DiagnoseDuplicateName (context, name_context.name_id , name_context.loc_id ,
246+ prev_id);
189247 return ;
190248 }
191249
@@ -197,6 +255,89 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
197255 }
198256}
199257
258+ // Adds the declaration to name lookup when appropriate.
259+ static auto MaybeAddToNameLookup (
260+ Context& context, const DeclNameStack::NameContext& name_context,
261+ const KeywordModifierSet& modifier_set,
262+ const std::optional<SemIR::Inst>& parent_scope_inst, SemIR::InstId decl_id)
263+ -> void {
264+ if (name_context.state == DeclNameStack::NameContext::State::Poisoned ||
265+ name_context.prev_inst_id ().has_value ()) {
266+ return ;
267+ }
268+
269+ // At interface scope, a function declaration introduces an associated
270+ // function.
271+ auto lookup_result_id = decl_id;
272+ if (parent_scope_inst && !name_context.has_qualifiers ) {
273+ if (auto interface_scope =
274+ parent_scope_inst->TryAs <SemIR::InterfaceDecl>()) {
275+ lookup_result_id = BuildAssociatedEntity (
276+ context, interface_scope->interface_id , decl_id);
277+ }
278+ }
279+
280+ context.decl_name_stack ().AddName (name_context, lookup_result_id,
281+ modifier_set.GetAccessKind ());
282+ }
283+
284+ // If the function is the entry point, do corresponding validation.
285+ static auto ValidateForEntryPoint (Context& context,
286+ Parse::AnyFunctionDeclId node_id,
287+ SemIR::FunctionId function_id,
288+ const SemIR::Function& function_info)
289+ -> void {
290+ if (!SemIR::IsEntryPoint (context.sem_ir (), function_id)) {
291+ return ;
292+ }
293+
294+ auto return_type_id = function_info.GetDeclaredReturnType (context.sem_ir ());
295+ // TODO: Update this once valid signatures for the entry point are decided.
296+ if (function_info.implicit_param_patterns_id .has_value () ||
297+ !function_info.param_patterns_id .has_value () ||
298+ !context.inst_blocks ().Get (function_info.param_patterns_id ).empty () ||
299+ (return_type_id.has_value () &&
300+ return_type_id != GetTupleType (context, {}) &&
301+ // TODO: Decide on valid return types for `Main.Run`. Perhaps we should
302+ // have an interface for this.
303+ return_type_id != MakeIntType (context, node_id, SemIR::IntKind::Signed,
304+ context.ints ().Add (32 )))) {
305+ CARBON_DIAGNOSTIC (InvalidMainRunSignature, Error,
306+ " invalid signature for `Main.Run` function; expected "
307+ " `fn ()` or `fn () -> i32`" );
308+ context.emitter ().Emit (node_id, InvalidMainRunSignature);
309+ }
310+ }
311+
312+ // Requests a vtable be created when processing a virtual function.
313+ static auto RequestVtableIfVirtual (
314+ Context& context, Parse::AnyFunctionDeclId node_id,
315+ SemIR::Function::VirtualModifier virtual_modifier,
316+ const std::optional<SemIR::Inst>& parent_scope_inst, SemIR::InstId decl_id)
317+ -> void {
318+ // In order to request a vtable, the function must be virtual, and in a class
319+ // scope.
320+ if (virtual_modifier == SemIR::Function::VirtualModifier::None ||
321+ !parent_scope_inst) {
322+ return ;
323+ }
324+ auto class_decl = parent_scope_inst->TryAs <SemIR::ClassDecl>();
325+ if (!class_decl) {
326+ return ;
327+ }
328+
329+ auto & class_info = context.classes ().Get (class_decl->class_id );
330+ if (virtual_modifier == SemIR::Function::VirtualModifier::Impl &&
331+ !class_info.base_id .has_value ()) {
332+ CARBON_DIAGNOSTIC (ImplWithoutBase, Error, " impl without base class" );
333+ context.emitter ().Build (node_id, ImplWithoutBase).Emit ();
334+ }
335+ // TODO: If this is an `impl` function, check there's a matching base
336+ // function that's impl or virtual.
337+ class_info.is_dynamic = true ;
338+ context.vtable_stack ().AddInstId (decl_id);
339+ }
340+
200341// Build a FunctionDecl describing the signature of a function. This
201342// handles the common logic shared by function declaration syntax and function
202343// definition syntax.
@@ -216,6 +357,8 @@ static auto BuildFunctionDecl(Context& context,
216357 context.TODO (node_id, " function with positional parameters" );
217358 name.param_patterns_id = SemIR::InstBlockId::Empty;
218359 }
360+ auto self_param_id =
361+ FindSelfPattern (context, name.implicit_param_patterns_id );
219362
220363 auto name_context = context.decl_name_stack ().FinishName (name);
221364 context.node_stack ()
@@ -226,89 +369,34 @@ static auto BuildFunctionDecl(Context& context,
226369 context.name_scopes ().GetInstIfValid (name_context.parent_scope_id );
227370 auto introducer =
228371 context.decl_introducer_state_stack ().Pop <Lex::TokenKind::Fn>();
229- DiagnoseModifiers (context, introducer, is_definition, parent_scope_inst_id ,
230- parent_scope_inst);
372+ DiagnoseModifiers (context, node_id, introducer, is_definition ,
373+ parent_scope_inst_id, parent_scope_inst, self_param_id );
231374 bool is_extern = introducer.modifier_set .HasAnyOf (KeywordModifierSet::Extern);
232- auto virtual_modifier =
233- introducer.modifier_set .ToEnum <SemIR::Function::VirtualModifier>()
234- .Case (KeywordModifierSet::Virtual,
235- SemIR::Function::VirtualModifier::Virtual)
236- .Case (KeywordModifierSet::Abstract,
237- SemIR::Function::VirtualModifier::Abstract)
238- .Case (KeywordModifierSet::Impl,
239- SemIR::Function::VirtualModifier::Impl)
240- .Default (SemIR::Function::VirtualModifier::None);
241- SemIR::Class* virtual_class_info = nullptr ;
242- if (virtual_modifier != SemIR::Function::VirtualModifier::None &&
243- parent_scope_inst) {
244- if (auto class_decl = parent_scope_inst->TryAs <SemIR::ClassDecl>()) {
245- virtual_class_info = &context.classes ().Get (class_decl->class_id );
246- if (virtual_modifier == SemIR::Function::VirtualModifier::Impl &&
247- !virtual_class_info->base_id .has_value ()) {
248- CARBON_DIAGNOSTIC (ImplWithoutBase, Error, " impl without base class" );
249- context.emitter ().Build (node_id, ImplWithoutBase).Emit ();
250- }
251- // TODO: If this is an `impl` function, check there's a matching base
252- // function that's impl or virtual.
253- virtual_class_info->is_dynamic = true ;
254- }
255- }
256- if (introducer.modifier_set .HasAnyOf (KeywordModifierSet::Interface)) {
257- // TODO: Once we are saving the modifiers for a function, add check that
258- // the function may only be defined if it is marked `default` or `final`.
259- context.TODO (introducer.modifier_node_id (ModifierOrder::Decl),
260- " interface modifier" );
261- }
375+ auto virtual_modifier = GetVirtualModifier (introducer.modifier_set );
262376
263377 // Add the function declaration.
264- auto decl_block_id = context. inst_block_stack (). Pop ();
265- auto function_decl = SemIR::FunctionDecl{
266- SemIR::TypeId::None, SemIR::FunctionId::None, decl_block_id };
378+ SemIR::FunctionDecl function_decl = {SemIR::TypeId::None,
379+ SemIR::FunctionId::None,
380+ context. inst_block_stack (). Pop () };
267381 auto decl_id =
268382 AddPlaceholderInst (context, SemIR::LocIdAndInst (node_id, function_decl));
383+ RequestVtableIfVirtual (context, node_id, virtual_modifier, parent_scope_inst,
384+ decl_id);
269385
270- // Find self parameter pattern.
271- // TODO: Do this during initial traversal of implicit params.
272- auto self_param_id = SemIR::InstId::None;
273- auto implicit_param_patterns =
274- context.inst_blocks ().GetOrEmpty (name.implicit_param_patterns_id );
275- if (const auto * i = llvm::find_if (implicit_param_patterns,
276- [&](auto implicit_param_id) {
277- return SemIR::IsSelfPattern (
278- context.sem_ir (), implicit_param_id);
279- });
280- i != implicit_param_patterns.end ()) {
281- self_param_id = *i;
282- }
283-
284- if (virtual_modifier != SemIR::Function::VirtualModifier::None &&
285- !self_param_id.has_value ()) {
286- CARBON_DIAGNOSTIC (VirtualWithoutSelf, Error, " virtual class function" );
287- context.emitter ().Build (node_id, VirtualWithoutSelf).Emit ();
288- }
289386 // Build the function entity. This will be merged into an existing function if
290387 // there is one, or otherwise added to the function store.
291388 auto function_info =
292- SemIR::Function{{ name_context.MakeEntityWithParamsBase (
293- name, decl_id, is_extern, introducer.extern_library )} ,
389+ SemIR::Function{name_context.MakeEntityWithParamsBase (
390+ name, decl_id, is_extern, introducer.extern_library ),
294391 {.return_slot_pattern_id = name.return_slot_pattern_id ,
295392 .virtual_modifier = virtual_modifier,
296393 .self_param_id = self_param_id}};
297394 if (is_definition) {
298395 function_info.definition_id = decl_id;
299396 }
300- if (virtual_class_info) {
301- context.vtable_stack ().AddInstId (decl_id);
302- }
303397
304- if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
305- DiagnosePoisonedName (context, name_context.name_id_for_new_inst (),
306- name_context.poisoning_loc_id , name_context.loc_id );
307- } else {
308- TryMergeRedecl (context, node_id, name_context.name_id ,
309- name_context.prev_inst_id (), name_context.loc_id ,
310- function_decl, function_info, is_definition);
311- }
398+ TryMergeRedecl (context, node_id, name_context, function_decl, function_info,
399+ is_definition);
312400
313401 // Create a new function if this isn't a valid redeclaration.
314402 if (!function_decl.function_id .has_value ()) {
@@ -338,43 +426,12 @@ static auto BuildFunctionDecl(Context& context,
338426 context.emitter ().Emit (TokenOnly (node_id), DefinedAbstractFunction);
339427 }
340428
341- // Check if we need to add this to name lookup, now that the function decl is
342- // done.
343- if (name_context.state != DeclNameStack::NameContext::State::Poisoned &&
344- !name_context.prev_inst_id ().has_value ()) {
345- // At interface scope, a function declaration introduces an associated
346- // function.
347- auto lookup_result_id = decl_id;
348- if (parent_scope_inst && !name_context.has_qualifiers ) {
349- if (auto interface_scope =
350- parent_scope_inst->TryAs <SemIR::InterfaceDecl>()) {
351- lookup_result_id = BuildAssociatedEntity (
352- context, interface_scope->interface_id , decl_id);
353- }
354- }
429+ // Add to name lookup if needed, now that the decl is built.
430+ MaybeAddToNameLookup (context, name_context, introducer.modifier_set ,
431+ parent_scope_inst, decl_id);
355432
356- context.decl_name_stack ().AddName (name_context, lookup_result_id,
357- introducer.modifier_set .GetAccessKind ());
358- }
359-
360- if (SemIR::IsEntryPoint (context.sem_ir (), function_decl.function_id )) {
361- auto return_type_id = function_info.GetDeclaredReturnType (context.sem_ir ());
362- // TODO: Update this once valid signatures for the entry point are decided.
363- if (function_info.implicit_param_patterns_id .has_value () ||
364- !function_info.param_patterns_id .has_value () ||
365- !context.inst_blocks ().Get (function_info.param_patterns_id ).empty () ||
366- (return_type_id.has_value () &&
367- return_type_id != GetTupleType (context, {}) &&
368- // TODO: Decide on valid return types for `Main.Run`. Perhaps we should
369- // have an interface for this.
370- return_type_id != MakeIntType (context, node_id, SemIR::IntKind::Signed,
371- context.ints ().Add (32 )))) {
372- CARBON_DIAGNOSTIC (InvalidMainRunSignature, Error,
373- " invalid signature for `Main.Run` function; expected "
374- " `fn ()` or `fn () -> i32`" );
375- context.emitter ().Emit (node_id, InvalidMainRunSignature);
376- }
377- }
433+ ValidateForEntryPoint (context, node_id, function_decl.function_id ,
434+ function_info);
378435
379436 if (!is_definition && context.sem_ir ().is_impl () && !is_extern) {
380437 context.definitions_required ().push_back (decl_id);
0 commit comments