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

Code before:
  }

  // If this instruction is splicing in an action result, that action result is
  // our operand.
  if (auto splice = eval_context.insts().TryGetAs<SemIR::SpliceInst>(inst_id)) {
    if (auto spliced_inst_id =
            GetConstantValue(eval_context, splice->inst_id, phase);
        spliced_inst_id.has_value()) {
      if (auto inst_value_id = eval_context.insts().TryGetAs<SemIR::InstValue>(
              spliced_inst_id)) {
        return inst_value_id->inst_id;
      }
    }
  }

  // Otherwise, this is a normal instruction.
  if (OperandIsDependent(eval_context.context(), inst_id)) {
    *phase = LatestPhase(*phase, Phase::TemplateSymbolic);
  }
  return inst_id;
}

static auto GetConstantValue(EvalContext& eval_context,
                             SemIR::TypeInstId inst_id, Phase* phase)
    -> SemIR::TypeInstId {
  // The input instruction is a TypeInstId, and eval does not change types, so
  // the result is also a valid TypeInstId.
  return SemIR::TypeInstId::UnsafeMake(GetConstantValue(
      eval_context, static_cast<SemIR::InstId>(inst_id), phase));
}

// Explicitly discard a `DestInstId`, because we should not be using the
// destination as part of evaluation.
static auto GetConstantValue(EvalContext& /*eval_context*/,
                             SemIR::DestInstId /*inst_id*/, Phase* /*phase*/)
    -> SemIR::DestInstId {
  return SemIR::InstId::None;
}

// Given a type which may refer to a generic parameter, returns the
// corresponding type in the evaluation context.
static auto GetConstantValue(EvalContext& eval_context, SemIR::TypeId type_id,
                             Phase* phase) -> SemIR::TypeId {
  auto const_id = eval_context.GetConstantValue(type_id);
  *phase =
      LatestPhase(*phase, GetPhase(eval_context.constant_values(), const_id));
  return eval_context.context().types().GetTypeIdForTypeConstantId(const_id);
}

// AbsoluteInstBlockId can not have its values substituted, so this overload is
// deleted. This prevents conversion to InstBlockId.

Review comment (suggestion):
```suggestion
  // The input instruction is a TypeInstId, and eval does not change concrete types, so
```
(Eval will replace symbolic types with their values in the context.)

Code after:
  // our operand.
  if (auto splice = eval_context.insts().TryGetAs<SemIR::SpliceInst>(inst_id)) {
    if (auto spliced_inst_id =
            GetConstantValue(eval_context, splice->inst_id, phase);
        spliced_inst_id.has_value()) {
      if (auto inst_value_id = eval_context.insts().TryGetAs<SemIR::InstValue>(
              spliced_inst_id)) {
        return inst_value_id->inst_id;
      }
    }
  }

  // Otherwise, this is a normal instruction.
  if (OperandIsDependent(eval_context.context(), inst_id)) {
    *phase = LatestPhase(*phase, Phase::TemplateSymbolic);
  }
  return inst_id;
}

static auto GetConstantValue(EvalContext& eval_context,
                             SemIR::TypeInstId inst_id, Phase* phase)
    -> SemIR::TypeInstId {
  // The input instruction is a TypeInstId, and eval does not change concrete
  // types (like TypeType which TypeInstId implies), so the result is also a
  // valid TypeInstId.
  return SemIR::TypeInstId::UnsafeMake(GetConstantValue(
      eval_context, static_cast<SemIR::InstId>(inst_id), phase));
}

// Explicitly discard a `DestInstId`, because we should not be using the
// destination as part of evaluation.
static auto GetConstantValue(EvalContext& /*eval_context*/,
                             SemIR::DestInstId /*inst_id*/, Phase* /*phase*/)
    -> SemIR::DestInstId {
  return SemIR::InstId::None;
}

// Given a type which may refer to a generic parameter, returns the
// corresponding type in the evaluation context.
static auto GetConstantValue(EvalContext& eval_context, SemIR::TypeId type_id,
                             Phase* phase) -> SemIR::TypeId {
  auto const_id = eval_context.GetConstantValue(type_id);
  *phase =
      LatestPhase(*phase, GetPhase(eval_context.constant_values(), const_id));
  return eval_context.context().types().GetTypeIdForTypeConstantId(const_id);
}

// AbsoluteInstBlockId can not have its values substituted, so this overload is
// deleted. This prevents conversion to InstBlockId.
static auto GetConstantValue(EvalContext& eval_context,
                             SemIR::AbsoluteInstBlockId inst_block_id,