Repository: carbon-language/carbon-lang
File: toolchain/lower/file_context.cpp (C++)

Code before:
  }

  if (auto* result = specific_functions_[specific_id.index]) {
    return result;
  }

  auto* result = BuildFunctionDecl(function_id, specific_id);
  // TODO: Add this function to a list of specific functions whose definitions
  // we need to emit.
  specific_functions_[specific_id.index] = result;
  // TODO: Should this be a pair of <function_id, specific_id> ?
  specific_function_definitions_.push_back(specific_id);
  return result;
}

auto FileContext::BuildFunctionTypeInfo(
    const SemIR::Function& function, SemIR::SpecificId specific_id,
    llvm::ArrayRef<SemIR::InstId> implicit_param_patterns,
    llvm::ArrayRef<SemIR::InstId> param_patterns,
    const SemIR::ReturnTypeInfo& return_info,
    llvm::SmallVector<llvm::Type*>& param_types,
    llvm::SmallVector<SemIR::InstId>& param_inst_ids, llvm::Type*& return_type,
    SemIR::InstId& return_param_id) -> void {
  return_type = nullptr;
  if (return_info.type_id.has_value()) {
    if (!types_[return_info.type_id.index]) {
      // The return type has not been completed, so bail out of creating the
      // function type.
      return;
    }
    return_type = GetType(return_info.type_id);
  }
  // TODO: Consider either storing `param_inst_ids` somewhere so that we can
  // reuse it from `BuildFunctionDefinition` and when building calls, or
  // factor out a mechanism to compute the mapping between parameters and
  // arguments on demand.
  auto max_llvm_params = (return_info.has_return_slot() ? 1 : 0) +
                         implicit_param_patterns.size() + param_patterns.size();
  param_types.reserve(max_llvm_params);
  param_inst_ids.reserve(max_llvm_params);
  if (return_info.has_return_slot()) {
    param_types.push_back(
        llvm::PointerType::get(return_type, /*AddressSpace=*/0));
    return_param_id = function.return_slot_pattern_id;
    param_inst_ids.push_back(return_param_id);
  }
  for (auto param_pattern_id : llvm::concat<const SemIR::InstId>(
           implicit_param_patterns, param_patterns)) {
    auto param_pattern = SemIR::Function::GetParamPatternInfoFromPatternId(
                             sem_ir(), param_pattern_id)
                             .inst;

Review comment (bug):
The old code was checking if `type_id.has_value()`. Using it as an index when it doesn't have a value seems incorrect - how come we're not checking the same condition anymore?

Code after:
  CARBON_FATAL("Missing value: {0} {1}", inst_id,
               sem_ir().insts().Get(inst_id));
}

auto FileContext::GetOrCreateFunction(SemIR::FunctionId function_id,
                                      SemIR::SpecificId specific_id)
    -> llvm::Function* {
  // Non-generic functions are declared eagerly.
  if (!specific_id.has_value()) {
    return GetFunction(function_id);
  }

  if (auto* result = specific_functions_[specific_id.index]) {
    return result;
  }

  auto* result = BuildFunctionDecl(function_id, specific_id);
  // TODO: Add this function to a list of specific functions whose definitions
  // we need to emit.
  specific_functions_[specific_id.index] = result;
  // TODO: Use this to generate definitions for these functions.
  specific_function_definitions_.push_back({function_id, specific_id});
  return result;
}

auto FileContext::BuildFunctionTypeInfo(const SemIR::Function& function,
                                        SemIR::SpecificId specific_id)
    -> FunctionTypeInfo {
  const auto return_info =
      SemIR::ReturnTypeInfo::ForFunction(sem_ir(), function, specific_id);

  if (!return_info.is_valid()) {
    // The return type has not been completed, create a trivial type instead.
    return {.type =
                llvm::FunctionType::get(llvm::Type::getVoidTy(llvm_context()),
                                        /*isVarArg=*/false)};
  }

  // TODO nit: add is_symbolic() to type_id to forward to
  // type_id.AsConstantId().is_symbolic(). Update call below too.
  auto get_llvm_type = [&](SemIR::TypeId type_id) -> llvm::Type* {
    if (!type_id.has_value()) {
      return nullptr;
    }
    return GetType(SemIR::GetTypeInSpecific(sem_ir(), specific_id, type_id));
  };

  auto implicit_param_patterns =
      sem_ir().inst_blocks().GetOrEmpty(function.implicit_param_patterns_id);
  // TODO: Include parameters corresponding to positional parameters.
  auto param_patterns =