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

Code before:
                               .int_kind = int_kind,
                               .bit_width_id = width_id};
  if (!ValidateIntType(context, loc_id, result)) {
    return SemIR::ErrorInst::ConstantId;
  }
  return MakeConstantResult(context, result, phase);
}

// Forms a constant float type as an evaluation result. Requires that width_id
// is constant.
static auto MakeFloatTypeResult(Context& context, SemIR::LocId loc_id,
                                SemIR::InstId width_id, Phase phase)
    -> SemIR::ConstantId {
  auto result = SemIR::FloatType{.type_id = SemIR::TypeType::TypeId,
                                 .bit_width_id = width_id,
                                 .float_kind = SemIR::FloatKind::None};
  if (!ValidateFloatTypeAndSetKind(context, loc_id, result)) {
    return SemIR::ErrorInst::ConstantId;
  }
  return MakeConstantResult(context, result, phase);
}

//// Performs a conversion from integer to character type.
// Performs a conversion between character types, diagnosing if the value
// doesn't fit in the destination type.
static auto PerformCharConvert(Context& context, SemIR::LocId loc_id,
                                      SemIR::InstId arg_id,
                                      SemIR::TypeId dest_type_id)
    -> SemIR::ConstantId {

  auto arg = context.insts().GetAs<SemIR::IntValue>(arg_id);
  auto arg_val = context.ints().Get(arg.int_id);

  auto [is_signed, bit_width_id] =
      context.sem_ir().types().GetIntTypeInfo(dest_type_id);
  
  if (!is_signed && arg_val.isNegative()) {
    CARBON_DIAGNOSTIC(
        NegativeIntInUnsignedType, Error,
        "negative integer value {0} converted to unsigned type {1}", TypedInt,
        SemIR::TypeId);
    context.emitter().Emit(loc_id, NegativeIntInUnsignedType,
                           {.type = arg.type_id, .value = arg_val},
                           dest_type_id);
  }
  
  int64_t value = arg_val.getSExtValue();

  // Values over 0x80 require multiple code units in UTF-8.
  if (value >= 0x80) {
    CARBON_DIAGNOSTIC(

Review comment (suggestion):
```suggestion
static auto PerformIntToCharConvert(Context& context, SemIR::LocId loc_id,
```

Code after:

// Forms a constant int type as an evaluation result. Requires that width_id is
// constant.
static auto MakeIntTypeResult(Context& context, SemIR::LocId loc_id,
                              SemIR::IntKind int_kind, SemIR::InstId width_id,
                              Phase phase) -> SemIR::ConstantId {
  auto result = SemIR::IntType{.type_id = SemIR::TypeType::TypeId,
                               .int_kind = int_kind,
                               .bit_width_id = width_id};
  if (!ValidateIntType(context, loc_id, result)) {
    return SemIR::ErrorInst::ConstantId;
  }
  return MakeConstantResult(context, result, phase);
}

// Forms a constant float type as an evaluation result. Requires that width_id
// is constant.
static auto MakeFloatTypeResult(Context& context, SemIR::LocId loc_id,
                                SemIR::InstId width_id, Phase phase)
    -> SemIR::ConstantId {
  auto result = SemIR::FloatType{.type_id = SemIR::TypeType::TypeId,
                                 .bit_width_id = width_id,
                                 .float_kind = SemIR::FloatKind::None};
  if (!ValidateFloatTypeAndSetKind(context, loc_id, result)) {
    return SemIR::ErrorInst::ConstantId;
  }
  return MakeConstantResult(context, result, phase);
}

// Performs a conversion between integer types, truncating if the value doesn't
// fit in the destination type.
static auto PerformIntConvert(Context& context, SemIR::InstId arg_id,
                              SemIR::TypeId dest_type_id) -> SemIR::ConstantId {
  auto arg_val =
      context.ints().Get(context.insts().GetAs<SemIR::IntValue>(arg_id).int_id);
  auto [dest_is_signed, bit_width_id] =
      context.sem_ir().types().GetIntTypeInfo(dest_type_id);
  if (bit_width_id.has_value()) {
    // TODO: If the value fits in the destination type, reuse the existing
    // int_id rather than recomputing it. This is probably the most common case.
    bool src_is_signed = context.sem_ir().types().IsSignedInt(
        context.insts().Get(arg_id).type_id());
    unsigned width = context.ints().Get(bit_width_id).getZExtValue();
    arg_val =
        src_is_signed ? arg_val.sextOrTrunc(width) : arg_val.zextOrTrunc(width);
  }
  return MakeIntResult(context, dest_type_id, dest_is_signed, arg_val);
}

// Performs a conversion between integer types, diagnosing if the value doesn't
// fit in the destination type.