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

Code before:
// overload for any field type that has a GetConstantValue() overload which
// canonicalizes a specific as part of forming its constant value.
static auto ResolveSpecificDeclForField(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 (!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
    // generic's declaration eval block is not yet constructed (with those
    // dependent instructions in it).
    //
    // TODO: Find a way to avoid this early out by making the evaluation of
    // instructions in the witness table that require a specific happen after
    // the generic is complete. Or find a way to limit this just to the impl
    // witness table and ensure the declarations will be resolved.
    return;
  }

  ResolveSpecificDeclaration(eval_context.context(),
                             eval_context.fallback_loc_id(), specific_id);
}

static auto ResolveSpecificDeclForField(
    EvalContext& eval_context, SemIR::SpecificInterfaceId specific_interface_id)
    -> void {
  if (!specific_interface_id.has_value()) {
    return;
  }
  ResolveSpecificDeclForField(eval_context, eval_context.specific_interfaces()
                                                .Get(specific_interface_id)
                                                .specific_id);
}

static auto ResolveSpecificDeclForField(EvalContext& eval_context,
                                        SemIR::FacetTypeId facet_type_id)
    -> void {
  const auto& info = eval_context.context().facet_types().Get(facet_type_id);
  for (const auto& interface : info.extend_constraints) {
    ResolveSpecificDeclForField(eval_context, interface.specific_id);
  }
  for (const auto& interface : info.self_impls_constraints) {
    ResolveSpecificDeclForField(eval_context, interface.specific_id);
  }
}

Review comment (suggestion):
Very minor, and only kind of part of this PR because this is pre-existing, but might want to consistently abbreviate `Decl` (rather than `Declaration`, since we've generally agreed on that abbreviation)

i.e.:

```suggestion
  ResolveSpecificDecl(eval_context.context(),
```

Code after:
  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;
  }
  ResolveSpecificDecl(eval_context.context(), eval_context.fallback_loc_id(),
                      specific_id);
}

// Resolves the specific declarations for a specific id in any field of the
// `inst` instruction.
static auto ResolveSpecificDeclForInst(EvalContext& eval_context,
                                       const SemIR::Inst& inst) -> void {
  for (auto arg_and_kind : {inst.arg0_and_kind(), inst.arg1_and_kind()}) {
    // This switch must handle 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.
    CARBON_KIND_SWITCH(arg_and_kind) {
      case CARBON_KIND(SemIR::FacetTypeId facet_type_id): {
        const auto& info =
            eval_context.context().facet_types().Get(facet_type_id);
        for (const auto& interface : info.extend_constraints) {
          ResolveSpecificDeclForSpecificId(eval_context, interface.specific_id);
        }
        for (const auto& interface : info.self_impls_constraints) {
          ResolveSpecificDeclForSpecificId(eval_context, interface.specific_id);