Kaynağa Gözat

Provide an `InstId` when evaluating a constant in cases where one is needed (#5202)

For each kind of instruction, specify whether its constant evaluation
needs an `InstId` or not. If it does, ensure that all constant
evaluation of that instruction provides one. Otherwise, allow calling
into the evaluator without providing an `InstId`.

This allows us to reliably use the `InstId` in evaluation steps that
either need a location or need to look at the original operands of the
instruction prior to evaluation, and also to support `TryEvalInst` calls
safely for instructions whose evaluation does not need an `InstId`.
Richard Smith 1 yıl önce
ebeveyn
işleme
0631e18184
29 değiştirilmiş dosya ile 320 ekleme ve 184 silme
  1. 9 12
      toolchain/check/eval.cpp
  2. 23 7
      toolchain/check/eval.h
  3. 95 110
      toolchain/check/eval_inst.cpp
  4. 70 4
      toolchain/check/eval_inst.h
  5. 3 2
      toolchain/check/impl_lookup.cpp
  6. 5 4
      toolchain/check/inst.cpp
  7. 6 7
      toolchain/check/interface.cpp
  8. 1 1
      toolchain/check/member_access.cpp
  9. 10 4
      toolchain/check/subst.cpp
  10. 2 2
      toolchain/check/testdata/array/fail_bound_negative.carbon
  11. 2 2
      toolchain/check/testdata/array/fail_bound_overflow.carbon
  12. 1 1
      toolchain/check/testdata/class/import.carbon
  13. 3 0
      toolchain/check/testdata/facet/min_prelude/convert_class_type_to_generic_facet_value.carbon
  14. 1 0
      toolchain/check/testdata/facet/min_prelude/convert_class_value_to_generic_facet_value_value.carbon
  15. 1 1
      toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon
  16. 7 5
      toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon
  17. 1 0
      toolchain/check/testdata/facet/min_prelude/fail_convert_class_type_to_generic_facet_value.carbon
  18. 1 0
      toolchain/check/testdata/facet/min_prelude/fail_deduction_uses_runtime_type_conversion.carbon
  19. 1 0
      toolchain/check/testdata/function/generic/call_method_on_generic_facet.carbon
  20. 2 2
      toolchain/check/testdata/generic/complete_type.carbon
  21. 1 1
      toolchain/check/testdata/if_expr/fail_not_in_function.carbon
  22. 2 2
      toolchain/check/testdata/impl/assoc_const_self.carbon
  23. 1 1
      toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon
  24. 33 5
      toolchain/check/testdata/impl/use_assoc_const.carbon
  25. 3 3
      toolchain/check/testdata/struct/import.carbon
  26. 3 3
      toolchain/check/testdata/tuple/import.carbon
  27. 1 3
      toolchain/check/type.cpp
  28. 22 0
      toolchain/sem_ir/inst_kind.h
  29. 10 2
      toolchain/sem_ir/typed_insts.h

+ 9 - 12
toolchain/check/eval.cpp

@@ -1744,13 +1744,16 @@ static auto TryEvalTypedInst(EvalContext& eval_context, SemIR::InstId inst_id,
       // Couldn't perform the action because it's still dependent.
       // Couldn't perform the action because it's still dependent.
       return MakeConstantResult(eval_context.context(), inst,
       return MakeConstantResult(eval_context.context(), inst,
                                 Phase::TemplateSymbolic);
                                 Phase::TemplateSymbolic);
-    } else {
+    } else if constexpr (InstT::Kind.constant_needs_inst_id()) {
+      CARBON_CHECK(inst_id.has_value());
       return ConvertEvalResultToConstantId(
       return ConvertEvalResultToConstantId(
           eval_context.context(),
           eval_context.context(),
-          EvalConstantInst(eval_context.context(),
-                           eval_context.GetDiagnosticLoc({inst_id}),
-                           inst.As<InstT>()),
+          EvalConstantInst(eval_context.context(), inst_id, inst.As<InstT>()),
           phase);
           phase);
+    } else {
+      return ConvertEvalResultToConstantId(
+          eval_context.context(),
+          EvalConstantInst(eval_context.context(), inst.As<InstT>()), phase);
     }
     }
   }
   }
 }
 }
@@ -1947,14 +1950,8 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
                                                               inst_id, inst);
                                                               inst_id, inst);
 }
 }
 
 
-auto TryEvalInst(Context& context, SemIR::LocId loc_id, SemIR::InstId inst_id,
-                 SemIR::Inst inst) -> SemIR::ConstantId {
-  EvalContext eval_context(&context, loc_id);
-  return TryEvalInstInContext(eval_context, inst_id, inst);
-}
-
-auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
-    -> SemIR::ConstantId {
+auto TryEvalInstUnsafe(Context& context, SemIR::InstId inst_id,
+                       SemIR::Inst inst) -> SemIR::ConstantId {
   EvalContext eval_context(&context, inst_id);
   EvalContext eval_context(&context, inst_id);
   return TryEvalInstInContext(eval_context, inst_id, inst);
   return TryEvalInstInContext(eval_context, inst_id, inst);
 }
 }

+ 23 - 7
toolchain/check/eval.h

