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

Code before:
      if (!target.diagnose) {
        return context.emitter().BuildSuppressed();
      }
      // TODO: Should this message change to say "object of type" when
      // converting from a reference expression?
      CARBON_DIAGNOSTIC(ImplicitAsConversionFailure, Error,
                        "cannot implicitly convert value of type {0} to {1}",
                        TypeOfInstId, SemIR::TypeId);
      CARBON_DIAGNOSTIC(ExplicitAsConversionFailure, Error,
                        "cannot convert value of type {0} to {1} with `as`",
                        TypeOfInstId, SemIR::TypeId);
      auto builder =
          context.emitter().Build(loc_id,
                                  target.kind == ConversionTarget::ExplicitAs
                                      ? ExplicitAsConversionFailure
                                      : ImplicitAsConversionFailure,
                                  expr_id, target.type_id);
      if (sem_ir.types().Is<SemIR::FacetType>(target.type_id)) {
        if (auto facet_access_type =
                context.insts().TryGetAs<SemIR::FacetAccessType>(expr_id)) {
          CARBON_DIAGNOSTIC(
              ConversionFailureFacetAccessTypeToFacetNote, Note,
              "expected type implementing {1}; found type {0} implementing {2}",
              SemIR::TypeId, SemIR::TypeId, SemIR::TypeId);
          builder.Note(loc_id, ConversionFailureFacetAccessTypeToFacetNote,
                       context.types().GetTypeIdForTypeInstId(expr_id),
                       target.type_id,
                       context.insts()
                           .Get(facet_access_type->facet_value_inst_id)
                           .type_id());
        } else if (context.insts().Get(expr_id).type_id() ==
                   SemIR::TypeType::SingletonTypeId) {
          CARBON_DIAGNOSTIC(ConversionFailureTypeToFacetNote, Note,
                            "expected type implementing {1}; found type {0}",
                            SemIR::TypeId, SemIR::TypeId);
          builder.Note(loc_id, ConversionFailureTypeToFacetNote,
                       context.types().GetTypeIdForTypeInstId(expr_id),
                       target.type_id);
        } else {
          CARBON_DIAGNOSTIC(
              ConversionFailureNonTypeToFacetNote, Note,
              "expected type implementing {0}; found non-type value",
              SemIR::TypeId);
          builder.Note(loc_id, ConversionFailureNonTypeToFacetNote,
                       target.type_id);
        }
      }
      return builder;
    });

    // Pull a value directly out of the initializer if possible and wanted.

Review comment (suggestion):
I think it is better to pass an `InstId` and use `InstIdAsType` in the diagnostic instead of `SemIR::TypeId`

Code after:
  // that `RequireConcreteType` returns true for facet types, since their
  // representation is fixed. This allows us to support using the `Self` of an
  // interface inside its definition.
  if (!RequireConcreteType(
          context, target.type_id, loc_id,
          [&] {
            CARBON_CHECK(!target.is_initializer(),
                         "Initialization of incomplete types is expected to be "
                         "caught elsewhere.");
            if (!target.diagnose) {
              return context.emitter().BuildSuppressed();
            }
            CARBON_DIAGNOSTIC(IncompleteTypeInValueConversion, Error,
                              "forming value of incomplete type {0}",
                              SemIR::TypeId);
            CARBON_DIAGNOSTIC(IncompleteTypeInConversion, Error,
                              "invalid use of incomplete type {0}",
                              SemIR::TypeId);
            return context.emitter().Build(
                loc_id,
                target.kind == ConversionTarget::Value
                    ? IncompleteTypeInValueConversion
                    : IncompleteTypeInConversion,
                target.type_id);
          },
          [&] {
            if (!target.diagnose || !target.is_initializer()) {
              return context.emitter().BuildSuppressed();
            }
            CARBON_DIAGNOSTIC(AbstractTypeInInit, Error,
                              "initialization of abstract type {0}",
                              SemIR::TypeId);
            return context.emitter().Build(loc_id, AbstractTypeInInit,
                                           target.type_id);
          })) {
    return SemIR::ErrorInst::SingletonInstId;
  }

  // Check whether any builtin conversion applies.
  expr_id = PerformBuiltinConversion(context, loc_id, expr_id, target);
  if (expr_id == SemIR::ErrorInst::SingletonInstId) {
    return expr_id;
  }

  // If this is not a builtin conversion, try an `ImplicitAs` conversion.
  if (sem_ir.insts().Get(expr_id).type_id() != target.type_id) {
    SemIR::InstId interface_args[] = {
        context.types().GetInstId(target.type_id)};
    Operator op = {
        .interface_name = target.kind == ConversionTarget::ExplicitAs
                              ? llvm::StringLiteral("As")