Repository: carbon-language/carbon-lang
File: toolchain/check/handle_function.cpp (C++)

Code before:

  if (virtual_modifier != SemIR::Function::VirtualModifier::None &&
      !self_param_id.has_value()) {
    CARBON_DIAGNOSTIC(VirtualWithoutSelf, Error, "virtual class function");
    context.emitter().Build(node_id, VirtualWithoutSelf).Emit();
  }
  // Build the function entity. This will be merged into an existing function if
  // there is one, or otherwise added to the function store.
  auto function_info =
      SemIR::Function{{name_context.MakeEntityWithParamsBase(
                          name, decl_id, is_extern, introducer.extern_library)},
                      {.return_slot_pattern_id = name.return_slot_pattern_id,
                       .virtual_modifier = virtual_modifier,
                       .self_param_id = self_param_id}};
  if (is_definition) {
    function_info.definition_id = decl_id;
  }
  if (virtual_class_info) {
    context.vtable_stack().AddInstId(decl_id);
  }

  if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
    DiagnosePoisonedName(context, name_context.name_id_for_new_inst(),
                         name_context.poisoning_loc_id, name_context.loc_id);
  } else {
    TryMergeRedecl(context, node_id, name_context.name_id,
                   name_context.prev_inst_id(), name_context.loc_id,
                   function_decl, function_info, is_definition);
  }

  // Create a new function if this isn't a valid redeclaration.
  if (!function_decl.function_id.has_value()) {
    if (function_info.is_extern && context.sem_ir().is_impl()) {
      DiagnoseExternRequiresDeclInApiFile(context, node_id);
    }
    function_info.generic_id = BuildGenericDecl(context, decl_id);
    function_decl.function_id = context.functions().Add(function_info);
  } else {
    FinishGenericRedecl(context, decl_id, function_info.generic_id);
    // TODO: Validate that the redeclaration doesn't set an access modifier.
  }
  function_decl.type_id =
      GetFunctionType(context, function_decl.function_id,
                      context.scope_stack().PeekSpecificId());

  // Write the function ID into the FunctionDecl.
  ReplaceInstBeforeConstantUse(context, decl_id, function_decl);

  // Diagnose 'definition of `abstract` function' using the canonical Function's
  // modifiers.
  if (is_definition &&

Review comment (suggestion):
Might be easier to read as a series of early returns?
```
if (!function_info.implicit_param_patterns_id.has_value()) {
  return;
}
if (function_info.param_patterns_id.has_value()) {
  return;
}
if (context.inst_blocks().Get(function_info.param_patterns_id).empty()) {
  return;
}
if (!return_type_id.has_value()) {
  return;
}
if (return_type_id == GetTupleType(context, {})) {
  return;
}
if (return_type_id == MakeIntType(..)) {
  return;
}
CARBON_DIAGNOSTIC...
```

Code after:

  context.decl_name_stack().AddName(name_context, lookup_result_id,
                                    modifier_set.GetAccessKind());
}

// If the function is the entry point, do corresponding validation.
static auto ValidateForEntryPoint(Context& context,
                                  Parse::AnyFunctionDeclId node_id,
                                  SemIR::FunctionId function_id,
                                  const SemIR::Function& function_info)
    -> void {
  if (!SemIR::IsEntryPoint(context.sem_ir(), function_id)) {
    return;
  }

  auto return_type_id = function_info.GetDeclaredReturnType(context.sem_ir());
  // TODO: Update this once valid signatures for the entry point are decided.
  if (function_info.implicit_param_patterns_id.has_value() ||
      !function_info.param_patterns_id.has_value() ||
      !context.inst_blocks().Get(function_info.param_patterns_id).empty() ||
      (return_type_id.has_value() &&
       return_type_id != GetTupleType(context, {}) &&
       // TODO: Decide on valid return types for `Main.Run`. Perhaps we should
       // have an interface for this.
       return_type_id != MakeIntType(context, node_id, SemIR::IntKind::Signed,
                                     context.ints().Add(32)))) {
    CARBON_DIAGNOSTIC(InvalidMainRunSignature, Error,
                      "invalid signature for `Main.Run` function; expected "
                      "`fn ()` or `fn () -> i32`");
    context.emitter().Emit(node_id, InvalidMainRunSignature);
  }
}

// Requests a vtable be created when processing a virtual function.
static auto RequestVtableIfVirtual(
    Context& context, Parse::AnyFunctionDeclId node_id,
    SemIR::Function::VirtualModifier virtual_modifier,
    const std::optional<SemIR::Inst>& parent_scope_inst, SemIR::InstId decl_id)
    -> void {
  // In order to request a vtable, the function must be virtual, and in a class
  // scope.
  if (virtual_modifier == SemIR::Function::VirtualModifier::None ||
      !parent_scope_inst) {
    return;
  }
  auto class_decl = parent_scope_inst->TryAs<SemIR::ClassDecl>();
  if (!class_decl) {
    return;
  }

  auto& class_info = context.classes().Get(class_decl->class_id);