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

Code before:
    if (param_const_inst_id != param_id) {
      Add(param_const_inst_id, arg_id, needs_substitution);
      continue;
    }

    // If we've not yet substituted into the parameter, do so now and try again.
    if (needs_substitution) {
      param_const_id = SubstConstant(context(), param_const_id, substitutions_);
      if (!param_const_id.has_value() || !param_const_id.is_symbolic()) {
        continue;
      }
      Add(context().constant_values().GetInstId(param_const_id), arg_id,
          /*needs_substitution=*/false);
    }
  }

  return true;
}

auto DeductionContext::CheckDeductionIsComplete() -> bool {
  // Check we deduced an argument value for every parameter, and convert each
  // argument to match the final parameter type after substituting any deduced
  // types it depends on.
  for (auto&& [i, deduced_arg_id] :
       llvm::enumerate(llvm::MutableArrayRef(result_arg_ids_)
                           .drop_front(first_deduced_index_.index))) {
    auto binding_index = first_deduced_index_.index + i;
    auto binding_id = context().inst_blocks().Get(
        context().generics().Get(generic_id_).bindings_id)[binding_index];
    if (!deduced_arg_id.has_value()) {
      if (diagnose_) {
        auto entity_name_id = context()
                                  .insts()
                                  .GetAs<SemIR::AnyBindName>(binding_id)
                                  .entity_name_id;
        CARBON_DIAGNOSTIC(DeductionIncomplete, Error,
                          "cannot deduce value for generic parameter `{0}`",
                          SemIR::NameId);
        auto diag = context().emitter().Build(
            loc_id_, DeductionIncomplete,
            context().entity_names().Get(entity_name_id).name_id);
        NoteGenericHere(context(), generic_id_, diag);
        diag.Emit();
      }
      return false;
    }

    // If the binding is symbolic it can refer to other earlier bindings in the
    // same generic, or from an enclosing specific. Substitute to replace those
    // and get a non-symbolic type in order for us to know the final type that
    // the argument needs to be converted to.

Review comment (suggestion):
Consider calling `GetConstantInstId` unconditionally rather than coupling this code to `ImportRefLoaded`. That would also handle other ways the binding ID might be being referenced indirectly (there are none so far, I think, but there could be others later).

Code after:
    }

    // If we've not yet substituted into the parameter, do so now and try again.
    if (needs_substitution) {
      param_const_id = SubstConstant(context(), param_const_id, substitutions_);
      if (!param_const_id.has_value() || !param_const_id.is_symbolic()) {
        continue;
      }
      Add(context().constant_values().GetInstId(param_const_id), arg_id,
          /*needs_substitution=*/false);
    }
  }

  return true;
}

// Gets the entity name of a generic binding. The generic binding may be an
// imported instruction.
static auto GetEntityNameForGenericBinding(Context& context,
                                           SemIR::InstId binding_id)
    -> SemIR::NameId {
  // If `binding_id` is imported, it may not have an entity name. Get a
  // canonical local instruction from its constant value which does.
  if (context.insts().Is<SemIR::ImportRefLoaded>(binding_id)) {
    binding_id = context.constant_values().GetConstantInstId(binding_id);
  }

  if (auto bind_name =
          context.insts().TryGetAs<SemIR::AnyBindName>(binding_id)) {
    return context.entity_names().Get(bind_name->entity_name_id).name_id;
  } else {
    CARBON_FATAL("Instruction without entity name in generic binding position");
  }
}

auto DeductionContext::CheckDeductionIsComplete() -> bool {
  // Check we deduced an argument value for every parameter, and convert each
  // argument to match the final parameter type after substituting any deduced
  // types it depends on.
  for (auto&& [i, deduced_arg_id] :
       llvm::enumerate(llvm::MutableArrayRef(result_arg_ids_)
                           .drop_front(first_deduced_index_.index))) {
    auto binding_index = first_deduced_index_.index + i;
    auto binding_id = context().inst_blocks().Get(
        context().generics().Get(generic_id_).bindings_id)[binding_index];
    if (!deduced_arg_id.has_value()) {
      if (diagnose_) {
        CARBON_DIAGNOSTIC(DeductionIncomplete, Error,
                          "cannot deduce value for generic parameter `{0}`",
                          SemIR::NameId);
        auto diag = context().emitter().Build(