@@ -18,15 +18,31 @@ namespace Carbon::Check {
 auto AddImportedConstant(Context& context, SemIR::Inst inst)
 auto AddImportedConstant(Context& context, SemIR::Inst inst)
     -> SemIR::ConstantId;
     -> SemIR::ConstantId;
 
 
-// Determines the phase of the instruction `inst`, and returns its constant
+// Evaluates the instruction `inst`. If `inst_id` is specified, it is the ID of
+// the instruction; otherwise, evaluation of the instruction must not require an
+// `InstId` to be provided.
+auto TryEvalInstUnsafe(Context& context, SemIR::InstId inst_id,
+                       SemIR::Inst inst) -> SemIR::ConstantId;
+
+// Determines the phase of the instruction `inst_id`, and returns its constant
 // value if it has constant phase. If it has runtime phase, returns
 // value if it has constant phase. If it has runtime phase, returns
 // `SemIR::ConstantId::NotConstant`.
 // `SemIR::ConstantId::NotConstant`.
-auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
-    -> SemIR::ConstantId;
-// Like the above but specific a LocId instead of deriving it from the
-// `inst_id`. This is most useful when passing `None` as the `inst_id`.
-auto TryEvalInst(Context& context, SemIR::LocId loc_id, SemIR::InstId inst_id,
-                 SemIR::Inst inst) -> SemIR::ConstantId;
+inline auto TryEvalInst(Context& context, SemIR::InstId inst_id)
+    -> SemIR::ConstantId {
+  return TryEvalInstUnsafe(context, inst_id, context.insts().Get(inst_id));
+}
+
+// Same, but for a typed instruction that doesn't have an InstId assigned yet,
+// in the case where evaluation doesn't need an InstId. This can be used to
+// avoid allocating an instruction in the case where you just want a constant
+// value and the instruction is known to not matter. However, even then care
+// should be taken: if the produced constant is symbolic, you may still need an
+// instruction to associate the constant with the enclosing generic.
+template <typename InstT>
+  requires(!InstT::Kind.constant_needs_inst_id())
+auto TryEvalInst(Context& context, InstT inst) -> SemIR::ConstantId {
+  return TryEvalInstUnsafe(context, SemIR::InstId::None, inst);
+}
 
 
 // Evaluates the eval block for a region of a specific. Produces a block
 // Evaluates the eval block for a region of a specific. Produces a block
 // containing the evaluated constant values of the instructions in the eval
 // containing the evaluated constant values of the instructions in the eval

+ 95 - 110
toolchain/check/eval_inst.cpp

@@ -14,32 +14,12 @@
 #include "toolchain/check/inst.h"
 #include "toolchain/check/inst.h"
 #include "toolchain/check/type.h"
 #include "toolchain/check/type.h"
 #include "toolchain/check/type_completion.h"
 #include "toolchain/check/type_completion.h"
+#include "toolchain/diagnostics/diagnostic.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/typed_insts.h"
 #include "toolchain/sem_ir/typed_insts.h"
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-// When calling from eval to various Check functions, we need the actual LocId.
-// This allows us to unwrap the SemIRLoc to do so.
-//
-// TODO: Decide whether to refactor calls everywhere to accept `SemIRLoc`, or
-// fold `SemIRLoc` into `LocId`. Either way, we would like eval to call other
-// code without unwrapping `SemIRLoc`.
-class UnwrapSemIRLoc {
- public:
-  auto operator()(Context& context, SemIRLoc loc) -> SemIR::LocId {
-    if (loc.is_inst_id_) {
-      if (loc.inst_id_.has_value()) {
-        return context.insts().GetLocId(loc.inst_id_);
-      } else {
-        return SemIR::LocId::None;
-      }
-    } else {
-      return loc.loc_id_;
-    }
-  }
-};
-
 // Performs an access into an aggregate, retrieving the specified element.
 // Performs an access into an aggregate, retrieving the specified element.
 static auto PerformAggregateAccess(Context& context, SemIR::Inst inst)
 static auto PerformAggregateAccess(Context& context, SemIR::Inst inst)
     -> ConstantEvalResult {
     -> ConstantEvalResult {
@@ -59,16 +39,16 @@ static auto PerformAggregateAccess(Context& context, SemIR::Inst inst)
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::ArrayInit inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::ArrayInit inst)
+    -> ConstantEvalResult {
   // TODO: Add an `ArrayValue` to represent a constant array object
   // TODO: Add an `ArrayValue` to represent a constant array object
   // representation instead of using a `TupleValue`.
   // representation instead of using a `TupleValue`.
   return ConstantEvalResult::NewSamePhase(
   return ConstantEvalResult::NewSamePhase(
       SemIR::TupleValue{.type_id = inst.type_id, .elements_id = inst.inits_id});
       SemIR::TupleValue{.type_id = inst.type_id, .elements_id = inst.inits_id});
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::ArrayType inst)
-    -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
+                      SemIR::ArrayType inst) -> ConstantEvalResult {
   auto bound_inst = context.insts().Get(inst.bound_id);
   auto bound_inst = context.insts().Get(inst.bound_id);
   auto int_bound = bound_inst.TryAs<SemIR::IntValue>();
   auto int_bound = bound_inst.TryAs<SemIR::IntValue>();
   if (!int_bound) {
   if (!int_bound) {
@@ -84,22 +64,24 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::ArrayType inst)
       bound_val.isNegative()) {
       bound_val.isNegative()) {
     CARBON_DIAGNOSTIC(ArrayBoundNegative, Error,
     CARBON_DIAGNOSTIC(ArrayBoundNegative, Error,
                       "array bound of {0} is negative", TypedInt);
                       "array bound of {0} is negative", TypedInt);
-    context.emitter().Emit(loc, ArrayBoundNegative,
-                           {.type = int_bound->type_id, .value = bound_val});
+    context.emitter().Emit(
+        context.insts().GetAs<SemIR::ArrayType>(inst_id).bound_id,
+        ArrayBoundNegative, {.type = int_bound->type_id, .value = bound_val});
     return ConstantEvalResult::Error;
     return ConstantEvalResult::Error;
   }
   }
   if (bound_val.getActiveBits() > 64) {
   if (bound_val.getActiveBits() > 64) {
     CARBON_DIAGNOSTIC(ArrayBoundTooLarge, Error,
     CARBON_DIAGNOSTIC(ArrayBoundTooLarge, Error,
                       "array bound of {0} is too large", TypedInt);
                       "array bound of {0} is too large", TypedInt);
-    context.emitter().Emit(loc, ArrayBoundTooLarge,
-                           {.type = int_bound->type_id, .value = bound_val});
+    context.emitter().Emit(
+        context.insts().GetAs<SemIR::ArrayType>(inst_id).bound_id,
+        ArrayBoundTooLarge, {.type = int_bound->type_id, .value = bound_val});
     return ConstantEvalResult::Error;
     return ConstantEvalResult::Error;
   }
   }
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::AsCompatible inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::AsCompatible inst)
+    -> ConstantEvalResult {
   // AsCompatible changes the type of the source instruction; its constant
   // AsCompatible changes the type of the source instruction; its constant
   // value, if there is one, needs to be modified to be of the same type.
   // value, if there is one, needs to be modified to be of the same type.
   auto value_id = context.constant_values().Get(inst.source_id);
   auto value_id = context.constant_values().Get(inst.source_id);
@@ -111,26 +93,26 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
   return ConstantEvalResult::NewAnyPhase(value_inst);
   return ConstantEvalResult::NewAnyPhase(value_inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::BindAlias inst)
+auto EvalConstantInst(Context& context, SemIR::BindAlias inst)
     -> ConstantEvalResult {
     -> ConstantEvalResult {
   // An alias evaluates to the value it's bound to.
   // An alias evaluates to the value it's bound to.
   return ConstantEvalResult::Existing(
   return ConstantEvalResult::Existing(
       context.constant_values().Get(inst.value_id));
       context.constant_values().Get(inst.value_id));
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::BindValue /*inst*/) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::BindValue /*inst*/)
+    -> ConstantEvalResult {
   // TODO: Handle this once we've decided how to represent constant values of
   // TODO: Handle this once we've decided how to represent constant values of
   // reference expressions.
   // reference expressions.
   return ConstantEvalResult::TODO;
   return ConstantEvalResult::TODO;
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::ClassElementAccess inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::ClassElementAccess inst)
+    -> ConstantEvalResult {
   return PerformAggregateAccess(context, inst);
   return PerformAggregateAccess(context, inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ClassDecl inst)
+auto EvalConstantInst(Context& context, SemIR::ClassDecl inst)
     -> ConstantEvalResult {
     -> ConstantEvalResult {
   // If the class has generic parameters, we don't produce a class type, but a
   // If the class has generic parameters, we don't produce a class type, but a
   // callable whose return value is a class type.
   // callable whose return value is a class type.
@@ -146,15 +128,15 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ClassDecl inst)
                        .specific_id = SemIR::SpecificId::None});
                        .specific_id = SemIR::SpecificId::None});
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::ClassInit inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::ClassInit inst)
+    -> ConstantEvalResult {
   // TODO: Add a `ClassValue` to represent a constant class object
   // TODO: Add a `ClassValue` to represent a constant class object
   // representation instead of using a `StructValue`.
   // representation instead of using a `StructValue`.
   return ConstantEvalResult::NewSamePhase(SemIR::StructValue{
   return ConstantEvalResult::NewSamePhase(SemIR::StructValue{
       .type_id = inst.type_id, .elements_id = inst.elements_id});
       .type_id = inst.type_id, .elements_id = inst.elements_id});
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ConstType inst)
+auto EvalConstantInst(Context& context, SemIR::ConstType inst)
     -> ConstantEvalResult {
     -> ConstantEvalResult {
   // `const (const T)` evaluates to `const T`.
   // `const (const T)` evaluates to `const T`.
   if (context.insts().Is<SemIR::ConstType>(inst.inner_id)) {
   if (context.insts().Is<SemIR::ConstType>(inst.inner_id)) {
@@ -165,28 +147,28 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ConstType inst)
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::Converted inst)
+auto EvalConstantInst(Context& context, SemIR::Converted inst)
     -> ConstantEvalResult {
     -> ConstantEvalResult {
   // A conversion evaluates to the result of the conversion.
   // A conversion evaluates to the result of the conversion.
   return ConstantEvalResult::Existing(
   return ConstantEvalResult::Existing(
       context.constant_values().Get(inst.result_id));
       context.constant_values().Get(inst.result_id));
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::Deref /*inst*/) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::Deref /*inst*/)
+    -> ConstantEvalResult {
   // TODO: Handle this.
   // TODO: Handle this.
   return ConstantEvalResult::TODO;
   return ConstantEvalResult::TODO;
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::ExportDecl inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::ExportDecl inst)
+    -> ConstantEvalResult {
   // An export instruction evaluates to the exported declaration.
   // An export instruction evaluates to the exported declaration.
   return ConstantEvalResult::Existing(
   return ConstantEvalResult::Existing(
       context.constant_values().Get(inst.value_id));
       context.constant_values().Get(inst.value_id));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::FacetAccessType inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::FacetAccessType inst)
+    -> ConstantEvalResult {
   if (auto facet_value = context.insts().TryGetAs<SemIR::FacetValue>(
   if (auto facet_value = context.insts().TryGetAs<SemIR::FacetValue>(
           inst.facet_value_inst_id)) {
           inst.facet_value_inst_id)) {
     return ConstantEvalResult::Existing(
     return ConstantEvalResult::Existing(
@@ -195,8 +177,13 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::FacetAccessWitness inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::FacetAccessWitness inst)
+    -> ConstantEvalResult {
+  // TODO: The `index` we are given is an index into the required_interfaces of
+  // the original facet type, but we're using it to index into the witnesses of
+  // the substituted facet type. There is no reason to expect those witnesses to
+  // be in the same order, or even for there to be the same number of witnesses.
+
   if (auto facet_value = context.insts().TryGetAs<SemIR::FacetValue>(
   if (auto facet_value = context.insts().TryGetAs<SemIR::FacetValue>(
           inst.facet_value_inst_id)) {
           inst.facet_value_inst_id)) {
     auto impl_witness_inst_id = context.inst_blocks().Get(
     auto impl_witness_inst_id = context.inst_blocks().Get(
@@ -207,15 +194,15 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::FloatType inst)
-    -> ConstantEvalResult {
-  return ValidateFloatType(context, loc, inst)
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
+                      SemIR::FloatType inst) -> ConstantEvalResult {
+  return ValidateFloatType(context, inst_id, inst)
              ? ConstantEvalResult::NewSamePhase(inst)
              ? ConstantEvalResult::NewSamePhase(inst)
              : ConstantEvalResult::Error;
              : ConstantEvalResult::Error;
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::FunctionDecl inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::FunctionDecl inst)
+    -> ConstantEvalResult {
   // A function declaration evaluates to a function object, which is an empty
   // A function declaration evaluates to a function object, which is an empty
   // object of function type.
   // object of function type.
   // TODO: Eventually we may need to handle captures here.
   // TODO: Eventually we may need to handle captures here.
@@ -223,10 +210,10 @@ auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
       .type_id = inst.type_id, .elements_id = SemIR::InstBlockId::Empty});
       .type_id = inst.type_id, .elements_id = SemIR::InstBlockId::Empty});
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc,
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
                       SemIR::LookupImplWitness inst) -> ConstantEvalResult {
                       SemIR::LookupImplWitness inst) -> ConstantEvalResult {
   auto result = EvalLookupSingleImplWitness(
   auto result = EvalLookupSingleImplWitness(
-      context, UnwrapSemIRLoc()(context, loc), inst);
+      context, context.insts().GetLocId(inst_id), inst);
   if (!result.has_value()) {
   if (!result.has_value()) {
     // We use NotConstant to communicate back to impl lookup that the lookup
     // We use NotConstant to communicate back to impl lookup that the lookup
     // failed. This can not happen for a deferred symbolic lookup in a generic
     // failed. This can not happen for a deferred symbolic lookup in a generic
@@ -241,7 +228,7 @@ auto EvalConstantInst(Context& context, SemIRLoc loc,
       context.constant_values().Get(result.concrete_witness()));
       context.constant_values().Get(result.concrete_witness()));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc,
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
                       SemIR::ImplWitnessAccess inst) -> ConstantEvalResult {
                       SemIR::ImplWitnessAccess inst) -> ConstantEvalResult {
   // This is PerformAggregateAccess followed by GetConstantValueInSpecific.
   // This is PerformAggregateAccess followed by GetConstantValueInSpecific.
   if (auto witness =
   if (auto witness =
@@ -263,36 +250,36 @@ auto EvalConstantInst(Context& context, SemIRLoc loc,
         ImplAccessMemberBeforeSet, Error,
         ImplAccessMemberBeforeSet, Error,
         "accessing member from impl before it has a defined value");
         "accessing member from impl before it has a defined value");
     // TODO: Add note pointing to the impl declaration.
     // TODO: Add note pointing to the impl declaration.
-    context.emitter().Emit(loc, ImplAccessMemberBeforeSet);
+    context.emitter().Emit(inst_id, ImplAccessMemberBeforeSet);
     return ConstantEvalResult::Error;
     return ConstantEvalResult::Error;
   }
   }
 
 
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::ImportRefUnloaded inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::ImportRefUnloaded inst)
+    -> ConstantEvalResult {
   CARBON_FATAL("ImportRefUnloaded should be loaded before TryEvalInst: {0}",
   CARBON_FATAL("ImportRefUnloaded should be loaded before TryEvalInst: {0}",
                inst);
                inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::InitializeFrom inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::InitializeFrom inst)
+    -> ConstantEvalResult {
   // Initialization is not performed in-place during constant evaluation, so
   // Initialization is not performed in-place during constant evaluation, so
   // just return the value of the initializer.
   // just return the value of the initializer.
   return ConstantEvalResult::Existing(
   return ConstantEvalResult::Existing(
       context.constant_values().Get(inst.src_id));
       context.constant_values().Get(inst.src_id));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::IntType inst)
-    -> ConstantEvalResult {
-  return ValidateIntType(context, loc, inst)
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
+                      SemIR::IntType inst) -> ConstantEvalResult {
+  return ValidateIntType(context, inst_id, inst)
              ? ConstantEvalResult::NewSamePhase(inst)
              ? ConstantEvalResult::NewSamePhase(inst)
              : ConstantEvalResult::Error;
              : ConstantEvalResult::Error;
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::InterfaceDecl inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::InterfaceDecl inst)
+    -> ConstantEvalResult {
   // If the interface has generic parameters, we don't produce an interface
   // If the interface has generic parameters, we don't produce an interface
   // type, but a callable whose return value is an interface type.
   // type, but a callable whose return value is an interface type.
   if (context.interfaces().Get(inst.interface_id).has_parameters()) {
   if (context.interfaces().Get(inst.interface_id).has_parameters()) {
@@ -305,14 +292,14 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
       context, inst.interface_id, SemIR::SpecificId::None));
       context, inst.interface_id, SemIR::SpecificId::None));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::NameRef inst)
+auto EvalConstantInst(Context& context, SemIR::NameRef inst)
     -> ConstantEvalResult {
     -> ConstantEvalResult {
   // A name reference evaluates to the value the name resolves to.
   // A name reference evaluates to the value the name resolves to.
   return ConstantEvalResult::Existing(
   return ConstantEvalResult::Existing(
       context.constant_values().Get(inst.value_id));
       context.constant_values().Get(inst.value_id));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc,
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
                       SemIR::RequireCompleteType inst) -> ConstantEvalResult {
                       SemIR::RequireCompleteType inst) -> ConstantEvalResult {
   auto witness_type_id =
   auto witness_type_id =
       GetSingletonType(context, SemIR::WitnessType::SingletonInstId);
       GetSingletonType(context, SemIR::WitnessType::SingletonInstId);
@@ -320,13 +307,16 @@ auto EvalConstantInst(Context& context, SemIRLoc loc,
   // If the type is a concrete constant, require it to be complete now.
   // If the type is a concrete constant, require it to be complete now.
   auto complete_type_id = inst.complete_type_id;
   auto complete_type_id = inst.complete_type_id;
   if (context.types().GetConstantId(complete_type_id).is_concrete()) {
   if (context.types().GetConstantId(complete_type_id).is_concrete()) {
-    if (!TryToCompleteType(context, complete_type_id, loc, [&] {
-          // TODO: It'd be nice to report the original type prior to
-          // evaluation here.
+    if (!TryToCompleteType(context, complete_type_id, inst_id, [&] {
           CARBON_DIAGNOSTIC(IncompleteTypeInMonomorphization, Error,
           CARBON_DIAGNOSTIC(IncompleteTypeInMonomorphization, Error,
-                            "type {0} is incomplete", SemIR::TypeId);
-          return context.emitter().Build(loc, IncompleteTypeInMonomorphization,
-                                         complete_type_id);
+                            "{0} evaluates to incomplete type {1}",
+                            SemIR::TypeId, SemIR::TypeId);
+          return context.emitter().Build(
+              inst_id, IncompleteTypeInMonomorphization,
+              context.insts()
+                  .GetAs<SemIR::RequireCompleteType>(inst_id)
+                  .complete_type_id,
+              complete_type_id);
         })) {
         })) {
       return ConstantEvalResult::Error;
       return ConstantEvalResult::Error;
     }
     }
@@ -340,14 +330,14 @@ auto EvalConstantInst(Context& context, SemIRLoc loc,
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::SpecificConstant inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::SpecificConstant inst)
+    -> ConstantEvalResult {
   // Pull the constant value out of the specific.
   // Pull the constant value out of the specific.
   return ConstantEvalResult::Existing(SemIR::GetConstantValueInSpecific(
   return ConstantEvalResult::Existing(SemIR::GetConstantValueInSpecific(
       context.sem_ir(), inst.specific_id, inst.inst_id));
       context.sem_ir(), inst.specific_id, inst.inst_id));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc,
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
                       SemIR::SpecificImplFunction inst) -> ConstantEvalResult {
                       SemIR::SpecificImplFunction inst) -> ConstantEvalResult {
   auto callee_inst = context.insts().Get(inst.callee_id);
   auto callee_inst = context.insts().Get(inst.callee_id);
   // If the callee is not a function value, we're not ready to evaluate this
   // If the callee is not a function value, we're not ready to evaluate this
@@ -393,8 +383,8 @@ auto EvalConstantInst(Context& context, SemIRLoc loc,
   CARBON_CHECK(static_cast<int>(interface_fn_args.size()) >= remaining_params);
   CARBON_CHECK(static_cast<int>(interface_fn_args.size()) >= remaining_params);
   args.append(interface_fn_args.end() - remaining_params,
   args.append(interface_fn_args.end() - remaining_params,
               interface_fn_args.end());
               interface_fn_args.end());
-  auto specific_id = MakeSpecific(context, loc, generic_id, args);
-  context.definitions_required_by_use().push_back({loc, specific_id});
+  auto specific_id = MakeSpecific(context, inst_id, generic_id, args);
+  context.definitions_required_by_use().push_back({inst_id, specific_id});
 
 
   return ConstantEvalResult::NewSamePhase(
   return ConstantEvalResult::NewSamePhase(
       SemIR::SpecificFunction{.type_id = inst.type_id,
       SemIR::SpecificFunction{.type_id = inst.type_id,
@@ -402,20 +392,21 @@ auto EvalConstantInst(Context& context, SemIRLoc loc,
                               .specific_id = specific_id});
                               .specific_id = specific_id});
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc loc,
+auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
                       SemIR::SpecificFunction inst) -> ConstantEvalResult {
                       SemIR::SpecificFunction inst) -> ConstantEvalResult {
   if (!SemIR::GetCalleeFunction(context.sem_ir(), inst.callee_id)
   if (!SemIR::GetCalleeFunction(context.sem_ir(), inst.callee_id)
            .self_type_id.has_value()) {
            .self_type_id.has_value()) {
     // This is not an associated function. Those will be required to be defined
     // This is not an associated function. Those will be required to be defined
     // as part of checking that the impl is complete.
     // as part of checking that the impl is complete.
-    context.definitions_required_by_use().push_back({loc, inst.specific_id});
+    context.definitions_required_by_use().push_back(
+        {inst_id, inst.specific_id});
   }
   }
   // Create new constant for a specific function.
   // Create new constant for a specific function.
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::SpliceBlock inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::SpliceBlock inst)
+    -> ConstantEvalResult {
   // SpliceBlock evaluates to the result value that is (typically) within the
   // SpliceBlock evaluates to the result value that is (typically) within the
   // block. This can be constant even if the block contains other non-constant
   // block. This can be constant even if the block contains other non-constant
   // instructions.
   // instructions.
@@ -423,8 +414,8 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
       context.constant_values().Get(inst.result_id));
       context.constant_values().Get(inst.result_id));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::SpliceInst inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::SpliceInst inst)
+    -> ConstantEvalResult {
   // The constant value of a SpliceInst is the constant value of the instruction
   // The constant value of a SpliceInst is the constant value of the instruction
   // being spliced. Note that `inst.inst_id` is the instruction being spliced,
   // being spliced. Note that `inst.inst_id` is the instruction being spliced,
   // so we need to go through another round of obtaining the constant value in
   // so we need to go through another round of obtaining the constant value in
@@ -440,36 +431,36 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
   return ConstantEvalResult::NotConstant;
   return ConstantEvalResult::NotConstant;
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::StructAccess inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::StructAccess inst)
+    -> ConstantEvalResult {
   return PerformAggregateAccess(context, inst);
   return PerformAggregateAccess(context, inst);
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::StructInit inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::StructInit inst)
+    -> ConstantEvalResult {
   return ConstantEvalResult::NewSamePhase(SemIR::StructValue{
   return ConstantEvalResult::NewSamePhase(SemIR::StructValue{
       .type_id = inst.type_id, .elements_id = inst.elements_id});
       .type_id = inst.type_id, .elements_id = inst.elements_id});
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::Temporary /*inst*/) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::Temporary /*inst*/)
+    -> ConstantEvalResult {
   // TODO: Handle this. Can we just return the value of `init_id`?
   // TODO: Handle this. Can we just return the value of `init_id`?
   return ConstantEvalResult::TODO;
   return ConstantEvalResult::TODO;
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::TupleAccess inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::TupleAccess inst)
+    -> ConstantEvalResult {
   return PerformAggregateAccess(context, inst);
   return PerformAggregateAccess(context, inst);
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::TupleInit inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& /*context*/, SemIR::TupleInit inst)
+    -> ConstantEvalResult {
   return ConstantEvalResult::NewSamePhase(SemIR::TupleValue{
   return ConstantEvalResult::NewSamePhase(SemIR::TupleValue{
       .type_id = inst.type_id, .elements_id = inst.elements_id});
       .type_id = inst.type_id, .elements_id = inst.elements_id});
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::TypeOfInst inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::TypeOfInst inst)
+    -> ConstantEvalResult {
   // Grab the type from the instruction produced as our operand.
   // Grab the type from the instruction produced as our operand.
   if (auto inst_value =
   if (auto inst_value =
           context.insts().TryGetAs<SemIR::InstValue>(inst.inst_id)) {
           context.insts().TryGetAs<SemIR::InstValue>(inst.inst_id)) {
@@ -479,8 +470,8 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
   return ConstantEvalResult::NewSamePhase(inst);
   return ConstantEvalResult::NewSamePhase(inst);
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::UnaryOperatorNot inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::UnaryOperatorNot inst)
+    -> ConstantEvalResult {
   // `not true` -> `false`, `not false` -> `true`.
   // `not true` -> `false`, `not false` -> `true`.
   // All other uses of unary `not` are non-constant.
   // All other uses of unary `not` are non-constant.
   auto const_id = context.constant_values().Get(inst.operand_id);
   auto const_id = context.constant_values().Get(inst.operand_id);
@@ -493,8 +484,8 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
   return ConstantEvalResult::NotConstant;
   return ConstantEvalResult::NotConstant;
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::ValueOfInitializer inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::ValueOfInitializer inst)
+    -> ConstantEvalResult {
   // Values of value expressions and initializing expressions are represented in
   // Values of value expressions and initializing expressions are represented in
   // the same way during constant evaluation, so just return the value of the
   // the same way during constant evaluation, so just return the value of the
   // operand.
   // operand.
@@ -502,18 +493,12 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
       context.constant_values().Get(inst.init_id));
       context.constant_values().Get(inst.init_id));
 }
 }
 
 
-auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
-                      SemIR::ValueParamPattern inst) -> ConstantEvalResult {
+auto EvalConstantInst(Context& context, SemIR::ValueParamPattern inst)
+    -> ConstantEvalResult {
   // TODO: Treat this as a non-expression (here and in GetExprCategory)
   // TODO: Treat this as a non-expression (here and in GetExprCategory)
   // once generic deduction doesn't need patterns to have constant values.
   // once generic deduction doesn't need patterns to have constant values.
   return ConstantEvalResult::Existing(
   return ConstantEvalResult::Existing(
       context.constant_values().Get(inst.subpattern_id));
       context.constant_values().Get(inst.subpattern_id));
 }
 }
 
 
-auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/,
-                      SemIR::VtablePtr /*inst*/) -> ConstantEvalResult {
-  // TODO: Handle this.
-  return ConstantEvalResult::TODO;
-}
-
 }  // namespace Carbon::Check
 }  // namespace Carbon::Check

+ 70 - 4
toolchain/check/eval_inst.h

@@ -6,6 +6,7 @@
 #define CARBON_TOOLCHAIN_CHECK_EVAL_INST_H_
 #define CARBON_TOOLCHAIN_CHECK_EVAL_INST_H_
 
 
 #include "toolchain/check/eval.h"
 #include "toolchain/check/eval.h"
+#include "toolchain/sem_ir/inst_kind.h"
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
@@ -93,6 +94,60 @@ constexpr ConstantEvalResult ConstantEvalResult::NotConstant =
 
 
 constexpr ConstantEvalResult ConstantEvalResult::TODO = NotConstant;
 constexpr ConstantEvalResult ConstantEvalResult::TODO = NotConstant;
 
 
+// Implementation details to compute the type of the `EvalConstantInst`
+// functions.
+namespace Internal {
+
+// Returns whether an `EvalConstantInst` overload is expected to exist for this
+// instruction constant kind.
+constexpr auto ConstantKindHasEvalConstantInst(SemIR::InstConstantKind kind)
+    -> bool {
+  switch (kind) {
+    case SemIR::InstConstantKind::Never:
+    case SemIR::InstConstantKind::InstAction:
+    case SemIR::InstConstantKind::WheneverPossible:
+    case SemIR::InstConstantKind::Always:
+    case SemIR::InstConstantKind::Unique:
+      return false;
+
+    case SemIR::InstConstantKind::Indirect:
+    case SemIR::InstConstantKind::SymbolicOnly:
+    case SemIR::InstConstantKind::Conditional:
+      return true;
+  }
+}
+
+// Given an instruction kind, determines the type that should be used to declare
+// `EvalConstantInst` for that instruction.
+template <typename InstT, bool HasFn, bool HasInstId>
+struct FunctionTypeForEvalConstantInstImpl {
+  // By default, we want no `EvalConstantInst` function at all. But we can't
+  // express that, so use the type `auto () -> voic` as a placaeholder.
+  using Type = auto() -> void;
+};
+template <typename InstT>
+struct FunctionTypeForEvalConstantInstImpl<InstT, true, false> {
+  // Can be evaluated, evaluation doesn't need InstId.
+  using Type = auto(Context& context, InstT inst) -> ConstantEvalResult;
+};
+template <typename InstT>
+struct FunctionTypeForEvalConstantInstImpl<InstT, true, true> {
+  // Can be evaluated, evaluation needs InstId.
+  using Type = auto(Context& context, SemIR::InstId inst_id, InstT inst)
+      -> ConstantEvalResult;
+};
+template <typename InstT>
+using FunctionTypeForEvalConstantInst =
+    typename FunctionTypeForEvalConstantInstImpl<
+        InstT, ConstantKindHasEvalConstantInst(InstT::Kind.constant_kind()),
+        InstT::Kind.constant_needs_inst_id()>::Type;
+
+}  // namespace Internal
+
+// Explicitly delete the overload generated for non-evaluatable instructions.
+// These all produce the same signature, so we only need to delete it once.
+auto EvalConstantInst() -> void = delete;
+
 // `EvalConstantInst` evaluates an instruction whose operands are all constant,
 // `EvalConstantInst` evaluates an instruction whose operands are all constant,
 // in a context unrelated to the enclosing evaluation. The function is given the
 // in a context unrelated to the enclosing evaluation. The function is given the
 // instruction after its operands, including its type, are replaced by their
 // instruction after its operands, including its type, are replaced by their
@@ -110,12 +165,23 @@ constexpr ConstantEvalResult ConstantEvalResult::TODO = NotConstant;
 // context itself. Those cases are handled by explicit specialization of
 // context itself. Those cases are handled by explicit specialization of
 // `TryEvalTypedInst` in `eval.cpp` instead.
 // `TryEvalTypedInst` in `eval.cpp` instead.
 //
 //
+// The signature of an overload is
+//
+//   auto EvalConstantInst(Context& context, SemIR::InstId inst_id, InstT inst)
+//       -> ConstantEvalResult;
+//
+// if `InstT::Kind.constant_needs_inst_id()` is true, and
+//
+//   auto EvalConstantInst(Context& context, InstT inst) -> ConstantEvalResult;
+//
+// otherwise.
+//
 // Overloads are *declared* for all types, because there isn't a good way to
 // Overloads are *declared* for all types, because there isn't a good way to
 // declare only the overloads we want here without duplicating the list of
 // declare only the overloads we want here without duplicating the list of
-// types. Missing overloads will be diagnosed when linking.
-#define CARBON_SEM_IR_INST_KIND(Kind)                                     \
-  auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::Kind inst) \
-      -> ConstantEvalResult;
+// types. Missing overloads will be diagnosed when linking. Excess overloads
+// map to a deleted signature to prevent accidental calls.
+#define CARBON_SEM_IR_INST_KIND(Kind) \
+  Internal::FunctionTypeForEvalConstantInst<SemIR::Kind> EvalConstantInst;
 #include "toolchain/sem_ir/inst_kind.def"
 #include "toolchain/sem_ir/inst_kind.def"
 
 
 }  // namespace Carbon::Check
 }  // namespace Carbon::Check

+ 3 - 2
toolchain/check/impl_lookup.cpp

@@ -344,8 +344,8 @@ static auto FindWitnessInImpls(Context& context, SemIR::LocId loc_id,
                                SemIR::ConstantId query_self_const_id,
                                SemIR::ConstantId query_self_const_id,
                                SemIR::SpecificInterface interface)
                                SemIR::SpecificInterface interface)
     -> SemIR::InstId {
     -> SemIR::InstId {
-  auto witness_const_id = TryEvalInst(
-      context, loc_id, SemIR::InstId::None,
+  auto witness_id = AddInstInNoBlock(
+      context, loc_id,
       SemIR::LookupImplWitness{
       SemIR::LookupImplWitness{
           .type_id =
           .type_id =
               GetSingletonType(context, SemIR::WitnessType::SingletonInstId),
               GetSingletonType(context, SemIR::WitnessType::SingletonInstId),
@@ -356,6 +356,7 @@ static auto FindWitnessInImpls(Context& context, SemIR::LocId loc_id,
       });
       });
   // We use a NotConstant result from eval to communicate back an impl
   // We use a NotConstant result from eval to communicate back an impl
   // lookup failure. See `EvalConstantInst()` for `LookupImplWitness`.
   // lookup failure. See `EvalConstantInst()` for `LookupImplWitness`.
+  auto witness_const_id = context.constant_values().Get(witness_id);
   if (!witness_const_id.is_constant()) {
   if (!witness_const_id.is_constant()) {
     return SemIR::InstId::None;
     return SemIR::InstId::None;
   }
   }

+ 5 - 4
toolchain/check/inst.cpp

@@ -28,7 +28,7 @@ static auto FinishInst(Context& context, SemIR::InstId inst_id,
   }
   }
 
 
   // If the instruction has a constant value, compute it.
   // If the instruction has a constant value, compute it.
-  auto const_id = TryEvalInst(context, inst_id, inst);
+  auto const_id = TryEvalInstUnsafe(context, inst_id, inst);
   context.constant_values().Set(inst_id, const_id);
   context.constant_values().Set(inst_id, const_id);
   if (const_id.is_constant()) {
   if (const_id.is_constant()) {
     CARBON_VLOG_TO(context.vlog_stream(), "Constant: {0} -> {1}\n", inst,
     CARBON_VLOG_TO(context.vlog_stream(), "Constant: {0} -> {1}\n", inst,
@@ -100,9 +100,10 @@ auto AddPatternInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
 
 
 auto GetOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
 auto GetOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
     -> SemIR::InstId {
     -> SemIR::InstId {
-  if (loc_id_and_inst.loc_id.is_implicit()) {
+  if (loc_id_and_inst.loc_id.is_implicit() &&
+      !loc_id_and_inst.inst.kind().constant_needs_inst_id()) {
     auto const_id =
     auto const_id =
-        TryEvalInst(context, SemIR::InstId::None, loc_id_and_inst.inst);
+        TryEvalInstUnsafe(context, SemIR::InstId::None, loc_id_and_inst.inst);
     if (const_id.has_value()) {
     if (const_id.has_value()) {
       CARBON_VLOG_TO(context.vlog_stream(), "GetOrAddInst: constant: {0}\n",
       CARBON_VLOG_TO(context.vlog_stream(), "GetOrAddInst: constant: {0}\n",
                      loc_id_and_inst.inst);
                      loc_id_and_inst.inst);
@@ -154,7 +155,7 @@ auto ReplaceInstPreservingConstantValue(Context& context, SemIR::InstId inst_id,
   context.sem_ir().insts().Set(inst_id, inst);
   context.sem_ir().insts().Set(inst_id, inst);
   CARBON_VLOG_TO(context.vlog_stream(), "ReplaceInst: {0} -> {1}\n", inst_id,
   CARBON_VLOG_TO(context.vlog_stream(), "ReplaceInst: {0} -> {1}\n", inst_id,
                  inst);
                  inst);
-  auto new_const_id = TryEvalInst(context, inst_id, inst);
+  auto new_const_id = TryEvalInstUnsafe(context, inst_id, inst);
   CARBON_CHECK(old_const_id == new_const_id);
   CARBON_CHECK(old_const_id == new_const_id);
 }
 }
 
 

+ 6 - 7
toolchain/check/interface.cpp

@@ -91,11 +91,10 @@ static auto GetSelfFacet(Context& context,
   auto type_inst_id = context.types().GetInstId(self_type_id);
   auto type_inst_id = context.types().GetInstId(self_type_id);
   auto witnesses_block_id =
   auto witnesses_block_id =
       context.inst_blocks().AddCanonical({self_witness_id});
       context.inst_blocks().AddCanonical({self_witness_id});
-  auto self_value_const_id =
-      TryEvalInst(context, SemIR::InstId::None,
-                  SemIR::FacetValue{.type_id = self_facet_type_id,
-                                    .type_inst_id = type_inst_id,
-                                    .witnesses_block_id = witnesses_block_id});
+  auto self_value_const_id = TryEvalInst(
+      context, SemIR::FacetValue{.type_id = self_facet_type_id,
+                                 .type_inst_id = type_inst_id,
+                                 .witnesses_block_id = witnesses_block_id});
   return context.constant_values().GetInstId(self_value_const_id);
   return context.constant_values().GetInstId(self_value_const_id);
 }
 }
 
 
@@ -164,8 +163,8 @@ auto GetSelfSpecificForInterfaceMemberWithSelfType(
       CARBON_CHECK(entity_name.bind_index_value >= 0);
       CARBON_CHECK(entity_name.bind_index_value >= 0);
       bind_name.entity_name_id =
       bind_name.entity_name_id =
           context.entity_names().AddCanonical(entity_name);
           context.entity_names().AddCanonical(entity_name);
-      new_arg_id = context.constant_values().GetInstId(
-          TryEvalInst(context, arg_id, bind_name));
+      new_arg_id =
+          context.constant_values().GetInstId(TryEvalInst(context, bind_name));
     }
     }
     arg_ids.push_back(new_arg_id);
     arg_ids.push_back(new_arg_id);
   }
   }

+ 1 - 1
toolchain/check/member_access.cpp

@@ -583,7 +583,7 @@ static auto GetAssociatedValueImpl(Context& context, SemIR::LocId loc_id,
   // That facet value has both the self type we need below and the witness
   // That facet value has both the self type we need below and the witness
   // we are going to use to look up the value of the associated member.
   // we are going to use to look up the value of the associated member.
   auto self_type_const_id = TryEvalInst(
   auto self_type_const_id = TryEvalInst(
-      context, SemIR::InstId::None,
+      context,
       SemIR::FacetAccessType{.type_id = SemIR::TypeType::SingletonTypeId,
       SemIR::FacetAccessType{.type_id = SemIR::TypeType::SingletonTypeId,
                              .facet_value_inst_id = facet_inst_id});
                              .facet_value_inst_id = facet_inst_id});
   // TODO: We should be able to lookup constant associated values from runtime
   // TODO: We should be able to lookup constant associated values from runtime

+ 10 - 4
toolchain/check/subst.cpp

@@ -7,6 +7,7 @@
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/check/eval.h"
 #include "toolchain/check/eval.h"
 #include "toolchain/check/generic.h"
 #include "toolchain/check/generic.h"
+#include "toolchain/check/inst.h"
 #include "toolchain/sem_ir/copy_on_write_block.h"
 #include "toolchain/sem_ir/copy_on_write_block.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/inst.h"
 #include "toolchain/sem_ir/inst.h"
@@ -402,12 +403,17 @@ class SubstConstantCallbacks final : public SubstInstCallbacks {
   }
   }
 
 
   // Rebuilds an instruction by building a new constant.
   // Rebuilds an instruction by building a new constant.
-  auto Rebuild(SemIR::InstId /*old_inst_id*/, SemIR::Inst new_inst) const
+  auto Rebuild(SemIR::InstId old_inst_id, SemIR::Inst new_inst) const
       -> SemIR::InstId override {
       -> SemIR::InstId override {
-    auto result_id = TryEvalInst(*context_, SemIR::InstId::None, new_inst);
-    CARBON_CHECK(result_id.is_constant(),
+    auto result_id = GetOrAddInst(
+        *context_,
+        SemIR::LocIdAndInst::UncheckedLoc(
+            context_->insts().GetLocId(old_inst_id).ToImplicit(), new_inst));
+    auto const_inst_id =
+        context_->constant_values().GetConstantInstId(result_id);
+    CARBON_CHECK(const_inst_id.has_value(),
                  "Substitution into constant produced non-constant");
                  "Substitution into constant produced non-constant");
-    return context_->constant_values().GetInstId(result_id);
+    return const_inst_id;
   }
   }
 
 
  private:
  private:

+ 2 - 2
toolchain/check/testdata/array/fail_bound_negative.carbon

@@ -10,9 +10,9 @@
 
 
 fn Negate(n: i32) -> i32 = "int.snegate";
 fn Negate(n: i32) -> i32 = "int.snegate";
 
 
-// CHECK:STDERR: fail_bound_negative.carbon:[[@LINE+4]]:8: error: array bound of -1 is negative [ArrayBoundNegative]
+// CHECK:STDERR: fail_bound_negative.carbon:[[@LINE+4]]:19: error: array bound of -1 is negative [ArrayBoundNegative]
 // CHECK:STDERR: var a: array(i32, Negate(1));
 // CHECK:STDERR: var a: array(i32, Negate(1));
-// CHECK:STDERR:        ^~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:                   ^~~~~~~~~
 // CHECK:STDERR:
 // CHECK:STDERR:
 var a: array(i32, Negate(1));
 var a: array(i32, Negate(1));
 
 

+ 2 - 2
toolchain/check/testdata/array/fail_bound_overflow.carbon

@@ -8,9 +8,9 @@
 // TIP: To dump output, run:
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/array/fail_bound_overflow.carbon
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/array/fail_bound_overflow.carbon
 
 
-// CHECK:STDERR: fail_bound_overflow.carbon:[[@LINE+4]]:8: error: array bound of 39999999999999999993 is too large [ArrayBoundTooLarge]
+// CHECK:STDERR: fail_bound_overflow.carbon:[[@LINE+4]]:19: error: array bound of 39999999999999999993 is too large [ArrayBoundTooLarge]
 // CHECK:STDERR: var a: array(i32, 39999999999999999993);
 // CHECK:STDERR: var a: array(i32, 39999999999999999993);
-// CHECK:STDERR:        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:                   ^~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
 // CHECK:STDERR:
 var a: array(i32, 39999999999999999993);
 var a: array(i32, 39999999999999999993);
 
 

+ 1 - 1
toolchain/check/testdata/class/import.carbon

@@ -364,5 +364,5 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F[%self.param_patt: %ForwardDeclared.7b34f2.1]() [from "a.carbon"];
 // CHECK:STDOUT: fn @F[%self.param_patt: %ForwardDeclared.7b34f2.1]() [from "a.carbon"];
 // CHECK:STDOUT:
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @G[addr <unexpected>.inst1141: %ptr.6cf]() [from "a.carbon"];
+// CHECK:STDOUT: fn @G[addr <unexpected>.inst1143: %ptr.6cf]() [from "a.carbon"];
 // CHECK:STDOUT:
 // CHECK:STDOUT:

+ 3 - 0
toolchain/check/testdata/facet/min_prelude/convert_class_type_to_generic_facet_value.carbon

@@ -245,6 +245,7 @@ fn G() {
 // CHECK:STDOUT:   %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod]
 // CHECK:STDOUT:   %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod]
 // CHECK:STDOUT:   %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam]
 // CHECK:STDOUT:   %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
+// CHECK:STDOUT:   %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %.loc18: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %.loc18: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%CallGenericMethod.specific_fn.934]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%CallGenericMethod.specific_fn.934]
@@ -278,6 +279,7 @@ fn G() {
 // CHECK:STDOUT:   %PassThroughToGenericMethod.ref: %PassThroughToGenericMethod.type = name_ref PassThroughToGenericMethod, file.%PassThroughToGenericMethod.decl [concrete = constants.%PassThroughToGenericMethod]
 // CHECK:STDOUT:   %PassThroughToGenericMethod.ref: %PassThroughToGenericMethod.type = name_ref PassThroughToGenericMethod, file.%PassThroughToGenericMethod.decl [concrete = constants.%PassThroughToGenericMethod]
 // CHECK:STDOUT:   %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam]
 // CHECK:STDOUT:   %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
+// CHECK:STDOUT:   %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %.loc26: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %.loc26: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %PassThroughToGenericMethod.specific_fn: <specific function> = specific_function %PassThroughToGenericMethod.ref, @PassThroughToGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%PassThroughToGenericMethod.specific_fn]
 // CHECK:STDOUT:   %PassThroughToGenericMethod.specific_fn: <specific function> = specific_function %PassThroughToGenericMethod.ref, @PassThroughToGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%PassThroughToGenericMethod.specific_fn]
@@ -535,6 +537,7 @@ fn G() {
 // CHECK:STDOUT:   %.loc18_36.3: init %GenericParam = class_init (), %.loc18_36.2 [concrete = constants.%GenericParam.val]
 // CHECK:STDOUT:   %.loc18_36.3: init %GenericParam = class_init (), %.loc18_36.2 [concrete = constants.%GenericParam.val]
 // CHECK:STDOUT:   %.loc18_36.4: ref %GenericParam = temporary %.loc18_36.2, %.loc18_36.3
 // CHECK:STDOUT:   %.loc18_36.4: ref %GenericParam = temporary %.loc18_36.2, %.loc18_36.3
 // CHECK:STDOUT:   %.loc18_38.1: ref %GenericParam = converted %.loc18_36.1, %.loc18_36.4
 // CHECK:STDOUT:   %.loc18_38.1: ref %GenericParam = converted %.loc18_36.1, %.loc18_36.4
+// CHECK:STDOUT:   %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %.loc18_53: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %.loc18_53: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%CallGenericMethod.specific_fn]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%CallGenericMethod.specific_fn]

+ 1 - 0
toolchain/check/testdata/facet/min_prelude/convert_class_value_to_generic_facet_value_value.carbon

@@ -319,6 +319,7 @@ fn B() {
 // CHECK:STDOUT:   %.loc20_42.3: init %GenericParam = class_init (), %.loc20_42.2 [concrete = constants.%GenericParam.val]
 // CHECK:STDOUT:   %.loc20_42.3: init %GenericParam = class_init (), %.loc20_42.2 [concrete = constants.%GenericParam.val]
 // CHECK:STDOUT:   %.loc20_42.4: ref %GenericParam = temporary %.loc20_42.2, %.loc20_42.3
 // CHECK:STDOUT:   %.loc20_42.4: ref %GenericParam = temporary %.loc20_42.2, %.loc20_42.3
 // CHECK:STDOUT:   %.loc20_44.1: ref %GenericParam = converted %.loc20_42.1, %.loc20_42.4
 // CHECK:STDOUT:   %.loc20_44.1: ref %GenericParam = converted %.loc20_42.1, %.loc20_42.4
+// CHECK:STDOUT:   %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %.loc20_59: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %.loc20_59: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet.8bd) [concrete = constants.%CallGenericMethod.specific_fn]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet.8bd) [concrete = constants.%CallGenericMethod.specific_fn]

+ 1 - 1
toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon

@@ -921,8 +921,8 @@ fn CallsWithTypeExplicit(U:! type) {
 // CHECK:STDOUT:   %require_complete: <witness> = require_complete_type @HandleTameAnimal2.%W.as_type.loc11_44.2 (%W.as_type) [symbolic = %require_complete (constants.%require_complete.ba9)]
 // CHECK:STDOUT:   %require_complete: <witness> = require_complete_type @HandleTameAnimal2.%W.as_type.loc11_44.2 (%W.as_type) [symbolic = %require_complete (constants.%require_complete.ba9)]
 // CHECK:STDOUT:   %W.as_wit.iface0.loc12_14.3: <witness> = facet_access_witness %W.loc11_22.2, element0 [symbolic = %W.as_wit.iface0.loc12_14.3 (constants.%W.as_wit.iface0)]
 // CHECK:STDOUT:   %W.as_wit.iface0.loc12_14.3: <witness> = facet_access_witness %W.loc11_22.2, element0 [symbolic = %W.as_wit.iface0.loc12_14.3 (constants.%W.as_wit.iface0)]
 // CHECK:STDOUT:   %Animal.facet.loc12_14.3: %Animal.type = facet_value %W.as_type.loc11_44.2, (%W.as_wit.iface0.loc12_14.3) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
 // CHECK:STDOUT:   %Animal.facet.loc12_14.3: %Animal.type = facet_value %W.as_type.loc11_44.2, (%W.as_wit.iface0.loc12_14.3) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
-// CHECK:STDOUT:   %W.as_wit.iface1.loc12_14.3: <witness> = facet_access_witness %W.loc11_22.2, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)]
 // CHECK:STDOUT:   %Eats.lookup_impl_witness: <witness> = lookup_impl_witness %W.loc11_22.2, @Eats [symbolic = %Eats.lookup_impl_witness (constants.%Eats.lookup_impl_witness)]
 // CHECK:STDOUT:   %Eats.lookup_impl_witness: <witness> = lookup_impl_witness %W.loc11_22.2, @Eats [symbolic = %Eats.lookup_impl_witness (constants.%Eats.lookup_impl_witness)]
+// CHECK:STDOUT:   %W.as_wit.iface1.loc12_14.3: <witness> = facet_access_witness %W.loc11_22.2, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)]
 // CHECK:STDOUT:   %facet_value.loc12_14.3: %facet_type.6ff = facet_value %W.as_type.loc11_44.2, (%Eats.lookup_impl_witness, %W.as_wit.iface1.loc12_14.3) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
 // CHECK:STDOUT:   %facet_value.loc12_14.3: %facet_type.6ff = facet_value %W.as_type.loc11_44.2, (%Eats.lookup_impl_witness, %W.as_wit.iface1.loc12_14.3) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
 // CHECK:STDOUT:   %FeedTame2.specific_fn.loc12_3.2: <specific function> = specific_function constants.%FeedTame2, @FeedTame2(%facet_value.loc12_14.3) [symbolic = %FeedTame2.specific_fn.loc12_3.2 (constants.%FeedTame2.specific_fn)]
 // CHECK:STDOUT:   %FeedTame2.specific_fn.loc12_3.2: <specific function> = specific_function constants.%FeedTame2, @FeedTame2(%facet_value.loc12_14.3) [symbolic = %FeedTame2.specific_fn.loc12_3.2 (constants.%FeedTame2.specific_fn)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:

+ 7 - 5
toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon

@@ -335,9 +335,9 @@ fn F() {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %require_complete.loc31_45: <witness> = require_complete_type @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad) [symbolic = %require_complete.loc31_45 (constants.%require_complete.234)]
 // CHECK:STDOUT:   %require_complete.loc31_45: <witness> = require_complete_type @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad) [symbolic = %require_complete.loc31_45 (constants.%require_complete.234)]
 // CHECK:STDOUT:   %require_complete.loc31_54: <witness> = require_complete_type @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) [symbolic = %require_complete.loc31_54 (constants.%require_complete.444)]
 // CHECK:STDOUT:   %require_complete.loc31_54: <witness> = require_complete_type @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) [symbolic = %require_complete.loc31_54 (constants.%require_complete.444)]
-// CHECK:STDOUT:   %Eats.type: type = facet_type <@Eats, @Eats(%Food.as_type.loc31_56.2)> [symbolic = %Eats.type (constants.%Eats.type.f54c3d.2)]
+// CHECK:STDOUT:   %Eats.type.2: type = facet_type <@Eats, @Eats(%Food.as_type.loc31_56.2)> [symbolic = %Eats.type.2 (constants.%Eats.type.f54c3d.2)]
 // CHECK:STDOUT:   %Eats.lookup_impl_witness: <witness> = lookup_impl_witness %T.loc31_17.2, @Eats, @Eats(%Food.as_type.loc31_56.2) [symbolic = %Eats.lookup_impl_witness (constants.%Eats.lookup_impl_witness)]
 // CHECK:STDOUT:   %Eats.lookup_impl_witness: <witness> = lookup_impl_witness %T.loc31_17.2, @Eats, @Eats(%Food.as_type.loc31_56.2) [symbolic = %Eats.lookup_impl_witness (constants.%Eats.lookup_impl_witness)]
-// CHECK:STDOUT:   %Eats.facet.loc31_76.2: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value %T.as_type.loc31_47.2, (%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)]
+// CHECK:STDOUT:   %Eats.facet.loc31_76.2: @HandleAnimal.%Eats.type.2 (%Eats.type.f54c3d.2) = facet_value %T.as_type.loc31_47.2, (%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)]
 // CHECK:STDOUT:   %Feed.specific_fn.loc31_64.2: <specific function> = specific_function constants.%Feed, @Feed(%Food.loc31_29.2, %Eats.facet.loc31_76.2) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.ea3)]
 // CHECK:STDOUT:   %Feed.specific_fn.loc31_64.2: <specific function> = specific_function constants.%Feed, @Feed(%Food.loc31_29.2, %Eats.facet.loc31_76.2) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.ea3)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn[%T.patt.loc31_17.1: %Animal.type, %Food.patt.loc31_29.1: %Edible.type](%a.param_patt: @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad), %food.param_patt: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae)) {
 // CHECK:STDOUT:   fn[%T.patt.loc31_17.1: %Animal.type, %Food.patt.loc31_29.1: %Edible.type](%a.param_patt: @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad), %food.param_patt: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae)) {
@@ -347,12 +347,14 @@ fn F() {
 // CHECK:STDOUT:     %food.ref: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) = name_ref food, %food
 // CHECK:STDOUT:     %food.ref: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) = name_ref food, %food
 // CHECK:STDOUT:     %.loc31_76.1: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)]
 // CHECK:STDOUT:     %.loc31_76.1: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)]
 // CHECK:STDOUT:     %.loc31_76.2: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)]
 // CHECK:STDOUT:     %.loc31_76.2: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)]
+// CHECK:STDOUT:     %Food.as_type.1: type = facet_access_type constants.%Food.5fe [symbolic = %Food.as_type.loc31_56.2 (constants.%Food.as_type.fae)]
+// CHECK:STDOUT:     %Eats.type.1: type = facet_type <@Eats, @Eats(constants.%Food.as_type.fae)> [symbolic = %Eats.type.2 (constants.%Eats.type.f54c3d.2)]
 // CHECK:STDOUT:     %.loc31_76.3: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)]
 // CHECK:STDOUT:     %.loc31_76.3: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)]
 // CHECK:STDOUT:     %T.as_type.loc31_76: type = facet_access_type constants.%T.fd4 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)]
 // CHECK:STDOUT:     %T.as_type.loc31_76: type = facet_access_type constants.%T.fd4 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)]
 // CHECK:STDOUT:     %.loc31_76.4: type = converted constants.%T.fd4, %T.as_type.loc31_76 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)]
 // CHECK:STDOUT:     %.loc31_76.4: type = converted constants.%T.fd4, %T.as_type.loc31_76 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)]
 // CHECK:STDOUT:     %.loc31_76.5: %Animal.type = converted %.loc31_76.4, constants.%T.fd4 [symbolic = %T.loc31_17.2 (constants.%T.fd4)]
 // CHECK:STDOUT:     %.loc31_76.5: %Animal.type = converted %.loc31_76.4, constants.%T.fd4 [symbolic = %T.loc31_17.2 (constants.%T.fd4)]
-// CHECK:STDOUT:     %Eats.facet.loc31_76.1: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value constants.%T.as_type.2ad, (constants.%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)]
-// CHECK:STDOUT:     %.loc31_76.6: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = converted constants.%T.as_type.2ad, %Eats.facet.loc31_76.1 [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)]
+// CHECK:STDOUT:     %Eats.facet.loc31_76.1: @HandleAnimal.%Eats.type.2 (%Eats.type.f54c3d.2) = facet_value constants.%T.as_type.2ad, (constants.%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)]
+// CHECK:STDOUT:     %.loc31_76.6: @HandleAnimal.%Eats.type.2 (%Eats.type.f54c3d.2) = converted constants.%T.as_type.2ad, %Eats.facet.loc31_76.1 [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)]
 // CHECK:STDOUT:     %Feed.specific_fn.loc31_64.1: <specific function> = specific_function %Feed.ref, @Feed(constants.%Food.5fe, constants.%Eats.facet.512) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.ea3)]
 // CHECK:STDOUT:     %Feed.specific_fn.loc31_64.1: <specific function> = specific_function %Feed.ref, @Feed(constants.%Food.5fe, constants.%Eats.facet.512) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.ea3)]
 // CHECK:STDOUT:     %Feed.call: init %empty_tuple.type = call %Feed.specific_fn.loc31_64.1(%a.ref, %food.ref)
 // CHECK:STDOUT:     %Feed.call: init %empty_tuple.type = call %Feed.specific_fn.loc31_64.1(%a.ref, %food.ref)
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:     return
@@ -495,7 +497,7 @@ fn F() {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %require_complete.loc31_45 => constants.%complete_type.357
 // CHECK:STDOUT:   %require_complete.loc31_45 => constants.%complete_type.357
 // CHECK:STDOUT:   %require_complete.loc31_54 => constants.%complete_type.357
 // CHECK:STDOUT:   %require_complete.loc31_54 => constants.%complete_type.357
-// CHECK:STDOUT:   %Eats.type => constants.%Eats.type.1ae
+// CHECK:STDOUT:   %Eats.type.2 => constants.%Eats.type.1ae
 // CHECK:STDOUT:   %Eats.lookup_impl_witness => constants.%impl_witness.4f1
 // CHECK:STDOUT:   %Eats.lookup_impl_witness => constants.%impl_witness.4f1
 // CHECK:STDOUT:   %Eats.facet.loc31_76.2 => constants.%Eats.facet.fa6
 // CHECK:STDOUT:   %Eats.facet.loc31_76.2 => constants.%Eats.facet.fa6
 // CHECK:STDOUT:   %Feed.specific_fn.loc31_64.2 => constants.%Feed.specific_fn.d82
 // CHECK:STDOUT:   %Feed.specific_fn.loc31_64.2 => constants.%Feed.specific_fn.d82

+ 1 - 0
toolchain/check/testdata/facet/min_prelude/fail_convert_class_type_to_generic_facet_value.carbon

@@ -210,6 +210,7 @@ fn G() {
 // CHECK:STDOUT:   %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod]
 // CHECK:STDOUT:   %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod]
 // CHECK:STDOUT:   %WrongGenericParam.ref: type = name_ref WrongGenericParam, file.%WrongGenericParam.decl [concrete = constants.%WrongGenericParam]
 // CHECK:STDOUT:   %WrongGenericParam.ref: type = name_ref WrongGenericParam, file.%WrongGenericParam.decl [concrete = constants.%WrongGenericParam]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
+// CHECK:STDOUT:   %Generic.type: type = facet_type <@Generic, @Generic(constants.%WrongGenericParam)> [concrete = constants.%Generic.type.c3b]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%WrongGenericParam, <error>) [concrete = <error>]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%WrongGenericParam, <error>) [concrete = <error>]
 // CHECK:STDOUT:   %CallGenericMethod.call: init %empty_tuple.type = call %CallGenericMethod.specific_fn() [concrete = <error>]
 // CHECK:STDOUT:   %CallGenericMethod.call: init %empty_tuple.type = call %CallGenericMethod.specific_fn() [concrete = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return

+ 1 - 0
toolchain/check/testdata/facet/min_prelude/fail_deduction_uses_runtime_type_conversion.carbon

@@ -304,6 +304,7 @@ fn G(holds_to: HoldsType((RuntimeConvertTo, ))) {
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F]
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F]
 // CHECK:STDOUT:   %from.ref: %RuntimeConvertFrom = name_ref from, %from [symbolic = constants.%from]
 // CHECK:STDOUT:   %from.ref: %RuntimeConvertFrom = name_ref from, %from [symbolic = constants.%from]
 // CHECK:STDOUT:   %holds_to.ref: %HoldsType.066 = name_ref holds_to, %holds_to
 // CHECK:STDOUT:   %holds_to.ref: %HoldsType.066 = name_ref holds_to, %holds_to
+// CHECK:STDOUT:   %tuple.elem0: type = tuple_access constants.%tuple, element0 [concrete = constants.%RuntimeConvertTo]
 // CHECK:STDOUT:   %impl.elem0: %.31e = impl_witness_access constants.%impl_witness, element0 [concrete = constants.%Convert.e81]
 // CHECK:STDOUT:   %impl.elem0: %.31e = impl_witness_access constants.%impl_witness, element0 [concrete = constants.%Convert.e81]
 // CHECK:STDOUT:   %bound_method: <bound method> = bound_method constants.%from, %impl.elem0 [symbolic = constants.%Convert.bound]
 // CHECK:STDOUT:   %bound_method: <bound method> = bound_method constants.%from, %impl.elem0 [symbolic = constants.%Convert.bound]
 // CHECK:STDOUT:   %.loc40_19.1: ref %RuntimeConvertTo = temporary_storage
 // CHECK:STDOUT:   %.loc40_19.1: ref %RuntimeConvertTo = temporary_storage

+ 1 - 0
toolchain/check/testdata/function/generic/call_method_on_generic_facet.carbon

@@ -273,6 +273,7 @@ fn G() {
 // CHECK:STDOUT:   %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod]
 // CHECK:STDOUT:   %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod]
 // CHECK:STDOUT:   %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam]
 // CHECK:STDOUT:   %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
 // CHECK:STDOUT:   %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric]
+// CHECK:STDOUT:   %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness.b42) [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness.b42) [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %.loc34: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %.loc34: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet.8bd]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet.8bd) [concrete = constants.%CallGenericMethod.specific_fn]
 // CHECK:STDOUT:   %CallGenericMethod.specific_fn: <specific function> = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet.8bd) [concrete = constants.%CallGenericMethod.specific_fn]

+ 2 - 2
toolchain/check/testdata/generic/complete_type.carbon

@@ -15,7 +15,7 @@ library "[[@TEST_NAME]]";
 class B;
 class B;
 
 
 class A(T:! type) {
 class A(T:! type) {
-  // CHECK:STDERR: fail_incomplete_in_class.carbon:[[@LINE+6]]:10: error: type `B` is incomplete [IncompleteTypeInMonomorphization]
+  // CHECK:STDERR: fail_incomplete_in_class.carbon:[[@LINE+6]]:10: error: `T` evaluates to incomplete type `B` [IncompleteTypeInMonomorphization]
   // CHECK:STDERR:   var v: T;
   // CHECK:STDERR:   var v: T;
   // CHECK:STDERR:          ^
   // CHECK:STDERR:          ^
   // CHECK:STDERR: fail_incomplete_in_class.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere]
   // CHECK:STDERR: fail_incomplete_in_class.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere]
@@ -61,7 +61,7 @@ library "[[@TEST_NAME]]";
 class B;
 class B;
 
 
 fn F(T:! type) {
 fn F(T:! type) {
-  // CHECK:STDERR: fail_incomplete_in_function_at_eof.carbon:[[@LINE+6]]:10: error: type `B` is incomplete [IncompleteTypeInMonomorphization]
+  // CHECK:STDERR: fail_incomplete_in_function_at_eof.carbon:[[@LINE+6]]:10: error: `T` evaluates to incomplete type `B` [IncompleteTypeInMonomorphization]
   // CHECK:STDERR:   var v: T;
   // CHECK:STDERR:   var v: T;
   // CHECK:STDERR:          ^
   // CHECK:STDERR:          ^
   // CHECK:STDERR: fail_incomplete_in_function_at_eof.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere]
   // CHECK:STDERR: fail_incomplete_in_function_at_eof.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere]

+ 1 - 1
toolchain/check/testdata/if_expr/fail_not_in_function.carbon

@@ -94,7 +94,7 @@ class C {
 // CHECK:STDOUT:     %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %x: %i32 = bind_name x, <unexpected>.inst1063.loc27_14
+// CHECK:STDOUT:   %x: %i32 = bind_name x, <unexpected>.inst1065.loc27_14
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %y.patt: %i32 = binding_pattern y
 // CHECK:STDOUT:     %y.patt: %i32 = binding_pattern y
 // CHECK:STDOUT:     %.loc37: %i32 = var_pattern %y.patt
 // CHECK:STDOUT:     %.loc37: %i32 = var_pattern %y.patt

+ 2 - 2
toolchain/check/testdata/impl/assoc_const_self.carbon

@@ -62,9 +62,9 @@ impl C as I where .V = () {}
 library "[[@TEST_NAME]]";
 library "[[@TEST_NAME]]";
 
 
 interface I(N:! Core.IntLiteral()) {
 interface I(N:! Core.IntLiteral()) {
-  // CHECK:STDERR: fail_monomorphization_failure.carbon:[[@LINE+3]]:11: error: array bound of -1 is negative [ArrayBoundNegative]
+  // CHECK:STDERR: fail_monomorphization_failure.carbon:[[@LINE+3]]:17: error: array bound of -1 is negative [ArrayBoundNegative]
   // CHECK:STDERR:   let V:! array(Self, N);
   // CHECK:STDERR:   let V:! array(Self, N);
-  // CHECK:STDERR:           ^~~~~~~~~~~~~~
+  // CHECK:STDERR:                 ^~~~
   let V:! array(Self, N);
   let V:! array(Self, N);
 }
 }
 
 

+ 1 - 1
toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon

@@ -336,8 +336,8 @@ fn TestSpecific(a: A({})) -> {} {
 // CHECK:STDOUT:   %require_complete.loc18: <witness> = require_complete_type @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) [symbolic = %require_complete.loc18 (constants.%require_complete.cfebb2.2)]
 // CHECK:STDOUT:   %require_complete.loc18: <witness> = require_complete_type @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) [symbolic = %require_complete.loc18 (constants.%require_complete.cfebb2.2)]
 // CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I, @I(%W.loc17_16.2) [symbolic = %I.assoc_type (constants.%I.assoc_type.1e5078.3)]
 // CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I, @I(%W.loc17_16.2) [symbolic = %I.assoc_type (constants.%I.assoc_type.1e5078.3)]
 // CHECK:STDOUT:   %assoc0: @TestGeneric.%I.assoc_type (%I.assoc_type.1e5078.3) = assoc_entity element0, @I.%F.decl [symbolic = %assoc0 (constants.%assoc0.8f0422.3)]
 // CHECK:STDOUT:   %assoc0: @TestGeneric.%I.assoc_type (%I.assoc_type.1e5078.3) = assoc_entity element0, @I.%F.decl [symbolic = %assoc0 (constants.%assoc0.8f0422.3)]
-// CHECK:STDOUT:   %F.type: type = fn_type @F.1, @I(%W.loc17_16.2) [symbolic = %F.type (constants.%F.type.2aef59.3)]
 // CHECK:STDOUT:   %I.lookup_impl_witness: <witness> = lookup_impl_witness %A.loc17_32.2, @I, @I(%W.loc17_16.2) [symbolic = %I.lookup_impl_witness (constants.%I.lookup_impl_witness)]
 // CHECK:STDOUT:   %I.lookup_impl_witness: <witness> = lookup_impl_witness %A.loc17_32.2, @I, @I(%W.loc17_16.2) [symbolic = %I.lookup_impl_witness (constants.%I.lookup_impl_witness)]
+// CHECK:STDOUT:   %F.type: type = fn_type @F.1, @I(%W.loc17_16.2) [symbolic = %F.type (constants.%F.type.2aef59.3)]
 // CHECK:STDOUT:   %I.facet: @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) = facet_value %A.loc17_32.2, (%I.lookup_impl_witness) [symbolic = %I.facet (constants.%I.facet.6d2)]
 // CHECK:STDOUT:   %I.facet: @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) = facet_value %A.loc17_32.2, (%I.lookup_impl_witness) [symbolic = %I.facet (constants.%I.facet.6d2)]
 // CHECK:STDOUT:   %.loc18_11: type = fn_type_with_self_type %F.type, %I.facet [symbolic = %.loc18_11 (constants.%.fe1)]
 // CHECK:STDOUT:   %.loc18_11: type = fn_type_with_self_type %F.type, %I.facet [symbolic = %.loc18_11 (constants.%.fe1)]
 // CHECK:STDOUT:   %impl.elem0.loc18_11.2: @TestGeneric.%.loc18_11 (%.fe1) = impl_witness_access %I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc18_11.2 (constants.%impl.elem0)]
 // CHECK:STDOUT:   %impl.elem0.loc18_11.2: @TestGeneric.%.loc18_11 (%.fe1) = impl_witness_access %I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc18_11.2 (constants.%impl.elem0)]

+ 33 - 5
toolchain/check/testdata/impl/use_assoc_const.carbon

@@ -557,6 +557,8 @@ fn F() {
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
 // CHECK:STDOUT:   %impl.elem0.loc9_46: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %impl.elem0.loc9_46: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %bound_method.loc9_46.1: <bound method> = bound_method %u.ref, %impl.elem0.loc9_46
 // CHECK:STDOUT:   %bound_method.loc9_46.1: <bound method> = bound_method %u.ref, %impl.elem0.loc9_46
+// CHECK:STDOUT:   %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:   %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   %specific_fn.loc9_46: <specific function> = specific_function %impl.elem0.loc9_46, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %specific_fn.loc9_46: <specific function> = specific_function %impl.elem0.loc9_46, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %bound_method.loc9_46.2: <bound method> = bound_method %u.ref, %specific_fn.loc9_46
 // CHECK:STDOUT:   %bound_method.loc9_46.2: <bound method> = bound_method %u.ref, %specific_fn.loc9_46
 // CHECK:STDOUT:   %impl.elem0.loc9_48: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
 // CHECK:STDOUT:   %impl.elem0.loc9_48: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
@@ -815,6 +817,8 @@ fn F() {
 // CHECK:STDOUT:   %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba]
 // CHECK:STDOUT:   %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba]
 // CHECK:STDOUT:   %impl.elem0.loc11_34: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %impl.elem0.loc11_34: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %bound_method.loc11_34.1: <bound method> = bound_method %u.ref, %impl.elem0.loc11_34
 // CHECK:STDOUT:   %bound_method.loc11_34.1: <bound method> = bound_method %u.ref, %impl.elem0.loc11_34
+// CHECK:STDOUT:   %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:   %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   %specific_fn.loc11_34: <specific function> = specific_function %impl.elem0.loc11_34, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %specific_fn.loc11_34: <specific function> = specific_function %impl.elem0.loc11_34, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %bound_method.loc11_34.2: <bound method> = bound_method %u.ref, %specific_fn.loc11_34
 // CHECK:STDOUT:   %bound_method.loc11_34.2: <bound method> = bound_method %u.ref, %specific_fn.loc11_34
 // CHECK:STDOUT:   %impl.elem0.loc11_36: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
 // CHECK:STDOUT:   %impl.elem0.loc11_36: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
@@ -1224,6 +1228,8 @@ fn F() {
 // CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
 // CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
 // CHECK:STDOUT:   %impl.elem0.loc12_16: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %impl.elem0.loc12_16: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %bound_method.loc12_16.1: <bound method> = bound_method %u.ref, %impl.elem0.loc12_16
 // CHECK:STDOUT:   %bound_method.loc12_16.1: <bound method> = bound_method %u.ref, %impl.elem0.loc12_16
+// CHECK:STDOUT:   %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:   %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   %specific_fn.loc12_16: <specific function> = specific_function %impl.elem0.loc12_16, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %specific_fn.loc12_16: <specific function> = specific_function %impl.elem0.loc12_16, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %bound_method.loc12_16.2: <bound method> = bound_method %u.ref, %specific_fn.loc12_16
 // CHECK:STDOUT:   %bound_method.loc12_16.2: <bound method> = bound_method %u.ref, %specific_fn.loc12_16
 // CHECK:STDOUT:   %impl.elem0.loc12_18: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
 // CHECK:STDOUT:   %impl.elem0.loc12_18: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
@@ -1245,6 +1251,8 @@ fn F() {
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
 // CHECK:STDOUT:   %impl.elem0.loc15_16: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %impl.elem0.loc15_16: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82]
 // CHECK:STDOUT:   %bound_method.loc15_16.1: <bound method> = bound_method %v.ref, %impl.elem0.loc15_16
 // CHECK:STDOUT:   %bound_method.loc15_16.1: <bound method> = bound_method %v.ref, %impl.elem0.loc15_16
+// CHECK:STDOUT:   %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:   %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   %specific_fn.loc15_16: <specific function> = specific_function %impl.elem0.loc15_16, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %specific_fn.loc15_16: <specific function> = specific_function %impl.elem0.loc15_16, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn]
 // CHECK:STDOUT:   %bound_method.loc15_16.2: <bound method> = bound_method %v.ref, %specific_fn.loc15_16
 // CHECK:STDOUT:   %bound_method.loc15_16.2: <bound method> = bound_method %v.ref, %specific_fn.loc15_16
 // CHECK:STDOUT:   %impl.elem0.loc15_18: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
 // CHECK:STDOUT:   %impl.elem0.loc15_18: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956]
@@ -1392,6 +1400,10 @@ fn F() {
 // CHECK:STDOUT:     %T.as_wit.iface0.loc25: <witness> = facet_access_witness constants.%T, element0 [symbolic = %T.as_wit.iface0.loc24_34.2 (constants.%T.as_wit.iface0)]
 // CHECK:STDOUT:     %T.as_wit.iface0.loc25: <witness> = facet_access_witness constants.%T, element0 [symbolic = %T.as_wit.iface0.loc24_34.2 (constants.%T.as_wit.iface0)]
 // CHECK:STDOUT:     %impl.elem1.loc25_11.1: @GenericCallF.%.loc25_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc25, element1 [symbolic = %impl.elem1.loc25_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %impl.elem1.loc25_11.1: @GenericCallF.%.loc25_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc25, element1 [symbolic = %impl.elem1.loc25_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %u.ref: @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = name_ref u, %u
 // CHECK:STDOUT:     %u.ref: @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = name_ref u, %u
+// CHECK:STDOUT:     %as_wit.iface0.1: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc24_34.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.1: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc24_34.2 (constants.%impl.elem0.d9c3a6.2)]
+// CHECK:STDOUT:     %as_wit.iface0.2: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc24_34.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.2: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc24_34.2 (constants.%impl.elem0.d9c3a6.2)]
 // CHECK:STDOUT:     %specific_impl_fn.loc25_11.1: <specific function> = specific_impl_function %impl.elem1.loc25_11.1, @F.1(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc25_11.2 (constants.%specific_impl_fn)]
 // CHECK:STDOUT:     %specific_impl_fn.loc25_11.1: <specific function> = specific_impl_function %impl.elem1.loc25_11.1, @F.1(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc25_11.2 (constants.%specific_impl_fn)]
 // CHECK:STDOUT:     %.loc25_15: init @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = call %specific_impl_fn.loc25_11.1(%u.ref)
 // CHECK:STDOUT:     %.loc25_15: init @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = call %specific_impl_fn.loc25_11.1(%u.ref)
 // CHECK:STDOUT:     %.loc25_16.1: @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = value_of_initializer %.loc25_15
 // CHECK:STDOUT:     %.loc25_16.1: @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = value_of_initializer %.loc25_15
@@ -1667,7 +1679,11 @@ fn F() {
 // CHECK:STDOUT:     %impl.elem1.loc9_11.1: @GenericAddResult.%.loc9_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc9_11, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %impl.elem1.loc9_11.1: @GenericAddResult.%.loc9_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc9_11, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %u.ref.loc9_14: @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = name_ref u, %u
 // CHECK:STDOUT:     %u.ref.loc9_14: @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = name_ref u, %u
 // CHECK:STDOUT:     %.loc9_15.1: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %.loc9_15.1: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
+// CHECK:STDOUT:     %as_wit.iface0.1: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.1: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %.loc9_15.2: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %.loc9_15.2: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
+// CHECK:STDOUT:     %as_wit.iface0.2: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.2: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %specific_impl_fn.loc9_11.1: <specific function> = specific_impl_function %impl.elem1.loc9_11.1, @F(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn.5d8)]
 // CHECK:STDOUT:     %specific_impl_fn.loc9_11.1: <specific function> = specific_impl_function %impl.elem1.loc9_11.1, @F(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn.5d8)]
 // CHECK:STDOUT:     %.loc9_15.3: init @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = call %specific_impl_fn.loc9_11.1(%u.ref.loc9_14)
 // CHECK:STDOUT:     %.loc9_15.3: init @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = call %specific_impl_fn.loc9_11.1(%u.ref.loc9_14)
 // CHECK:STDOUT:     %T.ref.loc9: %J.type = name_ref T, %T.loc8_21.1 [symbolic = %T.loc8_21.2 (constants.%T)]
 // CHECK:STDOUT:     %T.ref.loc9: %J.type = name_ref T, %T.loc8_21.1 [symbolic = %T.loc8_21.2 (constants.%T)]
@@ -1678,7 +1694,11 @@ fn F() {
 // CHECK:STDOUT:     %impl.elem1.loc9_20: @GenericAddResult.%.loc9_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc9_20, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %impl.elem1.loc9_20: @GenericAddResult.%.loc9_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc9_20, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %u.ref.loc9_23: @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = name_ref u, %u
 // CHECK:STDOUT:     %u.ref.loc9_23: @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = name_ref u, %u
 // CHECK:STDOUT:     %.loc9_24.1: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %.loc9_24.1: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
+// CHECK:STDOUT:     %as_wit.iface0.3: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.3: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %.loc9_24.2: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %.loc9_24.2: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
+// CHECK:STDOUT:     %as_wit.iface0.4: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.4: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)]
 // CHECK:STDOUT:     %specific_impl_fn.loc9_20: <specific function> = specific_impl_function %impl.elem1.loc9_20, @F(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn.5d8)]
 // CHECK:STDOUT:     %specific_impl_fn.loc9_20: <specific function> = specific_impl_function %impl.elem1.loc9_20, @F(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn.5d8)]
 // CHECK:STDOUT:     %.loc9_24.3: init @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = call %specific_impl_fn.loc9_20(%u.ref.loc9_23)
 // CHECK:STDOUT:     %.loc9_24.3: init @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = call %specific_impl_fn.loc9_20(%u.ref.loc9_23)
 // CHECK:STDOUT:     %as_wit.iface0.loc9_17.1: <witness> = facet_access_witness constants.%impl.elem0.c57618.2, element0 [symbolic = %as_wit.iface0.loc9_17.2 (constants.%as_wit.iface0)]
 // CHECK:STDOUT:     %as_wit.iface0.loc9_17.1: <witness> = facet_access_witness constants.%impl.elem0.c57618.2, element0 [symbolic = %as_wit.iface0.loc9_17.2 (constants.%as_wit.iface0)]
@@ -1892,6 +1912,10 @@ fn F() {
 // CHECK:STDOUT:     %impl.elem1.loc9_11.1: @GenericCallInterfaceQualified.%.loc9_11 (%.9ac) = impl_witness_access %T.as_wit.iface0.loc9, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %impl.elem1.loc9_11.1: @GenericCallInterfaceQualified.%.loc9_11 (%.9ac) = impl_witness_access %T.as_wit.iface0.loc9, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %bound_method.loc9_11: <bound method> = bound_method %t.ref, %impl.elem1.loc9_11.1
 // CHECK:STDOUT:     %bound_method.loc9_11: <bound method> = bound_method %t.ref, %impl.elem1.loc9_11.1
 // CHECK:STDOUT:     %u.ref: @GenericCallInterfaceQualified.%impl.elem0.loc8_51.2 (%impl.elem0.d9c3a6.2) = name_ref u, %u
 // CHECK:STDOUT:     %u.ref: @GenericCallInterfaceQualified.%impl.elem0.loc8_51.2 (%impl.elem0.d9c3a6.2) = name_ref u, %u
+// CHECK:STDOUT:     %as_wit.iface0.1: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_51.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.1: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_51.2 (constants.%impl.elem0.d9c3a6.2)]
+// CHECK:STDOUT:     %as_wit.iface0.2: <witness> = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_51.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.2: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_51.2 (constants.%impl.elem0.d9c3a6.2)]
 // CHECK:STDOUT:     %specific_impl_fn.loc9_11.1: <specific function> = specific_impl_function %impl.elem1.loc9_11.1, @G(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn)]
 // CHECK:STDOUT:     %specific_impl_fn.loc9_11.1: <specific function> = specific_impl_function %impl.elem1.loc9_11.1, @G(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn)]
 // CHECK:STDOUT:     %bound_method.loc9_19: <bound method> = bound_method %t.ref, %specific_impl_fn.loc9_11.1
 // CHECK:STDOUT:     %bound_method.loc9_19: <bound method> = bound_method %t.ref, %specific_impl_fn.loc9_11.1
 // CHECK:STDOUT:     %.loc9_19: init @GenericCallInterfaceQualified.%impl.elem0.loc8_51.2 (%impl.elem0.d9c3a6.2) = call %bound_method.loc9_19(%t.ref, %u.ref)
 // CHECK:STDOUT:     %.loc9_19: init @GenericCallInterfaceQualified.%impl.elem0.loc8_51.2 (%impl.elem0.d9c3a6.2) = call %bound_method.loc9_19(%t.ref, %u.ref)
@@ -2081,10 +2105,10 @@ fn F() {
 // CHECK:STDOUT:   %J.facet: %J.type = facet_value %T.as_type.loc8_45.2, (%T.as_wit.iface0.loc26_11.2) [symbolic = %J.facet (constants.%J.facet.869)]
 // CHECK:STDOUT:   %J.facet: %J.type = facet_value %T.as_type.loc8_45.2, (%T.as_wit.iface0.loc26_11.2) [symbolic = %J.facet (constants.%J.facet.869)]
 // CHECK:STDOUT:   %.loc26_11.2: type = fn_type_with_self_type constants.%F.type, %J.facet [symbolic = %.loc26_11.2 (constants.%.861)]
 // CHECK:STDOUT:   %.loc26_11.2: type = fn_type_with_self_type constants.%F.type, %J.facet [symbolic = %.loc26_11.2 (constants.%.861)]
 // CHECK:STDOUT:   %impl.elem1.loc26_11.2: @GenericCallFI32.%.loc26_11.2 (%.861) = impl_witness_access %T.as_wit.iface0.loc26_11.2, element1 [symbolic = %impl.elem1.loc26_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:   %impl.elem1.loc26_11.2: @GenericCallFI32.%.loc26_11.2 (%.861) = impl_witness_access %T.as_wit.iface0.loc26_11.2, element1 [symbolic = %impl.elem1.loc26_11.2 (constants.%impl.elem1)]
+// CHECK:STDOUT:   %impl.elem0.3: type = impl_witness_access %T.as_wit.iface0.loc26_11.2, element0 [symbolic = %impl.elem0.3 (constants.%impl.elem0.37e)]
 // CHECK:STDOUT:   %specific_impl_fn.loc26_11.2: <specific function> = specific_impl_function %impl.elem1.loc26_11.2, @F(%J.facet) [symbolic = %specific_impl_fn.loc26_11.2 (constants.%specific_impl_fn)]
 // CHECK:STDOUT:   %specific_impl_fn.loc26_11.2: <specific function> = specific_impl_function %impl.elem1.loc26_11.2, @F(%J.facet) [symbolic = %specific_impl_fn.loc26_11.2 (constants.%specific_impl_fn)]
-// CHECK:STDOUT:   %impl.elem0.loc26: type = impl_witness_access %T.as_wit.iface0.loc26_11.2, element0 [symbolic = %impl.elem0.loc26 (constants.%impl.elem0.37e)]
-// CHECK:STDOUT:   %require_complete.loc26_15: <witness> = require_complete_type @GenericCallFI32.%impl.elem0.loc26 (%impl.elem0.37e) [symbolic = %require_complete.loc26_15 (constants.%require_complete.8bd)]
-// CHECK:STDOUT:   %ImplicitAs.type: type = facet_type <@ImplicitAs, @ImplicitAs(%impl.elem0.loc26)> [symbolic = %ImplicitAs.type (constants.%ImplicitAs.type.820)]
+// CHECK:STDOUT:   %require_complete.loc26_15: <witness> = require_complete_type @GenericCallFI32.%impl.elem0.3 (%impl.elem0.37e) [symbolic = %require_complete.loc26_15 (constants.%require_complete.8bd)]
+// CHECK:STDOUT:   %ImplicitAs.type: type = facet_type <@ImplicitAs, @ImplicitAs(%impl.elem0.3)> [symbolic = %ImplicitAs.type (constants.%ImplicitAs.type.820)]
 // CHECK:STDOUT:   %require_complete.loc26_14: <witness> = require_complete_type @GenericCallFI32.%ImplicitAs.type (%ImplicitAs.type.820) [symbolic = %require_complete.loc26_14 (constants.%require_complete.1ce)]
 // CHECK:STDOUT:   %require_complete.loc26_14: <witness> = require_complete_type @GenericCallFI32.%ImplicitAs.type (%ImplicitAs.type.820) [symbolic = %require_complete.loc26_14 (constants.%require_complete.1ce)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn[%T.patt.loc8_20.1: %J_where.type](%t.param_patt: @GenericCallFI32.%T.as_type.loc8_45.2 (%T.as_type)) -> %i32 {
 // CHECK:STDOUT:   fn[%T.patt.loc8_20.1: %J_where.type](%t.param_patt: @GenericCallFI32.%T.as_type.loc8_45.2 (%T.as_type)) -> %i32 {
@@ -2096,9 +2120,13 @@ fn F() {
 // CHECK:STDOUT:     %T.as_wit.iface0.loc26_11.1: <witness> = facet_access_witness constants.%T, element0 [symbolic = %T.as_wit.iface0.loc26_11.2 (constants.%T.as_wit.iface0)]
 // CHECK:STDOUT:     %T.as_wit.iface0.loc26_11.1: <witness> = facet_access_witness constants.%T, element0 [symbolic = %T.as_wit.iface0.loc26_11.2 (constants.%T.as_wit.iface0)]
 // CHECK:STDOUT:     %impl.elem1.loc26_11.1: @GenericCallFI32.%.loc26_11.2 (%.861) = impl_witness_access %T.as_wit.iface0.loc26_11.1, element1 [symbolic = %impl.elem1.loc26_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %impl.elem1.loc26_11.1: @GenericCallFI32.%.loc26_11.2 (%.861) = impl_witness_access %T.as_wit.iface0.loc26_11.1, element1 [symbolic = %impl.elem1.loc26_11.2 (constants.%impl.elem1)]
 // CHECK:STDOUT:     %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2]
 // CHECK:STDOUT:     %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2]
+// CHECK:STDOUT:     %as_wit.iface0.1: <witness> = facet_access_witness constants.%J.facet.869, element0 [symbolic = %T.as_wit.iface0.loc26_11.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.1: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.3 (constants.%impl.elem0.37e)]
+// CHECK:STDOUT:     %as_wit.iface0.2: <witness> = facet_access_witness constants.%J.facet.869, element0 [symbolic = %T.as_wit.iface0.loc26_11.2 (constants.%T.as_wit.iface0)]
+// CHECK:STDOUT:     %impl.elem0.2: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.3 (constants.%impl.elem0.37e)]
 // CHECK:STDOUT:     %specific_impl_fn.loc26_11.1: <specific function> = specific_impl_function %impl.elem1.loc26_11.1, @F(constants.%J.facet.869) [symbolic = %specific_impl_fn.loc26_11.2 (constants.%specific_impl_fn)]
 // CHECK:STDOUT:     %specific_impl_fn.loc26_11.1: <specific function> = specific_impl_function %impl.elem1.loc26_11.1, @F(constants.%J.facet.869) [symbolic = %specific_impl_fn.loc26_11.2 (constants.%specific_impl_fn)]
-// CHECK:STDOUT:     %.loc26_14: @GenericCallFI32.%impl.elem0.loc26 (%impl.elem0.37e) = converted %int_2, <error> [concrete = <error>]
-// CHECK:STDOUT:     %.loc26_15: init @GenericCallFI32.%impl.elem0.loc26 (%impl.elem0.37e) = call %specific_impl_fn.loc26_11.1(<error>) [concrete = <error>]
+// CHECK:STDOUT:     %.loc26_14: @GenericCallFI32.%impl.elem0.3 (%impl.elem0.37e) = converted %int_2, <error> [concrete = <error>]
+// CHECK:STDOUT:     %.loc26_15: init @GenericCallFI32.%impl.elem0.3 (%impl.elem0.37e) = call %specific_impl_fn.loc26_11.1(<error>) [concrete = <error>]
 // CHECK:STDOUT:     %.loc26_16: %i32 = converted %.loc26_15, <error> [concrete = <error>]
 // CHECK:STDOUT:     %.loc26_16: %i32 = converted %.loc26_15, <error> [concrete = <error>]
 // CHECK:STDOUT:     return <error>
 // CHECK:STDOUT:     return <error>
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }

+ 3 - 3
toolchain/check/testdata/struct/import.carbon

@@ -328,7 +328,7 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
 // CHECK:STDOUT:   %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
-// CHECK:STDOUT:   %Implicit.import_ref.b8b = import_ref Implicit//default, inst1138 [no loc], unloaded
+// CHECK:STDOUT:   %Implicit.import_ref.b8b = import_ref Implicit//default, inst1142 [no loc], unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {
@@ -505,7 +505,7 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import_ref.c81: %struct_type.a.b = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
 // CHECK:STDOUT:   %Implicit.import_ref.c81: %struct_type.a.b = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
-// CHECK:STDOUT:   %Implicit.import_ref.b8b = import_ref Implicit//default, inst1138 [no loc], unloaded
+// CHECK:STDOUT:   %Implicit.import_ref.b8b = import_ref Implicit//default, inst1142 [no loc], unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {
@@ -622,7 +622,7 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
 // CHECK:STDOUT:   %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
-// CHECK:STDOUT:   %Implicit.import_ref.b8b = import_ref Implicit//default, inst1138 [no loc], unloaded
+// CHECK:STDOUT:   %Implicit.import_ref.b8b = import_ref Implicit//default, inst1142 [no loc], unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {

+ 3 - 3
toolchain/check/testdata/tuple/import.carbon

@@ -358,7 +358,7 @@ var c_bad: C((3, 4)) = F();
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
 // CHECK:STDOUT:   %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
-// CHECK:STDOUT:   %Implicit.import_ref.964 = import_ref Implicit//default, inst1174 [no loc], unloaded
+// CHECK:STDOUT:   %Implicit.import_ref.964 = import_ref Implicit//default, inst1179 [no loc], unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {
@@ -551,7 +551,7 @@ var c_bad: C((3, 4)) = F();
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
 // CHECK:STDOUT:   %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
-// CHECK:STDOUT:   %Implicit.import_ref.964 = import_ref Implicit//default, inst1174 [no loc], unloaded
+// CHECK:STDOUT:   %Implicit.import_ref.964 = import_ref Implicit//default, inst1179 [no loc], unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {
@@ -669,7 +669,7 @@ var c_bad: C((3, 4)) = F();
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
 // CHECK:STDOUT:   %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
 // CHECK:STDOUT:   %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
-// CHECK:STDOUT:   %Implicit.import_ref.964 = import_ref Implicit//default, inst1174 [no loc], unloaded
+// CHECK:STDOUT:   %Implicit.import_ref.964 = import_ref Implicit//default, inst1179 [no loc], unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {

+ 1 - 3
toolchain/check/type.cpp

@@ -72,10 +72,8 @@ auto ValidateFloatType(Context& context, SemIRLoc loc, SemIR::FloatType result)
 template <typename InstT, typename... EachArgT>
 template <typename InstT, typename... EachArgT>
 static auto GetTypeImpl(Context& context, EachArgT... each_arg)
 static auto GetTypeImpl(Context& context, EachArgT... each_arg)
     -> SemIR::TypeId {
     -> SemIR::TypeId {
-  // TODO: Remove inst_id parameter from TryEvalInst.
   InstT inst = {SemIR::TypeType::SingletonTypeId, each_arg...};
   InstT inst = {SemIR::TypeType::SingletonTypeId, each_arg...};
-  return context.types().GetTypeIdForTypeConstantId(
-      TryEvalInst(context, SemIR::InstId::None, inst));
+  return context.types().GetTypeIdForTypeConstantId(TryEvalInst(context, inst));
 }
 }
 
 
 // Gets or forms a type_id for a type, given the instruction kind and arguments,
 // Gets or forms a type_id for a type, given the instruction kind and arguments,

+ 22 - 0
toolchain/sem_ir/inst_kind.h

@@ -123,6 +123,7 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) {
     llvm::StringLiteral ir_name;
     llvm::StringLiteral ir_name;
     InstIsType is_type = InstIsType::Never;
     InstIsType is_type = InstIsType::Never;
     InstConstantKind constant_kind = InstConstantKind::Indirect;
     InstConstantKind constant_kind = InstConstantKind::Indirect;
+    bool constant_needs_inst_id = constant_kind == InstConstantKind::Unique;
     TerminatorKind terminator_kind = TerminatorKind::NotTerminator;
     TerminatorKind terminator_kind = TerminatorKind::NotTerminator;
     bool is_lowered = true;
     bool is_lowered = true;
     bool deduce_through = false;
     bool deduce_through = false;
@@ -160,6 +161,22 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) {
     return definition_info(*this).constant_kind;
     return definition_info(*this).constant_kind;
   }
   }
 
 
+  // Returns whether we need an `InstId` referring to the instruction to
+  // constant evaluate this instruction. If this is set to `true`, then:
+  //
+  //  - `Check::TryEvalInst` will not allow this instruction to be directly
+  //    evaluated without an `InstId`.
+  //  - `Check::EvalConstantInst` will be passed an `InstId` for the original
+  //    instruction being evaluated.
+  //
+  // This is set to true for instructions whose evaluation either might need a
+  // location, for example for diagnostics or for newly-created instructions,
+  // and for instructions whose evaluation needs to inspect the original form of
+  // its operands.
+  auto constant_needs_inst_id() const -> bool {
+    return definition_info(*this).constant_needs_inst_id;
+  }
+
   // Returns whether this instruction kind is a code block terminator, such as
   // Returns whether this instruction kind is a code block terminator, such as
   // an unconditional branch instruction, or part of the termination sequence,
   // an unconditional branch instruction, or part of the termination sequence,
   // such as a conditional branch instruction. The termination sequence of a
   // such as a conditional branch instruction. The termination sequence of a
@@ -214,6 +231,11 @@ class InstKind::Definition : public InstKind {
     return info_.constant_kind;
     return info_.constant_kind;
   }
   }
 
 
+  // Returns whether constant evaluation of this instruction needs an InstId.
+  constexpr auto constant_needs_inst_id() const -> bool {
+    return info_.constant_needs_inst_id;
+  }
+
   // Returns whether this instruction kind is a code block terminator. See
   // Returns whether this instruction kind is a code block terminator. See
   // InstKind::terminator_kind().
   // InstKind::terminator_kind().
   constexpr auto terminator_kind() const -> TerminatorKind {
   constexpr auto terminator_kind() const -> TerminatorKind {

+ 10 - 2
toolchain/sem_ir/typed_insts.h

@@ -188,6 +188,7 @@ struct ArrayType {
       {.ir_name = "array_type",
       {.ir_name = "array_type",
        .is_type = InstIsType::Always,
        .is_type = InstIsType::Always,
        .constant_kind = InstConstantKind::Conditional,
        .constant_kind = InstConstantKind::Conditional,
+       .constant_needs_inst_id = true,
        .deduce_through = true});
        .deduce_through = true});
 
 
   TypeId type_id;
   TypeId type_id;
@@ -771,6 +772,7 @@ struct FloatType {
       {.ir_name = "float_type",
       {.ir_name = "float_type",
        .is_type = InstIsType::Always,
        .is_type = InstIsType::Always,
        .constant_kind = InstConstantKind::Conditional,
        .constant_kind = InstConstantKind::Conditional,
+       .constant_needs_inst_id = true,
        .deduce_through = true});
        .deduce_through = true});
 
 
   TypeId type_id;
   TypeId type_id;
@@ -909,6 +911,7 @@ struct ImplWitnessAccess {
           {.ir_name = "impl_witness_access",
           {.ir_name = "impl_witness_access",
            .is_type = InstIsType::Maybe,
            .is_type = InstIsType::Maybe,
            .constant_kind = InstConstantKind::SymbolicOnly,
            .constant_kind = InstConstantKind::SymbolicOnly,
+           .constant_needs_inst_id = true,
            .is_lowered = false});
            .is_lowered = false});
 
 
   TypeId type_id;
   TypeId type_id;
@@ -1058,6 +1061,7 @@ struct IntType {
       {.ir_name = "int_type",
       {.ir_name = "int_type",
        .is_type = InstIsType::Always,
        .is_type = InstIsType::Always,
        .constant_kind = InstConstantKind::Conditional,
        .constant_kind = InstConstantKind::Conditional,
+       .constant_needs_inst_id = true,
        .deduce_through = true});
        .deduce_through = true});
 
 
   TypeId type_id;
   TypeId type_id;
@@ -1082,6 +1086,7 @@ struct LookupImplWitness {
       InstKind::LookupImplWitness.Define<Parse::NodeId>(
       InstKind::LookupImplWitness.Define<Parse::NodeId>(
           {.ir_name = "lookup_impl_witness",
           {.ir_name = "lookup_impl_witness",
            .constant_kind = InstConstantKind::SymbolicOnly,
            .constant_kind = InstConstantKind::SymbolicOnly,
+           .constant_needs_inst_id = true,
            .is_lowered = false});
            .is_lowered = false});
 
 
   // Always the type of the builtin `WitnessType` singleton instruction.
   // Always the type of the builtin `WitnessType` singleton instruction.
@@ -1285,6 +1290,7 @@ struct RequireCompleteType {
       InstKind::RequireCompleteType.Define<Parse::NodeId>(
       InstKind::RequireCompleteType.Define<Parse::NodeId>(
           {.ir_name = "require_complete_type",
           {.ir_name = "require_complete_type",
            .constant_kind = InstConstantKind::SymbolicOnly,
            .constant_kind = InstConstantKind::SymbolicOnly,
+           .constant_needs_inst_id = true,
            .is_lowered = false});
            .is_lowered = false});
   // Always the builtin witness type.
   // Always the builtin witness type.
   TypeId type_id;
   TypeId type_id;
@@ -1423,7 +1429,8 @@ struct SpecificConstant {
 struct SpecificFunction {
 struct SpecificFunction {
   static constexpr auto Kind = InstKind::SpecificFunction.Define<Parse::NodeId>(
   static constexpr auto Kind = InstKind::SpecificFunction.Define<Parse::NodeId>(
       {.ir_name = "specific_function",
       {.ir_name = "specific_function",
-       .constant_kind = InstConstantKind::Conditional});
+       .constant_kind = InstConstantKind::Conditional,
+       .constant_needs_inst_id = true});
 
 
   // Always the builtin SpecificFunctionType.
   // Always the builtin SpecificFunctionType.
   TypeId type_id;
   TypeId type_id;
@@ -1459,7 +1466,8 @@ struct SpecificImplFunction {
   static constexpr auto Kind =
   static constexpr auto Kind =
       InstKind::SpecificImplFunction.Define<Parse::NodeId>(
       InstKind::SpecificImplFunction.Define<Parse::NodeId>(
           {.ir_name = "specific_impl_function",
           {.ir_name = "specific_impl_function",
-           .constant_kind = InstConstantKind::SymbolicOnly});
+           .constant_kind = InstConstantKind::SymbolicOnly,
+           .constant_needs_inst_id = true});
 
 
   // Always the builtin SpecificFunctionType.
   // Always the builtin SpecificFunctionType.
   TypeId type_id;
   TypeId type_id;