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

Code before:
  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: 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(

Review comment (suggestion):
Maybe we should also clear the other out params? Or document and assume they are all initialized correctly? Just clearing one seems inconsistent either way, and not like something we'd want to accidentally end up depending on.

Code after:
  // TODO: For generics, handle references to symbolic constants.

  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);