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

Use the correct type for `Self` in generic classes and generic interfaces (#4087)

In a `class C(T:! type)`, the type `Self` should be `C(T)`, not merely
`C`. Similarly, in an `interface I(T:! type)`, the type of self should
be `I(T)`, not merely `I`.
Richard Smith пре 1 година
родитељ
комит
10a198a9e6
24 измењених фајлова са 395 додато и 224 уклоњено
  1. 1 8
      toolchain/check/eval.cpp
  2. 33 0
      toolchain/check/generic.cpp
  3. 14 0
      toolchain/check/generic.h
  4. 2 2
      toolchain/check/handle_class.cpp
  5. 13 5
      toolchain/check/handle_interface.cpp
  6. 21 0
      toolchain/check/subst.cpp
  7. 2 2
      toolchain/check/testdata/class/fail_generic_method.carbon
  8. 5 5
      toolchain/check/testdata/class/generic/basic.carbon
  9. 4 4
      toolchain/check/testdata/class/generic/call.carbon
  10. 4 4
      toolchain/check/testdata/class/generic/fail_todo_use.carbon
  11. 11 11
      toolchain/check/testdata/class/generic/import.carbon
  12. 1 1
      toolchain/check/testdata/class/generic/member_inline.carbon
  13. 8 8
      toolchain/check/testdata/class/generic/member_out_of_line.carbon
  14. 10 10
      toolchain/check/testdata/class/generic/redeclare.carbon
  15. 104 0
      toolchain/check/testdata/class/generic/self.carbon
  16. 3 3
      toolchain/check/testdata/class/generic_method.carbon
  17. 11 11
      toolchain/check/testdata/impl/fail_extend_impl_forall.carbon
  18. 12 10
      toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon
  19. 36 44
      toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon
  20. 66 63
      toolchain/check/testdata/interface/no_prelude/generic.carbon
  21. 22 21
      toolchain/check/testdata/interface/no_prelude/generic_import.carbon
  22. 4 4
      toolchain/check/testdata/packages/no_prelude/fail_export_name_params.carbon
  23. 4 4
      toolchain/check/testdata/struct/import.carbon
  24. 4 4
      toolchain/check/testdata/tuples/import.carbon

+ 1 - 8
toolchain/check/eval.cpp

@@ -6,6 +6,7 @@
 
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/check/diagnostic_helpers.h"
+#include "toolchain/check/generic.h"
 #include "toolchain/diagnostics/diagnostic_emitter.h"
 #include "toolchain/sem_ir/builtin_function_kind.h"
 #include "toolchain/sem_ir/function.h"
@@ -15,14 +16,6 @@
 
 namespace Carbon::Check {
 
-static auto MakeGenericInstance(Context& context, SemIR::GenericId generic_id,
-                                SemIR::InstBlockId args_id)
-    -> SemIR::GenericInstanceId {
-  auto instance_id = context.generic_instances().GetOrAdd(generic_id, args_id);
-  // TODO: Perform substitution into the generic declaration if needed.
-  return instance_id;
-}
-
 namespace {
 // The evaluation phase for an expression, computed by evaluation. These are
 // ordered so that the phase of an expression is the numerically highest phase

+ 33 - 0
toolchain/check/generic.cpp

@@ -40,4 +40,37 @@ auto FinishGenericDefinition(Context& /*context*/,
   // TODO: Track contents of this generic definition.
 }
 
+auto MakeGenericInstance(Context& context, SemIR::GenericId generic_id,
+                         SemIR::InstBlockId args_id)
+    -> SemIR::GenericInstanceId {
+  auto instance_id = context.generic_instances().GetOrAdd(generic_id, args_id);
+  // TODO: Perform substitution into the generic declaration if needed.
+  return instance_id;
+}
+
+auto MakeGenericSelfInstance(Context& context, SemIR::GenericId generic_id)
+    -> SemIR::GenericInstanceId {
+  // TODO: Remove this once we import generics properly.
+  if (!generic_id.is_valid()) {
+    return SemIR::GenericInstanceId::Invalid;
+  }
+
+  auto& generic = context.generics().Get(generic_id);
+  auto args = context.inst_blocks().Get(generic.bindings_id);
+
+  // Form a canonical argument list for the generic.
+  llvm::SmallVector<SemIR::InstId> arg_ids;
+  arg_ids.reserve(args.size());
+  for (auto arg_id : args) {
+    arg_ids.push_back(context.constant_values().GetConstantInstId(arg_id));
+  }
+  auto args_id = context.inst_blocks().AddCanonical(arg_ids);
+
+  // Build a corresponding instance.
+  // TODO: This could be made more efficient. We don't need to perform
+  // substitution here; we know we want identity mappings for all constants and
+  // types. We could also consider not storing the mapping at all in this case.
+  return MakeGenericInstance(context, generic_id, args_id);
+}
+
 }  // namespace Carbon::Check

+ 14 - 0
toolchain/check/generic.h

@@ -32,6 +32,20 @@ auto FinishGenericRedecl(Context& context, SemIR::InstId decl_id,
 auto FinishGenericDefinition(Context& context, SemIR::GenericId generic_id)
     -> void;
 
+// Builds a new generic instance, or finds an existing one if this instance of
+// this generic has already been referenced. Performs substitution into the
+// declaration, but not the definition, of the generic.
+//
+// `args_id` should be a canonical instruction block referring to constants.
+auto MakeGenericInstance(Context& context, SemIR::GenericId generic_id,
+                         SemIR::InstBlockId args_id)
+    -> SemIR::GenericInstanceId;
+
+// Builds the generic instance corresponding to the generic itself. For example,
+// for a generic `G(T:! type)`, this is `G(T)`.
+auto MakeGenericSelfInstance(Context& context, SemIR::GenericId generic_id)
+    -> SemIR::GenericInstanceId;
+
 }  // namespace Carbon::Check
 
 #endif  // CARBON_TOOLCHAIN_CHECK_GENERIC_H_

+ 2 - 2
toolchain/check/handle_class.cpp

@@ -260,8 +260,8 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
     // declaration.
     auto& class_info = context.classes().Get(class_decl.class_id);
     if (class_info.is_generic()) {
-      // TODO: Build generic arguments representing the parameters.
-      auto instance_id = SemIR::GenericInstanceId::Invalid;
+      auto instance_id =
+          MakeGenericSelfInstance(context, class_info.generic_id);
       class_info.self_type_id = context.GetTypeIdForTypeConstant(
           TryEvalInst(context, SemIR::InstId::Invalid,
                       SemIR::ClassType{.type_id = SemIR::TypeId::TypeType,

+ 13 - 5
toolchain/check/handle_interface.cpp

@@ -3,9 +3,9 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
 #include "toolchain/check/context.h"
+#include "toolchain/check/eval.h"
 #include "toolchain/check/generic.h"
 #include "toolchain/check/handle.h"
-#include "toolchain/check/interface.h"
 #include "toolchain/check/merge.h"
 #include "toolchain/check/modifiers.h"
 #include "toolchain/check/name_component.h"
@@ -152,10 +152,18 @@ auto HandleInterfaceDefinitionStart(Context& context,
 
   // Declare and introduce `Self`.
   if (!interface_info.is_defined()) {
-    // TODO: Once we support parameterized interfaces, this won't be the right
-    // type. For `interface X(T:! type)`, the type of `Self` is `X(T)`, whereas
-    // this will be simply `X`.
-    auto self_type_id = context.GetTypeIdForTypeInst(interface_decl_id);
+    SemIR::TypeId self_type_id = SemIR::TypeId::Invalid;
+    if (interface_info.is_generic()) {
+      auto instance_id =
+          MakeGenericSelfInstance(context, interface_info.generic_id);
+      self_type_id = context.GetTypeIdForTypeConstant(
+          TryEvalInst(context, SemIR::InstId::Invalid,
+                      SemIR::InterfaceType{.type_id = SemIR::TypeId::TypeType,
+                                           .interface_id = interface_id,
+                                           .instance_id = instance_id}));
+    } else {
+      self_type_id = context.GetTypeIdForTypeInst(interface_decl_id);
+    }
 
     // We model `Self` as a symbolic binding whose type is the interface.
     // Because there is no equivalent non-symbolic value, we use `Invalid` as

+ 21 - 0
toolchain/check/subst.cpp

@@ -5,6 +5,7 @@
 #include "toolchain/check/subst.h"
 
 #include "toolchain/check/eval.h"
+#include "toolchain/check/generic.h"
 #include "toolchain/sem_ir/copy_on_write_block.h"
 #include "toolchain/sem_ir/ids.h"
 
@@ -77,6 +78,13 @@ static auto PushOperand(Context& context, Worklist& worklist,
         worklist.Push(context.types().GetInstId(type_id));
       }
       break;
+    case SemIR::IdKind::For<SemIR::GenericInstanceId>:
+      if (auto instance_id = static_cast<SemIR::GenericInstanceId>(arg);
+          instance_id.is_valid()) {
+        PushOperand(context, worklist, SemIR::IdKind::For<SemIR::InstBlockId>,
+                    context.generic_instances().Get(instance_id).args_id.index);
+      }
+      break;
     default:
       break;
   }
@@ -128,6 +136,19 @@ static auto PopOperand(Context& context, Worklist& worklist, SemIR::IdKind kind,
       }
       return new_type_block.GetCanonical().index;
     }
+    case SemIR::IdKind::For<SemIR::GenericInstanceId>: {
+      auto instance_id = static_cast<SemIR::GenericInstanceId>(arg);
+      if (!instance_id.is_valid()) {
+        return arg;
+      }
+      auto& instance = context.generic_instances().Get(instance_id);
+      auto args_id =
+          PopOperand(context, worklist, SemIR::IdKind::For<SemIR::InstBlockId>,
+                     instance.args_id.index);
+      return MakeGenericInstance(context, instance.generic_id,
+                                 static_cast<SemIR::InstBlockId>(args_id))
+          .index;
+    }
     default:
       return arg;
   }

+ 2 - 2
toolchain/check/testdata/class/fail_generic_method.carbon

@@ -38,7 +38,7 @@ fn Class(N:! i32).F[self: Self](n: T) {}
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
 // CHECK:STDOUT:   %.2: type = unbound_element_type %Class.2, %T [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
@@ -81,7 +81,7 @@ fn Class(N:! i32).F[self: Self](n: T) {}
 // CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
 // CHECK:STDOUT:   %.loc12: %.2 = field_decl a, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
 // CHECK:STDOUT:     %self.loc13_8.1: %Class.2 = param self
 // CHECK:STDOUT:     %self.loc13_8.2: %Class.2 = bind_name self, %self.loc13_8.1
 // CHECK:STDOUT:     %T.ref.loc13: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]

+ 5 - 5
toolchain/check/testdata/class/generic/basic.carbon

@@ -29,8 +29,8 @@ class Class(T:! type) {
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
-// CHECK:STDOUT:   %.2: type = ptr_type %Class.2 [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
+// CHECK:STDOUT:   %.2: type = ptr_type %Class.2 [symbolic]
 // CHECK:STDOUT:   %.3: type = ptr_type %T [symbolic]
 // CHECK:STDOUT:   %GetAddr.type: type = fn_type @GetAddr [template]
 // CHECK:STDOUT:   %GetAddr: %GetAddr.type = struct_value () [template]
@@ -56,8 +56,8 @@ class Class(T:! type) {
 // CHECK:STDOUT: class @Class
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
 // CHECK:STDOUT:   %GetAddr.decl: %GetAddr.type = fn_decl @GetAddr [template = constants.%GetAddr] {
-// CHECK:STDOUT:     %Self.ref.loc12: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
-// CHECK:STDOUT:     %.loc12_29: type = ptr_type %Class.2 [template = constants.%.2]
+// CHECK:STDOUT:     %Self.ref.loc12: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:     %.loc12_29: type = ptr_type %Class.2 [symbolic = constants.%.2]
 // CHECK:STDOUT:     %self.loc12_19.1: %.2 = param self
 // CHECK:STDOUT:     %self.loc12_19.3: %.2 = bind_name self, %self.loc12_19.1
 // CHECK:STDOUT:     %.loc12_14: %.2 = addr_pattern %self.loc12_19.3
@@ -66,7 +66,7 @@ class Class(T:! type) {
 // CHECK:STDOUT:     %return.var.loc12: ref %.3 = var <return slot>
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %GetValue.decl: %GetValue.type = fn_decl @GetValue [template = constants.%GetValue] {
-// CHECK:STDOUT:     %Self.ref.loc17: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
+// CHECK:STDOUT:     %Self.ref.loc17: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
 // CHECK:STDOUT:     %self.loc17_15.1: %Class.2 = param self
 // CHECK:STDOUT:     %self.loc17_15.2: %Class.2 = bind_name self, %self.loc17_15.1
 // CHECK:STDOUT:     %T.ref.loc17: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]

+ 4 - 4
toolchain/check/testdata/class/generic/call.carbon

@@ -73,7 +73,7 @@ var a: Class(5, i32*);
 // CHECK:STDOUT:   %N: i32 = bind_symbolic_name N 1 [symbolic]
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T, %N) [symbolic]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
 // CHECK:STDOUT:   %.3: type = ptr_type i32 [template]
 // CHECK:STDOUT:   %.4: i32 = int_literal 5 [template]
@@ -142,7 +142,7 @@ var a: Class(5, i32*);
 // CHECK:STDOUT:   %N: i32 = bind_symbolic_name N 1 [symbolic]
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T, %N) [symbolic]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
 // CHECK:STDOUT:   %.3: type = ptr_type i32 [template]
 // CHECK:STDOUT: }
@@ -195,7 +195,7 @@ var a: Class(5, i32*);
 // CHECK:STDOUT:   %N: i32 = bind_symbolic_name N 1 [symbolic]
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T, %N) [symbolic]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
 // CHECK:STDOUT:   %.3: type = ptr_type i32 [template]
 // CHECK:STDOUT:   %.4: i32 = int_literal 1 [template]
@@ -252,7 +252,7 @@ var a: Class(5, i32*);
 // CHECK:STDOUT:   %N: i32 = bind_symbolic_name N 1 [symbolic]
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T, %N) [symbolic]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
 // CHECK:STDOUT:   %.3: i32 = int_literal 5 [template]
 // CHECK:STDOUT:   %.4: type = ptr_type i32 [template]

+ 4 - 4
toolchain/check/testdata/class/generic/fail_todo_use.carbon

@@ -43,8 +43,8 @@ fn Run() -> i32 {
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
-// CHECK:STDOUT:   %.2: type = ptr_type %Class.2 [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
+// CHECK:STDOUT:   %.2: type = ptr_type %Class.2 [symbolic]
 // CHECK:STDOUT:   %.3: type = ptr_type %T [symbolic]
 // CHECK:STDOUT:   %Get.type: type = fn_type @Get [template]
 // CHECK:STDOUT:   %Get: %Get.type = struct_value () [template]
@@ -85,8 +85,8 @@ fn Run() -> i32 {
 // CHECK:STDOUT: class @Class
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
 // CHECK:STDOUT:   %Get.decl: %Get.type = fn_decl @Get [template = constants.%Get] {
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
-// CHECK:STDOUT:     %.loc12_25: type = ptr_type %Class.2 [template = constants.%.2]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:     %.loc12_25: type = ptr_type %Class.2 [symbolic = constants.%.2]
 // CHECK:STDOUT:     %self.loc12_15.1: %.2 = param self
 // CHECK:STDOUT:     %self.loc12_15.3: %.2 = bind_name self, %self.loc12_15.1
 // CHECK:STDOUT:     %.loc12_10: %.2 = addr_pattern %self.loc12_15.3

+ 11 - 11
toolchain/check/testdata/class/generic/import.carbon

@@ -95,13 +95,13 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
 // CHECK:STDOUT:   %CompleteClass.type: type = generic_class_type @CompleteClass [template]
 // CHECK:STDOUT:   %CompleteClass.1: %CompleteClass.type = struct_value () [template]
-// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass [template]
+// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass, (%T) [symbolic]
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
-// CHECK:STDOUT:   %.2: type = unbound_element_type %CompleteClass.2, i32 [template]
+// CHECK:STDOUT:   %.2: type = unbound_element_type %CompleteClass.2, i32 [symbolic]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
 // CHECK:STDOUT:   %.3: type = struct_type {.n: i32} [template]
@@ -182,13 +182,13 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
 // CHECK:STDOUT:   %.2: type = unbound_element_type %Class.2, %T [symbolic]
 // CHECK:STDOUT:   %.3: type = struct_type {.x: %T} [symbolic]
 // CHECK:STDOUT:   %CompleteClass.type: type = generic_class_type @CompleteClass [template]
 // CHECK:STDOUT:   %CompleteClass.1: %CompleteClass.type = struct_value () [template]
 // CHECK:STDOUT:   %.4: type = struct_type {.n: i32} [template]
-// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass [template]
+// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass, (%T) [symbolic]
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
 // CHECK:STDOUT:   %CompleteClass.3: type = class_type @CompleteClass, (i32) [template]
@@ -270,8 +270,8 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %CompleteClass.type: type = generic_class_type @CompleteClass [template]
 // CHECK:STDOUT:   %CompleteClass.1: %CompleteClass.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {.n: i32} [template]
-// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, <unexpected instref inst+26> [symbolic]
+// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass, (%T) [symbolic]
 // CHECK:STDOUT:   %CompleteClass.3: type = class_type @CompleteClass, (i32) [template]
 // CHECK:STDOUT:   %.3: type = ptr_type %.2 [template]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
@@ -352,13 +352,13 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %CompleteClass.type: type = generic_class_type @CompleteClass [template]
 // CHECK:STDOUT:   %CompleteClass.1: %CompleteClass.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {.n: i32} [template]
-// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, <unexpected instref inst+26> [symbolic]
+// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass, (%T) [symbolic]
 // CHECK:STDOUT:   %CompleteClass.3: type = class_type @CompleteClass, (i32) [template]
 // CHECK:STDOUT:   %.3: type = ptr_type %.2 [template]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
-// CHECK:STDOUT:   %.4: type = unbound_element_type %CompleteClass.2, i32 [template]
+// CHECK:STDOUT:   %.4: type = unbound_element_type %CompleteClass.2, i32 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -427,8 +427,8 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %CompleteClass.type: type = generic_class_type @CompleteClass [template]
 // CHECK:STDOUT:   %CompleteClass.1: %CompleteClass.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {.n: i32} [template]
-// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, <unexpected instref inst+17> [symbolic]
+// CHECK:STDOUT:   %CompleteClass.2: type = class_type @CompleteClass, (%T) [symbolic]
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
 // CHECK:STDOUT:   %.3: type = ptr_type i32 [template]
@@ -495,11 +495,11 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, <unexpected instref inst+14> [symbolic]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
 // CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
 // CHECK:STDOUT:   %.2: %.type = struct_value () [template]
-// CHECK:STDOUT:   %.3: type = class_type @.1 [template]
+// CHECK:STDOUT:   %.3: type = class_type @.1, (%U) [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {

+ 1 - 1
toolchain/check/testdata/class/generic/member_inline.carbon

@@ -21,7 +21,7 @@ class Class(T:! type) {
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]

+ 8 - 8
toolchain/check/testdata/class/generic/member_out_of_line.carbon

@@ -106,7 +106,7 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
@@ -162,11 +162,11 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT:   %A.type: type = generic_class_type @A [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %A.1: %A.type = struct_value () [template]
-// CHECK:STDOUT:   %A.2: type = class_type @A [template]
+// CHECK:STDOUT:   %A.2: type = class_type @A, (%T) [symbolic]
 // CHECK:STDOUT:   %N: %T = bind_symbolic_name N 1 [symbolic]
 // CHECK:STDOUT:   %B.type: type = generic_class_type @B [template]
 // CHECK:STDOUT:   %B.1: %B.type = struct_value () [template]
-// CHECK:STDOUT:   %B.2: type = class_type @B [template]
+// CHECK:STDOUT:   %B.2: type = class_type @B, (%T, %N) [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
@@ -189,7 +189,7 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT:     %T.ref.loc10_22: type = name_ref T, %T.loc10_6.2 [symbolic = constants.%T]
 // CHECK:STDOUT:     %N.loc10_18.1: %T = param N
 // CHECK:STDOUT:     %N.loc10_18.2: %T = bind_symbolic_name N 1, %N.loc10_18.1 [symbolic = constants.%N]
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%B.2 [template = constants.%B.2]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%B.2 [symbolic = constants.%B.2]
 // CHECK:STDOUT:     %self.loc10_27.1: %B.2 = param self
 // CHECK:STDOUT:     @F.%self: %B.2 = bind_name self, %self.loc10_27.1
 // CHECK:STDOUT:     %T.ref.loc10_42: type = name_ref T, %T.loc10_6.2 [symbolic = constants.%T]
@@ -214,7 +214,7 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT: class @B
 // CHECK:STDOUT:     generic [file.%T.loc4_9.2: type, @A.%N.loc5_11.2: %T] {
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%B.2 [template = constants.%B.2]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%B.2 [symbolic = constants.%B.2]
 // CHECK:STDOUT:     %self.loc6_10.1: %B.2 = param self
 // CHECK:STDOUT:     %self.loc6_10.2: %B.2 = bind_name self, %self.loc6_10.1
 // CHECK:STDOUT:     %T.ref: type = name_ref T, file.%T.loc4_9.2 [symbolic = constants.%T]
@@ -282,7 +282,7 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT:   %Generic.type: type = generic_class_type @Generic [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Generic.1: %Generic.type = struct_value () [template]
-// CHECK:STDOUT:   %Generic.2: type = class_type @Generic [template]
+// CHECK:STDOUT:   %Generic.2: type = class_type @Generic, (%T) [symbolic]
 // CHECK:STDOUT:   %TooFew.type: type = fn_type @TooFew [template]
 // CHECK:STDOUT:   %TooFew: %TooFew.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
@@ -327,7 +327,7 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT:   %Generic.type: type = generic_class_type @Generic [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Generic.1: %Generic.type = struct_value () [template]
-// CHECK:STDOUT:   %Generic.2: type = class_type @Generic [template]
+// CHECK:STDOUT:   %Generic.2: type = class_type @Generic, (%T) [symbolic]
 // CHECK:STDOUT:   %TooMany.type: type = fn_type @TooMany [template]
 // CHECK:STDOUT:   %TooMany: %TooMany.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
@@ -379,7 +379,7 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT:   %Generic.type: type = generic_class_type @Generic [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Generic.1: %Generic.type = struct_value () [template]
-// CHECK:STDOUT:   %Generic.2: type = class_type @Generic [template]
+// CHECK:STDOUT:   %Generic.2: type = class_type @Generic, (%T.1) [symbolic]
 // CHECK:STDOUT:   %WrongType.type: type = fn_type @WrongType [template]
 // CHECK:STDOUT:   %WrongType: %WrongType.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]

+ 10 - 10
toolchain/check/testdata/class/generic/redeclare.carbon

@@ -93,7 +93,7 @@ class E(U:! type) {}
 // CHECK:STDOUT:   %Generic.type: type = generic_class_type @Generic [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Generic.1: %Generic.type = struct_value () [template]
-// CHECK:STDOUT:   %Generic.2: type = class_type @Generic [template]
+// CHECK:STDOUT:   %Generic.2: type = class_type @Generic, (%T) [symbolic]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -127,7 +127,7 @@ class E(U:! type) {}
 // CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %.2: %.type = struct_value () [template]
-// CHECK:STDOUT:   %.3: type = class_type @.1 [template]
+// CHECK:STDOUT:   %.3: type = class_type @.1, (%T) [symbolic]
 // CHECK:STDOUT:   %.4: type = struct_type {} [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -161,12 +161,12 @@ class E(U:! type) {}
 // CHECK:STDOUT:   %N.1: i32 = bind_symbolic_name N 0 [symbolic]
 // CHECK:STDOUT:   %B.type: type = generic_class_type @B [template]
 // CHECK:STDOUT:   %B.1: %B.type = struct_value () [template]
-// CHECK:STDOUT:   %B.2: type = class_type @B [template]
+// CHECK:STDOUT:   %B.2: type = class_type @B, (%N.1) [symbolic]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %N.2: %T = bind_symbolic_name N 1 [symbolic]
 // CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
 // CHECK:STDOUT:   %.2: %.type = struct_value () [template]
-// CHECK:STDOUT:   %.3: type = class_type @.1 [template]
+// CHECK:STDOUT:   %.3: type = class_type @.1, (%T, %N.2) [symbolic]
 // CHECK:STDOUT:   %.4: type = struct_type {} [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -211,13 +211,13 @@ class E(U:! type) {}
 // CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%T) [symbolic]
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
 // CHECK:STDOUT:   %U: i32 = bind_symbolic_name U 1 [symbolic]
 // CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
 // CHECK:STDOUT:   %.2: %.type = struct_value () [template]
-// CHECK:STDOUT:   %.3: type = class_type @.1 [template]
+// CHECK:STDOUT:   %.3: type = class_type @.1, (%T, %U) [symbolic]
 // CHECK:STDOUT:   %.4: type = struct_type {} [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -261,13 +261,13 @@ class E(U:! type) {}
 // CHECK:STDOUT:   %D.type: type = generic_class_type @D [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %D.1: %D.type = struct_value () [template]
-// CHECK:STDOUT:   %D.2: type = class_type @D [template]
+// CHECK:STDOUT:   %D.2: type = class_type @D, (%T.1) [symbolic]
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
 // CHECK:STDOUT:   %T.2: i32 = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
 // CHECK:STDOUT:   %.2: %.type = struct_value () [template]
-// CHECK:STDOUT:   %.3: type = class_type @.1 [template]
+// CHECK:STDOUT:   %.3: type = class_type @.1, (%T.2) [symbolic]
 // CHECK:STDOUT:   %.4: type = struct_type {} [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -309,11 +309,11 @@ class E(U:! type) {}
 // CHECK:STDOUT:   %E.type: type = generic_class_type @E [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %E.1: %E.type = struct_value () [template]
-// CHECK:STDOUT:   %E.2: type = class_type @E [template]
+// CHECK:STDOUT:   %E.2: type = class_type @E, (%T) [symbolic]
 // CHECK:STDOUT:   %U: type = bind_symbolic_name U 0 [symbolic]
 // CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
 // CHECK:STDOUT:   %.2: %.type = struct_value () [template]
-// CHECK:STDOUT:   %.3: type = class_type @.1 [template]
+// CHECK:STDOUT:   %.3: type = class_type @.1, (%U) [symbolic]
 // CHECK:STDOUT:   %.4: type = struct_type {} [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 104 - 0
toolchain/check/testdata/class/generic/self.carbon

@@ -0,0 +1,104 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic/self.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic/self.carbon
+
+class Class(T:! type) {
+  // `Self` is the same as `Class(T)` here.
+  // TODO: Find a better way to test two types are the same.
+  fn MakeSelf() -> Self;
+  fn MakeClass() -> Class(T);
+  fn F() {
+    var c: Class(T) = MakeSelf();
+    var s: Self = MakeClass();
+  }
+}
+
+// CHECK:STDOUT: --- self.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
+// CHECK:STDOUT:   %MakeSelf.type: type = fn_type @MakeSelf [template]
+// CHECK:STDOUT:   %MakeSelf: %MakeSelf.type = struct_value () [template]
+// CHECK:STDOUT:   %MakeClass.type: type = fn_type @MakeClass [template]
+// CHECK:STDOUT:   %MakeClass: %MakeClass.type = struct_value () [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %.2 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .Class = %Class.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %Class.decl: %Class.type = class_decl @Class [template = constants.%Class.1] {
+// CHECK:STDOUT:     %T.loc11_13.1: type = param T
+// CHECK:STDOUT:     %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Class
+// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
+// CHECK:STDOUT:   %MakeSelf.decl: %MakeSelf.type = fn_decl @MakeSelf [template = constants.%MakeSelf] {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:     %return.var.loc14: ref %Class.2 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %MakeClass.decl: %MakeClass.type = fn_decl @MakeClass [template = constants.%MakeClass] {
+// CHECK:STDOUT:     %Class.ref: %Class.type = name_ref Class, file.%Class.decl [template = constants.%Class.1]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
+// CHECK:STDOUT:     %.loc15_26: init type = call %Class.ref(%T.ref) [symbolic = constants.%Class.2]
+// CHECK:STDOUT:     %.loc15_28.1: type = value_of_initializer %.loc15_26 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:     %.loc15_28.2: type = converted %.loc15_26, %.loc15_28.1 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:     %return.var.loc15: ref %Class.2 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Class.2
+// CHECK:STDOUT:   .MakeSelf = %MakeSelf.decl
+// CHECK:STDOUT:   .MakeClass = %MakeClass.decl
+// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @MakeSelf() -> %Class.2
+// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type];
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @MakeClass() -> %Class.2
+// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type];
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F()
+// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %Class.ref: %Class.type = name_ref Class, file.%Class.decl [template = constants.%Class.1]
+// CHECK:STDOUT:   %T.ref: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
+// CHECK:STDOUT:   %.loc17_17: init type = call %Class.ref(%T.ref) [symbolic = constants.%Class.2]
+// CHECK:STDOUT:   %.loc17_19.1: type = value_of_initializer %.loc17_17 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:   %.loc17_19.2: type = converted %.loc17_17, %.loc17_19.1 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:   %c.var: ref %Class.2 = var c
+// CHECK:STDOUT:   %c: ref %Class.2 = bind_name c, %c.var
+// CHECK:STDOUT:   %MakeSelf.ref: %MakeSelf.type = name_ref MakeSelf, @Class.%MakeSelf.decl [template = constants.%MakeSelf]
+// CHECK:STDOUT:   %.loc17_9: ref %Class.2 = splice_block %c.var {}
+// CHECK:STDOUT:   %MakeSelf.call: init %Class.2 = call %MakeSelf.ref() to %.loc17_9
+// CHECK:STDOUT:   assign %c.var, %MakeSelf.call
+// CHECK:STDOUT:   %Self.ref: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
+// CHECK:STDOUT:   %s.var: ref %Class.2 = var s
+// CHECK:STDOUT:   %s: ref %Class.2 = bind_name s, %s.var
+// CHECK:STDOUT:   %MakeClass.ref: %MakeClass.type = name_ref MakeClass, @Class.%MakeClass.decl [template = constants.%MakeClass]
+// CHECK:STDOUT:   %.loc18: ref %Class.2 = splice_block %s.var {}
+// CHECK:STDOUT:   %MakeClass.call: init %Class.2 = call %MakeClass.ref() to %.loc18
+// CHECK:STDOUT:   assign %s.var, %MakeClass.call
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 3 - 3
toolchain/check/testdata/class/generic_method.carbon

@@ -22,7 +22,7 @@ fn Class(T:! type).F[self: Self](n: T) {}
 // CHECK:STDOUT:   %Class.type: type = generic_class_type @Class [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Class.1: %Class.type = struct_value () [template]
-// CHECK:STDOUT:   %Class.2: type = class_type @Class [template]
+// CHECK:STDOUT:   %Class.2: type = class_type @Class, (%T) [symbolic]
 // CHECK:STDOUT:   %.2: type = unbound_element_type %Class.2, %T [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
@@ -43,7 +43,7 @@ fn Class(T:! type).F[self: Self](n: T) {}
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
 // CHECK:STDOUT:     %T.loc16_10.1: type = param T
 // CHECK:STDOUT:     %T.loc16_10.2: type = bind_symbolic_name T 0, %T.loc16_10.1 [symbolic = constants.%T]
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
 // CHECK:STDOUT:     %self.loc16_22.1: %Class.2 = param self
 // CHECK:STDOUT:     @F.%self: %Class.2 = bind_name self, %self.loc16_22.1
 // CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc16_10.2 [symbolic = constants.%T]
@@ -57,7 +57,7 @@ fn Class(T:! type).F[self: Self](n: T) {}
 // CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
 // CHECK:STDOUT:   %.loc12: %.2 = field_decl a, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Class.2 [symbolic = constants.%Class.2]
 // CHECK:STDOUT:     %self.loc13_8.1: %Class.2 = param self
 // CHECK:STDOUT:     %self.loc13_8.2: %Class.2 = bind_name self, %self.loc13_8.1
 // CHECK:STDOUT:     %T.ref.loc13: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]

+ 11 - 11
toolchain/check/testdata/impl/fail_extend_impl_forall.carbon

@@ -28,13 +28,13 @@ class C {
 // CHECK:STDOUT:   %GenericInterface.type: type = generic_interface_type @GenericInterface [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %GenericInterface: %GenericInterface.type = struct_value () [template]
-// CHECK:STDOUT:   %Self: %GenericInterface = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.2: type = interface_type @GenericInterface, (%T) [symbolic]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
-// CHECK:STDOUT:   %.2: type = assoc_entity_type @GenericInterface, %F.type.1 [template]
-// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @GenericInterface.%F.decl [template]
+// CHECK:STDOUT:   %.3: type = assoc_entity_type @GenericInterface, %F.type.1 [template]
+// CHECK:STDOUT:   %.4: %.3 = assoc_entity element0, @GenericInterface.%F.decl [template]
 // CHECK:STDOUT:   %C: type = class_type @C [template]
-// CHECK:STDOUT:   %.4: type = interface_type @GenericInterface, (%T) [symbolic]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.5: <witness> = interface_witness (%F.2) [template]
@@ -57,13 +57,13 @@ class C {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @GenericInterface
 // CHECK:STDOUT:     generic [file.%T.loc11_28.2: type] {
-// CHECK:STDOUT:   %Self: %GenericInterface = bind_symbolic_name Self 1 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = constants.%Self]
 // CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {
 // CHECK:STDOUT:     %T.ref: type = name_ref T, file.%T.loc11_28.2 [symbolic = constants.%T]
 // CHECK:STDOUT:     %x.loc12_8.1: %T = param x
 // CHECK:STDOUT:     %x.loc12_8.2: %T = bind_name x, %x.loc12_8.1
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc12: %.2 = assoc_entity element0, %F.decl [template = constants.%.3]
+// CHECK:STDOUT:   %.loc12: %.3 = assoc_entity element0, %F.decl [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -71,7 +71,7 @@ class C {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.4 {
+// CHECK:STDOUT: impl @impl: %C as %.2 {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %T.ref: type = name_ref T, @C.%T.loc19_23.2 [symbolic = constants.%T]
 // CHECK:STDOUT:     %x.loc20_10.1: %T = param x
@@ -85,14 +85,14 @@ class C {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
-// CHECK:STDOUT:   %.loc19_54.1: type = value_of_initializer %.loc19_52 [symbolic = constants.%.4]
-// CHECK:STDOUT:   %.loc19_54.2: type = converted %.loc19_52, %.loc19_54.1 [symbolic = constants.%.4]
+// CHECK:STDOUT:   %.loc19_54.1: type = value_of_initializer %.loc19_52 [symbolic = constants.%.2]
+// CHECK:STDOUT:   %.loc19_54.2: type = converted %.loc19_52, %.loc19_54.1 [symbolic = constants.%.2]
 // CHECK:STDOUT:   impl_decl @impl {
 // CHECK:STDOUT:     %T.loc19_23.1: type = param T
 // CHECK:STDOUT:     %T.loc19_23.2: type = bind_symbolic_name T 0, %T.loc19_23.1 [symbolic = constants.%T]
 // CHECK:STDOUT:     %GenericInterface.ref: %GenericInterface.type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%GenericInterface]
 // CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc19_23.2 [symbolic = constants.%T]
-// CHECK:STDOUT:     %.loc19_52: init type = call %GenericInterface.ref(%T.ref) [symbolic = constants.%.4]
+// CHECK:STDOUT:     %.loc19_52: init type = call %GenericInterface.ref(%T.ref) [symbolic = constants.%.2]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -101,7 +101,7 @@ class C {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc12_8.2: %T)
-// CHECK:STDOUT:     generic [file.%T.loc11_28.2: type, @GenericInterface.%Self: %GenericInterface];
+// CHECK:STDOUT:     generic [file.%T.loc11_28.2: type, @GenericInterface.%Self: %.2];
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.2(@impl.%x.loc20_10.2: %T)
 // CHECK:STDOUT:     generic [@C.%T.loc19_23.2: type] {

+ 12 - 10
toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon

@@ -45,17 +45,19 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:   %.type.1: type = generic_interface_type @.1 [template]
 // CHECK:STDOUT:   %.2: type = tuple_type () [template]
 // CHECK:STDOUT:   %.3: %.type.1 = struct_value () [template]
-// CHECK:STDOUT:   %Self.1: %.3 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.4: type = interface_type @.1, (%T.1) [symbolic]
+// CHECK:STDOUT:   %Self.1: %.4 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %Generic.type: type = generic_interface_type @Generic [template]
 // CHECK:STDOUT:   %Generic: %Generic.type = struct_value () [template]
-// CHECK:STDOUT:   %.4: type = interface_type @.2 [template]
-// CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.5: type = interface_type @.2 [template]
+// CHECK:STDOUT:   %Self.2: %.5 = bind_symbolic_name Self 0 [symbolic]
 // CHECK:STDOUT:   %DifferentParams.type: type = generic_interface_type @DifferentParams [template]
 // CHECK:STDOUT:   %DifferentParams: %DifferentParams.type = struct_value () [template]
 // CHECK:STDOUT:   %T.2: %.2 = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %.type.2: type = generic_interface_type @.3 [template]
-// CHECK:STDOUT:   %.5: %.type.2 = struct_value () [template]
-// CHECK:STDOUT:   %Self.3: %.5 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.6: %.type.2 = struct_value () [template]
+// CHECK:STDOUT:   %.7: type = interface_type @.3, (%T.2) [symbolic]
+// CHECK:STDOUT:   %Self.3: %.7 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -73,12 +75,12 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:     %T.loc21_19.1: type = param T
 // CHECK:STDOUT:     %T.loc21_19.2: type = bind_symbolic_name T 0, %T.loc21_19.1 [symbolic = constants.%T.1]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.decl.loc29: type = interface_decl @.2 [template = constants.%.4] {}
+// CHECK:STDOUT:   %.decl.loc29: type = interface_decl @.2 [template = constants.%.5] {}
 // CHECK:STDOUT:   %DifferentParams.decl: %DifferentParams.type = interface_decl @DifferentParams [template = constants.%DifferentParams] {
 // CHECK:STDOUT:     %T.loc31_27.1: type = param T
 // CHECK:STDOUT:     %T.loc31_27.2: type = bind_symbolic_name T 0, %T.loc31_27.1 [symbolic = constants.%T.1]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.decl.loc38: %.type.2 = interface_decl @.3 [template = constants.%.5] {
+// CHECK:STDOUT:   %.decl.loc38: %.type.2 = interface_decl @.3 [template = constants.%.6] {
 // CHECK:STDOUT:     %.loc38_32.1: %.2 = tuple_literal ()
 // CHECK:STDOUT:     %.loc38_32.2: type = converted %.loc38_32.1, constants.%.2 [template = constants.%.2]
 // CHECK:STDOUT:     %T.loc38_27.1: %.2 = param T
@@ -90,7 +92,7 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @.1
 // CHECK:STDOUT:     generic [file.%T.loc19_22.2: type] {
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = constants.%Self.1]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 1 [symbolic = constants.%Self.1]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -101,7 +103,7 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:     generic [file.%T.loc21_19.2: type];
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @.2 {
-// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self.2]
+// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 0 [symbolic = constants.%Self.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -113,7 +115,7 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @.3
 // CHECK:STDOUT:     generic [file.%T.loc38_27.2: %.2] {
-// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 1 [symbolic = constants.%Self.3]
+// CHECK:STDOUT:   %Self: %.7 = bind_symbolic_name Self 1 [symbolic = constants.%Self.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self

+ 36 - 44
toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon

@@ -9,33 +9,16 @@
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon
 
 interface I(T:! type) {
-  // TODO: Declare `Self` as having type `I(T)` instead of `I`.
   // TODO: Use `default` here.
-  // CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+8]]:14: ERROR: Cannot implicitly convert from `<cannot stringify inst+7>` to `type`.
-  // CHECK:STDERR:   fn F[self: Self]() -> Self;
-  // CHECK:STDERR:              ^~~~
-  // CHECK:STDERR:
-  // CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+4]]:25: ERROR: Cannot implicitly convert from `<cannot stringify inst+7>` to `type`.
-  // CHECK:STDERR:   fn F[self: Self]() -> Self;
-  // CHECK:STDERR:                         ^~~~
-  // CHECK:STDERR:
   fn F[self: Self]() -> Self;
 }
 
-// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+14]]:1: ERROR: Duplicate name being declared in the same scope.
+// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+6]]:1: ERROR: Duplicate name being declared in the same scope.
 // CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; }
 // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE-6]]:3: Name is previously declared here.
 // CHECK:STDERR:   fn F[self: Self]() -> Self;
 // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
-// CHECK:STDERR:
-// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+7]]:24: ERROR: Cannot implicitly convert from `<cannot stringify inst+7>` to `type`.
-// CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; }
-// CHECK:STDERR:                        ^~~~
-// CHECK:STDERR:
-// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+3]]:35: ERROR: Cannot implicitly convert from `<cannot stringify inst+7>` to `type`.
-// CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; }
-// CHECK:STDERR:                                   ^~~~
 fn I(T:! type).F[self: Self]() -> Self { return self; }
 
 // CHECK:STDOUT: --- fail_todo_generic_default_fn.carbon
@@ -45,13 +28,14 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
 // CHECK:STDOUT:   %I.type: type = generic_interface_type @I [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %I: %I.type = struct_value () [template]
-// CHECK:STDOUT:   %Self: %I = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.2: type = interface_type @I, (%T) [symbolic]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
-// CHECK:STDOUT:   %.2: type = assoc_entity_type @I, %F.type [template]
-// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @I.%F.decl [template]
+// CHECK:STDOUT:   %.3: type = assoc_entity_type @I, %F.type [template]
+// CHECK:STDOUT:   %.4: %.3 = assoc_entity element0, @I.%F.decl [template]
 // CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
-// CHECK:STDOUT:   %.4: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.5: %.type = struct_value () [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -62,42 +46,50 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
 // CHECK:STDOUT:     %T.loc11_13.1: type = param T
 // CHECK:STDOUT:     %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.4] {
-// CHECK:STDOUT:     %T.loc39_6.1: type = param T
-// CHECK:STDOUT:     %T.loc39_6.2: type = bind_symbolic_name T 0, %T.loc39_6.1 [symbolic = constants.%T]
-// CHECK:STDOUT:     %Self.ref.loc39_24: %I = name_ref Self, @I.%Self [symbolic = constants.%Self]
-// CHECK:STDOUT:     %self.loc39_18.1: <error> = param self
-// CHECK:STDOUT:     @.1.%self: <error> = bind_name self, %self.loc39_18.1
-// CHECK:STDOUT:     %Self.ref.loc39_35: %I = name_ref Self, @I.%Self [symbolic = constants.%Self]
-// CHECK:STDOUT:     @.1.%return: ref <error> = var <return slot>
+// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.5] {
+// CHECK:STDOUT:     %T.loc22_6.1: type = param T
+// CHECK:STDOUT:     %T.loc22_6.2: type = bind_symbolic_name T 0, %T.loc22_6.1 [symbolic = constants.%T]
+// CHECK:STDOUT:     %Self.ref.loc22_24: %.2 = name_ref Self, @I.%Self [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc22_24.1: type = facet_type_access %Self.ref.loc22_24 [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc22_24.2: type = converted %Self.ref.loc22_24, %.loc22_24.1 [symbolic = constants.%Self]
+// CHECK:STDOUT:     %self.loc22_18.1: %Self = param self
+// CHECK:STDOUT:     @.1.%self: %Self = bind_name self, %self.loc22_18.1
+// CHECK:STDOUT:     %Self.ref.loc22_35: %.2 = name_ref Self, @I.%Self [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc22_35.1: type = facet_type_access %Self.ref.loc22_35 [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc22_35.2: type = converted %Self.ref.loc22_35, %.loc22_35.1 [symbolic = constants.%Self]
+// CHECK:STDOUT:     @.1.%return: ref %Self = var <return slot>
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @I
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
-// CHECK:STDOUT:   %Self: %I = bind_symbolic_name Self 1 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = constants.%Self]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
-// CHECK:STDOUT:     %Self.ref.loc22_14: %I = name_ref Self, %Self [symbolic = constants.%Self]
-// CHECK:STDOUT:     %self.loc22_8.1: <error> = param self
-// CHECK:STDOUT:     %self.loc22_8.2: <error> = bind_name self, %self.loc22_8.1
-// CHECK:STDOUT:     %Self.ref.loc22_25: %I = name_ref Self, %Self [symbolic = constants.%Self]
-// CHECK:STDOUT:     %return.var: ref <error> = var <return slot>
+// CHECK:STDOUT:     %Self.ref.loc13_14: %.2 = name_ref Self, %Self [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc13_14.1: type = facet_type_access %Self.ref.loc13_14 [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc13_14.2: type = converted %Self.ref.loc13_14, %.loc13_14.1 [symbolic = constants.%Self]
+// CHECK:STDOUT:     %self.loc13_8.1: %Self = param self
+// CHECK:STDOUT:     %self.loc13_8.2: %Self = bind_name self, %self.loc13_8.1
+// CHECK:STDOUT:     %Self.ref.loc13_25: %.2 = name_ref Self, %Self [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc13_25.1: type = facet_type_access %Self.ref.loc13_25 [symbolic = constants.%Self]
+// CHECK:STDOUT:     %.loc13_25.2: type = converted %Self.ref.loc13_25, %.loc13_25.1 [symbolic = constants.%Self]
+// CHECK:STDOUT:     %return.var: ref %Self = var <return slot>
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc22: %.2 = assoc_entity element0, %F.decl [template = constants.%.3]
+// CHECK:STDOUT:   %.loc13_29: %.3 = assoc_entity element0, %F.decl [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
-// CHECK:STDOUT:   .F = %.loc22
+// CHECK:STDOUT:   .F = %.loc13_29
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @F[@I.%self.loc22_8.2: <error>]() -> <error>
-// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type, @I.%Self: %I];
+// CHECK:STDOUT: fn @F[@I.%self.loc13_8.2: %Self]() -> %Self
+// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type, @I.%Self: %.2];
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @.1[%self: <error>]() -> <error>
-// CHECK:STDOUT:     generic [file.%T.loc39_6.2: type] {
+// CHECK:STDOUT: fn @.1[%self: %Self]() -> %Self
+// CHECK:STDOUT:     generic [file.%T.loc22_6.2: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %self.ref: <error> = name_ref self, %self
-// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT:   %self.ref: %Self = name_ref self, %self
+// CHECK:STDOUT:   return %self.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 66 - 63
toolchain/check/testdata/interface/no_prelude/generic.carbon

@@ -65,29 +65,31 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   %Simple.type: type = generic_interface_type @Simple [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Simple: %Simple.type = struct_value () [template]
-// CHECK:STDOUT:   %Self.1: %Simple = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.2: type = interface_type @Simple, (%T.1) [symbolic]
+// CHECK:STDOUT:   %Self.1: %.2 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %X: type = class_type @X [template]
-// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: type = struct_type {} [template]
 // CHECK:STDOUT:   %WithAssocFn.type: type = generic_interface_type @WithAssocFn [template]
 // CHECK:STDOUT:   %WithAssocFn: %WithAssocFn.type = struct_value () [template]
-// CHECK:STDOUT:   %Self.2: %WithAssocFn = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.4: type = interface_type @WithAssocFn, (%T.1) [symbolic]
+// CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
-// CHECK:STDOUT:   %.3: type = assoc_entity_type @WithAssocFn, %F.type.1 [template]
-// CHECK:STDOUT:   %.4: %.3 = assoc_entity element0, @WithAssocFn.%F.decl [template]
+// CHECK:STDOUT:   %.5: type = assoc_entity_type @WithAssocFn, %F.type.1 [template]
+// CHECK:STDOUT:   %.6: %.5 = assoc_entity element0, @WithAssocFn.%F.decl [template]
 // CHECK:STDOUT:   %C: type = class_type @C [template]
-// CHECK:STDOUT:   %.5: type = interface_type @Simple, (%C) [template]
-// CHECK:STDOUT:   %.6: <witness> = interface_witness () [template]
-// CHECK:STDOUT:   %.7: type = interface_type @WithAssocFn, (%C) [template]
+// CHECK:STDOUT:   %.7: type = interface_type @Simple, (%C) [template]
+// CHECK:STDOUT:   %.8: <witness> = interface_witness () [template]
+// CHECK:STDOUT:   %.9: type = interface_type @WithAssocFn, (%C) [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
-// CHECK:STDOUT:   %.8: <witness> = interface_witness (%F.2) [template]
-// CHECK:STDOUT:   %.9: type = ptr_type %.2 [template]
+// CHECK:STDOUT:   %.10: <witness> = interface_witness (%F.2) [template]
+// CHECK:STDOUT:   %.11: type = ptr_type %.3 [template]
 // CHECK:STDOUT:   %struct: %X = struct_value () [template]
 // CHECK:STDOUT:   %N: %T.1 = bind_symbolic_name N 1 [symbolic]
 // CHECK:STDOUT:   %WithImplicitArgs.type: type = generic_interface_type @WithImplicitArgs [template]
 // CHECK:STDOUT:   %WithImplicitArgs: %WithImplicitArgs.type = struct_value () [template]
-// CHECK:STDOUT:   %T.2: %.5 = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %T.2: %.7 = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %Receive.type: type = fn_type @Receive [template]
 // CHECK:STDOUT:   %Receive: %Receive.type = struct_value () [template]
 // CHECK:STDOUT:   %Pass.type: type = fn_type @Pass [template]
@@ -124,26 +126,26 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   %Receive.decl: %Receive.type = fn_decl @Receive [template = constants.%Receive] {
 // CHECK:STDOUT:     %Simple.ref.loc24: %Simple.type = name_ref Simple, %Simple.decl [template = constants.%Simple]
 // CHECK:STDOUT:     %C.ref.loc24: type = name_ref C, %C.decl [template = constants.%C]
-// CHECK:STDOUT:     %.loc24_22: init type = call %Simple.ref.loc24(%C.ref.loc24) [template = constants.%.5]
-// CHECK:STDOUT:     %.loc24_24.1: type = value_of_initializer %.loc24_22 [template = constants.%.5]
-// CHECK:STDOUT:     %.loc24_24.2: type = converted %.loc24_22, %.loc24_24.1 [template = constants.%.5]
-// CHECK:STDOUT:     %T.loc24_12.1: %.5 = param T
-// CHECK:STDOUT:     @Receive.%T: %.5 = bind_symbolic_name T 0, %T.loc24_12.1 [symbolic = constants.%T.2]
+// CHECK:STDOUT:     %.loc24_22: init type = call %Simple.ref.loc24(%C.ref.loc24) [template = constants.%.7]
+// CHECK:STDOUT:     %.loc24_24.1: type = value_of_initializer %.loc24_22 [template = constants.%.7]
+// CHECK:STDOUT:     %.loc24_24.2: type = converted %.loc24_22, %.loc24_24.1 [template = constants.%.7]
+// CHECK:STDOUT:     %T.loc24_12.1: %.7 = param T
+// CHECK:STDOUT:     @Receive.%T: %.7 = bind_symbolic_name T 0, %T.loc24_12.1 [symbolic = constants.%T.2]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Pass.decl: %Pass.type = fn_decl @Pass [template = constants.%Pass] {
 // CHECK:STDOUT:     %Simple.ref.loc25: %Simple.type = name_ref Simple, %Simple.decl [template = constants.%Simple]
 // CHECK:STDOUT:     %C.ref.loc25: type = name_ref C, %C.decl [template = constants.%C]
-// CHECK:STDOUT:     %.loc25_19: init type = call %Simple.ref.loc25(%C.ref.loc25) [template = constants.%.5]
-// CHECK:STDOUT:     %.loc25_21.1: type = value_of_initializer %.loc25_19 [template = constants.%.5]
-// CHECK:STDOUT:     %.loc25_21.2: type = converted %.loc25_19, %.loc25_21.1 [template = constants.%.5]
-// CHECK:STDOUT:     %T.loc25_9.1: %.5 = param T
-// CHECK:STDOUT:     @Pass.%T: %.5 = bind_symbolic_name T 0, %T.loc25_9.1 [symbolic = constants.%T.2]
+// CHECK:STDOUT:     %.loc25_19: init type = call %Simple.ref.loc25(%C.ref.loc25) [template = constants.%.7]
+// CHECK:STDOUT:     %.loc25_21.1: type = value_of_initializer %.loc25_19 [template = constants.%.7]
+// CHECK:STDOUT:     %.loc25_21.2: type = converted %.loc25_19, %.loc25_21.1 [template = constants.%.7]
+// CHECK:STDOUT:     %T.loc25_9.1: %.7 = param T
+// CHECK:STDOUT:     @Pass.%T: %.7 = bind_symbolic_name T 0, %T.loc25_9.1 [symbolic = constants.%T.2]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Simple
 // CHECK:STDOUT:     generic [file.%T.loc4_18.2: type] {
-// CHECK:STDOUT:   %Self: %Simple = bind_symbolic_name Self 1 [symbolic = constants.%Self.1]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = constants.%Self.1]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -152,12 +154,12 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @WithAssocFn
 // CHECK:STDOUT:     generic [file.%T.loc8_23.2: type] {
-// CHECK:STDOUT:   %Self: %WithAssocFn = bind_symbolic_name Self 1 [symbolic = constants.%Self.2]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 1 [symbolic = constants.%Self.2]
 // CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {
 // CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [template = constants.%X]
 // CHECK:STDOUT:     %return.var: ref %X = var <return slot>
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc10: %.3 = assoc_entity element0, %F.decl [template = constants.%.4]
+// CHECK:STDOUT:   %.loc10: %.5 = assoc_entity element0, %F.decl [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -168,19 +170,19 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT: interface @WithImplicitArgs
 // CHECK:STDOUT:     generic [file.%T.loc22_28.2: type, file.%N.loc22_38.2: %T.1];
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.5 {
-// CHECK:STDOUT:   %.1: <witness> = interface_witness () [template = constants.%.6]
+// CHECK:STDOUT: impl @impl.1: %C as %.7 {
+// CHECK:STDOUT:   %.1: <witness> = interface_witness () [template = constants.%.8]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.1
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C as %.9 {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [template = constants.%X]
 // CHECK:STDOUT:     %return.var: ref %X = var <return slot>
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F.decl) [template = constants.%.8]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F.decl) [template = constants.%.10]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .F = %F.decl
@@ -193,19 +195,19 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
-// CHECK:STDOUT:   %.loc14_19.1: type = value_of_initializer %.loc14_17 [template = constants.%.5]
-// CHECK:STDOUT:   %.loc14_19.2: type = converted %.loc14_17, %.loc14_19.1 [template = constants.%.5]
+// CHECK:STDOUT:   %.loc14_19.1: type = value_of_initializer %.loc14_17 [template = constants.%.7]
+// CHECK:STDOUT:   %.loc14_19.2: type = converted %.loc14_17, %.loc14_19.1 [template = constants.%.7]
 // CHECK:STDOUT:   impl_decl @impl.1 {
 // CHECK:STDOUT:     %Simple.ref: %Simple.type = name_ref Simple, file.%Simple.decl [template = constants.%Simple]
 // CHECK:STDOUT:     %C.ref.loc14: type = name_ref C, file.%C.decl [template = constants.%C]
-// CHECK:STDOUT:     %.loc14_17: init type = call %Simple.ref(%C.ref.loc14) [template = constants.%.5]
+// CHECK:STDOUT:     %.loc14_17: init type = call %Simple.ref(%C.ref.loc14) [template = constants.%.7]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc15_24.1: type = value_of_initializer %.loc15_22 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc15_24.2: type = converted %.loc15_22, %.loc15_24.1 [template = constants.%.7]
+// CHECK:STDOUT:   %.loc15_24.1: type = value_of_initializer %.loc15_22 [template = constants.%.9]
+// CHECK:STDOUT:   %.loc15_24.2: type = converted %.loc15_22, %.loc15_24.1 [template = constants.%.9]
 // CHECK:STDOUT:   impl_decl @impl.2 {
 // CHECK:STDOUT:     %WithAssocFn.ref: %WithAssocFn.type = name_ref WithAssocFn, file.%WithAssocFn.decl [template = constants.%WithAssocFn]
 // CHECK:STDOUT:     %C.ref.loc15: type = name_ref C, file.%C.decl [template = constants.%C]
-// CHECK:STDOUT:     %.loc15_22: init type = call %WithAssocFn.ref(%C.ref.loc15) [template = constants.%.7]
+// CHECK:STDOUT:     %.loc15_22: init type = call %WithAssocFn.ref(%C.ref.loc15) [template = constants.%.9]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -213,24 +215,24 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.1() -> %X
-// CHECK:STDOUT:     generic [file.%T.loc8_23.2: type, @WithAssocFn.%Self: %WithAssocFn];
+// CHECK:STDOUT:     generic [file.%T.loc8_23.2: type, @WithAssocFn.%Self: %.4];
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.2() -> @impl.2.%return.var: %X {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc17_15.1: %.2 = struct_literal ()
+// CHECK:STDOUT:   %.loc17_15.1: %.3 = struct_literal ()
 // CHECK:STDOUT:   %.loc17_15.2: init %X = class_init (), @impl.2.%return.var [template = constants.%struct]
 // CHECK:STDOUT:   %.loc17_16: init %X = converted %.loc17_15.1, %.loc17_15.2 [template = constants.%struct]
 // CHECK:STDOUT:   return %.loc17_16 to @impl.2.%return.var
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @Receive(%T: %.5)
-// CHECK:STDOUT:     generic [%T: %.5];
+// CHECK:STDOUT: fn @Receive(%T: %.7)
+// CHECK:STDOUT:     generic [%T: %.7];
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @Pass(%T: %.5)
-// CHECK:STDOUT:     generic [%T: %.5] {
+// CHECK:STDOUT: fn @Pass(%T: %.7)
+// CHECK:STDOUT:     generic [%T: %.7] {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %Receive.ref: %Receive.type = name_ref Receive, file.%Receive.decl [template = constants.%Receive]
-// CHECK:STDOUT:   %T.ref: %.5 = name_ref T, %T [symbolic = constants.%T.2]
+// CHECK:STDOUT:   %T.ref: %.7 = name_ref T, %T [symbolic = constants.%T.2]
 // CHECK:STDOUT:   %Receive.call: init %.1 = call %Receive.ref(%T.ref)
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -242,16 +244,17 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   %Generic.type: type = generic_interface_type @Generic [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Generic: %Generic.type = struct_value () [template]
-// CHECK:STDOUT:   %Self: %Generic = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.2: type = interface_type @Generic, (%T.1) [symbolic]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %A: type = class_type @A [template]
-// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: type = struct_type {} [template]
 // CHECK:STDOUT:   %B: type = class_type @B [template]
-// CHECK:STDOUT:   %.3: type = interface_type @Generic, (%A) [template]
-// CHECK:STDOUT:   %T.2: %.3 = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %.4: type = interface_type @Generic, (%A) [template]
+// CHECK:STDOUT:   %T.2: %.4 = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
-// CHECK:STDOUT:   %.4: type = interface_type @Generic, (%B) [template]
-// CHECK:STDOUT:   %T.3: %.4 = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %.5: type = interface_type @Generic, (%B) [template]
+// CHECK:STDOUT:   %T.3: %.5 = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
 // CHECK:STDOUT: }
@@ -273,26 +276,26 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
 // CHECK:STDOUT:     %Generic.ref.loc9: %Generic.type = name_ref Generic, %Generic.decl [template = constants.%Generic]
 // CHECK:STDOUT:     %A.ref: type = name_ref A, %A.decl [template = constants.%A]
-// CHECK:STDOUT:     %.loc9_17: init type = call %Generic.ref.loc9(%A.ref) [template = constants.%.3]
-// CHECK:STDOUT:     %.loc9_19.1: type = value_of_initializer %.loc9_17 [template = constants.%.3]
-// CHECK:STDOUT:     %.loc9_19.2: type = converted %.loc9_17, %.loc9_19.1 [template = constants.%.3]
-// CHECK:STDOUT:     %T.loc9_6.1: %.3 = param T
-// CHECK:STDOUT:     @F.%T: %.3 = bind_symbolic_name T 0, %T.loc9_6.1 [symbolic = constants.%T.2]
+// CHECK:STDOUT:     %.loc9_17: init type = call %Generic.ref.loc9(%A.ref) [template = constants.%.4]
+// CHECK:STDOUT:     %.loc9_19.1: type = value_of_initializer %.loc9_17 [template = constants.%.4]
+// CHECK:STDOUT:     %.loc9_19.2: type = converted %.loc9_17, %.loc9_19.1 [template = constants.%.4]
+// CHECK:STDOUT:     %T.loc9_6.1: %.4 = param T
+// CHECK:STDOUT:     @F.%T: %.4 = bind_symbolic_name T 0, %T.loc9_6.1 [symbolic = constants.%T.2]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
 // CHECK:STDOUT:     %Generic.ref.loc10: %Generic.type = name_ref Generic, %Generic.decl [template = constants.%Generic]
 // CHECK:STDOUT:     %B.ref: type = name_ref B, %B.decl [template = constants.%B]
-// CHECK:STDOUT:     %.loc10_17: init type = call %Generic.ref.loc10(%B.ref) [template = constants.%.4]
-// CHECK:STDOUT:     %.loc10_19.1: type = value_of_initializer %.loc10_17 [template = constants.%.4]
-// CHECK:STDOUT:     %.loc10_19.2: type = converted %.loc10_17, %.loc10_19.1 [template = constants.%.4]
-// CHECK:STDOUT:     %T.loc10_6.1: %.4 = param T
-// CHECK:STDOUT:     @G.%T: %.4 = bind_symbolic_name T 0, %T.loc10_6.1 [symbolic = constants.%T.3]
+// CHECK:STDOUT:     %.loc10_17: init type = call %Generic.ref.loc10(%B.ref) [template = constants.%.5]
+// CHECK:STDOUT:     %.loc10_19.1: type = value_of_initializer %.loc10_17 [template = constants.%.5]
+// CHECK:STDOUT:     %.loc10_19.2: type = converted %.loc10_17, %.loc10_19.1 [template = constants.%.5]
+// CHECK:STDOUT:     %T.loc10_6.1: %.5 = param T
+// CHECK:STDOUT:     @G.%T: %.5 = bind_symbolic_name T 0, %T.loc10_6.1 [symbolic = constants.%T.3]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Generic
 // CHECK:STDOUT:     generic [file.%T.loc4_19.2: type] {
-// CHECK:STDOUT:   %Self: %Generic = bind_symbolic_name Self 1 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = constants.%Self]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -309,14 +312,14 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   .Self = constants.%B
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @F(%T: %.3)
-// CHECK:STDOUT:     generic [%T: %.3];
+// CHECK:STDOUT: fn @F(%T: %.4)
+// CHECK:STDOUT:     generic [%T: %.4];
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @G(%T: %.4)
-// CHECK:STDOUT:     generic [%T: %.4] {
+// CHECK:STDOUT: fn @G(%T: %.5)
+// CHECK:STDOUT:     generic [%T: %.5] {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F]
-// CHECK:STDOUT:   %T.ref: %.4 = name_ref T, %T [symbolic = constants.%T.3]
+// CHECK:STDOUT:   %T.ref: %.5 = name_ref T, %T [symbolic = constants.%T.3]
 // CHECK:STDOUT:   %F.call: init %.1 = call %F.ref(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 22 - 21
toolchain/check/testdata/interface/no_prelude/generic_import.carbon

@@ -34,11 +34,12 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:   %AddWith.type: type = generic_interface_type @AddWith [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %AddWith: %AddWith.type = struct_value () [template]
-// CHECK:STDOUT:   %Self: %AddWith = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.2: type = interface_type @AddWith, (%T) [symbolic]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
-// CHECK:STDOUT:   %.2: type = assoc_entity_type @AddWith, %F.type [template]
-// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @AddWith.%F.decl [template]
+// CHECK:STDOUT:   %.3: type = assoc_entity_type @AddWith, %F.type [template]
+// CHECK:STDOUT:   %.4: %.3 = assoc_entity element0, @AddWith.%F.decl [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -53,9 +54,9 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @AddWith
 // CHECK:STDOUT:     generic [file.%T.loc4_19.2: type] {
-// CHECK:STDOUT:   %Self: %AddWith = bind_symbolic_name Self 1 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = constants.%Self]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {}
-// CHECK:STDOUT:   %.loc5: %.2 = assoc_entity element0, %F.decl [template = constants.%.3]
+// CHECK:STDOUT:   %.loc5: %.3 = assoc_entity element0, %F.decl [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -64,7 +65,7 @@ impl C as AddWith(C) {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F()
-// CHECK:STDOUT:     generic [file.%T.loc4_19.2: type, @AddWith.%Self: %AddWith];
+// CHECK:STDOUT:     generic [file.%T.loc4_19.2: type, @AddWith.%Self: %.2];
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- b.carbon
 // CHECK:STDOUT:
@@ -73,16 +74,16 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %AddWith.type: type = generic_interface_type @AddWith [template]
 // CHECK:STDOUT:   %.2: type = tuple_type () [template]
-// CHECK:STDOUT:   %AddWith.1: %AddWith.type = struct_value () [template]
-// CHECK:STDOUT:   %AddWith.2: %AddWith.type = struct_value () [template]
-// CHECK:STDOUT:   %Self: %AddWith.2 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %AddWith: %AddWith.type = struct_value () [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, <unexpected instref inst+13> [symbolic]
-// CHECK:STDOUT:   %.3: type = interface_type @AddWith, (%C) [template]
+// CHECK:STDOUT:   %.3: type = interface_type @AddWith, (%T) [symbolic]
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.4: type = interface_type @AddWith, (%C) [template]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
-// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.1) [template]
+// CHECK:STDOUT:   %.5: <witness> = interface_witness (%F.1) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -90,18 +91,18 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:     .AddWith = %import_ref.1
 // CHECK:STDOUT:     .C = %C.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1: %AddWith.type = import_ref ir1, inst+4, loaded [template = constants.%AddWith.1]
+// CHECK:STDOUT:   %import_ref.1: %AddWith.type = import_ref ir1, inst+4, loaded [template = constants.%AddWith]
 // CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir1, inst+8, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.4: %F.type.2 = import_ref ir1, inst+10, loaded [template = constants.%F.2]
-// CHECK:STDOUT:   %.loc7_20.1: type = value_of_initializer %.loc7_18 [template = constants.%.3]
-// CHECK:STDOUT:   %.loc7_20.2: type = converted %.loc7_18, %.loc7_20.1 [template = constants.%.3]
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir1, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.4: %F.type.2 = import_ref ir1, inst+11, loaded [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc7_20.1: type = value_of_initializer %.loc7_18 [template = constants.%.4]
+// CHECK:STDOUT:   %.loc7_20.2: type = converted %.loc7_18, %.loc7_20.1 [template = constants.%.4]
 // CHECK:STDOUT:   impl_decl @impl {
 // CHECK:STDOUT:     %C.ref.loc7_6: type = name_ref C, %C.decl [template = constants.%C]
-// CHECK:STDOUT:     %AddWith.ref: %AddWith.type = name_ref AddWith, %import_ref.1 [template = constants.%AddWith.1]
+// CHECK:STDOUT:     %AddWith.ref: %AddWith.type = name_ref AddWith, %import_ref.1 [template = constants.%AddWith]
 // CHECK:STDOUT:     %C.ref.loc7_19: type = name_ref C, %C.decl [template = constants.%C]
-// CHECK:STDOUT:     %.loc7_18: init type = call %AddWith.ref(%C.ref.loc7_19) [template = constants.%.3]
+// CHECK:STDOUT:     %.loc7_18: init type = call %AddWith.ref(%C.ref.loc7_19) [template = constants.%.4]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -112,9 +113,9 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:   witness = (file.%import_ref.4)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C as %.4 {
 // CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {}
-// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F.decl) [template = constants.%.4]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F.decl) [template = constants.%.5]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .F = %F.decl

+ 4 - 4
toolchain/check/testdata/packages/no_prelude/fail_export_name_params.carbon

@@ -35,10 +35,10 @@ export C2(T:! type);
 // CHECK:STDOUT:   %C1.type: type = generic_class_type @C1 [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %C1.1: %C1.type = struct_value () [template]
-// CHECK:STDOUT:   %C1.2: type = class_type @C1 [template]
+// CHECK:STDOUT:   %C1.2: type = class_type @C1, (%T) [symbolic]
 // CHECK:STDOUT:   %C2.type: type = generic_class_type @C2 [template]
 // CHECK:STDOUT:   %C2.1: %C2.type = struct_value () [template]
-// CHECK:STDOUT:   %C2.2: type = class_type @C2 [template]
+// CHECK:STDOUT:   %C2.2: type = class_type @C2, (%T) [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -68,11 +68,11 @@ export C2(T:! type);
 // CHECK:STDOUT:   %C1.type: type = generic_class_type @C1 [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %C1.1: %C1.type = struct_value () [template]
-// CHECK:STDOUT:   %C1.2: type = class_type @C1 [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, <unexpected instref inst+17> [symbolic]
+// CHECK:STDOUT:   %C1.2: type = class_type @C1, (%T) [symbolic]
 // CHECK:STDOUT:   %C2.type: type = generic_class_type @C2 [template]
 // CHECK:STDOUT:   %C2.1: %C2.type = struct_value () [template]
-// CHECK:STDOUT:   %C2.2: type = class_type @C2 [template]
+// CHECK:STDOUT:   %C2.2: type = class_type @C2, (%T) [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {

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

@@ -73,7 +73,7 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT:   %S: %.11 = bind_symbolic_name S 0 [symbolic]
 // CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%S) [symbolic]
 // CHECK:STDOUT:   %.12: type = struct_type {} [template]
 // CHECK:STDOUT:   %.13: i32 = int_literal 1 [template]
 // CHECK:STDOUT:   %.14: i32 = int_literal 2 [template]
@@ -202,9 +202,9 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
 // CHECK:STDOUT:   %.10: type = struct_type {} [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
 // CHECK:STDOUT:   %.11: type = struct_type {.a: i32, .b: i32} [template]
 // CHECK:STDOUT:   %S: %.11 = bind_symbolic_name S 0, <unexpected instref inst+100> [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%S) [symbolic]
 // CHECK:STDOUT:   %.12: i32 = int_literal 1 [template]
 // CHECK:STDOUT:   %.13: i32 = int_literal 2 [template]
 // CHECK:STDOUT:   %.14: type = ptr_type %.11 [template]
@@ -324,9 +324,9 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
 // CHECK:STDOUT:   %.3: type = struct_type {.a: i32, .b: i32} [template]
 // CHECK:STDOUT:   %S: %.3 = bind_symbolic_name S 0, <unexpected instref inst+18> [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%S) [symbolic]
 // CHECK:STDOUT:   %.4: i32 = int_literal 1 [template]
 // CHECK:STDOUT:   %.5: i32 = int_literal 2 [template]
 // CHECK:STDOUT:   %.6: type = struct_type {.c: i32, .d: i32} [template]
@@ -387,9 +387,9 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
 // CHECK:STDOUT:   %.3: type = struct_type {.a: i32, .b: i32} [template]
 // CHECK:STDOUT:   %S: %.3 = bind_symbolic_name S 0, <unexpected instref inst+18> [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%S) [symbolic]
 // CHECK:STDOUT:   %.4: i32 = int_literal 3 [template]
 // CHECK:STDOUT:   %.5: i32 = int_literal 4 [template]
 // CHECK:STDOUT:   %.6: type = ptr_type %.3 [template]

+ 4 - 4
toolchain/check/testdata/tuples/import.carbon

@@ -81,7 +81,7 @@ var c_bad: C((3, 4)) = F();
 // CHECK:STDOUT:   %X: %.9 = bind_symbolic_name X 0 [symbolic]
 // CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%X) [symbolic]
 // CHECK:STDOUT:   %.18: type = struct_type {} [template]
 // CHECK:STDOUT:   %tuple.5: %.9 = tuple_value (%.15, %.16) [template]
 // CHECK:STDOUT:   %C.3: type = class_type @C, (%tuple.5) [template]
@@ -228,8 +228,8 @@ var c_bad: C((3, 4)) = F();
 // CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
 // CHECK:STDOUT:   %.14: type = struct_type {} [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
 // CHECK:STDOUT:   %X: %.8 = bind_symbolic_name X 0, <unexpected instref inst+102> [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%X) [symbolic]
 // CHECK:STDOUT:   %.15: i32 = int_literal 1 [template]
 // CHECK:STDOUT:   %.16: i32 = int_literal 2 [template]
 // CHECK:STDOUT:   %tuple: %.8 = tuple_value (%.15, %.16) [template]
@@ -365,9 +365,9 @@ var c_bad: C((3, 4)) = F();
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
 // CHECK:STDOUT:   %.3: type = tuple_type (i32, i32) [template]
 // CHECK:STDOUT:   %X: %.3 = bind_symbolic_name X 0, <unexpected instref inst+14> [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%X) [symbolic]
 // CHECK:STDOUT:   %.4: i32 = int_literal 1 [template]
 // CHECK:STDOUT:   %.5: i32 = int_literal 2 [template]
 // CHECK:STDOUT:   %.6: i32 = int_literal 3 [template]
@@ -430,9 +430,9 @@ var c_bad: C((3, 4)) = F();
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = struct_type {} [template]
-// CHECK:STDOUT:   %C.2: type = class_type @C [template]
 // CHECK:STDOUT:   %.3: type = tuple_type (i32, i32) [template]
 // CHECK:STDOUT:   %X: %.3 = bind_symbolic_name X 0, <unexpected instref inst+14> [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, (%X) [symbolic]
 // CHECK:STDOUT:   %.4: i32 = int_literal 3 [template]
 // CHECK:STDOUT:   %.5: i32 = int_literal 4 [template]
 // CHECK:STDOUT:   %.6: type = ptr_type %.3 [template]