Просмотр исходного кода

Refactor IdBase to provide CRTP-based printing (#4626)

This removes a lot of boilerplate `Print` functions in favor of a
CRTP-based approach that uses a `Label` field as an automatic prefix.
This `Label` is also made available for other purposes, particularly
`IdKind` crash messages in this change. In particular, for
`RequireIdKind` in node_stack.h from using numeric IdKinds (e.g., 5 and
24) to something that will print `IdKind(<label>)` (this came up
recently on #toolchain).

While I'm in here, also doing some other tinkering:

- Moving operators to be `friend` members, to reduce the extra
templating now that the base types are templated.
- Adjusts IntId diagnostics from `int [...]` to `int(...)` for
consistency with other id printing.
- Changes InstBlockId's label from "block" to "inst_block", since we
have multiple blocks now.
- Fixes StructTypeFieldsId to use "struct_type_fields" instead of
"type_block" (from `TypeBlockId`)
- Does some more adjustments from camelCase to snake_case for
consistency
Jon Ross-Perkins 1 год назад
Родитель
Сommit
bc24a6c5d8

+ 43 - 36
toolchain/base/index_base.h

@@ -18,6 +18,18 @@ namespace Carbon {
 template <typename DataType>
 class DataIterator;
 
+// Non-templated portions of `IdBase`.
+struct AnyIdBase {
+  static constexpr int32_t InvalidIndex = -1;
+
+  AnyIdBase() = delete;
+  constexpr explicit AnyIdBase(int index) : index(index) {}
+
+  constexpr auto is_valid() const -> bool { return index != InvalidIndex; }
+
+  int32_t index;
+};
+
 // A lightweight handle to an item identified by an opaque ID.
 //
 // This class is intended to be derived from by classes representing a specific
@@ -27,23 +39,34 @@ class DataIterator;
 // Classes derived from IdBase are designed to be passed by value, not
 // reference or pointer. They are also designed to be small and efficient to
 // store in data structures.
-struct IdBase : public Printable<IdBase> {
-  static constexpr int32_t InvalidIndex = -1;
-
-  IdBase() = delete;
-  constexpr explicit IdBase(int index) : index(index) {}
-
-  auto Print(llvm::raw_ostream& output) const -> void {
+//
+// This uses CRTP for the `Print` function. Children should have:
+//   static constexpr llvm::StringLiteral Label = "my_label";
+// Children can also define their own `Print` function, removing the dependency
+// on `Label`.
+template <typename IdT>
+struct IdBase : public AnyIdBase, public Printable<IdT> {
+  using AnyIdBase::AnyIdBase;
+
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << IdT::Label;
     if (is_valid()) {
-      output << index;
+      out << index;
     } else {
-      output << "<invalid>";
+      out << "<invalid>";
     }
   }
 
-  constexpr auto is_valid() const -> bool { return index != InvalidIndex; }
-
-  int32_t index;
+  // Support simple equality comparison for ID types.
+  friend constexpr auto operator==(IdT lhs, IdT rhs) -> bool {
+    return lhs.index == rhs.index;
+  }
+  // Support equality comparison when the RHS is convertible to IdT.
+  template <typename RHSType>
+    requires std::convertible_to<RHSType, IdT>
+  friend auto operator==(IdT lhs, RHSType rhs) -> bool {
+    return lhs.index == IdT(rhs).index;
+  }
 };
 
 // A lightweight handle to an item that behaves like an index.
@@ -51,31 +74,15 @@ struct IdBase : public Printable<IdBase> {
 // Unlike IdBase, classes derived from IndexBase are not completely opaque, and
 // provide at least an ordering between indexes that has meaning to an API
 // user. Additional semantics may be specified by the derived class.
-struct IndexBase : public IdBase {
-  using IdBase::IdBase;
-};
+template <typename IdT>
+struct IndexBase : public IdBase<IdT> {
+  using IdBase<IdT>::IdBase;
 
-// Support equality comparison when one operand is a child of `IdBase`
-// (including `IndexBase`) and the other operand is either the same type or
-// convertible to that type.
-template <typename IndexType>
-  requires std::derived_from<IndexType, IdBase>
-constexpr auto operator==(IndexType lhs, IndexType rhs) -> bool {
-  return lhs.index == rhs.index;
-}
-template <typename IndexType, typename RHSType>
-  requires std::derived_from<IndexType, IdBase> &&
-           std::convertible_to<RHSType, IndexType>
-auto operator==(IndexType lhs, RHSType rhs) -> bool {
-  return lhs.index == IndexType(rhs).index;
-}
-
-// Relational comparisons are only supported for types derived from `IndexBase`.
-template <typename IndexType>
-  requires std::derived_from<IndexType, IndexBase>
-auto operator<=>(IndexType lhs, IndexType rhs) -> std::strong_ordering {
-  return lhs.index <=> rhs.index;
-}
+  // Support relational comparisons for index types.
+  friend auto operator<=>(IdT lhs, IdT rhs) -> std::strong_ordering {
+    return lhs.index <=> rhs.index;
+  }
+};
 
 // A random-access iterator for arrays using IndexBase-derived types.
 template <typename IndexT>

+ 8 - 9
toolchain/base/int.h

@@ -53,6 +53,7 @@ struct IntStoreTestPeer;
 // invalid integer.
 class IntId : public Printable<IntId> {
  public:
+  static constexpr llvm::StringLiteral Label = "int";
   using ValueType = llvm::APInt;
 
   // The encoding of integer IDs ensures that valid IDs associated with tokens
@@ -122,15 +123,16 @@ class IntId : public Printable<IntId> {
   constexpr auto AsRaw() const -> int32_t { return id_; }
 
   auto Print(llvm::raw_ostream& out) const -> void {
-    out << "int [";
+    out << Label << "(";
     if (is_value()) {
-      out << "value: " << AsValue() << "]";
+      out << "value: " << AsValue();
     } else if (is_index()) {
-      out << "index: " << AsIndex() << "]";
+      out << "index: " << AsIndex();
     } else {
       CARBON_CHECK(!is_valid());
-      out << "invalid]";
+      out << "<invalid>";
     }
+    out << ")";
   }
 
   friend constexpr auto operator==(IntId lhs, IntId rhs) -> bool {
@@ -349,14 +351,11 @@ class IntStore {
   friend struct Testing::IntStoreTestPeer;
 
   // Used for `values_`; tracked using `IntId`'s index range.
-  struct APIntId : IdBase, Printable<APIntId> {
+  struct APIntId : IdBase<APIntId> {
+    static constexpr llvm::StringLiteral Label = "ap_int";
     using ValueType = llvm::APInt;
     static const APIntId Invalid;
     using IdBase::IdBase;
-    auto Print(llvm::raw_ostream& out) const -> void {
-      out << "ap_int";
-      IdBase::Print(out);
-    }
   };
 
   static constexpr int MinAPWidth = 64;

+ 8 - 21
toolchain/base/value_ids.h

@@ -43,26 +43,20 @@ class Real : public Printable<Real> {
 
 // Corresponds to a float value represented by an APFloat. This is used for
 // floating-point values in SemIR.
-struct FloatId : public IdBase, public Printable<FloatId> {
+struct FloatId : public IdBase<FloatId> {
+  static constexpr llvm::StringLiteral Label = "float";
   using ValueType = llvm::APFloat;
   static const FloatId Invalid;
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "float";
-    IdBase::Print(out);
-  }
 };
 constexpr FloatId FloatId::Invalid(FloatId::InvalidIndex);
 
 // Corresponds to a Real value.
-struct RealId : public IdBase, public Printable<RealId> {
+struct RealId : public IdBase<RealId> {
+  static constexpr llvm::StringLiteral Label = "real";
   using ValueType = Real;
   static const RealId Invalid;
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "real";
-    IdBase::Print(out);
-  }
 };
 constexpr RealId RealId::Invalid(RealId::InvalidIndex);
 
@@ -70,27 +64,20 @@ constexpr RealId RealId::Invalid(RealId::InvalidIndex);
 //
 // `NameId` relies on the values of this type other than `Invalid` all being
 // non-negative.
-struct IdentifierId : public IdBase, public Printable<IdentifierId> {
+struct IdentifierId : public IdBase<IdentifierId> {
+  static constexpr llvm::StringLiteral Label = "identifier";
   using ValueType = llvm::StringRef;
   static const IdentifierId Invalid;
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "identifier";
-    IdBase::Print(out);
-  }
 };
 constexpr IdentifierId IdentifierId::Invalid(IdentifierId::InvalidIndex);
 
 // Corresponds to StringRefs for string literals.
-struct StringLiteralValueId : public IdBase,
-                              public Printable<StringLiteralValueId> {
+struct StringLiteralValueId : public IdBase<StringLiteralValueId> {
+  static constexpr llvm::StringLiteral Label = "string";
   using ValueType = llvm::StringRef;
   static const StringLiteralValueId Invalid;
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "string";
-    IdBase::Print(out);
-  }
 };
 constexpr StringLiteralValueId StringLiteralValueId::Invalid(
     StringLiteralValueId::InvalidIndex);

+ 4 - 4
toolchain/check/node_stack.h

@@ -20,7 +20,7 @@ namespace Carbon::Check {
 class IdUnion {
  public:
   // The default constructor forms an invalid ID.
-  explicit constexpr IdUnion() : index(IdBase::InvalidIndex) {}
+  explicit constexpr IdUnion() : index(AnyIdBase::InvalidIndex) {}
 
   template <typename IdT>
     requires SemIR::IdKind::Contains<IdT>
@@ -49,7 +49,7 @@ class IdUnion {
   }
 
  private:
-  decltype(IdBase::index) index;
+  decltype(AnyIdBase::index) index;
 };
 
 // The stack of parse nodes representing the current state of a Check::Context.
@@ -690,8 +690,8 @@ class NodeStack {
       -> void {
     CARBON_CHECK(NodeKindToIdKind(parse_kind) == id_kind,
                  "Unexpected Id::Kind mapping for {0}: expected {1}, found {2}",
-                 parse_kind, static_cast<int>(id_kind),
-                 static_cast<int>(NodeKindToIdKind(parse_kind)));
+                 parse_kind, SemIR::IdKind(id_kind),
+                 SemIR::IdKind(NodeKindToIdKind(parse_kind)));
   }
 
   // Require an entry to have the given Parse::NodeKind.

+ 2 - 1
toolchain/check/scope_index.h

@@ -17,7 +17,8 @@ namespace Carbon::Check {
 //
 // `ScopeIndex` values are comparable. Lower `ScopeIndex` values correspond to
 // scopes entered earlier in the file.
-struct ScopeIndex : public IndexBase, public Printable<ScopeIndex> {
+struct ScopeIndex : public IndexBase<ScopeIndex> {
+  static constexpr llvm::StringLiteral Label = "scope";
   static const ScopeIndex Package;
 
   using IndexBase::IndexBase;

+ 1 - 1
toolchain/check/testdata/alias/fail_control_flow.carbon

@@ -31,7 +31,7 @@ alias a = true or false;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
-// CHECK:STDOUT:   %.loc22: bool = block_arg <unexpected instblockref block5> [template = constants.%true]
+// CHECK:STDOUT:   %.loc22: bool = block_arg <unexpected instblockref inst_block5> [template = constants.%true]
 // CHECK:STDOUT:   %a: <error> = bind_alias a, <error> [template = <error>]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 32 - 32
toolchain/check/testdata/basics/builtin_insts.carbon

@@ -24,47 +24,47 @@
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   struct_type_fields:
-// CHECK:STDOUT:     type_block0:     {}
+// CHECK:STDOUT:     struct_type_fields0: {}
 // CHECK:STDOUT:   types:
-// CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
-// CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
-// CHECK:STDOUT:     'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'type(TypeType)':  {kind: copy, type: type(TypeType)}
+// CHECK:STDOUT:     'type(Error)':     {kind: copy, type: type(Error)}
+// CHECK:STDOUT:     'type(inst(NamespaceType))': {kind: copy, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     type_block0:     {}
 // CHECK:STDOUT:   insts:
-// CHECK:STDOUT:     instTypeType:    {kind: TypeType, type: typeTypeType}
-// CHECK:STDOUT:     instAutoType:    {kind: AutoType, type: typeTypeType}
-// CHECK:STDOUT:     instBoolType:    {kind: BoolType, type: typeTypeType}
-// CHECK:STDOUT:     instBoundMethodType: {kind: BoundMethodType, type: typeTypeType}
-// CHECK:STDOUT:     instErrorInst:   {kind: ErrorInst, type: typeError}
-// CHECK:STDOUT:     instIntLiteralType: {kind: IntLiteralType, type: typeTypeType}
-// CHECK:STDOUT:     instLegacyFloatType: {kind: LegacyFloatType, type: typeTypeType}
-// CHECK:STDOUT:     instNamespaceType: {kind: NamespaceType, type: typeTypeType}
-// CHECK:STDOUT:     instSpecificFunctionType: {kind: SpecificFunctionType, type: typeTypeType}
-// CHECK:STDOUT:     instStringType:  {kind: StringType, type: typeTypeType}
-// CHECK:STDOUT:     instVtableType:  {kind: VtableType, type: typeTypeType}
-// CHECK:STDOUT:     instWitnessType: {kind: WitnessType, type: typeTypeType}
-// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'inst(TypeType)':  {kind: TypeType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(AutoType)':  {kind: AutoType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(BoolType)':  {kind: BoolType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(BoundMethodType)': {kind: BoundMethodType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(ErrorInst)': {kind: ErrorInst, type: type(Error)}
+// CHECK:STDOUT:     'inst(IntLiteralType)': {kind: IntLiteralType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(LegacyFloatType)': {kind: LegacyFloatType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(NamespaceType)': {kind: NamespaceType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(SpecificFunctionType)': {kind: SpecificFunctionType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(StringType)': {kind: StringType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(VtableType)': {kind: VtableType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst(WitnessType)': {kind: WitnessType, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     instTypeType:    templateConstant(instTypeType)
-// CHECK:STDOUT:     instAutoType:    templateConstant(instAutoType)
-// CHECK:STDOUT:     instBoolType:    templateConstant(instBoolType)
-// CHECK:STDOUT:     instBoundMethodType: templateConstant(instBoundMethodType)
-// CHECK:STDOUT:     instErrorInst:   templateConstant(instErrorInst)
-// CHECK:STDOUT:     instIntLiteralType: templateConstant(instIntLiteralType)
-// CHECK:STDOUT:     instLegacyFloatType: templateConstant(instLegacyFloatType)
-// CHECK:STDOUT:     instNamespaceType: templateConstant(instNamespaceType)
-// CHECK:STDOUT:     instSpecificFunctionType: templateConstant(instSpecificFunctionType)
-// CHECK:STDOUT:     instStringType:  templateConstant(instStringType)
-// CHECK:STDOUT:     instVtableType:  templateConstant(instVtableType)
-// CHECK:STDOUT:     instWitnessType: templateConstant(instWitnessType)
-// CHECK:STDOUT:     'inst+0':          templateConstant(inst+0)
+// CHECK:STDOUT:     'inst(TypeType)':  template_constant(inst(TypeType))
+// CHECK:STDOUT:     'inst(AutoType)':  template_constant(inst(AutoType))
+// CHECK:STDOUT:     'inst(BoolType)':  template_constant(inst(BoolType))
+// CHECK:STDOUT:     'inst(BoundMethodType)': template_constant(inst(BoundMethodType))
+// CHECK:STDOUT:     'inst(ErrorInst)': template_constant(inst(ErrorInst))
+// CHECK:STDOUT:     'inst(IntLiteralType)': template_constant(inst(IntLiteralType))
+// CHECK:STDOUT:     'inst(LegacyFloatType)': template_constant(inst(LegacyFloatType))
+// CHECK:STDOUT:     'inst(NamespaceType)': template_constant(inst(NamespaceType))
+// CHECK:STDOUT:     'inst(SpecificFunctionType)': template_constant(inst(SpecificFunctionType))
+// CHECK:STDOUT:     'inst(StringType)': template_constant(inst(StringType))
+// CHECK:STDOUT:     'inst(VtableType)': template_constant(inst(VtableType))
+// CHECK:STDOUT:     'inst(WitnessType)': template_constant(inst(WitnessType))
+// CHECK:STDOUT:     'inst+0':          template_constant(inst+0)
 // CHECK:STDOUT:   symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
-// CHECK:STDOUT:     empty:           {}
+// CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:         {}
 // CHECK:STDOUT:     import_refs:     {}
 // CHECK:STDOUT:     global_init:     {}
-// CHECK:STDOUT:     block4:
+// CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT: ...

+ 49 - 49
toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon

@@ -36,43 +36,43 @@ fn B() {
 // CHECK:STDOUT:     name_scope0:     {inst: inst+0, parent_scope: name_scope<invalid>, has_error: false, extended_scopes: [], names: {name0: inst+1}}
 // CHECK:STDOUT:   entity_names:    {}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [block4]}
+// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [inst_block4]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   struct_type_fields:
-// CHECK:STDOUT:     type_block0:     {}
+// CHECK:STDOUT:     struct_type_fields0: {}
 // CHECK:STDOUT:   types:
-// CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
-// CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
-// CHECK:STDOUT:     'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'type(TypeType)':  {kind: copy, type: type(TypeType)}
+// CHECK:STDOUT:     'type(Error)':     {kind: copy, type: type(Error)}
+// CHECK:STDOUT:     'type(inst(NamespaceType))': {kind: copy, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'type(inst+2)':    {kind: none, type: type(inst+3)}
 // CHECK:STDOUT:     'type(inst+3)':    {kind: none, type: type(inst+3)}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     type_block0:     {}
 // CHECK:STDOUT:   insts:
-// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
-// CHECK:STDOUT:     'inst+1':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+2)}
-// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+3':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+4':          {kind: StructValue, arg0: empty, type: type(inst+2)}
+// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     'inst+1':          {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst+2)}
+// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+3':          {kind: TupleType, arg0: type_block0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+4':          {kind: StructValue, arg0: inst_block_empty, type: type(inst+2)}
 // CHECK:STDOUT:     'inst+5':          {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     'inst+0':          templateConstant(inst+0)
-// CHECK:STDOUT:     'inst+1':          templateConstant(inst+4)
-// CHECK:STDOUT:     'inst+2':          templateConstant(inst+2)
-// CHECK:STDOUT:     'inst+3':          templateConstant(inst+3)
-// CHECK:STDOUT:     'inst+4':          templateConstant(inst+4)
+// CHECK:STDOUT:     'inst+0':          template_constant(inst+0)
+// CHECK:STDOUT:     'inst+1':          template_constant(inst+4)
+// CHECK:STDOUT:     'inst+2':          template_constant(inst+2)
+// CHECK:STDOUT:     'inst+3':          template_constant(inst+3)
+// CHECK:STDOUT:     'inst+4':          template_constant(inst+4)
 // CHECK:STDOUT:   symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
-// CHECK:STDOUT:     empty:           {}
+// CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
 // CHECK:STDOUT:       0:               inst+1
 // CHECK:STDOUT:     import_refs:     {}
 // CHECK:STDOUT:     global_init:     {}
-// CHECK:STDOUT:     block4:
+// CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst+5
-// CHECK:STDOUT:     block5:
+// CHECK:STDOUT:     inst_block5:
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+1
 // CHECK:STDOUT: ...
@@ -111,66 +111,66 @@ fn B() {
 // CHECK:STDOUT:   entity_names:
 // CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: comp_time_bind<invalid>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [block4]}
+// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [inst_block4]}
 // CHECK:STDOUT:     function1:       {name: name1, parent_scope: name_scope1}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   struct_type_fields:
-// CHECK:STDOUT:     type_block0:     {}
+// CHECK:STDOUT:     struct_type_fields0: {}
 // CHECK:STDOUT:   types:
-// CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
-// CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
-// CHECK:STDOUT:     'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'type(TypeType)':  {kind: copy, type: type(TypeType)}
+// CHECK:STDOUT:     'type(Error)':     {kind: copy, type: type(Error)}
+// CHECK:STDOUT:     'type(inst(NamespaceType))': {kind: copy, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'type(inst+4)':    {kind: none, type: type(inst+5)}
 // CHECK:STDOUT:     'type(inst+5)':    {kind: none, type: type(inst+5)}
 // CHECK:STDOUT:     'type(inst+10)':   {kind: none, type: type(inst+5)}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     type_block0:     {}
 // CHECK:STDOUT:   insts:
-// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'inst+1':          {kind: ImportDecl, arg0: name1}
-// CHECK:STDOUT:     'inst+2':          {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(instNamespaceType)}
-// CHECK:STDOUT:     'inst+3':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+4)}
-// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+5':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+6':          {kind: StructValue, arg0: empty, type: type(inst+4)}
-// CHECK:STDOUT:     'inst+7':          {kind: NameRef, arg0: name1, arg1: inst+2, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'inst+2':          {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     'inst+3':          {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst+4)}
+// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+5':          {kind: TupleType, arg0: type_block0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+6':          {kind: StructValue, arg0: inst_block_empty, type: type(inst+4)}
+// CHECK:STDOUT:     'inst+7':          {kind: NameRef, arg0: name1, arg1: inst+2, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'inst+8':          {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: entity_name0, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+9':          {kind: FunctionDecl, arg0: function1, arg1: empty, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+11':         {kind: StructValue, arg0: empty, type: type(inst+10)}
+// CHECK:STDOUT:     'inst+9':          {kind: FunctionDecl, arg0: function1, arg1: inst_block_empty, type: type(inst+10)}
+// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+11':         {kind: StructValue, arg0: inst_block_empty, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+12':         {kind: NameRef, arg0: name1, arg1: inst+8, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+13':         {kind: Call, arg0: inst+12, arg1: empty, type: type(inst+5)}
+// CHECK:STDOUT:     'inst+13':         {kind: Call, arg0: inst+12, arg1: inst_block_empty, type: type(inst+5)}
 // CHECK:STDOUT:     'inst+14':         {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     'inst+0':          templateConstant(inst+0)
-// CHECK:STDOUT:     'inst+2':          templateConstant(inst+2)
-// CHECK:STDOUT:     'inst+3':          templateConstant(inst+6)
-// CHECK:STDOUT:     'inst+4':          templateConstant(inst+4)
-// CHECK:STDOUT:     'inst+5':          templateConstant(inst+5)
-// CHECK:STDOUT:     'inst+6':          templateConstant(inst+6)
-// CHECK:STDOUT:     'inst+7':          templateConstant(inst+2)
-// CHECK:STDOUT:     'inst+8':          templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+9':          templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+10':         templateConstant(inst+10)
-// CHECK:STDOUT:     'inst+11':         templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+12':         templateConstant(inst+11)
+// CHECK:STDOUT:     'inst+0':          template_constant(inst+0)
+// CHECK:STDOUT:     'inst+2':          template_constant(inst+2)
+// CHECK:STDOUT:     'inst+3':          template_constant(inst+6)
+// CHECK:STDOUT:     'inst+4':          template_constant(inst+4)
+// CHECK:STDOUT:     'inst+5':          template_constant(inst+5)
+// CHECK:STDOUT:     'inst+6':          template_constant(inst+6)
+// CHECK:STDOUT:     'inst+7':          template_constant(inst+2)
+// CHECK:STDOUT:     'inst+8':          template_constant(inst+11)
+// CHECK:STDOUT:     'inst+9':          template_constant(inst+11)
+// CHECK:STDOUT:     'inst+10':         template_constant(inst+10)
+// CHECK:STDOUT:     'inst+11':         template_constant(inst+11)
+// CHECK:STDOUT:     'inst+12':         template_constant(inst+11)
 // CHECK:STDOUT:   symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
-// CHECK:STDOUT:     empty:           {}
+// CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
 // CHECK:STDOUT:       0:               inst+3
 // CHECK:STDOUT:     import_refs:
 // CHECK:STDOUT:       0:               inst+2
 // CHECK:STDOUT:       1:               inst+8
 // CHECK:STDOUT:     global_init:     {}
-// CHECK:STDOUT:     block4:
+// CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst+7
 // CHECK:STDOUT:       1:               inst+12
 // CHECK:STDOUT:       2:               inst+13
 // CHECK:STDOUT:       3:               inst+14
-// CHECK:STDOUT:     block5:
+// CHECK:STDOUT:     inst_block5:
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+1
 // CHECK:STDOUT:       2:               inst+3

+ 49 - 49
toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon

@@ -36,43 +36,43 @@ fn B() {
 // CHECK:STDOUT:     name_scope0:     {inst: inst+0, parent_scope: name_scope<invalid>, has_error: false, extended_scopes: [], names: {name0: inst+1}}
 // CHECK:STDOUT:   entity_names:    {}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [block4]}
+// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [inst_block4]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   struct_type_fields:
-// CHECK:STDOUT:     type_block0:     {}
+// CHECK:STDOUT:     struct_type_fields0: {}
 // CHECK:STDOUT:   types:
-// CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
-// CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
-// CHECK:STDOUT:     'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'type(TypeType)':  {kind: copy, type: type(TypeType)}
+// CHECK:STDOUT:     'type(Error)':     {kind: copy, type: type(Error)}
+// CHECK:STDOUT:     'type(inst(NamespaceType))': {kind: copy, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'type(inst+2)':    {kind: none, type: type(inst+3)}
 // CHECK:STDOUT:     'type(inst+3)':    {kind: none, type: type(inst+3)}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     type_block0:     {}
 // CHECK:STDOUT:   insts:
-// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
-// CHECK:STDOUT:     'inst+1':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+2)}
-// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+3':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+4':          {kind: StructValue, arg0: empty, type: type(inst+2)}
+// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     'inst+1':          {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst+2)}
+// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+3':          {kind: TupleType, arg0: type_block0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+4':          {kind: StructValue, arg0: inst_block_empty, type: type(inst+2)}
 // CHECK:STDOUT:     'inst+5':          {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     'inst+0':          templateConstant(inst+0)
-// CHECK:STDOUT:     'inst+1':          templateConstant(inst+4)
-// CHECK:STDOUT:     'inst+2':          templateConstant(inst+2)
-// CHECK:STDOUT:     'inst+3':          templateConstant(inst+3)
-// CHECK:STDOUT:     'inst+4':          templateConstant(inst+4)
+// CHECK:STDOUT:     'inst+0':          template_constant(inst+0)
+// CHECK:STDOUT:     'inst+1':          template_constant(inst+4)
+// CHECK:STDOUT:     'inst+2':          template_constant(inst+2)
+// CHECK:STDOUT:     'inst+3':          template_constant(inst+3)
+// CHECK:STDOUT:     'inst+4':          template_constant(inst+4)
 // CHECK:STDOUT:   symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
-// CHECK:STDOUT:     empty:           {}
+// CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
 // CHECK:STDOUT:       0:               inst+1
 // CHECK:STDOUT:     import_refs:     {}
 // CHECK:STDOUT:     global_init:     {}
-// CHECK:STDOUT:     block4:
+// CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst+5
-// CHECK:STDOUT:     block5:
+// CHECK:STDOUT:     inst_block5:
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+1
 // CHECK:STDOUT: ...
@@ -91,66 +91,66 @@ fn B() {
 // CHECK:STDOUT:   entity_names:
 // CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: comp_time_bind<invalid>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [block4]}
+// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [inst_block4]}
 // CHECK:STDOUT:     function1:       {name: name1, parent_scope: name_scope1}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   struct_type_fields:
-// CHECK:STDOUT:     type_block0:     {}
+// CHECK:STDOUT:     struct_type_fields0: {}
 // CHECK:STDOUT:   types:
-// CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
-// CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
-// CHECK:STDOUT:     'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'type(TypeType)':  {kind: copy, type: type(TypeType)}
+// CHECK:STDOUT:     'type(Error)':     {kind: copy, type: type(Error)}
+// CHECK:STDOUT:     'type(inst(NamespaceType))': {kind: copy, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'type(inst+4)':    {kind: none, type: type(inst+5)}
 // CHECK:STDOUT:     'type(inst+5)':    {kind: none, type: type(inst+5)}
 // CHECK:STDOUT:     'type(inst+10)':   {kind: none, type: type(inst+5)}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     type_block0:     {}
 // CHECK:STDOUT:   insts:
-// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'inst+1':          {kind: ImportDecl, arg0: name1}
-// CHECK:STDOUT:     'inst+2':          {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(instNamespaceType)}
-// CHECK:STDOUT:     'inst+3':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+4)}
-// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+5':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+6':          {kind: StructValue, arg0: empty, type: type(inst+4)}
-// CHECK:STDOUT:     'inst+7':          {kind: NameRef, arg0: name1, arg1: inst+2, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'inst+2':          {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     'inst+3':          {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst+4)}
+// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+5':          {kind: TupleType, arg0: type_block0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+6':          {kind: StructValue, arg0: inst_block_empty, type: type(inst+4)}
+// CHECK:STDOUT:     'inst+7':          {kind: NameRef, arg0: name1, arg1: inst+2, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'inst+8':          {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: entity_name0, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+9':          {kind: FunctionDecl, arg0: function1, arg1: empty, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+11':         {kind: StructValue, arg0: empty, type: type(inst+10)}
+// CHECK:STDOUT:     'inst+9':          {kind: FunctionDecl, arg0: function1, arg1: inst_block_empty, type: type(inst+10)}
+// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+11':         {kind: StructValue, arg0: inst_block_empty, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+12':         {kind: NameRef, arg0: name1, arg1: inst+8, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+13':         {kind: Call, arg0: inst+12, arg1: empty, type: type(inst+5)}
+// CHECK:STDOUT:     'inst+13':         {kind: Call, arg0: inst+12, arg1: inst_block_empty, type: type(inst+5)}
 // CHECK:STDOUT:     'inst+14':         {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     'inst+0':          templateConstant(inst+0)
-// CHECK:STDOUT:     'inst+2':          templateConstant(inst+2)
-// CHECK:STDOUT:     'inst+3':          templateConstant(inst+6)
-// CHECK:STDOUT:     'inst+4':          templateConstant(inst+4)
-// CHECK:STDOUT:     'inst+5':          templateConstant(inst+5)
-// CHECK:STDOUT:     'inst+6':          templateConstant(inst+6)
-// CHECK:STDOUT:     'inst+7':          templateConstant(inst+2)
-// CHECK:STDOUT:     'inst+8':          templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+9':          templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+10':         templateConstant(inst+10)
-// CHECK:STDOUT:     'inst+11':         templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+12':         templateConstant(inst+11)
+// CHECK:STDOUT:     'inst+0':          template_constant(inst+0)
+// CHECK:STDOUT:     'inst+2':          template_constant(inst+2)
+// CHECK:STDOUT:     'inst+3':          template_constant(inst+6)
+// CHECK:STDOUT:     'inst+4':          template_constant(inst+4)
+// CHECK:STDOUT:     'inst+5':          template_constant(inst+5)
+// CHECK:STDOUT:     'inst+6':          template_constant(inst+6)
+// CHECK:STDOUT:     'inst+7':          template_constant(inst+2)
+// CHECK:STDOUT:     'inst+8':          template_constant(inst+11)
+// CHECK:STDOUT:     'inst+9':          template_constant(inst+11)
+// CHECK:STDOUT:     'inst+10':         template_constant(inst+10)
+// CHECK:STDOUT:     'inst+11':         template_constant(inst+11)
+// CHECK:STDOUT:     'inst+12':         template_constant(inst+11)
 // CHECK:STDOUT:   symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
-// CHECK:STDOUT:     empty:           {}
+// CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
 // CHECK:STDOUT:       0:               inst+3
 // CHECK:STDOUT:     import_refs:
 // CHECK:STDOUT:       0:               inst+2
 // CHECK:STDOUT:       1:               inst+8
 // CHECK:STDOUT:     global_init:     {}
-// CHECK:STDOUT:     block4:
+// CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst+7
 // CHECK:STDOUT:       1:               inst+12
 // CHECK:STDOUT:       2:               inst+13
 // CHECK:STDOUT:       3:               inst+14
-// CHECK:STDOUT:     block5:
+// CHECK:STDOUT:     inst_block5:
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+1
 // CHECK:STDOUT:       2:               inst+3

+ 59 - 59
toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon

@@ -27,16 +27,16 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:   entity_names:
 // CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope<invalid>, index: comp_time_bind<invalid>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, return_slot_pattern: inst+15, body: [block9]}
+// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, return_slot_pattern: inst+15, body: [inst_block9]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   struct_type_fields:
-// CHECK:STDOUT:     type_block0:     {}
+// CHECK:STDOUT:     struct_type_fields0: {}
 // CHECK:STDOUT:   types:
-// CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
-// CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
-// CHECK:STDOUT:     'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'type(TypeType)':  {kind: copy, type: type(TypeType)}
+// CHECK:STDOUT:     'type(Error)':     {kind: copy, type: type(Error)}
+// CHECK:STDOUT:     'type(inst(NamespaceType))': {kind: copy, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'type(inst+20)':   {kind: none, type: type(inst+1)}
 // CHECK:STDOUT:     'type(inst+1)':    {kind: none, type: type(inst+1)}
 // CHECK:STDOUT:     'type(inst+9)':    {kind: pointer, type: type(inst+22)}
@@ -47,84 +47,84 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:       0:               type(inst+1)
 // CHECK:STDOUT:       1:               type(inst+1)
 // CHECK:STDOUT:   insts:
-// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
-// CHECK:STDOUT:     'inst+1':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+2':          {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+3':          {kind: Converted, arg0: inst+2, arg1: inst+1, type: typeTypeType}
+// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     'inst+1':          {kind: TupleType, arg0: type_block0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+2':          {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst+1)}
+// CHECK:STDOUT:     'inst+3':          {kind: Converted, arg0: inst+2, arg1: inst+1, type: type(TypeType)}
 // CHECK:STDOUT:     'inst+4':          {kind: BindName, arg0: entity_name0, arg1: inst+16, type: type(inst+1)}
 // CHECK:STDOUT:     'inst+5':          {kind: BindingPattern, arg0: entity_name0, type: type(inst+1)}
 // CHECK:STDOUT:     'inst+6':          {kind: ValueParamPattern, arg0: inst+5, arg1: runtime_param0, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+7':          {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+8':          {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+9':          {kind: TupleType, arg0: type_block1, type: typeTypeType}
-// CHECK:STDOUT:     'inst+10':         {kind: TupleLiteral, arg0: block5, type: type(inst+9)}
-// CHECK:STDOUT:     'inst+11':         {kind: Converted, arg0: inst+7, arg1: inst+1, type: typeTypeType}
-// CHECK:STDOUT:     'inst+12':         {kind: Converted, arg0: inst+8, arg1: inst+1, type: typeTypeType}
-// CHECK:STDOUT:     'inst+13':         {kind: Converted, arg0: inst+10, arg1: inst+9, type: typeTypeType}
+// CHECK:STDOUT:     'inst+7':          {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst+1)}
+// CHECK:STDOUT:     'inst+8':          {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst+1)}
+// CHECK:STDOUT:     'inst+9':          {kind: TupleType, arg0: type_block1, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+10':         {kind: TupleLiteral, arg0: inst_block5, type: type(inst+9)}
+// CHECK:STDOUT:     'inst+11':         {kind: Converted, arg0: inst+7, arg1: inst+1, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+12':         {kind: Converted, arg0: inst+8, arg1: inst+1, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+13':         {kind: Converted, arg0: inst+10, arg1: inst+9, type: type(TypeType)}
 // CHECK:STDOUT:     'inst+14':         {kind: ReturnSlotPattern, arg0: inst+10, type: type(inst+9)}
 // CHECK:STDOUT:     'inst+15':         {kind: OutParamPattern, arg0: inst+14, arg1: runtime_param1, type: type(inst+9)}
 // CHECK:STDOUT:     'inst+16':         {kind: ValueParam, arg0: runtime_param0, arg1: name1, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+17':         {kind: OutParam, arg0: runtime_param1, arg1: nameReturnSlot, type: type(inst+9)}
+// CHECK:STDOUT:     'inst+17':         {kind: OutParam, arg0: runtime_param1, arg1: name(ReturnSlot), type: type(inst+9)}
 // CHECK:STDOUT:     'inst+18':         {kind: ReturnSlot, arg0: inst+10, arg1: inst+17, type: type(inst+9)}
-// CHECK:STDOUT:     'inst+19':         {kind: FunctionDecl, arg0: function0, arg1: block8, type: type(inst+20)}
-// CHECK:STDOUT:     'inst+20':         {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+21':         {kind: StructValue, arg0: empty, type: type(inst+20)}
-// CHECK:STDOUT:     'inst+22':         {kind: PointerType, arg0: type(inst+9), type: typeTypeType}
+// CHECK:STDOUT:     'inst+19':         {kind: FunctionDecl, arg0: function0, arg1: inst_block8, type: type(inst+20)}
+// CHECK:STDOUT:     'inst+20':         {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+21':         {kind: StructValue, arg0: inst_block_empty, type: type(inst+20)}
+// CHECK:STDOUT:     'inst+22':         {kind: PointerType, arg0: type(inst+9), type: type(TypeType)}
 // CHECK:STDOUT:     'inst+23':         {kind: NameRef, arg0: name1, arg1: inst+4, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+24':         {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+25':         {kind: TupleLiteral, arg0: block10, type: type(inst+9)}
+// CHECK:STDOUT:     'inst+24':         {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst+1)}
+// CHECK:STDOUT:     'inst+25':         {kind: TupleLiteral, arg0: inst_block10, type: type(inst+9)}
 // CHECK:STDOUT:     'inst+26':         {kind: TupleAccess, arg0: inst+18, arg1: element0, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+27':         {kind: TupleInit, arg0: block11, arg1: inst+26, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+28':         {kind: TupleValue, arg0: empty, type: type(inst+1)}
+// CHECK:STDOUT:     'inst+27':         {kind: TupleInit, arg0: inst_block11, arg1: inst+26, type: type(inst+1)}
+// CHECK:STDOUT:     'inst+28':         {kind: TupleValue, arg0: inst_block_empty, type: type(inst+1)}
 // CHECK:STDOUT:     'inst+29':         {kind: Converted, arg0: inst+23, arg1: inst+27, type: type(inst+1)}
 // CHECK:STDOUT:     'inst+30':         {kind: TupleAccess, arg0: inst+18, arg1: element1, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+31':         {kind: TupleInit, arg0: empty, arg1: inst+30, type: type(inst+1)}
+// CHECK:STDOUT:     'inst+31':         {kind: TupleInit, arg0: inst_block_empty, arg1: inst+30, type: type(inst+1)}
 // CHECK:STDOUT:     'inst+32':         {kind: Converted, arg0: inst+24, arg1: inst+31, type: type(inst+1)}
-// CHECK:STDOUT:     'inst+33':         {kind: TupleInit, arg0: block12, arg1: inst+18, type: type(inst+9)}
-// CHECK:STDOUT:     'inst+34':         {kind: TupleValue, arg0: block13, type: type(inst+9)}
+// CHECK:STDOUT:     'inst+33':         {kind: TupleInit, arg0: inst_block12, arg1: inst+18, type: type(inst+9)}
+// CHECK:STDOUT:     'inst+34':         {kind: TupleValue, arg0: inst_block13, type: type(inst+9)}
 // CHECK:STDOUT:     'inst+35':         {kind: Converted, arg0: inst+25, arg1: inst+33, type: type(inst+9)}
 // CHECK:STDOUT:     'inst+36':         {kind: ReturnExpr, arg0: inst+35, arg1: inst+18}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     'inst+0':          templateConstant(inst+0)
-// CHECK:STDOUT:     'inst+1':          templateConstant(inst+1)
-// CHECK:STDOUT:     'inst+3':          templateConstant(inst+1)
-// CHECK:STDOUT:     'inst+9':          templateConstant(inst+9)
-// CHECK:STDOUT:     'inst+11':         templateConstant(inst+1)
-// CHECK:STDOUT:     'inst+12':         templateConstant(inst+1)
-// CHECK:STDOUT:     'inst+13':         templateConstant(inst+9)
-// CHECK:STDOUT:     'inst+19':         templateConstant(inst+21)
-// CHECK:STDOUT:     'inst+20':         templateConstant(inst+20)
-// CHECK:STDOUT:     'inst+21':         templateConstant(inst+21)
-// CHECK:STDOUT:     'inst+22':         templateConstant(inst+22)
-// CHECK:STDOUT:     'inst+27':         templateConstant(inst+28)
-// CHECK:STDOUT:     'inst+28':         templateConstant(inst+28)
-// CHECK:STDOUT:     'inst+29':         templateConstant(inst+28)
-// CHECK:STDOUT:     'inst+31':         templateConstant(inst+28)
-// CHECK:STDOUT:     'inst+32':         templateConstant(inst+28)
-// CHECK:STDOUT:     'inst+33':         templateConstant(inst+34)
-// CHECK:STDOUT:     'inst+34':         templateConstant(inst+34)
-// CHECK:STDOUT:     'inst+35':         templateConstant(inst+34)
+// CHECK:STDOUT:     'inst+0':          template_constant(inst+0)
+// CHECK:STDOUT:     'inst+1':          template_constant(inst+1)
+// CHECK:STDOUT:     'inst+3':          template_constant(inst+1)
+// CHECK:STDOUT:     'inst+9':          template_constant(inst+9)
+// CHECK:STDOUT:     'inst+11':         template_constant(inst+1)
+// CHECK:STDOUT:     'inst+12':         template_constant(inst+1)
+// CHECK:STDOUT:     'inst+13':         template_constant(inst+9)
+// CHECK:STDOUT:     'inst+19':         template_constant(inst+21)
+// CHECK:STDOUT:     'inst+20':         template_constant(inst+20)
+// CHECK:STDOUT:     'inst+21':         template_constant(inst+21)
+// CHECK:STDOUT:     'inst+22':         template_constant(inst+22)
+// CHECK:STDOUT:     'inst+27':         template_constant(inst+28)
+// CHECK:STDOUT:     'inst+28':         template_constant(inst+28)
+// CHECK:STDOUT:     'inst+29':         template_constant(inst+28)
+// CHECK:STDOUT:     'inst+31':         template_constant(inst+28)
+// CHECK:STDOUT:     'inst+32':         template_constant(inst+28)
+// CHECK:STDOUT:     'inst+33':         template_constant(inst+34)
+// CHECK:STDOUT:     'inst+34':         template_constant(inst+34)
+// CHECK:STDOUT:     'inst+35':         template_constant(inst+34)
 // CHECK:STDOUT:   symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
-// CHECK:STDOUT:     empty:           {}
+// CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
 // CHECK:STDOUT:       0:               inst+19
 // CHECK:STDOUT:     import_refs:     {}
 // CHECK:STDOUT:     global_init:     {}
-// CHECK:STDOUT:     block4:
+// CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst+6
-// CHECK:STDOUT:     block5:
+// CHECK:STDOUT:     inst_block5:
 // CHECK:STDOUT:       0:               inst+7
 // CHECK:STDOUT:       1:               inst+8
-// CHECK:STDOUT:     block6:
+// CHECK:STDOUT:     inst_block6:
 // CHECK:STDOUT:       0:               inst+16
 // CHECK:STDOUT:       1:               inst+17
-// CHECK:STDOUT:     block7:
+// CHECK:STDOUT:     inst_block7:
 // CHECK:STDOUT:       0:               inst+5
 // CHECK:STDOUT:       1:               inst+6
 // CHECK:STDOUT:       2:               inst+14
 // CHECK:STDOUT:       3:               inst+15
-// CHECK:STDOUT:     block8:
+// CHECK:STDOUT:     inst_block8:
 // CHECK:STDOUT:       0:               inst+2
 // CHECK:STDOUT:       1:               inst+3
 // CHECK:STDOUT:       2:               inst+7
@@ -137,7 +137,7 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:       9:               inst+4
 // CHECK:STDOUT:       10:              inst+17
 // CHECK:STDOUT:       11:              inst+18
-// CHECK:STDOUT:     block9:
+// CHECK:STDOUT:     inst_block9:
 // CHECK:STDOUT:       0:               inst+23
 // CHECK:STDOUT:       1:               inst+24
 // CHECK:STDOUT:       2:               inst+25
@@ -150,17 +150,17 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:       9:               inst+33
 // CHECK:STDOUT:       10:              inst+35
 // CHECK:STDOUT:       11:              inst+36
-// CHECK:STDOUT:     block10:
+// CHECK:STDOUT:     inst_block10:
 // CHECK:STDOUT:       0:               inst+23
 // CHECK:STDOUT:       1:               inst+24
-// CHECK:STDOUT:     block11:         {}
-// CHECK:STDOUT:     block12:
+// CHECK:STDOUT:     inst_block11:    {}
+// CHECK:STDOUT:     inst_block12:
 // CHECK:STDOUT:       0:               inst+29
 // CHECK:STDOUT:       1:               inst+32
-// CHECK:STDOUT:     block13:
+// CHECK:STDOUT:     inst_block13:
 // CHECK:STDOUT:       0:               inst+28
 // CHECK:STDOUT:       1:               inst+28
-// CHECK:STDOUT:     block14:
+// CHECK:STDOUT:     inst_block14:
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+19
 // CHECK:STDOUT: ...

+ 100 - 100
toolchain/check/testdata/basics/no_prelude/raw_ir.carbon

@@ -28,136 +28,136 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope<invalid>, index: comp_time_bind0}
 // CHECK:STDOUT:     entity_name1:    {name: name2, parent_scope: name_scope<invalid>, index: comp_time_bind<invalid>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, return_slot_pattern: inst+19, body: [block14]}
+// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, return_slot_pattern: inst+19, body: [inst_block14]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:
-// CHECK:STDOUT:     generic0:        {decl: inst+24, bindings: block10}
+// CHECK:STDOUT:     generic0:        {decl: inst+24, bindings: inst_block10}
 // CHECK:STDOUT:   specifics:
-// CHECK:STDOUT:     specific0:       {generic: generic0, args: block12}
+// CHECK:STDOUT:     specific0:       {generic: generic0, args: inst_block12}
 // CHECK:STDOUT:   struct_type_fields:
-// CHECK:STDOUT:     type_block0:     {}
+// CHECK:STDOUT:     struct_type_fields0: {}
 // CHECK:STDOUT:   types:
-// CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
-// CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
-// CHECK:STDOUT:     'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
+// CHECK:STDOUT:     'type(TypeType)':  {kind: copy, type: type(TypeType)}
+// CHECK:STDOUT:     'type(Error)':     {kind: copy, type: type(Error)}
+// CHECK:STDOUT:     'type(inst(NamespaceType))': {kind: copy, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     'type(inst+28)':   {kind: none, type: type(inst+11)}
 // CHECK:STDOUT:     'type(inst+11)':   {kind: none, type: type(inst+11)}
-// CHECK:STDOUT:     'type(symbolicConstant0)': {kind: copy, type: type(symbolicConstant0)}
-// CHECK:STDOUT:     'type(symbolicConstant2)': {kind: pointer, type: type(symbolicConstant6)}
-// CHECK:STDOUT:     'type(symbolicConstant6)': {kind: copy, type: type(symbolicConstant6)}
-// CHECK:STDOUT:     'type(symbolicConstant3)': {kind: copy, type: type(symbolicConstant3)}
-// CHECK:STDOUT:     'type(symbolicConstant5)': {kind: pointer, type: type(symbolicConstant6)}
+// CHECK:STDOUT:     'type(symbolic_constant0)': {kind: copy, type: type(symbolic_constant0)}
+// CHECK:STDOUT:     'type(symbolic_constant2)': {kind: pointer, type: type(symbolic_constant6)}
+// CHECK:STDOUT:     'type(symbolic_constant6)': {kind: copy, type: type(symbolic_constant6)}
+// CHECK:STDOUT:     'type(symbolic_constant3)': {kind: copy, type: type(symbolic_constant3)}
+// CHECK:STDOUT:     'type(symbolic_constant5)': {kind: pointer, type: type(symbolic_constant6)}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     type_block0:     {}
 // CHECK:STDOUT:     type_block1:
-// CHECK:STDOUT:       0:               typeTypeType
+// CHECK:STDOUT:       0:               type(TypeType)
 // CHECK:STDOUT:       1:               type(inst+11)
 // CHECK:STDOUT:     type_block2:
-// CHECK:STDOUT:       0:               type(symbolicConstant0)
+// CHECK:STDOUT:       0:               type(symbolic_constant0)
 // CHECK:STDOUT:       1:               type(inst+11)
 // CHECK:STDOUT:     type_block3:
-// CHECK:STDOUT:       0:               type(symbolicConstant3)
+// CHECK:STDOUT:       0:               type(symbolic_constant3)
 // CHECK:STDOUT:       1:               type(inst+11)
 // CHECK:STDOUT:   insts:
-// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
-// CHECK:STDOUT:     'inst+1':          {kind: BindSymbolicName, arg0: entity_name0, arg1: inst+20, type: typeTypeType}
-// CHECK:STDOUT:     'inst+2':          {kind: BindSymbolicName, arg0: entity_name0, arg1: inst<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+3':          {kind: SymbolicBindingPattern, arg0: entity_name0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+4':          {kind: SymbolicBindingPattern, arg0: entity_name0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+5':          {kind: ValueParamPattern, arg0: inst+3, arg1: runtime_param<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+6':          {kind: NameRef, arg0: name1, arg1: inst+1, type: typeTypeType}
-// CHECK:STDOUT:     'inst+7':          {kind: BindName, arg0: entity_name1, arg1: inst+21, type: type(symbolicConstant3)}
-// CHECK:STDOUT:     'inst+8':          {kind: BindingPattern, arg0: entity_name1, type: type(symbolicConstant3)}
-// CHECK:STDOUT:     'inst+9':          {kind: ValueParamPattern, arg0: inst+8, arg1: runtime_param0, type: type(symbolicConstant3)}
-// CHECK:STDOUT:     'inst+10':         {kind: NameRef, arg0: name1, arg1: inst+1, type: typeTypeType}
-// CHECK:STDOUT:     'inst+11':         {kind: TupleType, arg0: type_block0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+12':         {kind: TupleLiteral, arg0: empty, type: type(inst+11)}
-// CHECK:STDOUT:     'inst+13':         {kind: TupleType, arg0: type_block1, type: typeTypeType}
-// CHECK:STDOUT:     'inst+14':         {kind: TupleLiteral, arg0: block6, type: type(inst+13)}
-// CHECK:STDOUT:     'inst+15':         {kind: Converted, arg0: inst+12, arg1: inst+11, type: typeTypeType}
-// CHECK:STDOUT:     'inst+16':         {kind: TupleType, arg0: type_block2, type: typeTypeType}
-// CHECK:STDOUT:     'inst+17':         {kind: Converted, arg0: inst+14, arg1: inst+16, type: typeTypeType}
-// CHECK:STDOUT:     'inst+18':         {kind: ReturnSlotPattern, arg0: inst+14, type: type(symbolicConstant5)}
-// CHECK:STDOUT:     'inst+19':         {kind: OutParamPattern, arg0: inst+18, arg1: runtime_param1, type: type(symbolicConstant5)}
-// CHECK:STDOUT:     'inst+20':         {kind: ValueParam, arg0: runtime_param<invalid>, arg1: name1, type: typeTypeType}
-// CHECK:STDOUT:     'inst+21':         {kind: ValueParam, arg0: runtime_param0, arg1: name2, type: type(symbolicConstant3)}
-// CHECK:STDOUT:     'inst+22':         {kind: OutParam, arg0: runtime_param1, arg1: nameReturnSlot, type: type(symbolicConstant5)}
-// CHECK:STDOUT:     'inst+23':         {kind: ReturnSlot, arg0: inst+14, arg1: inst+22, type: type(symbolicConstant5)}
-// CHECK:STDOUT:     'inst+24':         {kind: FunctionDecl, arg0: function0, arg1: block9, type: type(inst+28)}
-// CHECK:STDOUT:     'inst+25':         {kind: BindSymbolicName, arg0: entity_name0, arg1: inst<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+26':         {kind: SymbolicBindingPattern, arg0: entity_name0, type: typeTypeType}
-// CHECK:STDOUT:     'inst+27':         {kind: TupleType, arg0: type_block3, type: typeTypeType}
-// CHECK:STDOUT:     'inst+28':         {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
-// CHECK:STDOUT:     'inst+29':         {kind: StructValue, arg0: empty, type: type(inst+28)}
-// CHECK:STDOUT:     'inst+30':         {kind: PointerType, arg0: type(symbolicConstant2), type: typeTypeType}
-// CHECK:STDOUT:     'inst+31':         {kind: NameRef, arg0: name2, arg1: inst+7, type: type(symbolicConstant3)}
-// CHECK:STDOUT:     'inst+32':         {kind: TupleLiteral, arg0: empty, type: type(inst+11)}
-// CHECK:STDOUT:     'inst+33':         {kind: TupleLiteral, arg0: block15, type: type(symbolicConstant5)}
-// CHECK:STDOUT:     'inst+34':         {kind: TupleAccess, arg0: inst+23, arg1: element0, type: type(symbolicConstant3)}
-// CHECK:STDOUT:     'inst+35':         {kind: InitializeFrom, arg0: inst+31, arg1: inst+34, type: type(symbolicConstant3)}
+// CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     'inst+1':          {kind: BindSymbolicName, arg0: entity_name0, arg1: inst+20, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+2':          {kind: BindSymbolicName, arg0: entity_name0, arg1: inst<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+3':          {kind: SymbolicBindingPattern, arg0: entity_name0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+4':          {kind: SymbolicBindingPattern, arg0: entity_name0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+5':          {kind: ValueParamPattern, arg0: inst+3, arg1: runtime_param<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+6':          {kind: NameRef, arg0: name1, arg1: inst+1, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+7':          {kind: BindName, arg0: entity_name1, arg1: inst+21, type: type(symbolic_constant3)}
+// CHECK:STDOUT:     'inst+8':          {kind: BindingPattern, arg0: entity_name1, type: type(symbolic_constant3)}
+// CHECK:STDOUT:     'inst+9':          {kind: ValueParamPattern, arg0: inst+8, arg1: runtime_param0, type: type(symbolic_constant3)}
+// CHECK:STDOUT:     'inst+10':         {kind: NameRef, arg0: name1, arg1: inst+1, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+11':         {kind: TupleType, arg0: type_block0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+12':         {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst+11)}
+// CHECK:STDOUT:     'inst+13':         {kind: TupleType, arg0: type_block1, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+14':         {kind: TupleLiteral, arg0: inst_block6, type: type(inst+13)}
+// CHECK:STDOUT:     'inst+15':         {kind: Converted, arg0: inst+12, arg1: inst+11, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+16':         {kind: TupleType, arg0: type_block2, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+17':         {kind: Converted, arg0: inst+14, arg1: inst+16, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+18':         {kind: ReturnSlotPattern, arg0: inst+14, type: type(symbolic_constant5)}
+// CHECK:STDOUT:     'inst+19':         {kind: OutParamPattern, arg0: inst+18, arg1: runtime_param1, type: type(symbolic_constant5)}
+// CHECK:STDOUT:     'inst+20':         {kind: ValueParam, arg0: runtime_param<invalid>, arg1: name1, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+21':         {kind: ValueParam, arg0: runtime_param0, arg1: name2, type: type(symbolic_constant3)}
+// CHECK:STDOUT:     'inst+22':         {kind: OutParam, arg0: runtime_param1, arg1: name(ReturnSlot), type: type(symbolic_constant5)}
+// CHECK:STDOUT:     'inst+23':         {kind: ReturnSlot, arg0: inst+14, arg1: inst+22, type: type(symbolic_constant5)}
+// CHECK:STDOUT:     'inst+24':         {kind: FunctionDecl, arg0: function0, arg1: inst_block9, type: type(inst+28)}
+// CHECK:STDOUT:     'inst+25':         {kind: BindSymbolicName, arg0: entity_name0, arg1: inst<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+26':         {kind: SymbolicBindingPattern, arg0: entity_name0, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+27':         {kind: TupleType, arg0: type_block3, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+28':         {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: type(TypeType)}
+// CHECK:STDOUT:     'inst+29':         {kind: StructValue, arg0: inst_block_empty, type: type(inst+28)}
+// CHECK:STDOUT:     'inst+30':         {kind: PointerType, arg0: type(symbolic_constant2), type: type(TypeType)}
+// CHECK:STDOUT:     'inst+31':         {kind: NameRef, arg0: name2, arg1: inst+7, type: type(symbolic_constant3)}
+// CHECK:STDOUT:     'inst+32':         {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst+11)}
+// CHECK:STDOUT:     'inst+33':         {kind: TupleLiteral, arg0: inst_block15, type: type(symbolic_constant5)}
+// CHECK:STDOUT:     'inst+34':         {kind: TupleAccess, arg0: inst+23, arg1: element0, type: type(symbolic_constant3)}
+// CHECK:STDOUT:     'inst+35':         {kind: InitializeFrom, arg0: inst+31, arg1: inst+34, type: type(symbolic_constant3)}
 // CHECK:STDOUT:     'inst+36':         {kind: TupleAccess, arg0: inst+23, arg1: element1, type: type(inst+11)}
-// CHECK:STDOUT:     'inst+37':         {kind: TupleInit, arg0: empty, arg1: inst+36, type: type(inst+11)}
-// CHECK:STDOUT:     'inst+38':         {kind: TupleValue, arg0: empty, type: type(inst+11)}
+// CHECK:STDOUT:     'inst+37':         {kind: TupleInit, arg0: inst_block_empty, arg1: inst+36, type: type(inst+11)}
+// CHECK:STDOUT:     'inst+38':         {kind: TupleValue, arg0: inst_block_empty, type: type(inst+11)}
 // CHECK:STDOUT:     'inst+39':         {kind: Converted, arg0: inst+32, arg1: inst+37, type: type(inst+11)}
-// CHECK:STDOUT:     'inst+40':         {kind: TupleInit, arg0: block16, arg1: inst+23, type: type(symbolicConstant5)}
-// CHECK:STDOUT:     'inst+41':         {kind: Converted, arg0: inst+33, arg1: inst+40, type: type(symbolicConstant5)}
+// CHECK:STDOUT:     'inst+40':         {kind: TupleInit, arg0: inst_block16, arg1: inst+23, type: type(symbolic_constant5)}
+// CHECK:STDOUT:     'inst+41':         {kind: Converted, arg0: inst+33, arg1: inst+40, type: type(symbolic_constant5)}
 // CHECK:STDOUT:     'inst+42':         {kind: ReturnExpr, arg0: inst+41, arg1: inst+23}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     'inst+0':          templateConstant(inst+0)
-// CHECK:STDOUT:     'inst+1':          symbolicConstant3
-// CHECK:STDOUT:     'inst+2':          symbolicConstant0
-// CHECK:STDOUT:     'inst+3':          symbolicConstant4
-// CHECK:STDOUT:     'inst+4':          symbolicConstant1
-// CHECK:STDOUT:     'inst+5':          symbolicConstant4
-// CHECK:STDOUT:     'inst+6':          symbolicConstant3
-// CHECK:STDOUT:     'inst+10':         symbolicConstant3
-// CHECK:STDOUT:     'inst+11':         templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+13':         templateConstant(inst+13)
-// CHECK:STDOUT:     'inst+15':         templateConstant(inst+11)
-// CHECK:STDOUT:     'inst+16':         symbolicConstant2
-// CHECK:STDOUT:     'inst+17':         symbolicConstant5
-// CHECK:STDOUT:     'inst+24':         templateConstant(inst+29)
-// CHECK:STDOUT:     'inst+25':         symbolicConstant3
-// CHECK:STDOUT:     'inst+26':         symbolicConstant4
-// CHECK:STDOUT:     'inst+27':         symbolicConstant5
-// CHECK:STDOUT:     'inst+28':         templateConstant(inst+28)
-// CHECK:STDOUT:     'inst+29':         templateConstant(inst+29)
-// CHECK:STDOUT:     'inst+30':         symbolicConstant6
-// CHECK:STDOUT:     'inst+37':         templateConstant(inst+38)
-// CHECK:STDOUT:     'inst+38':         templateConstant(inst+38)
-// CHECK:STDOUT:     'inst+39':         templateConstant(inst+38)
+// CHECK:STDOUT:     'inst+0':          template_constant(inst+0)
+// CHECK:STDOUT:     'inst+1':          symbolic_constant3
+// CHECK:STDOUT:     'inst+2':          symbolic_constant0
+// CHECK:STDOUT:     'inst+3':          symbolic_constant4
+// CHECK:STDOUT:     'inst+4':          symbolic_constant1
+// CHECK:STDOUT:     'inst+5':          symbolic_constant4
+// CHECK:STDOUT:     'inst+6':          symbolic_constant3
+// CHECK:STDOUT:     'inst+10':         symbolic_constant3
+// CHECK:STDOUT:     'inst+11':         template_constant(inst+11)
+// CHECK:STDOUT:     'inst+13':         template_constant(inst+13)
+// CHECK:STDOUT:     'inst+15':         template_constant(inst+11)
+// CHECK:STDOUT:     'inst+16':         symbolic_constant2
+// CHECK:STDOUT:     'inst+17':         symbolic_constant5
+// CHECK:STDOUT:     'inst+24':         template_constant(inst+29)
+// CHECK:STDOUT:     'inst+25':         symbolic_constant3
+// CHECK:STDOUT:     'inst+26':         symbolic_constant4
+// CHECK:STDOUT:     'inst+27':         symbolic_constant5
+// CHECK:STDOUT:     'inst+28':         template_constant(inst+28)
+// CHECK:STDOUT:     'inst+29':         template_constant(inst+29)
+// CHECK:STDOUT:     'inst+30':         symbolic_constant6
+// CHECK:STDOUT:     'inst+37':         template_constant(inst+38)
+// CHECK:STDOUT:     'inst+38':         template_constant(inst+38)
+// CHECK:STDOUT:     'inst+39':         template_constant(inst+38)
 // CHECK:STDOUT:   symbolic_constants:
-// CHECK:STDOUT:     symbolicConstant0: {inst: inst+2, generic: generic<invalid>, index: genericInst<invalid>, .Self: false}
-// CHECK:STDOUT:     symbolicConstant1: {inst: inst+4, generic: generic<invalid>, index: genericInst<invalid>, .Self: false}
-// CHECK:STDOUT:     symbolicConstant2: {inst: inst+16, generic: generic<invalid>, index: genericInst<invalid>, .Self: false}
-// CHECK:STDOUT:     symbolicConstant3: {inst: inst+2, generic: generic0, index: genericInstInDecl0, .Self: false}
-// CHECK:STDOUT:     symbolicConstant4: {inst: inst+4, generic: generic0, index: genericInstInDecl1, .Self: false}
-// CHECK:STDOUT:     symbolicConstant5: {inst: inst+16, generic: generic0, index: genericInstInDecl2, .Self: false}
-// CHECK:STDOUT:     symbolicConstant6: {inst: inst+30, generic: generic<invalid>, index: genericInst<invalid>, .Self: false}
+// CHECK:STDOUT:     symbolic_constant0: {inst: inst+2, generic: generic<invalid>, index: generic_inst<invalid>, .Self: false}
+// CHECK:STDOUT:     symbolic_constant1: {inst: inst+4, generic: generic<invalid>, index: generic_inst<invalid>, .Self: false}
+// CHECK:STDOUT:     symbolic_constant2: {inst: inst+16, generic: generic<invalid>, index: generic_inst<invalid>, .Self: false}
+// CHECK:STDOUT:     symbolic_constant3: {inst: inst+2, generic: generic0, index: generic_inst_in_decl0, .Self: false}
+// CHECK:STDOUT:     symbolic_constant4: {inst: inst+4, generic: generic0, index: generic_inst_in_decl1, .Self: false}
+// CHECK:STDOUT:     symbolic_constant5: {inst: inst+16, generic: generic0, index: generic_inst_in_decl2, .Self: false}
+// CHECK:STDOUT:     symbolic_constant6: {inst: inst+30, generic: generic<invalid>, index: generic_inst<invalid>, .Self: false}
 // CHECK:STDOUT:   inst_blocks:
-// CHECK:STDOUT:     empty:           {}
+// CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
 // CHECK:STDOUT:       0:               inst+24
 // CHECK:STDOUT:     import_refs:     {}
 // CHECK:STDOUT:     global_init:     {}
-// CHECK:STDOUT:     block4:
+// CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst+5
-// CHECK:STDOUT:     block5:
+// CHECK:STDOUT:     inst_block5:
 // CHECK:STDOUT:       0:               inst+9
-// CHECK:STDOUT:     block6:
+// CHECK:STDOUT:     inst_block6:
 // CHECK:STDOUT:       0:               inst+10
 // CHECK:STDOUT:       1:               inst+12
-// CHECK:STDOUT:     block7:
+// CHECK:STDOUT:     inst_block7:
 // CHECK:STDOUT:       0:               inst+21
 // CHECK:STDOUT:       1:               inst+22
-// CHECK:STDOUT:     block8:
+// CHECK:STDOUT:     inst_block8:
 // CHECK:STDOUT:       0:               inst+3
 // CHECK:STDOUT:       1:               inst+5
 // CHECK:STDOUT:       2:               inst+8
 // CHECK:STDOUT:       3:               inst+9
 // CHECK:STDOUT:       4:               inst+18
 // CHECK:STDOUT:       5:               inst+19
-// CHECK:STDOUT:     block9:
+// CHECK:STDOUT:     inst_block9:
 // CHECK:STDOUT:       0:               inst+6
 // CHECK:STDOUT:       1:               inst+10
 // CHECK:STDOUT:       2:               inst+12
@@ -170,19 +170,19 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:       9:               inst+7
 // CHECK:STDOUT:       10:              inst+22
 // CHECK:STDOUT:       11:              inst+23
-// CHECK:STDOUT:     block10:
+// CHECK:STDOUT:     inst_block10:
 // CHECK:STDOUT:       0:               inst+1
-// CHECK:STDOUT:     block11:
+// CHECK:STDOUT:     inst_block11:
 // CHECK:STDOUT:       0:               inst+25
 // CHECK:STDOUT:       1:               inst+26
 // CHECK:STDOUT:       2:               inst+27
-// CHECK:STDOUT:     block12:
+// CHECK:STDOUT:     inst_block12:
 // CHECK:STDOUT:       0:               inst+2
-// CHECK:STDOUT:     block13:
+// CHECK:STDOUT:     inst_block13:
 // CHECK:STDOUT:       0:               inst+2
 // CHECK:STDOUT:       1:               inst+2
 // CHECK:STDOUT:       2:               inst+16
-// CHECK:STDOUT:     block14:
+// CHECK:STDOUT:     inst_block14:
 // CHECK:STDOUT:       0:               inst+31
 // CHECK:STDOUT:       1:               inst+32
 // CHECK:STDOUT:       2:               inst+33
@@ -194,13 +194,13 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:       8:               inst+40
 // CHECK:STDOUT:       9:               inst+41
 // CHECK:STDOUT:       10:              inst+42
-// CHECK:STDOUT:     block15:
+// CHECK:STDOUT:     inst_block15:
 // CHECK:STDOUT:       0:               inst+31
 // CHECK:STDOUT:       1:               inst+32
-// CHECK:STDOUT:     block16:
+// CHECK:STDOUT:     inst_block16:
 // CHECK:STDOUT:       0:               inst+35
 // CHECK:STDOUT:       1:               inst+39
-// CHECK:STDOUT:     block17:
+// CHECK:STDOUT:     inst_block17:
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+24
 // CHECK:STDOUT: ...

+ 3 - 3
toolchain/check/testdata/basics/no_prelude/verbose.carbon

@@ -12,11 +12,11 @@
 // NOAUTOUPDATE
 // SET-CHECK-SUBSET
 // CHECK:STDERR: Node Push 0: FunctionIntroducer -> <none>
-// CHECK:STDERR: AddPlaceholderInst: {kind: FunctionDecl, arg0: function<invalid>, arg1: empty}
-// CHECK:STDERR: ReplaceInst: inst+{{[0-9]+}} -> {kind: FunctionDecl, arg0: function{{[0-9]+}}, arg1: empty, type: type(inst+{{[0-9]+}})}
+// CHECK:STDERR: AddPlaceholderInst: {kind: FunctionDecl, arg0: function<invalid>, arg1: inst_block_empty}
+// CHECK:STDERR: ReplaceInst: inst+{{[0-9]+}} -> {kind: FunctionDecl, arg0: function{{[0-9]+}}, arg1: inst_block_empty, type: type(inst+{{[0-9]+}})}
 // CHECK:STDERR: inst_block_stack_ Push 1
 // CHECK:STDERR: AddInst: {kind: Return}
-// CHECK:STDERR: inst_block_stack_ Pop 1: block{{[0-9]+}}
+// CHECK:STDERR: inst_block_stack_ Pop 1: inst_block{{[0-9]+}}
 
 fn Foo() {
   return;

+ 1 - 1
toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon

@@ -58,7 +58,7 @@ var or_: F(true or true);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
-// CHECK:STDOUT:   %.loc42_17: bool = block_arg <unexpected instblockref block23> [template = constants.%true]
+// CHECK:STDOUT:   %.loc42_17: bool = block_arg <unexpected instblockref inst_block23> [template = constants.%true]
 // CHECK:STDOUT:   %F.call: init type = call <unexpected>.inst+73.loc42_10(%.loc42_17)
 // CHECK:STDOUT:   %.loc42_24.1: type = value_of_initializer %F.call
 // CHECK:STDOUT:   %.loc42_24.2: type = converted %F.call, %.loc42_24.1

+ 2 - 1
toolchain/lex/token_index.h

@@ -23,7 +23,8 @@ namespace Carbon::Lex {
 // meaningfully compared.
 //
 // All other APIs to query a `TokenIndex` are on the `TokenizedBuffer`.
-struct TokenIndex : public IndexBase {
+struct TokenIndex : public IndexBase<TokenIndex> {
+  static constexpr llvm::StringLiteral Label = "token";
   static const TokenIndex Invalid;
   // Comments aren't tokenized, so this is the first token after FileStart.
   static const TokenIndex FirstNonCommentToken;

+ 4 - 2
toolchain/lex/tokenized_buffer.h

@@ -37,7 +37,8 @@ class TokenizedBuffer;
 // same line or the relative position of different lines within the source.
 //
 // All other APIs to query a `LineIndex` are on the `TokenizedBuffer`.
-struct LineIndex : public IndexBase {
+struct LineIndex : public IndexBase<LineIndex> {
+  static constexpr llvm::StringLiteral Label = "line";
   static const LineIndex Invalid;
   using IndexBase::IndexBase;
 };
@@ -45,7 +46,8 @@ struct LineIndex : public IndexBase {
 constexpr LineIndex LineIndex::Invalid(InvalidIndex);
 
 // Indices for comments within the buffer.
-struct CommentIndex : public IndexBase {
+struct CommentIndex : public IndexBase<CommentIndex> {
+  static constexpr llvm::StringLiteral Label = "comment";
   static const CommentIndex Invalid;
   using IndexBase::IndexBase;
 };

+ 3 - 1
toolchain/parse/node_ids.h

@@ -19,7 +19,9 @@ struct InvalidNodeId {};
 // Objects of this type are small and cheap to copy and store. They don't
 // contain any of the information about the node, and serve as a handle that
 // can be used with the underlying tree to query for detailed information.
-struct NodeId : public IdBase {
+struct NodeId : public IdBase<NodeId> {
+  static constexpr llvm::StringLiteral Label = "node";
+
   // An explicitly invalid node ID.
   static constexpr InvalidNodeId Invalid;
 

+ 2 - 1
toolchain/parse/tree.h

@@ -25,7 +25,8 @@ struct DeferredDefinition;
 
 // The index of a deferred function definition within the parse tree's deferred
 // definition store.
-struct DeferredDefinitionIndex : public IndexBase {
+struct DeferredDefinitionIndex : public IndexBase<DeferredDefinitionIndex> {
+  static constexpr llvm::StringLiteral Label = "deferred_def";
   using ValueType = DeferredDefinition;
 
   static const DeferredDefinitionIndex Invalid;

+ 1 - 1
toolchain/parse/tree_and_subtrees.cpp

@@ -139,7 +139,7 @@ auto TreeAndSubtrees::PrintNode(llvm::raw_ostream& output, NodeId n, int depth,
   // If children are being added, include node_index in order to disambiguate
   // nodes.
   if (preorder) {
-    output << "node_index: " << n << ", ";
+    output << "node_index: " << n.index << ", ";
   }
   output << "kind: '" << tree_->node_kind(n) << "', text: '"
          << tokens_->GetTokenText(tree_->node_token(n)) << "'";

+ 16 - 1
toolchain/sem_ir/id_kind.h

@@ -7,6 +7,7 @@
 
 #include <algorithm>
 
+#include "common/ostream.h"
 #include "toolchain/base/int.h"
 #include "toolchain/sem_ir/ids.h"
 
@@ -14,7 +15,7 @@ namespace Carbon::SemIR {
 
 // An enum whose values are the specified types.
 template <typename... Types>
-class TypeEnum {
+class TypeEnum : public Printable<TypeEnum<Types...>> {
  public:
   static constexpr size_t NumTypes = sizeof...(Types);
   static constexpr size_t NumValues = NumTypes + 2;
@@ -96,6 +97,20 @@ class TypeEnum {
     return value_ != RawEnumType::Invalid;
   }
 
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << "IdKind(";
+    if (value_ == RawEnumType::None) {
+      out << "None";
+    } else {
+      static constexpr std::array<llvm::StringLiteral, sizeof...(Types)> Names =
+          {
+              Types::Label...,
+          };
+      out << Names[static_cast<int>(value_)];
+    }
+    out << ")";
+  }
+
  private:
   // Translates a type to its enum value, or `Invalid`.
   template <typename IdT, bool AllowInvalid>

+ 27 - 21
toolchain/sem_ir/ids.cpp

@@ -10,11 +10,13 @@
 namespace Carbon::SemIR {
 
 auto InstId::Print(llvm::raw_ostream& out) const -> void {
-  out << "inst";
   if (!is_valid()) {
     IdBase::Print(out);
-  } else if (is_builtin()) {
-    out << builtin_inst_kind();
+    return;
+  }
+  out << Label;
+  if (is_builtin()) {
+    out << "(" << builtin_inst_kind() << ")";
   } else {
     // Use the `+` as a small reminder that this is a delta, rather than an
     // absolute index.
@@ -26,34 +28,36 @@ auto ConstantId::Print(llvm::raw_ostream& out, bool disambiguate) const
     -> void {
   if (!is_valid()) {
     IdBase::Print(out);
-  } else if (is_template()) {
+    return;
+  }
+  if (is_template()) {
     if (disambiguate) {
-      out << "templateConstant(";
+      out << "template_constant(";
     }
     out << template_inst_id();
     if (disambiguate) {
       out << ")";
     }
   } else if (is_symbolic()) {
-    out << "symbolicConstant" << symbolic_index();
+    out << "symbolic_constant" << symbolic_index();
   } else {
+    CARBON_CHECK(!is_constant());
     out << "runtime";
   }
 }
 
 auto RuntimeParamIndex::Print(llvm::raw_ostream& out) const -> void {
-  out << "runtime_param";
   if (*this == Unknown) {
-    out << "<unknown>";
+    out << Label << "<unknown>";
   } else {
     IndexBase::Print(out);
   }
 }
 
 auto GenericInstIndex::Print(llvm::raw_ostream& out) const -> void {
-  out << "genericInst";
+  out << "generic_inst";
   if (is_valid()) {
-    out << (region() == Declaration ? "InDecl" : "InDef") << index();
+    out << (region() == Declaration ? "_in_decl" : "_in_def") << index();
   } else {
     out << "<invalid>";
   }
@@ -90,7 +94,11 @@ auto NameId::ForIdentifier(IdentifierId id) -> NameId {
 }
 
 auto NameId::Print(llvm::raw_ostream& out) const -> void {
-  out << "name";
+  if (!is_valid() || index >= 0) {
+    IdBase::Print(out);
+    return;
+  }
+  out << Label << "(";
   if (*this == SelfValue) {
     out << "SelfValue";
   } else if (*this == SelfType) {
@@ -104,16 +112,17 @@ auto NameId::Print(llvm::raw_ostream& out) const -> void {
   } else if (*this == Base) {
     out << "Base";
   } else {
-    CARBON_CHECK(!is_valid() || index >= 0, "Unknown index {0}", index);
+    CARBON_FATAL("Unknown index {0}", index);
     IdBase::Print(out);
   }
+  out << ")";
 }
 
 auto InstBlockId::Print(llvm::raw_ostream& out) const -> void {
   if (*this == Unreachable) {
     out << "unreachable";
   } else if (*this == Empty) {
-    out << "empty";
+    out << Label << "_empty";
   } else if (*this == Exports) {
     out << "exports";
   } else if (*this == ImportRefs) {
@@ -121,13 +130,12 @@ auto InstBlockId::Print(llvm::raw_ostream& out) const -> void {
   } else if (*this == GlobalInit) {
     out << "global_init";
   } else {
-    out << "block";
     IdBase::Print(out);
   }
 }
 
 auto TypeId::Print(llvm::raw_ostream& out) const -> void {
-  out << "type";
+  out << Label << "(";
   if (*this == TypeType::SingletonTypeId) {
     out << "TypeType";
   } else if (*this == AutoType::SingletonTypeId) {
@@ -135,10 +143,9 @@ auto TypeId::Print(llvm::raw_ostream& out) const -> void {
   } else if (*this == ErrorInst::SingletonTypeId) {
     out << "Error";
   } else {
-    out << "(";
     AsConstantId().Print(out, /*disambiguate=*/false);
-    out << ")";
   }
+  out << ")";
 }
 
 auto LibraryNameId::ForStringLiteralValueId(StringLiteralValueId id)
@@ -153,18 +160,17 @@ auto LibraryNameId::ForStringLiteralValueId(StringLiteralValueId id)
 }
 
 auto LibraryNameId::Print(llvm::raw_ostream& out) const -> void {
-  out << "libraryName";
   if (*this == Default) {
-    out << "Default";
+    out << Label << "Default";
   } else if (*this == Error) {
-    out << "<error>";
+    out << Label << "<error>";
   } else {
     IdBase::Print(out);
   }
 }
 
 auto LocId::Print(llvm::raw_ostream& out) const -> void {
-  out << "loc_";
+  out << Label << "_";
   if (is_node_id() || !is_valid()) {
     out << node_id();
   } else {

+ 75 - 103
toolchain/sem_ir/ids.h

@@ -33,7 +33,8 @@ struct StructTypeField;
 struct TypeInfo;
 
 // The ID of an instruction.
-struct InstId : public IdBase, public Printable<InstId> {
+struct InstId : public IdBase<InstId> {
+  static constexpr llvm::StringLiteral Label = "inst";
   using ValueType = Inst;
 
   // An explicitly invalid ID.
@@ -110,7 +111,9 @@ constexpr InstId InstId::PackageNamespace = InstId(BuiltinInstKind::ValidCount);
 // constant instruction that defines the constant. Symbolic constants are an
 // index into a separate table of `SymbolicConstant`s maintained by the constant
 // value store.
-struct ConstantId : public IdBase, public Printable<ConstantId> {
+struct ConstantId : public IdBase<ConstantId> {
+  static constexpr llvm::StringLiteral Label = "constant";
+
   // An ID for an expression that is not constant.
   static const ConstantId NotConstant;
   // An explicitly invalid ID.
@@ -183,17 +186,14 @@ constexpr ConstantId ConstantId::NotConstant = ConstantId(NotConstantIndex);
 constexpr ConstantId ConstantId::Invalid = ConstantId(InvalidIndex);
 
 // The ID of a EntityName.
-struct EntityNameId : public IdBase, public Printable<EntityNameId> {
+struct EntityNameId : public IdBase<EntityNameId> {
+  static constexpr llvm::StringLiteral Label = "entity_name";
   using ValueType = EntityName;
 
   // An explicitly invalid ID.
   static const EntityNameId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "entity_name";
-    IdBase::Print(out);
-  }
 };
 
 constexpr EntityNameId EntityNameId::Invalid = EntityNameId(InvalidIndex);
@@ -201,17 +201,13 @@ constexpr EntityNameId EntityNameId::Invalid = EntityNameId(InvalidIndex);
 // The index of a compile-time binding. This is the de Bruijn level for the
 // binding -- that is, this is the number of other compile time bindings whose
 // scope encloses this binding.
-struct CompileTimeBindIndex : public IndexBase,
-                              public Printable<CompileTimeBindIndex> {
+struct CompileTimeBindIndex : public IndexBase<CompileTimeBindIndex> {
+  static constexpr llvm::StringLiteral Label = "comp_time_bind";
+
   // An explicitly invalid index.
   static const CompileTimeBindIndex Invalid;
 
   using IndexBase::IndexBase;
-
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "comp_time_bind";
-    IndexBase::Print(out);
-  }
 };
 
 constexpr CompileTimeBindIndex CompileTimeBindIndex::Invalid =
@@ -224,8 +220,9 @@ constexpr CompileTimeBindIndex CompileTimeBindIndex::Invalid =
 // runtime parameter index.
 // TODO: Rename this to CallParamIndex, for consistency with the "`Call`
 // parameters" terminology in EntityWithParamsBase.
-struct RuntimeParamIndex : public IndexBase,
-                           public Printable<RuntimeParamIndex> {
+struct RuntimeParamIndex : public IndexBase<RuntimeParamIndex> {
+  static constexpr llvm::StringLiteral Label = "runtime_param";
+
   // An explicitly invalid index.
   static const RuntimeParamIndex Invalid;
 
@@ -244,114 +241,94 @@ constexpr RuntimeParamIndex RuntimeParamIndex::Unknown =
     RuntimeParamIndex(InvalidIndex - 1);
 
 // The ID of a function.
-struct FunctionId : public IdBase, public Printable<FunctionId> {
+struct FunctionId : public IdBase<FunctionId> {
+  static constexpr llvm::StringLiteral Label = "function";
   using ValueType = Function;
 
   // An explicitly invalid ID.
   static const FunctionId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "function";
-    IdBase::Print(out);
-  }
 };
 
 constexpr FunctionId FunctionId::Invalid = FunctionId(InvalidIndex);
 
 // The ID of an IR within the set of all IRs being evaluated in the current
 // check execution.
-struct CheckIRId : public IdBase, public Printable<CheckIRId> {
+struct CheckIRId : public IdBase<CheckIRId> {
+  static constexpr llvm::StringLiteral Label = "check_ir";
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "check_ir";
-    IdBase::Print(out);
-  }
 };
 
 // The ID of a class.
-struct ClassId : public IdBase, public Printable<ClassId> {
+struct ClassId : public IdBase<ClassId> {
+  static constexpr llvm::StringLiteral Label = "class";
   using ValueType = Class;
 
   // An explicitly invalid ID.
   static const ClassId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "class";
-    IdBase::Print(out);
-  }
 };
 
 constexpr ClassId ClassId::Invalid = ClassId(InvalidIndex);
 
 // The ID of an interface.
-struct InterfaceId : public IdBase, public Printable<InterfaceId> {
+struct InterfaceId : public IdBase<InterfaceId> {
+  static constexpr llvm::StringLiteral Label = "interface";
   using ValueType = Interface;
 
   // An explicitly invalid ID.
   static const InterfaceId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "interface";
-    IdBase::Print(out);
-  }
 };
 
 constexpr InterfaceId InterfaceId::Invalid = InterfaceId(InvalidIndex);
 
 // The ID of an faceet type value.
-struct FacetTypeId : public IdBase, public Printable<FacetTypeId> {
+struct FacetTypeId : public IdBase<FacetTypeId> {
+  static constexpr llvm::StringLiteral Label = "facet_type";
   using ValueType = FacetTypeInfo;
 
   // An explicitly invalid ID.
   static const FacetTypeId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "facet type";
-    IdBase::Print(out);
-  }
 };
 
 constexpr FacetTypeId FacetTypeId::Invalid = FacetTypeId(InvalidIndex);
 
 // The ID of an impl.
-struct ImplId : public IdBase, public Printable<ImplId> {
+struct ImplId : public IdBase<ImplId> {
+  static constexpr llvm::StringLiteral Label = "impl";
   using ValueType = Impl;
 
   // An explicitly invalid ID.
   static const ImplId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "impl";
-    IdBase::Print(out);
-  }
 };
 
 constexpr ImplId ImplId::Invalid = ImplId(InvalidIndex);
 
 // The ID of a generic.
-struct GenericId : public IdBase, public Printable<GenericId> {
+struct GenericId : public IdBase<GenericId> {
+  static constexpr llvm::StringLiteral Label = "generic";
   using ValueType = Generic;
 
   // An explicitly invalid ID.
   static const GenericId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "generic";
-    IdBase::Print(out);
-  }
 };
 
 constexpr GenericId GenericId::Invalid = GenericId(InvalidIndex);
 
 // The ID of a specific, which is the result of specifying the generic arguments
 // for a generic.
-struct SpecificId : public IdBase, public Printable<SpecificId> {
+struct SpecificId : public IdBase<SpecificId> {
+  static constexpr llvm::StringLiteral Label = "specific";
   using ValueType = Specific;
 
   // An explicitly invalid ID. This is typically used to represent a non-generic
@@ -359,10 +336,6 @@ struct SpecificId : public IdBase, public Printable<SpecificId> {
   static const SpecificId Invalid;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "specific";
-    IdBase::Print(out);
-  }
 };
 
 constexpr SpecificId SpecificId::Invalid = SpecificId(InvalidIndex);
@@ -371,7 +344,7 @@ constexpr SpecificId SpecificId::Invalid = SpecificId(InvalidIndex);
 // region of a generic. A corresponding specific version of the instruction can
 // be found in each specific corresponding to that generic. This is a pair of a
 // region and an index, stored in 32 bits.
-struct GenericInstIndex : public IndexBase, public Printable<GenericInstIndex> {
+struct GenericInstIndex : public IndexBase<GenericInstIndex> {
   // Where the value is first used within the generic.
   enum Region : uint8_t {
     // In the declaration.
@@ -418,7 +391,8 @@ constexpr GenericInstIndex GenericInstIndex::Invalid =
     GenericInstIndex::MakeInvalid();
 
 // The ID of an IR within the set of imported IRs, both direct and indirect.
-struct ImportIRId : public IdBase, public Printable<ImportIRId> {
+struct ImportIRId : public IdBase<ImportIRId> {
+  static constexpr llvm::StringLiteral Label = "ir";
   using ValueType = ImportIR;
 
   // An explicitly invalid ID.
@@ -430,17 +404,16 @@ struct ImportIRId : public IdBase, public Printable<ImportIRId> {
   static const ImportIRId ApiForImpl;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "ir";
-    IdBase::Print(out);
-  }
 };
 
 constexpr ImportIRId ImportIRId::Invalid = ImportIRId(InvalidIndex);
 constexpr ImportIRId ImportIRId::ApiForImpl = ImportIRId(0);
 
 // A boolean value.
-struct BoolValue : public IdBase, public Printable<BoolValue> {
+struct BoolValue : public IdBase<BoolValue> {
+  // Not used by `Print`, but for `IdKind`.
+  static constexpr llvm::StringLiteral Label = "bool";
+
   static const BoolValue False;
   static const BoolValue True;
 
@@ -465,7 +438,10 @@ constexpr BoolValue BoolValue::True = BoolValue(1);
 //
 // This might eventually capture any other properties of an integer type that
 // affect its semantics, such as overflow behavior.
-struct IntKind : public IdBase, public Printable<IntKind> {
+struct IntKind : public IdBase<IntKind> {
+  // Not used by `Print`, but for `IdKind`.
+  static constexpr llvm::StringLiteral Label = "int_kind";
+
   static const IntKind Unsigned;
   static const IntKind Signed;
 
@@ -480,8 +456,11 @@ struct IntKind : public IdBase, public Printable<IntKind> {
 constexpr IntKind IntKind::Unsigned = IntKind(0);
 constexpr IntKind IntKind::Signed = IntKind(1);
 
-// A float kind value
-struct FloatKind : public IdBase, public Printable<FloatKind> {
+// A float kind value.
+struct FloatKind : public IdBase<FloatKind> {
+  // Not used by `Print`, but for `IdKind`.
+  static constexpr llvm::StringLiteral Label = "float_kind";
+
   using IdBase::IdBase;
 
   auto Print(llvm::raw_ostream& out) const -> void { out << "float"; }
@@ -489,7 +468,9 @@ struct FloatKind : public IdBase, public Printable<FloatKind> {
 
 // The ID of a name. A name is either a string or a special name such as
 // `self`, `Self`, or `base`.
-struct NameId : public IdBase, public Printable<NameId> {
+struct NameId : public IdBase<NameId> {
+  static constexpr llvm::StringLiteral Label = "name";
+
   // names().GetFormatted() is used for diagnostics.
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
 
@@ -541,7 +522,8 @@ constexpr int NameId::NonIndexValueCount = 8;
 static_assert(NameId::NonIndexValueCount == -NameId::Vptr.index);
 
 // The ID of a name scope.
-struct NameScopeId : public IdBase, public Printable<NameScopeId> {
+struct NameScopeId : public IdBase<NameScopeId> {
+  static constexpr llvm::StringLiteral Label = "name_scope";
   using ValueType = NameScope;
 
   // An explicitly invalid ID.
@@ -550,17 +532,14 @@ struct NameScopeId : public IdBase, public Printable<NameScopeId> {
   static const NameScopeId Package;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "name_scope";
-    IdBase::Print(out);
-  }
 };
 
 constexpr NameScopeId NameScopeId::Invalid = NameScopeId(InvalidIndex);
 constexpr NameScopeId NameScopeId::Package = NameScopeId(0);
 
 // The ID of an instruction block.
-struct InstBlockId : public IdBase, public Printable<InstBlockId> {
+struct InstBlockId : public IdBase<InstBlockId> {
+  static constexpr llvm::StringLiteral Label = "inst_block";
   // Types for BlockValueStore<InstBlockId>.
   using ElementType = InstId;
   using ValueType = llvm::MutableArrayRef<ElementType>;
@@ -599,9 +578,9 @@ constexpr InstBlockId InstBlockId::GlobalInit = InstBlockId(3);
 constexpr InstBlockId InstBlockId::Invalid = InstBlockId(InvalidIndex);
 constexpr InstBlockId InstBlockId::Unreachable = InstBlockId(InvalidIndex - 1);
 
-// The ID of a type block.
-struct StructTypeFieldsId : public IdBase,
-                            public Printable<StructTypeFieldsId> {
+// The ID of a struct type field block.
+struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
+  static constexpr llvm::StringLiteral Label = "struct_type_fields";
   // Types for BlockValueStore<StructTypeFieldsId>.
   using ElementType = StructTypeField;
   using ValueType = llvm::MutableArrayRef<StructTypeField>;
@@ -614,10 +593,6 @@ struct StructTypeFieldsId : public IdBase,
   static const StructTypeFieldsId Empty;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "type_block";
-    IdBase::Print(out);
-  }
 };
 
 constexpr StructTypeFieldsId StructTypeFieldsId::Invalid =
@@ -625,7 +600,9 @@ constexpr StructTypeFieldsId StructTypeFieldsId::Invalid =
 constexpr StructTypeFieldsId StructTypeFieldsId::Empty = StructTypeFieldsId(0);
 
 // The ID of a type.
-struct TypeId : public IdBase, public Printable<TypeId> {
+struct TypeId : public IdBase<TypeId> {
+  static constexpr llvm::StringLiteral Label = "type";
+
   // `StringifyTypeExpr` is used for diagnostics. However, where possible, an
   // `InstId` describing how the type was written should be preferred, using
   // `InstIdAsType` or `TypeOfInstId` as the diagnostic argument type.
@@ -652,7 +629,8 @@ struct TypeId : public IdBase, public Printable<TypeId> {
 constexpr TypeId TypeId::Invalid = TypeId(InvalidIndex);
 
 // The ID of a type block.
-struct TypeBlockId : public IdBase, public Printable<TypeBlockId> {
+struct TypeBlockId : public IdBase<TypeBlockId> {
+  static constexpr llvm::StringLiteral Label = "type_block";
   // Types for BlockValueStore<TypeBlockId>.
   using ElementType = TypeId;
   using ValueType = llvm::MutableArrayRef<ElementType>;
@@ -665,32 +643,25 @@ struct TypeBlockId : public IdBase, public Printable<TypeBlockId> {
   static const TypeBlockId Empty;
 
   using IdBase::IdBase;
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "type_block";
-    IdBase::Print(out);
-  }
 };
 
 constexpr TypeBlockId TypeBlockId::Invalid = TypeBlockId(InvalidIndex);
 constexpr TypeBlockId TypeBlockId::Empty = TypeBlockId(0);
 
 // An index for element access, for structs, tuples, and classes.
-struct ElementIndex : public IndexBase, public Printable<ElementIndex> {
+struct ElementIndex : public IndexBase<ElementIndex> {
+  static constexpr llvm::StringLiteral Label = "element";
   using IndexBase::IndexBase;
 
   // An explicitly invalid ID.
   static const ElementIndex Invalid;
-
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "element";
-    IndexBase::Print(out);
-  }
 };
 
 constexpr ElementIndex ElementIndex::Invalid = ElementIndex(InvalidIndex);
 
 // The ID of a library name. This is either a string literal or `default`.
-struct LibraryNameId : public IdBase, public Printable<NameId> {
+struct LibraryNameId : public IdBase<LibraryNameId> {
+  static constexpr llvm::StringLiteral Label = "library_name";
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
 
   // An explicitly invalid ID.
@@ -721,18 +692,14 @@ constexpr LibraryNameId LibraryNameId::Default =
 constexpr LibraryNameId LibraryNameId::Error = LibraryNameId(InvalidIndex - 2);
 
 // The ID of an ImportIRInst.
-struct ImportIRInstId : public IdBase, public Printable<ImportIRInstId> {
+struct ImportIRInstId : public IdBase<ImportIRInstId> {
+  static constexpr llvm::StringLiteral Label = "import_ir_inst";
   using ValueType = ImportIRInst;
 
   // An explicitly invalid ID.
   static const ImportIRInstId Invalid;
 
   using IdBase::IdBase;
-
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "import_ir_inst";
-    IdBase::Print(out);
-  }
 };
 
 constexpr ImportIRInstId ImportIRInstId::Invalid = ImportIRInstId(InvalidIndex);
@@ -743,7 +710,9 @@ constexpr ImportIRInstId ImportIRInstId::Invalid = ImportIRInstId(InvalidIndex);
 // - index > Invalid: A Parse::NodeId in the current IR.
 // - index < Invalid: An ImportIRInstId.
 // - index == Invalid: Can be used for either.
-struct LocId : public IdBase, public Printable<LocId> {
+struct LocId : public IdBase<LocId> {
+  static constexpr llvm::StringLiteral Label = "loc";
+
   // This bit, if set for a node ID location, indicates a location for
   // operations performed implicitly.
   static const int32_t ImplicitBit = 1 << 30;
@@ -818,9 +787,12 @@ constexpr LocId LocId::Invalid = LocId(Parse::NodeId::Invalid);
 // - In the case the specific instruction has no field in the same position, the
 //   `Any[...]` type will hold a default constructed `AnyRawId` with an invalid
 //   value.
-struct AnyRawId : public IdBase {
-  constexpr AnyRawId() : IdBase(IdBase::InvalidIndex) {}
-  constexpr explicit AnyRawId(int32_t id) : IdBase(id) {}
+struct AnyRawId : public AnyIdBase {
+  // For IdKind.
+  static constexpr llvm::StringLiteral Label = "any_raw";
+
+  constexpr explicit AnyRawId() : AnyIdBase(AnyIdBase::InvalidIndex) {}
+  constexpr explicit AnyRawId(int32_t id) : AnyIdBase(id) {}
 };
 
 }  // namespace Carbon::SemIR

+ 6 - 4
toolchain/sem_ir/impl.h

@@ -59,11 +59,10 @@ struct Impl : public EntityWithParamsBase,
 class ImplStore {
  private:
   // An ID of either a single impl or a lookup bucket.
-  class ImplOrLookupBucketId : public IdBase {
-   private:
-    explicit constexpr ImplOrLookupBucketId(int index) : IdBase(index) {}
-
+  class ImplOrLookupBucketId : public IdBase<ImplOrLookupBucketId> {
    public:
+    static constexpr llvm::StringLiteral Label = "impl_or_lookup_bucket";
+
     // An explicitly invalid ID, corresponding to to ImplId::Invalid.
     static const ImplOrLookupBucketId Invalid;
 
@@ -90,6 +89,9 @@ class ImplStore {
       CARBON_CHECK(!is_bucket());
       return ImplId(index);
     }
+
+   private:
+    explicit constexpr ImplOrLookupBucketId(int index) : IdBase(index) {}
   };
 
  public:

+ 1 - 1
toolchain/sem_ir/inst.h

@@ -275,7 +275,7 @@ class Inst : public Printable<Inst> {
       : kind_(kind), type_id_(type_id), arg0_(arg0), arg1_(arg1) {}
 
   // Convert a field to its raw representation, used as `arg0_` / `arg1_`.
-  static constexpr auto ToRaw(IdBase base) -> int32_t { return base.index; }
+  static constexpr auto ToRaw(AnyIdBase base) -> int32_t { return base.index; }
   static constexpr auto ToRaw(IntId id) -> int32_t { return id.AsRaw(); }
 
   // Convert a field from its raw representation.

+ 8 - 7
toolchain/sem_ir/yaml_test.cpp

@@ -50,9 +50,10 @@ TEST(SemIRTest, YAML) {
   auto type_block_id = Yaml::Scalar(MatchesRegex(R"(type_block\d+)"));
   auto inst_id = Yaml::Scalar(MatchesRegex(R"(inst\+\d+)"));
   auto constant_id =
-      Yaml::Scalar(MatchesRegex(R"(templateConstant\(inst(\w+|\+\d+)\))"));
-  auto inst_builtin = Yaml::Scalar(MatchesRegex(R"(inst\w+)"));
-  auto type_id = Yaml::Scalar(MatchesRegex(R"(type(\w+|\(inst(\w+|\+\d+)\)))"));
+      Yaml::Scalar(MatchesRegex(R"(template_constant\(inst(\w+|\+\d+)\))"));
+  auto inst_builtin = Yaml::Scalar(MatchesRegex(R"(inst\(\w+\))"));
+  auto type_id =
+      Yaml::Scalar(MatchesRegex(R"(type\((\w+|inst\(\w+\)|inst\+\d+)\))"));
   auto type_builtin = Pair(type_id, Yaml::Mapping(_));
 
   auto file = Yaml::Mapping(ElementsAre(
@@ -79,7 +80,7 @@ TEST(SemIRTest, YAML) {
                Contains(Pair(_, Yaml::Mapping(ElementsAre(
                                     Pair("kind", "TupleType"),
                                     Pair("arg0", type_block_id),
-                                    Pair("type", "typeTypeType"))))),
+                                    Pair("type", "type(TypeType)"))))),
                // A 2-arg instruction.
                Contains(Pair(
                    _, Yaml::Mapping(ElementsAre(Pair("kind", "Assign"),
@@ -91,12 +92,12 @@ TEST(SemIRTest, YAML) {
       // This production has only two instruction blocks.
       Pair("inst_blocks",
            Yaml::Mapping(ElementsAre(
-               Pair("empty", Yaml::Mapping(IsEmpty())),
+               Pair("inst_block_empty", Yaml::Mapping(IsEmpty())),
                Pair("exports", Yaml::Mapping(Each(Pair(_, inst_id)))),
                Pair("import_refs", Yaml::Mapping(IsEmpty())),
                Pair("global_init", Yaml::Mapping(IsEmpty())),
-               Pair("block4", Yaml::Mapping(Each(Pair(_, inst_id)))),
-               Pair("block5", Yaml::Mapping(Each(Pair(_, inst_id)))))))));
+               Pair("inst_block4", Yaml::Mapping(Each(Pair(_, inst_id)))),
+               Pair("inst_block5", Yaml::Mapping(Each(Pair(_, inst_id)))))))));
 
   auto root = Yaml::Sequence(ElementsAre(Yaml::Mapping(
       ElementsAre(Pair("filename", "test.carbon"), Pair("sem_ir", file)))));