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

Code before:
      (!allow_unsafe || cat == SemIR::ExprCategory::Initializing)) {
    // TODO: Allow removing `partial` for initializing expressions as a safe
    // conversion. `PerformBuiltinConversion` will need to initialize the vptr
    // as part of the conversion.
    return false;
  }

  if (quals.HasAnyOf(SemIR::TypeQualifiers::MaybeUnformed) &&
      (!allow_unsafe || cat == SemIR::ExprCategory::Initializing)) {
    // As an unsafe conversion, `MaybeUnformed` can be removed from a value or
    // reference expression.
    return false;
  }

  return true;
}

static auto DiagnoseConversionFailureToConstraintValue(
    Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
    SemIR::TypeId target_type_id) -> void {
  CARBON_CHECK(context.types().IsFacetType(target_type_id));

  // If the source type is/has a facet value (converted with `as type` or
  // otherwise), then we can include its FacetType in the diagnostic to help
  // explain what interfaces the source type implements.
  expr_id = GetCanonicalFacetOrTypeValue(context, expr_id);
  auto expr_type_id = context.insts().Get(expr_id).type_id();

  if (context.types().Is<SemIR::FacetType>(expr_type_id)) {
    CARBON_DIAGNOSTIC(ConversionFailureFacetToFacet, Error,
                      "cannot convert type {0} that implements {1} into type "
                      "implementing {2}",
                      InstIdAsType, SemIR::TypeId, SemIR::TypeId);
    context.emitter().Emit(loc_id, ConversionFailureFacetToFacet, expr_id,
                           expr_type_id, target_type_id);
  } else {
    CARBON_DIAGNOSTIC(ConversionFailureTypeToFacet, Error,
                      "cannot convert type {0} into type implementing {1}",
                      InstIdAsType, SemIR::TypeId);
    context.emitter().Emit(loc_id, ConversionFailureTypeToFacet, expr_id,
                           target_type_id);
  }
}

static auto PerformBuiltinConversion(
    Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
    ConversionTarget target, SemIR::ClassType* vtable_class_type = nullptr)
    -> SemIR::InstId {
  auto& sem_ir = context.sem_ir();
  auto value = sem_ir.insts().Get(value_id);
  auto value_type_id = value.type_id();

Review comment (suggestion):
Perhaps make a separate local variable here, so that it's clearer in uses that they're not using the argument?

```suggestion
  SemIR::InstId canonical_expr_id = GetCanonicalFacetOrTypeValue(context, expr_id);
```

Code after:
      (!allow_unsafe || cat == SemIR::ExprCategory::Initializing)) {
    // TODO: Allow removing `partial` for initializing expressions as a safe
    // conversion. `PerformBuiltinConversion` will need to initialize the vptr
    // as part of the conversion.
    return false;
  }

  if (quals.HasAnyOf(SemIR::TypeQualifiers::MaybeUnformed) &&
      (!allow_unsafe || cat == SemIR::ExprCategory::Initializing)) {
    // As an unsafe conversion, `MaybeUnformed` can be removed from a value or
    // reference expression.
    return false;
  }

  return true;
}

static auto DiagnoseConversionFailureToConstraintValue(
    Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
    SemIR::TypeId target_type_id) -> void {
  CARBON_CHECK(context.types().IsFacetType(target_type_id));

  // If the source type is/has a facet value (converted with `as type` or
  // otherwise), then we can include its `FacetType` in the diagnostic to help
  // explain what interfaces the source type implements.
  auto const_expr_id = GetCanonicalFacetOrTypeValue(context, expr_id);
  auto const_expr_type_id = context.insts().Get(const_expr_id).type_id();

  if (context.types().Is<SemIR::FacetType>(const_expr_type_id)) {
    CARBON_DIAGNOSTIC(ConversionFailureFacetToFacet, Error,
                      "cannot convert type {0} that implements {1} into type "
                      "implementing {2}",
                      InstIdAsType, SemIR::TypeId, SemIR::TypeId);
    context.emitter().Emit(loc_id, ConversionFailureFacetToFacet, expr_id,
                           const_expr_type_id, target_type_id);
  } else {
    CARBON_DIAGNOSTIC(ConversionFailureTypeToFacet, Error,
                      "cannot convert type {0} into type implementing {1}",
                      InstIdAsType, SemIR::TypeId);
    context.emitter().Emit(loc_id, ConversionFailureTypeToFacet, expr_id,
                           target_type_id);
  }
}

static auto PerformBuiltinConversion(
    Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
    ConversionTarget target, SemIR::ClassType* vtable_class_type = nullptr)
    -> SemIR::InstId {
  auto& sem_ir = context.sem_ir();
  auto value = sem_ir.insts().Get(value_id);
  auto value_type_id = value.type_id();