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

Code before:
}  // namespace

// Adds instructions to compute the substituted version of `type_id` in each
// specific into the eval block for the current generic region. Returns a
// symbolic type ID that refers to the substituted type in each specific.
static auto AddGenericTypeToEvalBlock(Context& context, SemIR::LocId loc_id,
                                      SemIR::TypeId type_id) -> SemIR::TypeId {
  // Substitute into the type's constant instruction and rebuild it in the eval
  // block.
  auto rebuild_generic_constant_callbacks =
      RebuildGenericConstantInEvalBlockCallbacks(&context, loc_id);
  auto type_inst_id = SubstInst(context, context.types().GetInstId(type_id),
                                rebuild_generic_constant_callbacks);
  return context.types().GetTypeIdForTypeConstantId(
      context.constant_values().GetAttached(type_inst_id));
}

// Adds instructions to compute the substituted value of `inst_id` in each
// specific into the eval block for the current generic region. Returns a
// symbolic constant instruction ID that refers to the substituted constant
// value in each specific.
static auto AddGenericConstantToEvalBlock(Context& context,
                                          SemIR::InstId inst_id)
    -> SemIR::ConstantId {
  CARBON_CHECK(context.constant_values().Get(inst_id).is_symbolic(),
               "Adding generic constant {0} with non-symbolic constant {1}",
               context.insts().Get(inst_id),
               context.constant_values().Get(inst_id));

  // Substitute into the constant value and rebuild it in the eval block if
  // we've not encountered it before.
  auto const_inst_id = context.constant_values().GetConstantInstId(inst_id);
  auto callbacks = RebuildGenericConstantInEvalBlockCallbacks(
      &context, SemIR::LocId(inst_id));
  auto new_inst_id = SubstInst(context, const_inst_id, callbacks);
  CARBON_CHECK(new_inst_id != const_inst_id,
               "No substitutions performed for generic constant {0}",
               context.insts().Get(inst_id));
  return context.constant_values().GetAttached(new_inst_id);
}

// Adds an instruction that performs a template action to the eval block for the
// generic. The instruction should not yet have been added to any block. The
// instruction might refer to types and constants that need to be rewritten, so
// substitute into it first.
static auto AddTemplateActionToEvalBlock(Context& context,
                                         SemIR::InstId inst_id) -> void {
  // Substitute into the constant value and rebuild it in the eval block.
  auto rebuild_template_action_callbacks =
      RebuildTemplateActionInEvalBlockCallbacks(&context, SemIR::LocId(inst_id),
                                                inst_id);

Review comment (suggestion):
I think there's a subtlety here that I didn't appreciate when I filed issue #5599: prior to [p2964](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2964.md), "symbolic value" could either mean "a value that is symbolic" or "an expression whose phase is symbolic". p2964 proposed to stop using it with that second meaning (because it's confusing to use the term "value" to refer to an expression), but implicitly proposed to keep using it with the first meaning.

So some uses of "symbolic value" should be updated to "symbolic constant", but some of them should stay as they are, because they are talking about a value, not an expression. I think this is one of the cases that shouldn't be changed.

Code after:

 private:
  SemIR::InstId action_inst_id_;
};
}  // namespace

// Adds instructions to compute the substituted version of `type_id` in each
// specific into the eval block for the current generic region. Returns a
// symbolic type ID that refers to the substituted type in each specific.
static auto AddGenericTypeToEvalBlock(Context& context, SemIR::LocId loc_id,
                                      SemIR::TypeId type_id) -> SemIR::TypeId {
  // Substitute into the type's constant instruction and rebuild it in the eval
  // block.
  auto rebuild_generic_constant_callbacks =
      RebuildGenericConstantInEvalBlockCallbacks(&context, loc_id);
  auto type_inst_id = SubstInst(context, context.types().GetInstId(type_id),
                                rebuild_generic_constant_callbacks);
  return context.types().GetTypeIdForTypeConstantId(
      context.constant_values().GetAttached(type_inst_id));
}

// Adds instructions to compute the substituted value of `inst_id` in each
// specific into the eval block for the current generic region. Returns a
// symbolic constant instruction ID that refers to the substituted constant
// value in each specific.
static auto AddGenericConstantToEvalBlock(Context& context,
                                          SemIR::InstId inst_id)
    -> SemIR::ConstantId {
  CARBON_CHECK(context.constant_values().Get(inst_id).is_symbolic(),
               "Adding generic constant {0} with non-symbolic value {1}",
               context.insts().Get(inst_id),
               context.constant_values().Get(inst_id));

  // Substitute into the constant value and rebuild it in the eval block if
  // we've not encountered it before.
  auto const_inst_id = context.constant_values().GetConstantInstId(inst_id);
  auto callbacks = RebuildGenericConstantInEvalBlockCallbacks(
      &context, SemIR::LocId(inst_id));
  auto new_inst_id = SubstInst(context, const_inst_id, callbacks);
  CARBON_CHECK(new_inst_id != const_inst_id,
               "No substitutions performed for generic constant {0}",
               context.insts().Get(inst_id));
  return context.constant_values().GetAttached(new_inst_id);
}

// Adds an instruction that performs a template action to the eval block for the
// generic. The instruction should not yet have been added to any block. The
// instruction might refer to types and constants that need to be rewritten, so
// substitute into it first.
static auto AddTemplateActionToEvalBlock(Context& context,
                                         SemIR::InstId inst_id) -> void {