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

Code before:
    } else if (context.types().Is<SemIR::FacetType>(type_of_expr_id)) {
      facet_value_inst_id = expr_id;
    }

    if (facet_value_inst_id.has_value()) {
      CARBON_DIAGNOSTIC(
          ConversionFailureFacetToFacet, Error,
          "cannot{0:| implicitly} convert type {1} that implements {2} "
          "into type implementing {3}{0: with `as`|}",
          BoolAsSelect, InstIdAsType, TypeOfInstId, SemIR::TypeId);
      return context.emitter().Build(
          loc_id, ConversionFailureFacetToFacet,
          target.kind == ConversionTarget::ExplicitAs, expr_id,
          facet_value_inst_id, target.type_id);
    } else {
      CARBON_DIAGNOSTIC(ConversionFailureTypeToFacet, Error,
                        "cannot{0:| implicitly} convert type {1} "
                        "into type implementing {2}{0: with `as`|}",
                        BoolAsSelect, InstIdAsType, SemIR::TypeId);
      return context.emitter().Build(
          loc_id, ConversionFailureTypeToFacet,
          target.kind == ConversionTarget::ExplicitAs, expr_id, target.type_id);
    }
  } else {
    CARBON_DIAGNOSTIC(
        ConversionFailureNonTypeToTypeOrFacet, Error,
        "cannot{0:| implicitly} convert non-type value of type {1} "
        "{2:to|into type implementing} {3}{0: with `as`|}",
        BoolAsSelect, TypeOfInstId, BoolAsSelect, SemIR::TypeId);
    return context.emitter().Build(
        loc_id, ConversionFailureNonTypeToTypeOrFacet,
        target.kind == ConversionTarget::ExplicitAs, expr_id,
        target.type_id == SemIR::TypeType::SingletonTypeId, target.type_id);
  }
}

auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
             ConversionTarget target) -> SemIR::InstId {
  auto& sem_ir = context.sem_ir();
  auto orig_expr_id = expr_id;

  // Start by making sure both sides are non-errors. If any part is an error,
  // the result is an error and we shouldn't diagnose.
  if (sem_ir.insts().Get(expr_id).type_id() ==
          SemIR::ErrorInst::SingletonTypeId ||
      target.type_id == SemIR::ErrorInst::SingletonTypeId) {
    return SemIR::ErrorInst::SingletonInstId;
  }

  if (SemIR::GetExprCategory(sem_ir, expr_id) == SemIR::ExprCategory::NotExpr) {
    // TODO: We currently encounter this for use of namespaces and functions.

Review comment (bug):
Here is a case where leaning into the fact that types are facets makes things more concise without introducing confusion.
```suggestion
        ConversionFailureNonTypeToFacet, Error,
```

Code after:
    } else if (context.types().Is<SemIR::FacetType>(type_of_expr_id)) {
      facet_value_inst_id = expr_id;
    }

    if (facet_value_inst_id.has_value()) {
      CARBON_DIAGNOSTIC(
          ConversionFailureFacetToFacet, Error,
          "cannot{0:| implicitly} convert type {1} that implements {2} "
          "into type implementing {3}{0: with `as`|}",
          BoolAsSelect, InstIdAsType, TypeOfInstId, SemIR::TypeId);
      return context.emitter().Build(
          loc_id, ConversionFailureFacetToFacet,
          target.kind == ConversionTarget::ExplicitAs, expr_id,
          facet_value_inst_id, target.type_id);
    } else {
      CARBON_DIAGNOSTIC(ConversionFailureTypeToFacet, Error,
                        "cannot{0:| implicitly} convert type {1} "
                        "into type implementing {2}{0: with `as`|}",
                        BoolAsSelect, InstIdAsType, SemIR::TypeId);
      return context.emitter().Build(
          loc_id, ConversionFailureTypeToFacet,
          target.kind == ConversionTarget::ExplicitAs, expr_id, target.type_id);
    }
  } else {
    CARBON_DIAGNOSTIC(
        ConversionFailureNonTypeToFacet, Error,
        "cannot{0:| implicitly} convert non-type value of type {1} "
        "{2:to|into type implementing} {3}{0: with `as`|}",
        BoolAsSelect, TypeOfInstId, BoolAsSelect, SemIR::TypeId);
    return context.emitter().Build(
        loc_id, ConversionFailureNonTypeToFacet,
        target.kind == ConversionTarget::ExplicitAs, expr_id,
        target.type_id == SemIR::TypeType::SingletonTypeId, target.type_id);
  }
}

auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
             ConversionTarget target) -> SemIR::InstId {
  auto& sem_ir = context.sem_ir();
  auto orig_expr_id = expr_id;

  // Start by making sure both sides are non-errors. If any part is an error,
  // the result is an error and we shouldn't diagnose.
  if (sem_ir.insts().Get(expr_id).type_id() ==
          SemIR::ErrorInst::SingletonTypeId ||
      target.type_id == SemIR::ErrorInst::SingletonTypeId) {
    return SemIR::ErrorInst::SingletonInstId;
  }

  if (SemIR::GetExprCategory(sem_ir, expr_id) == SemIR::ExprCategory::NotExpr) {
    // TODO: We currently encounter this for use of namespaces and functions.