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

Code before:
  if (inst_id.has_value()) {
    inst->SetType(GetTypeOfInst(eval_context, inst_id, phase));
  }
  return IsConstant(*phase);
}

template <typename InstT>
static auto ReplaceTypeWithConstantValue(EvalContext& eval_context,
                                         SemIR::InstId inst_id, InstT* inst,
                                         Phase* phase) -> bool {
  if (inst_id.has_value()) {
    inst->type_id = GetTypeOfInst(eval_context, inst_id, phase);
  }
  return IsConstant(*phase);
}

template <typename... T>
struct KindHasGetConstantValueOverload;

template <typename... Types>
struct KindHasGetConstantValueOverload<TypeEnum<Types...>> {
  static constexpr auto Value(TypeEnum<Types...> e) -> bool {
    constexpr auto Values = [] {
      std::array<bool, SemIR::IdKind::NumValues> values = {false};
      ((values[SemIR::IdKind::template For<Types>.ToIndex()] =
            HasGetConstantValueOverload<Types>),
       ...);
      return values;
    }();
    return Values[e.ToIndex()];
  }
};

// Resolves the specific declarations for a specific id in any field of the
// `inst` instruction. This must be done for any field type that has a
// GetConstantValue() overload which canonicalizes a specific (and thus
// potentially forms a new specific) as part of forming its constant value.
static auto ResolveSpecificDeclForInst(EvalContext& eval_context,
                                       const SemIR::Inst& inst) -> void {
  auto resolve_specific_decl = [&](SemIR::SpecificId specific_id) {
    if (!specific_id.has_value()) {
      return;
    }

    const auto& specific = eval_context.specifics().Get(specific_id);
    const auto& generic = eval_context.generics().Get(specific.generic_id);
    if (!generic.decl_block_id.has_value()) {
      // Impl witness table construction happens before its own generic is
      // finished, in order to make the table's instructions dependent
      // instructions of the Impl's generic. So we can not resolve the specific
      // declaration for such instructions at the time they are created, as the

Review comment (bug):
The way this is initializing from a concept seems weird. I would've thought you could write something like:

```
    constexpr std::array<bool, SemIR::IdKind::NumTypes> Values = {
        ((HasGetConstantValueOverload<Types>), ...)};
```

But that doesn't work. I don't know if you have ideas -- I also would suggest spending against much time on this, it seems minor. I assume you're using the struct to duck the nullptr thing I was doing, which seems fine though the need for a forward declaration seems like an odd quirk of C++.

Code after:
  if (inst_id.has_value()) {
    inst->SetType(GetTypeOfInst(eval_context, inst_id, phase));
  }
  return IsConstant(*phase);
}

template <typename InstT>
static auto ReplaceTypeWithConstantValue(EvalContext& eval_context,
                                         SemIR::InstId inst_id, InstT* inst,
                                         Phase* phase) -> bool {
  if (inst_id.has_value()) {
    inst->type_id = GetTypeOfInst(eval_context, inst_id, phase);
  }
  return IsConstant(*phase);
}

template <typename... T>
struct KindHasGetConstantValueOverload;

template <typename... Types>
struct KindHasGetConstantValueOverload<TypeEnum<Types...>> {
  static constexpr auto Value(TypeEnum<Types...> e) -> bool {
    constexpr auto Values = [] {
      std::array<bool, SemIR::IdKind::NumValues> values = {false};
      ((values[SemIR::IdKind::template For<Types>.ToIndex()] =
            HasGetConstantValueOverload<Types>),
       ...);
      return values;
    }();
    return Values[e.ToIndex()];
  }
};

static auto ResolveSpecificDeclForSpecificId(EvalContext& eval_context,
                                             SemIR::SpecificId specific_id)
    -> void {
  if (!specific_id.has_value()) {
    return;
  }

  const auto& specific = eval_context.specifics().Get(specific_id);
  const auto& generic = eval_context.generics().Get(specific.generic_id);
  if (specific_id == generic.self_specific_id) {
    // Impl witness table construction happens before its generic decl is
    // finish, in order to make the table's instructions dependent
    // instructions of the Impl's generic. But those instructions can refer to
    // the generic's self specific. We can not resolve the specific
    // declaration for the self specific until the generic is finished, but it
    // is explicitly resolved at that time in `FinishGenericDecl()`.
    return;
  }