Преглед изворни кода

Add an `EvalOrAddInst` function. (#5258)

Use that instead of `AddInstInNoBlock` to get the value of an
instruction when evaluation might depend on the `InstId` but only the
`ConstantId` of the instruction is desired by the consumer.
Richard Smith пре 1 година
родитељ
комит
bfef32b482

+ 2 - 1
toolchain/check/eval.cpp

@@ -1744,7 +1744,8 @@ static auto TryEvalTypedInst(EvalContext& eval_context, SemIR::InstId inst_id,
       // Couldn't perform the action because it's still dependent.
       return MakeConstantResult(eval_context.context(), inst,
                                 Phase::TemplateSymbolic);
-    } else if constexpr (InstT::Kind.constant_needs_inst_id()) {
+    } else if constexpr (InstT::Kind.constant_needs_inst_id() !=
+                         SemIR::InstConstantNeedsInstIdKind::No) {
       CARBON_CHECK(inst_id.has_value());
       return ConvertEvalResultToConstantId(
           eval_context.context(),

+ 6 - 1
toolchain/check/eval.h

@@ -8,6 +8,7 @@
 #include "toolchain/check/context.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/inst.h"
+#include "toolchain/sem_ir/inst_kind.h"
 
 namespace Carbon::Check {
 
@@ -38,8 +39,12 @@ inline auto TryEvalInst(Context& context, SemIR::InstId inst_id)
 // 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.
+//
+// To evaluate an instruction and add it to SemIR only if necessary, use
+// EvalOrAddInst instead.
 template <typename InstT>
-  requires(!InstT::Kind.constant_needs_inst_id())
+  requires(InstT::Kind.constant_needs_inst_id() ==
+           SemIR::InstConstantNeedsInstIdKind::No)
 auto TryEvalInst(Context& context, InstT inst) -> SemIR::ConstantId {
   return TryEvalInstUnsafe(context, SemIR::InstId::None, inst);
 }

+ 2 - 1
toolchain/check/eval_inst.h

@@ -140,7 +140,8 @@ template <typename InstT>
 using FunctionTypeForEvalConstantInst =
     typename FunctionTypeForEvalConstantInstImpl<
         InstT, ConstantKindHasEvalConstantInst(InstT::Kind.constant_kind()),
-        InstT::Kind.constant_needs_inst_id()>::Type;
+        InstT::Kind.constant_needs_inst_id() !=
+            SemIR::InstConstantNeedsInstIdKind::No>::Type;
 
 }  // namespace Internal
 

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

+ 80 - 8
toolchain/check/inst.cpp

@@ -10,6 +10,7 @@
 #include "toolchain/check/generic_region_stack.h"
 #include "toolchain/sem_ir/constant.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/inst_kind.h"
 
 namespace Carbon::Check {
 
@@ -100,20 +101,91 @@ auto AddPatternInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
 
 auto GetOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
     -> SemIR::InstId {
-  if (loc_id_and_inst.loc_id.is_implicit() &&
-      !loc_id_and_inst.inst.kind().constant_needs_inst_id()) {
-    auto const_id =
-        TryEvalInstUnsafe(context, SemIR::InstId::None, loc_id_and_inst.inst);
-    if (const_id.has_value()) {
-      CARBON_VLOG_TO(context.vlog_stream(), "GetOrAddInst: constant: {0}\n",
-                     loc_id_and_inst.inst);
-      return context.constant_values().GetInstId(const_id);
+  CARBON_CHECK(!loc_id_and_inst.inst.kind().has_cleanup());
+
+  auto handle_constant_id = [&](SemIR::ConstantId const_id) -> SemIR::InstId {
+    CARBON_CHECK(const_id.has_value());
+
+    // If we didn't produce a constant value for the instruction, we have to add
+    // the instruction.
+    if (!const_id.is_constant()) {
+      return SemIR::InstId::None;
+    }
+
+    CARBON_VLOG_TO(context.vlog_stream(), "GetOrAddInst: constant: {0}\n",
+                   loc_id_and_inst.inst);
+    return context.constant_values().GetInstId(const_id);
+  };
+
+  // If the instruction is implicit, produce its constant value instead if
+  // possible.
+  if (loc_id_and_inst.loc_id.is_implicit()) {
+    switch (loc_id_and_inst.inst.kind().constant_needs_inst_id()) {
+      case SemIR::InstConstantNeedsInstIdKind::No: {
+        // Evaluation doesn't need an InstId. Just do it.
+        auto const_id = TryEvalInstUnsafe(context, SemIR::InstId::None,
+                                          loc_id_and_inst.inst);
+        if (auto result_inst_id = handle_constant_id(const_id);
+            result_inst_id.has_value()) {
+          return result_inst_id;
+        }
+        break;
+      }
+
+      case SemIR::InstConstantNeedsInstIdKind::DuringEvaluation: {
+        // Evaluation temporarily needs an InstId. Add one for now.
+        auto inst_id = AddInstInNoBlock(context, loc_id_and_inst);
+        auto const_id = context.constant_values().Get(inst_id);
+        if (auto result_inst_id = handle_constant_id(const_id);
+            result_inst_id.has_value()) {
+          // TODO: We didn't end up needing the `inst_id` instruction. Consider
+          // removing it from `insts` if it's still the most recently added
+          // instruction.
+          CARBON_CHECK(result_inst_id != inst_id);
+          return result_inst_id;
+        }
+        context.inst_block_stack().AddInstId(inst_id);
+        return inst_id;
+      }
+
+      case SemIR::InstConstantNeedsInstIdKind::Permanent: {
+        // Evaluation needs a permanent InstId. Add the instruction.
+        break;
+      }
     }
   }
+
   // TODO: For an implicit instruction, this reattempts evaluation.
   return AddInst(context, loc_id_and_inst);
 }
 
+auto EvalOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
+    -> SemIR::ConstantId {
+  CARBON_CHECK(!loc_id_and_inst.inst.kind().has_cleanup());
+
+  switch (loc_id_and_inst.inst.kind().constant_needs_inst_id()) {
+    case SemIR::InstConstantNeedsInstIdKind::No: {
+      // Evaluation doesn't need an InstId. Just do it.
+      return TryEvalInstUnsafe(context, SemIR::InstId::None,
+                               loc_id_and_inst.inst);
+    }
+
+    case SemIR::InstConstantNeedsInstIdKind::DuringEvaluation: {
+      // Evaluation temporarily needs an InstId. Add one for now.
+      auto inst_id = AddInstInNoBlock(context, loc_id_and_inst);
+      // TODO: Consider removing `inst_id` from `insts` if it's still the most
+      // recently added instruction.
+      return context.constant_values().Get(inst_id);
+    }
+
+    case SemIR::InstConstantNeedsInstIdKind::Permanent: {
+      // Evaluation needs a permanent InstId. Add the instruction.
+      auto inst_id = AddInst(context, loc_id_and_inst);
+      return context.constant_values().Get(inst_id);
+    }
+  }
+}
+
 auto AddPlaceholderInstInNoBlock(Context& context,
                                  SemIR::LocIdAndInst loc_id_and_inst)
     -> SemIR::InstId {

+ 17 - 0
toolchain/check/inst.h

@@ -64,6 +64,23 @@ auto GetOrAddInst(Context& context, LocT loc, InstT inst) -> SemIR::InstId {
   return GetOrAddInst(context, SemIR::LocIdAndInst(loc, inst));
 }
 
+// Evaluate the given instruction, and returns the corresponding constant value.
+// Adds the instruction to the current block if it might be referenced by its
+// constant value; otherwise, does not add the instruction to an instruction
+// block.
+auto EvalOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
+    -> SemIR::ConstantId;
+
+// Convenience for EvalOrAddInst with typed nodes.
+//
+// As a safety check, prevent use with storage insts (see `AddInstWithCleanup`).
+template <typename InstT, typename LocT>
+  requires(!InstT::Kind.has_cleanup())
+auto EvalOrAddInst(Context& context, LocT loc, InstT inst)
+    -> SemIR::ConstantId {
+  return EvalOrAddInst(context, SemIR::LocIdAndInst(loc, inst));
+}
+
 // Adds an instruction and enqueues it to be added to the eval block of the
 // enclosing generic, returning the produced ID. The instruction is expected to
 // be a dependent template instantiation action.

+ 3 - 5
toolchain/check/subst.cpp

@@ -405,15 +405,13 @@ class SubstConstantCallbacks final : public SubstInstCallbacks {
   // Rebuilds an instruction by building a new constant.
   auto Rebuild(SemIR::InstId old_inst_id, SemIR::Inst new_inst) const
       -> SemIR::InstId override {
-    auto result_id = GetOrAddInst(
+    auto const_id = EvalOrAddInst(
         *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(),
+    CARBON_CHECK(const_id.has_value(),
                  "Substitution into constant produced non-constant");
-    return const_inst_id;
+    return context_->constant_values().GetInstId(const_id);
   }
 
  private:

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

@@ -245,7 +245,6 @@ fn G() {
 // 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:   %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:   %.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]
@@ -279,7 +278,6 @@ fn G() {
 // 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:   %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:   %.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]
@@ -537,7 +535,6 @@ fn G() {
 // 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_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:   %.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]

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

@@ -319,7 +319,6 @@ fn B() {
 // 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_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:   %.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]

+ 4 - 6
toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon

@@ -919,8 +919,8 @@ fn CallsWithTypeExplicit(U:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // 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:   %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.iface0: <witness> = facet_access_witness %W.loc11_22.2, element0 [symbolic = %W.as_wit.iface0 (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) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
 // 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)]
@@ -932,16 +932,14 @@ fn CallsWithTypeExplicit(U:! type) {
 // CHECK:STDOUT:     %w.ref: @HandleTameAnimal2.%W.as_type.loc11_44.2 (%W.as_type) = name_ref w, %w
 // CHECK:STDOUT:     %W.as_type.loc12_14.1: type = facet_access_type constants.%W [symbolic = %W.as_type.loc11_44.2 (constants.%W.as_type)]
 // CHECK:STDOUT:     %.loc12_14.1: type = converted constants.%W, %W.as_type.loc12_14.1 [symbolic = %W.as_type.loc11_44.2 (constants.%W.as_type)]
-// CHECK:STDOUT:     %W.as_wit.iface0.loc12_14.1: <witness> = facet_access_witness constants.%W, element0 [symbolic = %W.as_wit.iface0.loc12_14.3 (constants.%W.as_wit.iface0)]
-// CHECK:STDOUT:     %Animal.facet.loc12_14.1: %Animal.type = facet_value constants.%W.as_type, (%W.as_wit.iface0.loc12_14.1) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
+// CHECK:STDOUT:     %Animal.facet.loc12_14.1: %Animal.type = facet_value constants.%W.as_type, (constants.%W.as_wit.iface0) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
 // CHECK:STDOUT:     %.loc12_14.2: %Animal.type = converted %.loc12_14.1, %Animal.facet.loc12_14.1 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
 // CHECK:STDOUT:     %W.as_wit.iface1.loc12_14.1: <witness> = facet_access_witness constants.%W, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)]
 // CHECK:STDOUT:     %facet_value.loc12_14.1: %facet_type.6ff = facet_value constants.%W.as_type, (constants.%Eats.lookup_impl_witness, %W.as_wit.iface1.loc12_14.1) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
 // CHECK:STDOUT:     %.loc12_14.3: %facet_type.6ff = converted constants.%W.as_type, %facet_value.loc12_14.1 [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
 // CHECK:STDOUT:     %W.as_type.loc12_14.2: type = facet_access_type constants.%W [symbolic = %W.as_type.loc11_44.2 (constants.%W.as_type)]
 // CHECK:STDOUT:     %.loc12_14.4: type = converted constants.%W, %W.as_type.loc12_14.2 [symbolic = %W.as_type.loc11_44.2 (constants.%W.as_type)]
-// CHECK:STDOUT:     %W.as_wit.iface0.loc12_14.2: <witness> = facet_access_witness constants.%W, element0 [symbolic = %W.as_wit.iface0.loc12_14.3 (constants.%W.as_wit.iface0)]
-// CHECK:STDOUT:     %Animal.facet.loc12_14.2: %Animal.type = facet_value constants.%W.as_type, (%W.as_wit.iface0.loc12_14.2) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
+// CHECK:STDOUT:     %Animal.facet.loc12_14.2: %Animal.type = facet_value constants.%W.as_type, (constants.%W.as_wit.iface0) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
 // CHECK:STDOUT:     %.loc12_14.5: %Animal.type = converted %.loc12_14.4, %Animal.facet.loc12_14.2 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
 // CHECK:STDOUT:     %W.as_wit.iface1.loc12_14.2: <witness> = facet_access_witness constants.%W, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)]
 // CHECK:STDOUT:     %facet_value.loc12_14.2: %facet_type.6ff = facet_value constants.%W.as_type, (constants.%Eats.lookup_impl_witness, %W.as_wit.iface1.loc12_14.2) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]

+ 5 - 7
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:   %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:   %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.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:   %Eats.type: type = facet_type <@Eats, @Eats(%Food.as_type.loc31_56.2)> [symbolic = %Eats.type (constants.%Eats.type.f54c3d.2)]
+// 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:   %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:   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,14 +347,12 @@ fn F() {
 // 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.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:     %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.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.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:     %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:     %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:     return
@@ -497,8 +495,8 @@ fn F() {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %require_complete.loc31_45 => constants.%complete_type.357
 // CHECK:STDOUT:   %require_complete.loc31_54 => constants.%complete_type.357
-// CHECK:STDOUT:   %Eats.type.2 => constants.%Eats.type.1ae
 // CHECK:STDOUT:   %Eats.lookup_impl_witness => constants.%impl_witness.4f1
+// CHECK:STDOUT:   %Eats.type => constants.%Eats.type.1ae
 // 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: }

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

@@ -210,7 +210,6 @@ fn G() {
 // 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:   %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.call: init %empty_tuple.type = call %CallGenericMethod.specific_fn() [concrete = <error>]
 // CHECK:STDOUT:   return

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

@@ -304,7 +304,6 @@ fn G(holds_to: HoldsType((RuntimeConvertTo, ))) {
 // 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:   %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:   %bound_method: <bound method> = bound_method constants.%from, %impl.elem0 [symbolic = constants.%Convert.bound]
 // CHECK:STDOUT:   %.loc40_19.1: ref %RuntimeConvertTo = temporary_storage

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

@@ -273,7 +273,6 @@ fn G() {
 // 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:   %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:   %.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]

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

@@ -559,8 +559,6 @@ fn F() {
 // 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:   %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:   %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]
@@ -820,8 +818,6 @@ fn F() {
 // 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:   %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:   %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]
@@ -1232,8 +1228,6 @@ fn F() {
 // 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:   %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:   %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]
@@ -1255,8 +1249,6 @@ fn F() {
 // 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:   %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:   %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]
@@ -1404,10 +1396,6 @@ 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:     %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:     %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:     %.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
@@ -1683,11 +1671,7 @@ 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:     %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:     %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:     %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:     %.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)]
@@ -1698,11 +1682,7 @@ 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:     %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:     %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:     %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:     %.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)]
@@ -1916,10 +1896,6 @@ 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:     %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:     %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:     %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)
@@ -2109,10 +2085,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:   %.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.elem0.3: type = impl_witness_access %T.as_wit.iface0.loc26_11.2, element0 [symbolic = %impl.elem0.3 (constants.%impl.elem0.37e)]
+// CHECK:STDOUT:   %impl.elem0.1: type = impl_witness_access %T.as_wit.iface0.loc26_11.2, element0 [symbolic = %impl.elem0.1 (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:   %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_15: <witness> = require_complete_type @GenericCallFI32.%impl.elem0.1 (%impl.elem0.37e) [symbolic = %require_complete.loc26_15 (constants.%require_complete.8bd)]
+// CHECK:STDOUT:   %ImplicitAs.type: type = facet_type <@ImplicitAs, @ImplicitAs(%impl.elem0.1)> [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:
 // 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 {
@@ -2124,13 +2100,9 @@ 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:     %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:     %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:     %.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_14: @GenericCallFI32.%impl.elem0.1 (%impl.elem0.37e) = converted %int_2, <error> [concrete = <error>]
+// CHECK:STDOUT:     %.loc26_15: init @GenericCallFI32.%impl.elem0.1 (%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:     return <error>
 // CHECK:STDOUT:   }

+ 25 - 3
toolchain/sem_ir/inst_kind.h

@@ -86,6 +86,19 @@ enum class InstConstantKind : int8_t {
   Unique,
 };
 
+// Whether constant evaluation of an instruction needs the instruction to have
+// been created and allocated an InstId, or only needs the instruction operands.
+enum class InstConstantNeedsInstIdKind : int8_t {
+  // This instruction kind doesn't need an InstId to be evaluated.
+  No,
+  // This instruction needs an InstId during evaluation, but doesn't need the
+  // instruction to persist after evaluation.
+  DuringEvaluation,
+  // This instruction needs a permanent instruction ID, for example because that
+  // instruction ID can appear in the constant result of evaluation.
+  Permanent,
+};
+
 // Whether an instruction is a terminator or part of the terminator sequence.
 // The instructions in a block appear in the order NotTerminator, then
 // TerminatorSequence, then Terminator, which is also the numerical order of
@@ -123,7 +136,10 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) {
     llvm::StringLiteral ir_name;
     InstIsType is_type = InstIsType::Never;
     InstConstantKind constant_kind = InstConstantKind::Indirect;
-    bool constant_needs_inst_id = constant_kind == InstConstantKind::Unique;
+    InstConstantNeedsInstIdKind constant_needs_inst_id =
+        constant_kind == InstConstantKind::Unique
+            ? InstConstantNeedsInstIdKind::Permanent
+            : InstConstantNeedsInstIdKind::No;
     TerminatorKind terminator_kind = TerminatorKind::NotTerminator;
     bool is_lowered = true;
     bool deduce_through = false;
@@ -173,7 +189,7 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) {
   // 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 {
+  auto constant_needs_inst_id() const -> InstConstantNeedsInstIdKind {
     return definition_info(*this).constant_needs_inst_id;
   }
 
@@ -192,6 +208,12 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) {
     return definition_info(*this).deduce_through;
   }
 
+  // Returns true if this instruction has scoped cleanup associated, typically a
+  // destructor.
+  constexpr auto has_cleanup() const -> bool {
+    return definition_info(*this).has_cleanup;
+  }
+
  private:
   // Returns the DefinitionInfo for the kind.
   static auto definition_info(InstKind kind) -> const DefinitionInfo&;
@@ -232,7 +254,7 @@ class InstKind::Definition : public InstKind {
   }
 
   // Returns whether constant evaluation of this instruction needs an InstId.
-  constexpr auto constant_needs_inst_id() const -> bool {
+  constexpr auto constant_needs_inst_id() const -> InstConstantNeedsInstIdKind {
     return info_.constant_needs_inst_id;
   }
 

+ 13 - 8
toolchain/sem_ir/typed_insts.h

@@ -188,7 +188,7 @@ struct ArrayType {
       {.ir_name = "array_type",
        .is_type = InstIsType::Always,
        .constant_kind = InstConstantKind::Conditional,
-       .constant_needs_inst_id = true,
+       .constant_needs_inst_id = InstConstantNeedsInstIdKind::DuringEvaluation,
        .deduce_through = true});
 
   TypeId type_id;
@@ -773,7 +773,7 @@ struct FloatType {
       {.ir_name = "float_type",
        .is_type = InstIsType::Always,
        .constant_kind = InstConstantKind::Conditional,
-       .constant_needs_inst_id = true,
+       .constant_needs_inst_id = InstConstantNeedsInstIdKind::DuringEvaluation,
        .deduce_through = true});
 
   TypeId type_id;
@@ -924,7 +924,8 @@ struct ImplWitnessAccess {
           {.ir_name = "impl_witness_access",
            .is_type = InstIsType::Maybe,
            .constant_kind = InstConstantKind::SymbolicOnly,
-           .constant_needs_inst_id = true,
+           .constant_needs_inst_id =
+               InstConstantNeedsInstIdKind::DuringEvaluation,
            .is_lowered = false});
 
   TypeId type_id;
@@ -1108,7 +1109,7 @@ struct IntType {
       {.ir_name = "int_type",
        .is_type = InstIsType::Always,
        .constant_kind = InstConstantKind::Conditional,
-       .constant_needs_inst_id = true,
+       .constant_needs_inst_id = InstConstantNeedsInstIdKind::DuringEvaluation,
        .deduce_through = true});
 
   TypeId type_id;
@@ -1133,7 +1134,8 @@ struct LookupImplWitness {
       InstKind::LookupImplWitness.Define<Parse::NodeId>(
           {.ir_name = "lookup_impl_witness",
            .constant_kind = InstConstantKind::SymbolicOnly,
-           .constant_needs_inst_id = true,
+           .constant_needs_inst_id =
+               InstConstantNeedsInstIdKind::DuringEvaluation,
            .is_lowered = false});
 
   // Always the type of the builtin `WitnessType` singleton instruction.
@@ -1337,7 +1339,8 @@ struct RequireCompleteType {
       InstKind::RequireCompleteType.Define<Parse::NodeId>(
           {.ir_name = "require_complete_type",
            .constant_kind = InstConstantKind::SymbolicOnly,
-           .constant_needs_inst_id = true,
+           .constant_needs_inst_id =
+               InstConstantNeedsInstIdKind::DuringEvaluation,
            .is_lowered = false});
   // Always the builtin witness type.
   TypeId type_id;
@@ -1477,7 +1480,8 @@ struct SpecificFunction {
   static constexpr auto Kind = InstKind::SpecificFunction.Define<Parse::NodeId>(
       {.ir_name = "specific_function",
        .constant_kind = InstConstantKind::Conditional,
-       .constant_needs_inst_id = true});
+       // InstId is added to definitions_required_by_use.
+       .constant_needs_inst_id = InstConstantNeedsInstIdKind::Permanent});
 
   // Always the builtin SpecificFunctionType.
   TypeId type_id;
@@ -1514,7 +1518,8 @@ struct SpecificImplFunction {
       InstKind::SpecificImplFunction.Define<Parse::NodeId>(
           {.ir_name = "specific_impl_function",
            .constant_kind = InstConstantKind::SymbolicOnly,
-           .constant_needs_inst_id = true});
+           // InstId is added to definitions_required_by_use.
+           .constant_needs_inst_id = InstConstantNeedsInstIdKind::Permanent});
 
   // Always the builtin SpecificFunctionType.
   TypeId type_id;