Răsfoiți Sursa

Substitute into generic class and interface definitions when we require them to be fully defined. (#4139)

When referring to a constant within a specific, such as a field of a
generic class, use that specific version of the constant's value.
Richard Smith 1 an în urmă
părinte
comite
fe359b1a08
36 a modificat fișierele cu 396 adăugiri și 290 ștergeri
  1. 7 2
      toolchain/check/context.cpp
  2. 5 0
      toolchain/check/decl_name_stack.cpp
  3. 10 6
      toolchain/check/eval.cpp
  4. 37 1
      toolchain/check/generic.cpp
  5. 6 0
      toolchain/check/generic.h
  6. 1 1
      toolchain/check/testdata/array/generic_empty.carbon
  7. 7 7
      toolchain/check/testdata/basics/no_prelude/raw_ir.carbon
  8. 1 1
      toolchain/check/testdata/builtins/int/make_type_signed.carbon
  9. 1 1
      toolchain/check/testdata/builtins/int/make_type_unsigned.carbon
  10. 2 2
      toolchain/check/testdata/class/fail_generic_method.carbon
  11. 16 11
      toolchain/check/testdata/class/generic/basic.carbon
  12. 4 0
      toolchain/check/testdata/class/generic/call.carbon
  13. 24 13
      toolchain/check/testdata/class/generic/fail_todo_use.carbon
  14. 96 150
      toolchain/check/testdata/class/generic/field.carbon
  15. 11 6
      toolchain/check/testdata/class/generic/import.carbon
  16. 1 1
      toolchain/check/testdata/class/generic/member_inline.carbon
  17. 7 1
      toolchain/check/testdata/class/generic/member_out_of_line.carbon
  18. 2 0
      toolchain/check/testdata/class/generic/self.carbon
  19. 7 2
      toolchain/check/testdata/class/generic_method.carbon
  20. 1 1
      toolchain/check/testdata/eval/fail_symbolic.carbon
  21. 4 4
      toolchain/check/testdata/eval/symbolic.carbon
  22. 4 4
      toolchain/check/testdata/function/generic/no_prelude/fail_type_param_mismatch.carbon
  23. 3 3
      toolchain/check/testdata/function/generic/no_prelude/indirect_generic_type.carbon
  24. 5 5
      toolchain/check/testdata/function/generic/no_prelude/type_param.carbon
  25. 4 4
      toolchain/check/testdata/function/generic/no_prelude/type_param_scope.carbon
  26. 7 7
      toolchain/check/testdata/function/generic/redeclare.carbon
  27. 7 2
      toolchain/check/testdata/impl/fail_extend_impl_forall.carbon
  28. 5 5
      toolchain/check/testdata/interface/no_prelude/as_type_of_type.carbon
  29. 3 0
      toolchain/check/testdata/interface/no_prelude/fail_add_member_outside_definition.carbon
  30. 12 2
      toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon
  31. 2 2
      toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon
  32. 42 32
      toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon
  33. 21 6
      toolchain/check/testdata/interface/no_prelude/generic.carbon
  34. 7 2
      toolchain/check/testdata/interface/no_prelude/generic_import.carbon
  35. 3 1
      toolchain/sem_ir/constant.cpp
  36. 21 5
      toolchain/sem_ir/generic.cpp

+ 7 - 2
toolchain/check/context.cpp

@@ -13,6 +13,7 @@
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/check/decl_name_stack.h"
 #include "toolchain/check/eval.h"
+#include "toolchain/check/generic.h"
 #include "toolchain/check/generic_region_stack.h"
 #include "toolchain/check/import_ref.h"
 #include "toolchain/check/inst_block_stack.h"
@@ -797,7 +798,9 @@ class TypeCompleter {
           }
           return false;
         }
-        // TODO: Trigger generic resolution here for a generic class.
+        if (inst.instance_id.is_valid()) {
+          ResolveSpecificDefinition(context_, inst.instance_id);
+        }
         Push(class_info.object_repr_id);
         break;
       }
@@ -1092,7 +1095,9 @@ auto Context::TryToDefineType(
       return false;
     }
 
-    // TODO: Trigger generic resolution here for a generic instance.
+    if (interface->instance_id.is_valid()) {
+      ResolveSpecificDefinition(*this, interface->instance_id);
+    }
   }
 
   return true;

+ 5 - 0
toolchain/check/decl_name_stack.cpp

@@ -206,6 +206,11 @@ static auto PushNameQualifierScope(Context& context,
   // parameter scope.
   context.scope_stack().PopIfEmpty();
 
+  // When declaring a member of a generic, resolve the self specific.
+  if (instance_id.is_valid()) {
+    ResolveSpecificDefinition(context, instance_id);
+  }
+
   context.scope_stack().Push(scope_inst_id, scope_id, instance_id, has_error);
 
   // Enter a parameter scope in case the qualified name itself has parameters.

+ 10 - 6
toolchain/check/eval.cpp

@@ -1332,12 +1332,16 @@ auto TryEvalInstInContext(EvalContext& eval_context, SemIR::InstId inst_id,
         const auto& specific =
             eval_context.generic_instances().Get(eval_context.specific_id);
         auto args = eval_context.inst_blocks().Get(specific.args_id);
-        CARBON_CHECK(static_cast<size_t>(bind_name.bind_index.index) <
-                     args.size())
-            << "Use of binding " << bind_name.bind_index
-            << " with no corresponding value.";
-        return eval_context.context.constant_values().Get(
-            args[bind_name.bind_index.index]);
+        if (static_cast<size_t>(bind_name.bind_index.index) >= args.size()) {
+          // TODO: For now we don't provide a mapping for the `Self` type in an
+          // interface, and fall back to the canonical constant type.
+          CARBON_CHECK(bind_name.name_id == SemIR::NameId::SelfType)
+              << "Use of binding " << bind_name.bind_index
+              << " with no corresponding value.";
+        } else {
+          return eval_context.context.constant_values().Get(
+              args[bind_name.bind_index.index]);
+        }
       }
 
       // The constant form of a symbolic binding is an idealized form of the

+ 37 - 1
toolchain/check/generic.cpp

@@ -130,7 +130,16 @@ static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id,
   context.inst_block_stack().Push();
 
   Map<SemIR::InstId, SemIR::InstId> constants_in_generic;
-  // TODO: For the definition region, populate constants from the declaration.
+
+  // For the definition region, populate constants from the declaration.
+  if (region == SemIR::GenericInstIndex::Region::Definition) {
+    auto decl_eval_block = context.inst_blocks().Get(
+        context.generics().Get(generic_id).decl_block_id);
+    for (auto inst_id : decl_eval_block) {
+      constants_in_generic.Insert(
+          context.constant_values().GetConstantInstId(inst_id), inst_id);
+    }
+  }
 
   // The work done in this loop might invalidate iterators into the generic
   // region stack, but shouldn't add new dependent instructions to the current
@@ -293,6 +302,33 @@ auto MakeGenericSelfInstance(Context& context, SemIR::GenericId generic_id)
   return MakeGenericInstance(context, generic_id, args_id);
 }
 
+auto ResolveSpecificDefinition(Context& context,
+                               SemIR::GenericInstanceId specific_id) -> bool {
+  auto& specific = context.generic_instances().Get(specific_id);
+  auto generic_id = specific.generic_id;
+
+  // TODO: Remove this once we import generics properly.
+  if (!generic_id.is_valid()) {
+    return true;
+  }
+
+  if (!specific.definition_block_id.is_valid()) {
+    // Evaluate the eval block for the definition of the generic.
+    auto& generic = context.generics().Get(generic_id);
+    if (!generic.definition_block_id.is_valid()) {
+      // The generic is not defined yet.
+      return false;
+    }
+    auto definition_block_id = TryEvalBlockForSpecific(
+        context, specific_id, SemIR::GenericInstIndex::Region::Definition);
+    // Note that TryEvalBlockForSpecific may reallocate the list of generic
+    // instances, so re-lookup the instance here.
+    context.generic_instances().Get(specific_id).definition_block_id =
+        definition_block_id;
+  }
+  return true;
+}
+
 auto GetTypeInInstance(Context& context, SemIR::GenericInstanceId instance_id,
                        SemIR::TypeId type_id) -> SemIR::TypeId {
   auto const_id = context.types().GetConstantId(type_id);

+ 6 - 0
toolchain/check/generic.h

@@ -46,6 +46,12 @@ auto MakeGenericInstance(Context& context, SemIR::GenericId generic_id,
 auto MakeGenericSelfInstance(Context& context, SemIR::GenericId generic_id)
     -> SemIR::GenericInstanceId;
 
+// Attempts to resolve the definition of the given specific, by evaluating the
+// eval block of the corresponding generic and storing a corresponding value
+// block in the specific. Returns false if a definition is not available.
+auto ResolveSpecificDefinition(Context& context,
+                               SemIR::GenericInstanceId specific_id) -> bool;
+
 // Gets the substituted value of a type within a specified instance of a
 // generic. Note that this does not perform substitution, and will return
 // `Invalid` if the substituted type is not yet known.

+ 1 - 1
toolchain/check/testdata/array/generic_empty.carbon

@@ -42,7 +42,7 @@ fn G(T:! type) {
 // CHECK:STDOUT: fn @G(%T: type)
 // CHECK:STDOUT:     generic [%T: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T.ref (constants.%T)]
+// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.loc13_16: i32 = int_literal 0 [template = constants.%.2]
 // CHECK:STDOUT:   %.loc13_17: type = array_type %.loc13_16, %T [symbolic = %.loc13_17 (constants.%.3)]
 // CHECK:STDOUT:   %arr.var: ref @G.%.loc13_17 (%.3) = var arr

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

@@ -41,7 +41,7 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:     type3:           {constant: template inst+10, value_rep: {kind: unknown, type: type<invalid>}}
 // CHECK:STDOUT:     type4:           {constant: symbolic 1, value_rep: {kind: pointer, type: type8}}
 // CHECK:STDOUT:     type5:           {constant: symbolic 2, value_rep: {kind: copy, type: type5}}
-// CHECK:STDOUT:     type6:           {constant: symbolic 3, value_rep: {kind: unknown, type: type<invalid>}}
+// CHECK:STDOUT:     type6:           {constant: symbolic 3, value_rep: {kind: pointer, type: type8}}
 // CHECK:STDOUT:     type7:           {constant: template inst+17, value_rep: {kind: none, type: type2}}
 // CHECK:STDOUT:     type8:           {constant: symbolic 4, value_rep: {kind: copy, type: type8}}
 // CHECK:STDOUT:   type_blocks:
@@ -73,17 +73,17 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:     'inst+17':         {kind: FunctionType, arg0: function0, type: typeTypeType}
 // CHECK:STDOUT:     'inst+18':         {kind: StructValue, arg0: empty, type: type7}
 // CHECK:STDOUT:     'inst+19':         {kind: PointerType, arg0: type4, type: typeTypeType}
-// CHECK:STDOUT:     'inst+20':         {kind: NameRef, arg0: name2, arg1: inst+6, type: type1}
+// CHECK:STDOUT:     'inst+20':         {kind: NameRef, arg0: name2, arg1: inst+6, type: type5}
 // CHECK:STDOUT:     'inst+21':         {kind: TupleLiteral, arg0: empty, type: type2}
-// CHECK:STDOUT:     'inst+22':         {kind: TupleLiteral, arg0: block13, type: type4}
-// CHECK:STDOUT:     'inst+23':         {kind: TupleAccess, arg0: inst+15, arg1: element0, type: type1}
-// CHECK:STDOUT:     'inst+24':         {kind: InitializeFrom, arg0: inst+20, arg1: inst+23, type: type1}
+// CHECK:STDOUT:     'inst+22':         {kind: TupleLiteral, arg0: block13, type: type6}
+// CHECK:STDOUT:     'inst+23':         {kind: TupleAccess, arg0: inst+15, arg1: element0, type: type5}
+// CHECK:STDOUT:     'inst+24':         {kind: InitializeFrom, arg0: inst+20, arg1: inst+23, type: type5}
 // CHECK:STDOUT:     'inst+25':         {kind: TupleAccess, arg0: inst+15, arg1: element1, type: type2}
 // CHECK:STDOUT:     'inst+26':         {kind: TupleInit, arg0: empty, arg1: inst+25, type: type2}
 // CHECK:STDOUT:     'inst+27':         {kind: TupleValue, arg0: block15, type: type2}
 // CHECK:STDOUT:     'inst+28':         {kind: Converted, arg0: inst+21, arg1: inst+26, type: type2}
-// CHECK:STDOUT:     'inst+29':         {kind: TupleInit, arg0: block14, arg1: inst+15, type: type4}
-// CHECK:STDOUT:     'inst+30':         {kind: Converted, arg0: inst+22, arg1: inst+29, type: type4}
+// CHECK:STDOUT:     'inst+29':         {kind: TupleInit, arg0: block14, arg1: inst+15, type: type6}
+// CHECK:STDOUT:     'inst+30':         {kind: Converted, arg0: inst+22, arg1: inst+29, type: type6}
 // CHECK:STDOUT:     'inst+31':         {kind: ReturnExpr, arg0: inst+30, arg1: inst+15}
 // CHECK:STDOUT:   constant_values:
 // CHECK:STDOUT:     'inst+0':          template inst+0

+ 1 - 1
toolchain/check/testdata/builtins/int/make_type_signed.carbon

@@ -213,7 +213,7 @@ var m: Int(1000000000);
 // CHECK:STDOUT: fn @Symbolic(%N: i32, %x: file.%int.make_type_signed.loc14_28 (%.6)) -> %.6
 // CHECK:STDOUT:     generic [%N: i32] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %x.ref: %.6 = name_ref x, %x
+// CHECK:STDOUT:   %x.ref: file.%int.make_type_signed.loc14_28 (%.6) = name_ref x, %x
 // CHECK:STDOUT:   return %x.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/builtins/int/make_type_unsigned.carbon

@@ -213,7 +213,7 @@ var m: UInt(1000000000);
 // CHECK:STDOUT: fn @Symbolic(%N: i32, %x: file.%int.make_type_unsigned.loc14_29 (%.6)) -> %.6
 // CHECK:STDOUT:     generic [%N: i32] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %x.ref: %.6 = name_ref x, %x
+// CHECK:STDOUT:   %x.ref: file.%int.make_type_unsigned.loc14_29 (%.6) = name_ref x, %x
 // CHECK:STDOUT:   return %x.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

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

@@ -82,7 +82,7 @@ fn Class(N:! i32).F[self: Self](n: T) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Class
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
-// CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T.ref.loc12 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = file.%T.loc11_13.2 (constants.%T)]
 // CHECK:STDOUT:   %.loc12: <unexpected instref inst+28> (%.2) = field_decl a, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
 // CHECK:STDOUT:     %.loc13: type = specific_constant constants.%Class.2, file.%Class.decl(constants.%T) [symbolic = %.loc13 (constants.%Class.2)]
@@ -122,7 +122,7 @@ fn Class(N:! i32).F[self: Self](n: T) {}
 // CHECK:STDOUT:   @Class.%T.ref.loc13 => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%Class.decl(@Class.%T.ref.loc12) {
+// CHECK:STDOUT: specific file.%Class.decl(file.%T.loc11_13.2) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
 // CHECK:STDOUT: }

+ 16 - 11
toolchain/check/testdata/class/generic/basic.carbon

@@ -75,7 +75,7 @@ class Class(T:! type) {
 // CHECK:STDOUT:     %T.ref.loc17: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T.ref.loc17 (constants.%T)]
 // CHECK:STDOUT:     %return.var.loc17: ref %T = var <return slot>
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %T.ref.loc21: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T.ref.loc21 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc21: type = name_ref T, file.%T.loc11_13.2 [symbolic = file.%T.loc11_13.2 (constants.%T)]
 // CHECK:STDOUT:   %.loc21: <unexpected instref inst+41> (%.4) = field_decl k, element0 [template]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -88,27 +88,32 @@ class Class(T:! type) {
 // CHECK:STDOUT: fn @GetAddr[addr @Class.%self.loc12_19.3: @Class.%.loc12_29 (%.2)]() -> %.3
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %self.ref: %.2 = name_ref self, @Class.%self.loc12_19.3
-// CHECK:STDOUT:   %.loc13_17.1: ref %Class.2 = deref %self.ref
-// CHECK:STDOUT:   %k.ref: %.4 = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
-// CHECK:STDOUT:   %.loc13_17.2: ref %T = class_element_access %.loc13_17.1, element0
-// CHECK:STDOUT:   %.loc13_12: %.3 = addr_of %.loc13_17.2
+// CHECK:STDOUT:   %self.ref: @Class.%.loc12_29 (%.2) = name_ref self, @Class.%self.loc12_19.3
+// CHECK:STDOUT:   %.loc13_17.1: ref @Class.%.loc12_25 (%Class.2) = deref %self.ref
+// CHECK:STDOUT:   %k.ref: <unexpected instref inst+49> (%.4) = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
+// CHECK:STDOUT:   %.loc13_17.2: ref @Class.%T.ref.loc12 (%T) = class_element_access %.loc13_17.1, element0
+// CHECK:STDOUT:   %.loc13_12: @Class.%.loc12_38 (%.3) = addr_of %.loc13_17.2
 // CHECK:STDOUT:   return %.loc13_12
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @GetValue[@Class.%self.loc17_15.2: @Class.%.loc17 (%Class.2)]() -> %T
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %self.ref: %Class.2 = name_ref self, @Class.%self.loc17_15.2
-// CHECK:STDOUT:   %k.ref: %.4 = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
-// CHECK:STDOUT:   %.loc18_16.1: ref %T = class_element_access %self.ref, element0
-// CHECK:STDOUT:   %.loc18_16.2: %T = bind_value %.loc18_16.1
+// CHECK:STDOUT:   %self.ref: @Class.%.loc17 (%Class.2) = name_ref self, @Class.%self.loc17_15.2
+// CHECK:STDOUT:   %k.ref: <unexpected instref inst+55> (%.4) = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
+// CHECK:STDOUT:   %.loc18_16.1: ref @Class.%T.ref.loc17 (%T) = class_element_access %self.ref, element0
+// CHECK:STDOUT:   %.loc18_16.2: @Class.%T.ref.loc17 (%T) = bind_value %.loc18_16.1
 // CHECK:STDOUT:   return %.loc18_16.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+40> => constants.%Class.2
+// CHECK:STDOUT:   <unexpected instref inst+41> => constants.%.4
+// CHECK:STDOUT:   <unexpected instref inst+37> => <unexpected instref inst+38>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Class.%GetAddr.decl(constants.%T) {
@@ -125,7 +130,7 @@ class Class(T:! type) {
 // CHECK:STDOUT:   @Class.%T.ref.loc17 => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%Class.decl(@Class.%T.ref.loc21) {
+// CHECK:STDOUT: specific file.%Class.decl(file.%T.loc11_13.2) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
 // CHECK:STDOUT: }

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

@@ -146,12 +146,16 @@ var a: Class(5, i32*);
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc4_13.2 => constants.%.3
 // CHECK:STDOUT:   file.%N.loc4_23.2 => constants.%.4
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Class.decl(constants.%.1, constants.%.6) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc4_13.2 => constants.%.1
 // CHECK:STDOUT:   file.%N.loc4_23.2 => constants.%.6
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_too_few.carbon

+ 24 - 13
toolchain/check/testdata/class/generic/fail_todo_use.carbon

@@ -56,9 +56,10 @@ fn Run() -> i32 {
 // CHECK:STDOUT:   %Run.type: type = fn_type @Run [template]
 // CHECK:STDOUT:   %Run: %Run.type = struct_value () [template]
 // CHECK:STDOUT:   %Class.3: type = class_type @Class, file.%Class.decl(i32) [template]
-// CHECK:STDOUT:   %.7: i32 = int_literal 0 [template]
-// CHECK:STDOUT:   %.8: type = struct_type {.k: i32} [template]
-// CHECK:STDOUT:   %.9: type = ptr_type %Class.3 [template]
+// CHECK:STDOUT:   %.7: type = unbound_element_type %Class.3, i32 [template]
+// CHECK:STDOUT:   %.8: i32 = int_literal 0 [template]
+// CHECK:STDOUT:   %.9: type = struct_type {.k: i32} [template]
+// CHECK:STDOUT:   %.10: type = ptr_type %Class.3 [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -99,7 +100,7 @@ fn Run() -> i32 {
 // CHECK:STDOUT:     %.loc12_34: type = ptr_type %T [symbolic = %.loc12_34 (constants.%.3)]
 // CHECK:STDOUT:     %return.var: ref %.3 = var <return slot>
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %T.ref.loc16: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T.ref.loc16 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc16: type = name_ref T, file.%T.loc11_13.2 [symbolic = file.%T.loc11_13.2 (constants.%T)]
 // CHECK:STDOUT:   %.loc16: <unexpected instref inst+32> (%.4) = field_decl k, element0 [template]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -111,11 +112,11 @@ fn Run() -> i32 {
 // CHECK:STDOUT: fn @Get[addr @Class.%self.loc12_15.3: @Class.%.loc12_25 (%.2)]() -> %.3
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %self.ref: %.2 = name_ref self, @Class.%self.loc12_15.3
-// CHECK:STDOUT:   %.loc13_17.1: ref %Class.2 = deref %self.ref
-// CHECK:STDOUT:   %k.ref: %.4 = name_ref k, @Class.%.loc16 [template = @Class.%.loc16]
-// CHECK:STDOUT:   %.loc13_17.2: ref %T = class_element_access %.loc13_17.1, element0
-// CHECK:STDOUT:   %.loc13_12: %.3 = addr_of %.loc13_17.2
+// CHECK:STDOUT:   %self.ref: @Class.%.loc12_25 (%.2) = name_ref self, @Class.%self.loc12_15.3
+// CHECK:STDOUT:   %.loc13_17.1: ref @Class.%.loc12_21 (%Class.2) = deref %self.ref
+// CHECK:STDOUT:   %k.ref: <unexpected instref inst+40> (%.4) = name_ref k, @Class.%.loc16 [template = @Class.%.loc16]
+// CHECK:STDOUT:   %.loc13_17.2: ref @Class.%T.ref.loc12 (%T) = class_element_access %.loc13_17.1, element0
+// CHECK:STDOUT:   %.loc13_12: @Class.%.loc12_34 (%.3) = addr_of %.loc13_17.2
 // CHECK:STDOUT:   return %.loc13_12
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -132,13 +133,13 @@ fn Run() -> i32 {
 // CHECK:STDOUT:   %.loc25_19.2: type = converted %.loc25_15.3, %.loc25_19.1 [template = constants.%Class.3]
 // CHECK:STDOUT:   %v.var: ref %Class.3 = var v
 // CHECK:STDOUT:   %v: ref %Class.3 = bind_name v, %v.var
-// CHECK:STDOUT:   %.loc25_29: i32 = int_literal 0 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc25_30: %.8 = struct_literal (%.loc25_29)
+// CHECK:STDOUT:   %.loc25_29: i32 = int_literal 0 [template = constants.%.8]
+// CHECK:STDOUT:   %.loc25_30: %.9 = struct_literal (%.loc25_29)
 // CHECK:STDOUT:   assign %v.var, <error>
 // CHECK:STDOUT:   %v.ref: ref %Class.3 = name_ref v, %v
 // CHECK:STDOUT:   %Get.ref: %Get.type = name_ref Get, @Class.%Get.decl [template = constants.%Get]
 // CHECK:STDOUT:   %.loc36_11: <bound method> = bound_method %v.ref, %Get.ref
-// CHECK:STDOUT:   %.loc36_10: %.9 = addr_of %v.ref
+// CHECK:STDOUT:   %.loc36_10: %.10 = addr_of %v.ref
 // CHECK:STDOUT:   %Get.call: init %.3 = call %.loc36_11(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
@@ -146,6 +147,11 @@ fn Run() -> i32 {
 // CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+31> => constants.%Class.2
+// CHECK:STDOUT:   <unexpected instref inst+32> => constants.%.4
+// CHECK:STDOUT:   <unexpected instref inst+28> => <unexpected instref inst+29>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Class.%Get.decl(constants.%T) {
@@ -156,7 +162,7 @@ fn Run() -> i32 {
 // CHECK:STDOUT:   @Class.%.loc12_34 => constants.%.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%Class.decl(@Class.%T.ref.loc16) {
+// CHECK:STDOUT: specific file.%Class.decl(file.%T.loc11_13.2) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
 // CHECK:STDOUT: }
@@ -164,5 +170,10 @@ fn Run() -> i32 {
 // CHECK:STDOUT: specific file.%Class.decl(i32) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+31> => constants.%Class.3
+// CHECK:STDOUT:   <unexpected instref inst+32> => constants.%.7
+// CHECK:STDOUT:   <unexpected instref inst+28> => <unexpected instref inst+29>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 96 - 150
toolchain/check/testdata/class/generic/field.carbon

@@ -7,47 +7,20 @@
 // TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic/field.carbon
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic/field.carbon
-// CHECK:STDERR: fail_todo_field.carbon: ERROR: Main//default previously provided by `field.carbon`.
-// CHECK:STDERR:
-
-// --- field.carbon
 
 class Class(T:! type) {
   var x: T;
 }
 
-// TODO: This case only works because the parameters of Class and G have the
-// same name and index, so canonicalize to the same type.
-fn G(T:! type, c: Class(T)) -> T {
+fn F(c: Class(i32)) -> i32 {
   return c.x;
 }
 
-// --- fail_todo_field.carbon
-
-class Class(T:! type) {
-  var x: T;
-}
-
-fn F(c: Class(i32)) -> i32 {
-  // CHECK:STDERR: fail_todo_field.carbon:[[@LINE+8]]:3: ERROR: Cannot implicitly convert from `T` to `i32`.
-  // CHECK:STDERR:   return c.x;
-  // CHECK:STDERR:   ^~~~~~~~~~~
-  // CHECK:STDERR:
-  // CHECK:STDERR: fail_todo_field.carbon:[[@LINE+4]]:10: ERROR: Cannot implicitly convert from `Class` to `Class`.
-  // CHECK:STDERR:   return c.x;
-  // CHECK:STDERR:          ^~~
-  // CHECK:STDERR:
+fn G(T:! type, c: Class(T)) -> T {
   return c.x;
 }
 
 fn H(U:! type, c: Class(U)) -> U {
-  // CHECK:STDERR: fail_todo_field.carbon:[[@LINE+7]]:3: ERROR: Cannot implicitly convert from `T` to `U`.
-  // CHECK:STDERR:   return c.x;
-  // CHECK:STDERR:   ^~~~~~~~~~~
-  // CHECK:STDERR:
-  // CHECK:STDERR: fail_todo_field.carbon:[[@LINE+3]]:10: ERROR: Cannot implicitly convert from `Class` to `Class`.
-  // CHECK:STDERR:   return c.x;
-  // CHECK:STDERR:          ^~~
   return c.x;
 }
 
@@ -61,94 +34,20 @@ fn H(U:! type, c: Class(U)) -> U {
 // CHECK:STDOUT:   %Class.2: type = class_type @Class, file.%Class.decl(%T) [symbolic]
 // CHECK:STDOUT:   %.2: type = unbound_element_type %Class.2, %T [symbolic]
 // CHECK:STDOUT:   %.3: type = struct_type {.x: %T} [symbolic]
-// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
-// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
-// CHECK:STDOUT:   %.4: type = ptr_type %.3 [symbolic]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
-// CHECK:STDOUT:     .Class = %Class.decl
-// CHECK:STDOUT:     .G = %G.decl
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %Core: <namespace> = namespace %Core.import, [template] {}
-// CHECK:STDOUT:   %Class.decl: %Class.type = class_decl @Class [template = constants.%Class.1] {
-// CHECK:STDOUT:     %T.loc2_13.1: type = param T
-// CHECK:STDOUT:     %T.loc2_13.2: type = bind_symbolic_name T 0, %T.loc2_13.1 [symbolic = %T.loc2_13.2 (constants.%T)]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
-// CHECK:STDOUT:     %T.loc8_6.1: type = param T
-// CHECK:STDOUT:     @G.%T: type = bind_symbolic_name T 0, %T.loc8_6.1 [symbolic = @G.%T (constants.%T)]
-// CHECK:STDOUT:     %Class.ref: %Class.type = name_ref Class, %Class.decl [template = constants.%Class.1]
-// CHECK:STDOUT:     %T.ref.loc8_25: type = name_ref T, @G.%T [symbolic = @G.%T (constants.%T)]
-// CHECK:STDOUT:     %.loc8_24: init type = call %Class.ref(%T.ref.loc8_25) [symbolic = %.loc8_24 (constants.%Class.2)]
-// CHECK:STDOUT:     %.loc8_26.1: type = value_of_initializer %.loc8_24 [symbolic = %.loc8_24 (constants.%Class.2)]
-// CHECK:STDOUT:     %.loc8_26.2: type = converted %.loc8_24, %.loc8_26.1 [symbolic = %.loc8_24 (constants.%Class.2)]
-// CHECK:STDOUT:     %c.loc8_16.1: file.%.loc8_24 (%Class.2) = param c
-// CHECK:STDOUT:     @G.%c: file.%.loc8_24 (%Class.2) = bind_name c, %c.loc8_16.1
-// CHECK:STDOUT:     %T.ref.loc8_32: type = name_ref T, @G.%T [symbolic = @G.%T (constants.%T)]
-// CHECK:STDOUT:     @G.%return: ref %T = var <return slot>
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: class @Class
-// CHECK:STDOUT:     generic [file.%T.loc2_13.2: type] {
-// CHECK:STDOUT:   %T.ref: type = name_ref T, file.%T.loc2_13.2 [symbolic = %T.ref (constants.%T)]
-// CHECK:STDOUT:   %.loc3: <unexpected instref inst+18> (%.2) = field_decl x, element0 [template]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%Class.2
-// CHECK:STDOUT:   .x = %.loc3
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: fn @G(%T: type, %c: file.%.loc8_24 (%Class.2)) -> %T
-// CHECK:STDOUT:     generic [%T: type] {
-// CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %c.ref: %Class.2 = name_ref c, %c
-// CHECK:STDOUT:   %x.ref: %.2 = name_ref x, @Class.%.loc3 [template = @Class.%.loc3]
-// CHECK:STDOUT:   %.loc9_11.1: ref %T = class_element_access %c.ref, element0
-// CHECK:STDOUT:   %.loc9_11.2: %T = bind_value %.loc9_11.1
-// CHECK:STDOUT:   return %.loc9_11.2
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
-// CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   file.%T.loc2_13.2 => constants.%T
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%Class.decl(@Class.%T.ref) {
-// CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   file.%T.loc2_13.2 => constants.%T
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%G.decl(constants.%T) {
-// CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   @G.%T => constants.%T
-// CHECK:STDOUT:   file.%.loc8_24 => constants.%Class.2
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_field.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, file.%Class.decl(%T) [symbolic]
-// CHECK:STDOUT:   %.2: type = unbound_element_type %Class.2, %T [symbolic]
-// CHECK:STDOUT:   %.3: type = struct_type {.x: %T} [symbolic]
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
 // CHECK:STDOUT:   %Class.3: type = class_type @Class, file.%Class.decl(i32) [template]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
-// CHECK:STDOUT:   %.4: type = ptr_type %.3 [symbolic]
+// CHECK:STDOUT:   %.4: type = unbound_element_type %Class.3, i32 [template]
+// CHECK:STDOUT:   %.5: type = ptr_type %.3 [symbolic]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
 // CHECK:STDOUT:   %U: type = bind_symbolic_name U 0 [symbolic]
 // CHECK:STDOUT:   %Class.4: type = class_type @Class, file.%Class.decl(%U) [symbolic]
 // CHECK:STDOUT:   %H.type: type = fn_type @H [template]
 // CHECK:STDOUT:   %H: %H.type = struct_value () [template]
+// CHECK:STDOUT:   %.6: type = unbound_element_type %Class.4, %U [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -161,52 +60,66 @@ fn H(U:! type, c: Class(U)) -> U {
 // CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Class = %Class.decl
 // CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     .G = %G.decl
 // CHECK:STDOUT:     .H = %H.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %Core: <namespace> = namespace %Core.import, [template] {}
 // CHECK:STDOUT:   %Class.decl: %Class.type = class_decl @Class [template = constants.%Class.1] {
-// CHECK:STDOUT:     %T.loc2_13.1: type = param T
-// CHECK:STDOUT:     %T.loc2_13.2: type = bind_symbolic_name T 0, %T.loc2_13.1 [symbolic = %T.loc2_13.2 (constants.%T)]
+// 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 = %T.loc11_13.2 (constants.%T)]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
-// CHECK:STDOUT:     %Class.ref.loc6: %Class.type = name_ref Class, %Class.decl [template = constants.%Class.1]
-// CHECK:STDOUT:     %int.make_type_32.loc6_15: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:     %.loc6_14.1: type = value_of_initializer %int.make_type_32.loc6_15 [template = i32]
-// CHECK:STDOUT:     %.loc6_14.2: type = converted %int.make_type_32.loc6_15, %.loc6_14.1 [template = i32]
-// CHECK:STDOUT:     %.loc6_14.3: init type = call %Class.ref.loc6(%.loc6_14.2) [template = constants.%Class.3]
-// CHECK:STDOUT:     %.loc6_18.1: type = value_of_initializer %.loc6_14.3 [template = constants.%Class.3]
-// CHECK:STDOUT:     %.loc6_18.2: type = converted %.loc6_14.3, %.loc6_18.1 [template = constants.%Class.3]
-// CHECK:STDOUT:     %c.loc6_6.1: %Class.3 = param c
-// CHECK:STDOUT:     @F.%c: %Class.3 = bind_name c, %c.loc6_6.1
-// CHECK:STDOUT:     %int.make_type_32.loc6_24: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:     %.loc6_24.1: type = value_of_initializer %int.make_type_32.loc6_24 [template = i32]
-// CHECK:STDOUT:     %.loc6_24.2: type = converted %int.make_type_32.loc6_24, %.loc6_24.1 [template = i32]
+// CHECK:STDOUT:     %Class.ref.loc15: %Class.type = name_ref Class, %Class.decl [template = constants.%Class.1]
+// CHECK:STDOUT:     %int.make_type_32.loc15_15: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc15_14.1: type = value_of_initializer %int.make_type_32.loc15_15 [template = i32]
+// CHECK:STDOUT:     %.loc15_14.2: type = converted %int.make_type_32.loc15_15, %.loc15_14.1 [template = i32]
+// CHECK:STDOUT:     %.loc15_14.3: init type = call %Class.ref.loc15(%.loc15_14.2) [template = constants.%Class.3]
+// CHECK:STDOUT:     %.loc15_18.1: type = value_of_initializer %.loc15_14.3 [template = constants.%Class.3]
+// CHECK:STDOUT:     %.loc15_18.2: type = converted %.loc15_14.3, %.loc15_18.1 [template = constants.%Class.3]
+// CHECK:STDOUT:     %c.loc15_6.1: %Class.3 = param c
+// CHECK:STDOUT:     @F.%c: %Class.3 = bind_name c, %c.loc15_6.1
+// CHECK:STDOUT:     %int.make_type_32.loc15_24: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc15_24.1: type = value_of_initializer %int.make_type_32.loc15_24 [template = i32]
+// CHECK:STDOUT:     %.loc15_24.2: type = converted %int.make_type_32.loc15_24, %.loc15_24.1 [template = i32]
 // CHECK:STDOUT:     @F.%return: ref i32 = var <return slot>
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %T.loc19_6.1: type = param T
+// CHECK:STDOUT:     @G.%T: type = bind_symbolic_name T 0, %T.loc19_6.1 [symbolic = @G.%T (constants.%T)]
+// CHECK:STDOUT:     %Class.ref.loc19: %Class.type = name_ref Class, %Class.decl [template = constants.%Class.1]
+// CHECK:STDOUT:     %T.ref.loc19_25: type = name_ref T, @G.%T [symbolic = @G.%T (constants.%T)]
+// CHECK:STDOUT:     %.loc19_24: init type = call %Class.ref.loc19(%T.ref.loc19_25) [symbolic = %.loc19_24 (constants.%Class.2)]
+// CHECK:STDOUT:     %.loc19_26.1: type = value_of_initializer %.loc19_24 [symbolic = %.loc19_24 (constants.%Class.2)]
+// CHECK:STDOUT:     %.loc19_26.2: type = converted %.loc19_24, %.loc19_26.1 [symbolic = %.loc19_24 (constants.%Class.2)]
+// CHECK:STDOUT:     %c.loc19_16.1: file.%.loc19_24 (%Class.2) = param c
+// CHECK:STDOUT:     @G.%c: file.%.loc19_24 (%Class.2) = bind_name c, %c.loc19_16.1
+// CHECK:STDOUT:     %T.ref.loc19_32: type = name_ref T, @G.%T [symbolic = @G.%T (constants.%T)]
+// CHECK:STDOUT:     @G.%return: ref %T = var <return slot>
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:   %H.decl: %H.type = fn_decl @H [template = constants.%H] {
-// CHECK:STDOUT:     %U.loc18_6.1: type = param U
-// CHECK:STDOUT:     @H.%U: type = bind_symbolic_name U 0, %U.loc18_6.1 [symbolic = @H.%U (constants.%U)]
-// CHECK:STDOUT:     %Class.ref.loc18: %Class.type = name_ref Class, %Class.decl [template = constants.%Class.1]
-// CHECK:STDOUT:     %U.ref.loc18_25: type = name_ref U, @H.%U [symbolic = @H.%U (constants.%U)]
-// CHECK:STDOUT:     %.loc18_24: init type = call %Class.ref.loc18(%U.ref.loc18_25) [symbolic = %.loc18_24 (constants.%Class.4)]
-// CHECK:STDOUT:     %.loc18_26.1: type = value_of_initializer %.loc18_24 [symbolic = %.loc18_24 (constants.%Class.4)]
-// CHECK:STDOUT:     %.loc18_26.2: type = converted %.loc18_24, %.loc18_26.1 [symbolic = %.loc18_24 (constants.%Class.4)]
-// CHECK:STDOUT:     %c.loc18_16.1: file.%.loc18_24 (%Class.4) = param c
-// CHECK:STDOUT:     @H.%c: file.%.loc18_24 (%Class.4) = bind_name c, %c.loc18_16.1
-// CHECK:STDOUT:     %U.ref.loc18_32: type = name_ref U, @H.%U [symbolic = @H.%U (constants.%U)]
+// CHECK:STDOUT:     %U.loc23_6.1: type = param U
+// CHECK:STDOUT:     @H.%U: type = bind_symbolic_name U 0, %U.loc23_6.1 [symbolic = @H.%U (constants.%U)]
+// CHECK:STDOUT:     %Class.ref.loc23: %Class.type = name_ref Class, %Class.decl [template = constants.%Class.1]
+// CHECK:STDOUT:     %U.ref.loc23_25: type = name_ref U, @H.%U [symbolic = @H.%U (constants.%U)]
+// CHECK:STDOUT:     %.loc23_24: init type = call %Class.ref.loc23(%U.ref.loc23_25) [symbolic = %.loc23_24 (constants.%Class.4)]
+// CHECK:STDOUT:     %.loc23_26.1: type = value_of_initializer %.loc23_24 [symbolic = %.loc23_24 (constants.%Class.4)]
+// CHECK:STDOUT:     %.loc23_26.2: type = converted %.loc23_24, %.loc23_26.1 [symbolic = %.loc23_24 (constants.%Class.4)]
+// CHECK:STDOUT:     %c.loc23_16.1: file.%.loc23_24 (%Class.4) = param c
+// CHECK:STDOUT:     @H.%c: file.%.loc23_24 (%Class.4) = bind_name c, %c.loc23_16.1
+// CHECK:STDOUT:     %U.ref.loc23_32: type = name_ref U, @H.%U [symbolic = @H.%U (constants.%U)]
 // CHECK:STDOUT:     @H.%return: ref %U = var <return slot>
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Class
-// CHECK:STDOUT:     generic [file.%T.loc2_13.2: type] {
-// CHECK:STDOUT:   %T.ref: type = name_ref T, file.%T.loc2_13.2 [symbolic = %T.ref (constants.%T)]
-// CHECK:STDOUT:   %.loc3: <unexpected instref inst+18> (%.2) = field_decl x, element0 [template]
+// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
+// CHECK:STDOUT:   %T.ref: type = name_ref T, file.%T.loc11_13.2 [symbolic = file.%T.loc11_13.2 (constants.%T)]
+// CHECK:STDOUT:   %.loc12: <unexpected instref inst+18> (%.2) = field_decl x, element0 [template]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Class.2
-// CHECK:STDOUT:   .x = %.loc3
+// CHECK:STDOUT:   .x = %.loc12
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
@@ -214,43 +127,76 @@ fn H(U:! type, c: Class(U)) -> U {
 // CHECK:STDOUT: fn @F(%c: %Class.3) -> i32 {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %c.ref: %Class.3 = name_ref c, %c
-// CHECK:STDOUT:   %x.ref: %.2 = name_ref x, @Class.%.loc3 [template = @Class.%.loc3]
-// CHECK:STDOUT:   %.loc15: %T = class_element_access <error>, element0 [template = <error>]
-// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT:   %x.ref: %.4 = name_ref x, @Class.%.loc12 [template = @Class.%.loc12]
+// CHECK:STDOUT:   %.loc16_11.1: ref i32 = class_element_access %c.ref, element0
+// CHECK:STDOUT:   %.loc16_11.2: i32 = bind_value %.loc16_11.1
+// CHECK:STDOUT:   return %.loc16_11.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @H(%U: type, %c: file.%.loc18_24 (%Class.4)) -> %U
+// CHECK:STDOUT: fn @G(%T: type, %c: file.%.loc19_24 (%Class.2)) -> %T
+// CHECK:STDOUT:     generic [%T: type] {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %c.ref: file.%.loc19_24 (%Class.2) = name_ref c, %c
+// CHECK:STDOUT:   %x.ref: <unexpected instref inst+68> (%.2) = name_ref x, @Class.%.loc12 [template = @Class.%.loc12]
+// CHECK:STDOUT:   %.loc20_11.1: ref @G.%T (%T) = class_element_access %c.ref, element0
+// CHECK:STDOUT:   %.loc20_11.2: @G.%T (%T) = bind_value %.loc20_11.1
+// CHECK:STDOUT:   return %.loc20_11.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @H(%U: type, %c: file.%.loc23_24 (%Class.4)) -> %U
 // CHECK:STDOUT:     generic [%U: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %c.ref: %Class.4 = name_ref c, %c
-// CHECK:STDOUT:   %x.ref: %.2 = name_ref x, @Class.%.loc3 [template = @Class.%.loc3]
-// CHECK:STDOUT:   %.loc26: %T = class_element_access <error>, element0 [template = <error>]
-// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT:   %c.ref: file.%.loc23_24 (%Class.4) = name_ref c, %c
+// CHECK:STDOUT:   %x.ref: <unexpected instref inst+91> (%.6) = name_ref x, @Class.%.loc12 [template = @Class.%.loc12]
+// CHECK:STDOUT:   %.loc24_11.1: ref @H.%U (%U) = class_element_access %c.ref, element0
+// CHECK:STDOUT:   %.loc24_11.2: @H.%U (%U) = bind_value %.loc24_11.1
+// CHECK:STDOUT:   return %.loc24_11.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   file.%T.loc2_13.2 => constants.%T
+// CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+17> => constants.%Class.2
+// CHECK:STDOUT:   <unexpected instref inst+18> => constants.%.2
+// CHECK:STDOUT:   <unexpected instref inst+14> => <unexpected instref inst+15>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%Class.decl(@Class.%T.ref) {
+// CHECK:STDOUT: specific file.%Class.decl(file.%T.loc11_13.2) {
 // CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   file.%T.loc2_13.2 => constants.%T
+// CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Class.decl(i32) {
 // CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   file.%T.loc2_13.2 => i32
+// CHECK:STDOUT:   file.%T.loc11_13.2 => i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+17> => constants.%Class.3
+// CHECK:STDOUT:   <unexpected instref inst+18> => constants.%.4
+// CHECK:STDOUT:   <unexpected instref inst+14> => <unexpected instref inst+15>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%G.decl(constants.%T) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   @G.%T => constants.%T
+// CHECK:STDOUT:   file.%.loc19_24 => constants.%Class.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Class.decl(constants.%U) {
 // CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   file.%T.loc2_13.2 => constants.%U
+// CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%U
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+17> => constants.%Class.4
+// CHECK:STDOUT:   <unexpected instref inst+18> => constants.%.6
+// CHECK:STDOUT:   <unexpected instref inst+14> => <unexpected instref inst+15>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%H.decl(constants.%U) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   @H.%U => constants.%U
-// CHECK:STDOUT:   file.%.loc18_24 => constants.%Class.4
+// CHECK:STDOUT:   file.%.loc23_24 => constants.%Class.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

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

@@ -154,7 +154,7 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %int.make_type_32.loc7: init type = call constants.%Int32() [template = i32]
 // CHECK:STDOUT:   %.loc7_10.1: type = value_of_initializer %int.make_type_32.loc7 [template = i32]
 // CHECK:STDOUT:   %.loc7_10.2: type = converted %int.make_type_32.loc7, %.loc7_10.1 [template = i32]
-// CHECK:STDOUT:   %.loc7_8: %.2 = field_decl n, element0 [template]
+// CHECK:STDOUT:   %.loc7_8: <unexpected instref inst+39> (%.2) = field_decl n, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {
 // CHECK:STDOUT:     %int.make_type_32.loc8: init type = call constants.%Int32() [template = i32]
 // CHECK:STDOUT:     %.loc8_13.1: type = value_of_initializer %int.make_type_32.loc8 [template = i32]
@@ -193,6 +193,11 @@ class Class(U:! type) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%CompleteClass.decl(file.%T.loc6_21.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc6_21.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%CompleteClass.decl(i32) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc6_21.2 => i32
@@ -225,7 +230,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %Class.type = import_ref ir0, inst+6, loaded [template = constants.%Class.1]
 // CHECK:STDOUT:   %import_ref.2: %CompleteClass.type = import_ref ir0, inst+13, loaded [template = constants.%CompleteClass.1]
-// CHECK:STDOUT:   %import_ref.3: %F.type = import_ref ir0, inst+51, loaded [template = constants.%F]
+// CHECK:STDOUT:   %import_ref.3: %F.type = import_ref ir0, inst+53, loaded [template = constants.%F]
 // CHECK:STDOUT:   %import_ref.4 = import_ref ir0, inst+16, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref ir0, inst+26, unloaded
 // CHECK:STDOUT:   %import_ref.6 = import_ref ir0, inst+34, unloaded
@@ -316,7 +321,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref ir1, inst+6, unloaded
 // CHECK:STDOUT:   %import_ref.2: %CompleteClass.type = import_ref ir1, inst+13, loaded [template = constants.%CompleteClass.1]
-// CHECK:STDOUT:   %import_ref.3: %F.type.1 = import_ref ir1, inst+51, loaded [template = constants.%F.1]
+// CHECK:STDOUT:   %import_ref.3: %F.type.1 = import_ref ir1, inst+53, loaded [template = constants.%F.1]
 // CHECK:STDOUT:   %import_ref.4: %Int32.type = import_ref ir4, inst+4, loaded [template = constants.%Int32]
 // CHECK:STDOUT:   %import_ref.5 = import_ref ir1, inst+16, unloaded
 // CHECK:STDOUT:   %import_ref.6 = import_ref ir1, inst+26, unloaded
@@ -406,7 +411,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref ir1, inst+6, unloaded
 // CHECK:STDOUT:   %import_ref.2: %CompleteClass.type = import_ref ir1, inst+13, loaded [template = constants.%CompleteClass.1]
-// CHECK:STDOUT:   %import_ref.3: %F.type = import_ref ir1, inst+51, loaded [template = constants.%F]
+// CHECK:STDOUT:   %import_ref.3: %F.type = import_ref ir1, inst+53, loaded [template = constants.%F]
 // CHECK:STDOUT:   %import_ref.4: %Int32.type = import_ref ir4, inst+4, loaded [template = constants.%Int32]
 // CHECK:STDOUT:   %import_ref.5 = import_ref ir1, inst+16, unloaded
 // CHECK:STDOUT:   %import_ref.6: %.4 = import_ref ir1, inst+26, loaded [template = %.1]
@@ -493,7 +498,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref ir1, inst+6, unloaded
 // CHECK:STDOUT:   %import_ref.2: %CompleteClass.type = import_ref ir1, inst+13, loaded [template = constants.%CompleteClass.1]
-// CHECK:STDOUT:   %import_ref.3: %F.type = import_ref ir1, inst+51, loaded [template = constants.%F]
+// CHECK:STDOUT:   %import_ref.3: %F.type = import_ref ir1, inst+53, loaded [template = constants.%F]
 // CHECK:STDOUT:   %import_ref.4 = import_ref ir1, inst+16, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref ir1, inst+26, unloaded
 // CHECK:STDOUT:   %import_ref.6 = import_ref ir1, inst+34, unloaded
@@ -567,7 +572,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %Class.type = import_ref ir0, inst+6, loaded [template = constants.%Class.1]
 // CHECK:STDOUT:   %import_ref.2 = import_ref ir0, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref ir0, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir0, inst+53, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {

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

@@ -58,7 +58,7 @@ class Class(T:! type) {
 // CHECK:STDOUT: fn @F(@Class.%n.loc12_8.2: @Class.%T.ref.loc12_11 (%T)) -> %T
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %n.ref: %T = name_ref n, @Class.%n.loc12_8.2
+// CHECK:STDOUT:   %n.ref: @Class.%T.ref.loc12_11 (%T) = name_ref n, @Class.%n.loc12_8.2
 // CHECK:STDOUT:   return %n.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 7 - 1
toolchain/check/testdata/class/generic/member_out_of_line.carbon

@@ -152,13 +152,15 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT: fn @F(%n: %T) -> %T
 // CHECK:STDOUT:     generic [file.%T.loc4_13.2: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %n.ref: %T = name_ref n, %n
+// CHECK:STDOUT:   %n.ref: @Class.%T.ref.loc5_11 (%T) = name_ref n, %n
 // CHECK:STDOUT:   return %n.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc4_13.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Class.%F.decl(constants.%T) {
@@ -250,12 +252,16 @@ fn Generic(T:! ()).WrongType() {}
 // CHECK:STDOUT: specific file.%A.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc4_9.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @A.%B.decl(constants.%T, constants.%N) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   @A.%T.ref => constants.%T
 // CHECK:STDOUT:   @A.%N.loc5_11.2 => constants.%N
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @B.%F.decl(constants.%T, constants.%N) {

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

@@ -108,6 +108,8 @@ class Class(T:! type) {
 // CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Class.%MakeSelf.decl(constants.%T) {

+ 7 - 2
toolchain/check/testdata/class/generic_method.carbon

@@ -56,7 +56,7 @@ fn Class(T:! type).F[self: Self](n: T) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Class
 // CHECK:STDOUT:     generic [file.%T.loc11_13.2: type] {
-// CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T.ref.loc12 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = file.%T.loc11_13.2 (constants.%T)]
 // CHECK:STDOUT:   %.loc12: <unexpected instref inst+28> (%.2) = field_decl a, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
 // CHECK:STDOUT:     %.loc13: type = specific_constant constants.%Class.2, file.%Class.decl(constants.%T) [symbolic = %.loc13 (constants.%Class.2)]
@@ -83,6 +83,11 @@ fn Class(T:! type).F[self: Self](n: T) {}
 // CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+27> => constants.%Class.2
+// CHECK:STDOUT:   <unexpected instref inst+28> => constants.%.2
+// CHECK:STDOUT:   <unexpected instref inst+14> => <unexpected instref inst+15>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Class.%F.decl(constants.%T) {
@@ -91,7 +96,7 @@ fn Class(T:! type).F[self: Self](n: T) {}
 // CHECK:STDOUT:   @Class.%T.ref.loc13 => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific file.%Class.decl(@Class.%T.ref.loc12) {
+// CHECK:STDOUT: specific file.%Class.decl(file.%T.loc11_13.2) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
 // CHECK:STDOUT: }

+ 1 - 1
toolchain/check/testdata/eval/fail_symbolic.carbon

@@ -54,7 +54,7 @@ fn G(N:! i32) {
 // CHECK:STDOUT:     generic [%N: i32] {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:   %N.ref: i32 = name_ref N, %N [symbolic = %N.ref (constants.%N)]
+// CHECK:STDOUT:   %N.ref: i32 = name_ref N, %N [symbolic = %N (constants.%N)]
 // CHECK:STDOUT:   %.loc16_11.1: type = value_of_initializer %int.make_type_32 [template = i32]
 // CHECK:STDOUT:   %.loc16_11.2: type = converted %int.make_type_32, %.loc16_11.1 [template = i32]
 // CHECK:STDOUT:   %.loc16_17: type = array_type %N.ref, i32 [template = <error>]

+ 4 - 4
toolchain/check/testdata/eval/symbolic.carbon

@@ -50,19 +50,19 @@ fn F(T:! type) {
 // CHECK:STDOUT: fn @F(%T: type)
 // CHECK:STDOUT:     generic [%T: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %T.ref.loc13_11: type = name_ref T, %T [symbolic = %T.ref.loc13_11 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc13_11: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.loc13_12: type = ptr_type %T [symbolic = %.loc13_12 (constants.%.2)]
-// CHECK:STDOUT:   %T.ref.loc13_21: type = name_ref T, %T [symbolic = %T.ref.loc13_11 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc13_21: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.loc13_15: type = const_type %T [symbolic = %.loc13_15 (constants.%.3)]
 // CHECK:STDOUT:   %.loc13_22.1: %.4 = tuple_literal (%.loc13_12, %.loc13_15)
 // CHECK:STDOUT:   %.loc13_22.2: type = converted %.loc13_22.1, constants.%.5 [symbolic = %.loc13_22.2 (constants.%.5)]
 // CHECK:STDOUT:   %u.var: ref @F.%.loc13_22.2 (%.5) = var u
 // CHECK:STDOUT:   %u: ref @F.%.loc13_22.2 (%.5) = bind_name u, %u.var
-// CHECK:STDOUT:   %T.ref.loc14: type = name_ref T, %T [symbolic = %T.ref.loc13_11 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc14: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.loc14: type = struct_type {.a: %T} [symbolic = %.loc14 (constants.%.8)]
 // CHECK:STDOUT:   %v.var: ref @F.%.loc14 (%.8) = var v
 // CHECK:STDOUT:   %v: ref @F.%.loc14 (%.8) = bind_name v, %v.var
-// CHECK:STDOUT:   %T.ref.loc15: type = name_ref T, %T [symbolic = %T.ref.loc13_11 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc15: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.loc15_14: i32 = int_literal 5 [template = constants.%.9]
 // CHECK:STDOUT:   %.loc15_15: type = array_type %.loc15_14, %T [symbolic = %.loc15_15 (constants.%.10)]
 // CHECK:STDOUT:   %w.var: ref @F.%.loc15_15 (%.10) = var w

+ 4 - 4
toolchain/check/testdata/function/generic/no_prelude/fail_type_param_mismatch.carbon

@@ -42,15 +42,15 @@ fn F(T:! type, U:! type) {
 // CHECK:STDOUT: fn @F(%T: type, %U: type)
 // CHECK:STDOUT:     generic [%T: type, %U: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T.ref (constants.%T)]
+// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.loc12: type = ptr_type %T [symbolic = %.loc12 (constants.%.2)]
 // CHECK:STDOUT:   %p.var: ref @F.%.loc12 (%.2) = var p
 // CHECK:STDOUT:   %p: ref @F.%.loc12 (%.2) = bind_name p, %p.var
-// CHECK:STDOUT:   %U.ref: type = name_ref U, %U [symbolic = %U.ref (constants.%U)]
+// CHECK:STDOUT:   %U.ref: type = name_ref U, %U [symbolic = %U (constants.%U)]
 // CHECK:STDOUT:   %p.ref: ref @F.%.loc12 (%.2) = name_ref p, %p
 // CHECK:STDOUT:   %.loc16_15: @F.%.loc12 (%.2) = bind_value %p.ref
-// CHECK:STDOUT:   %.loc16_14: ref @F.%T.ref (%T) = deref %.loc16_15
-// CHECK:STDOUT:   %n: @F.%U.ref (%U) = bind_name n, <error>
+// CHECK:STDOUT:   %.loc16_14: ref @F.%T (%T) = deref %.loc16_15
+// CHECK:STDOUT:   %n: @F.%U (%U) = bind_name n, <error>
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 3 - 3
toolchain/check/testdata/function/generic/no_prelude/indirect_generic_type.carbon

@@ -44,9 +44,9 @@ fn F(T:! type, p: T**) -> T* {
 // CHECK:STDOUT: fn @F(%T: type, %p: file.%.loc11_21 (%.2)) -> %.1
 // CHECK:STDOUT:     generic [%T: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %p.ref: %.2 = name_ref p, %p
-// CHECK:STDOUT:   %.loc12_10.1: ref %.1 = deref %p.ref
-// CHECK:STDOUT:   %.loc12_10.2: %.1 = bind_value %.loc12_10.1
+// CHECK:STDOUT:   %p.ref: file.%.loc11_21 (%.2) = name_ref p, %p
+// CHECK:STDOUT:   %.loc12_10.1: ref file.%.loc11_20 (%.1) = deref %p.ref
+// CHECK:STDOUT:   %.loc12_10.2: file.%.loc11_20 (%.1) = bind_value %.loc12_10.1
 // CHECK:STDOUT:   return %.loc12_10.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 5 - 5
toolchain/check/testdata/function/generic/no_prelude/type_param.carbon

@@ -36,16 +36,16 @@ fn F(T:! type) {
 // CHECK:STDOUT: fn @F(%T: type)
 // CHECK:STDOUT:     generic [%T: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, %T [symbolic = %T.ref.loc12 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.loc12: type = ptr_type %T [symbolic = %.loc12 (constants.%.2)]
 // CHECK:STDOUT:   %p.var: ref @F.%.loc12 (%.2) = var p
 // CHECK:STDOUT:   %p: ref @F.%.loc12 (%.2) = bind_name p, %p.var
-// CHECK:STDOUT:   %T.ref.loc13: type = name_ref T, %T [symbolic = %T.ref.loc12 (constants.%T)]
+// CHECK:STDOUT:   %T.ref.loc13: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %p.ref: ref @F.%.loc12 (%.2) = name_ref p, %p
 // CHECK:STDOUT:   %.loc13_15: @F.%.loc12 (%.2) = bind_value %p.ref
-// CHECK:STDOUT:   %.loc13_14.1: ref @F.%T.ref.loc12 (%T) = deref %.loc13_15
-// CHECK:STDOUT:   %.loc13_14.2: @F.%T.ref.loc12 (%T) = bind_value %.loc13_14.1
-// CHECK:STDOUT:   %n: @F.%T.ref.loc12 (%T) = bind_name n, %.loc13_14.2
+// CHECK:STDOUT:   %.loc13_14.1: ref @F.%T (%T) = deref %.loc13_15
+// CHECK:STDOUT:   %.loc13_14.2: @F.%T (%T) = bind_value %.loc13_14.1
+// CHECK:STDOUT:   %n: @F.%T (%T) = bind_name n, %.loc13_14.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 4 - 4
toolchain/check/testdata/function/generic/no_prelude/type_param_scope.carbon

@@ -40,10 +40,10 @@ fn F(T:! type, n: T) -> T {
 // CHECK:STDOUT: fn @F(%T: type, %n: @F.%T (%T)) -> %T
 // CHECK:STDOUT:     generic [%T: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T.ref (constants.%T)]
-// CHECK:STDOUT:   %n.ref: @F.%T.ref (%T) = name_ref n, %n
-// CHECK:STDOUT:   %m: @F.%T.ref (%T) = bind_name m, %n.ref
-// CHECK:STDOUT:   %m.ref: @F.%T.ref (%T) = name_ref m, %m
+// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %n.ref: @F.%T (%T) = name_ref n, %n
+// CHECK:STDOUT:   %m: @F.%T (%T) = bind_name m, %n.ref
+// CHECK:STDOUT:   %m.ref: @F.%T (%T) = name_ref m, %m
 // CHECK:STDOUT:   return %m.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 7 - 7
toolchain/check/testdata/function/generic/redeclare.carbon

@@ -138,10 +138,10 @@ fn F(U:! type, T:! type) -> U* {
 // CHECK:STDOUT:     generic [file.%T.loc4_6.2: type] {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl.loc4 [template = constants.%F]
-// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T.ref (constants.%T)]
-// CHECK:STDOUT:   %F.call: init <unexpected instref inst+26> (%.1) = call %F.ref(%T.ref)
-// CHECK:STDOUT:   %.loc7_14.1: <unexpected instref inst+26> (%.1) = value_of_initializer %F.call
-// CHECK:STDOUT:   %.loc7_14.2: <unexpected instref inst+26> (%.1) = converted %F.call, %.loc7_14.1
+// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = file.%T.loc4_6.2 (constants.%T)]
+// CHECK:STDOUT:   %F.call: init file.%.loc4 (%.1) = call %F.ref(%T.ref)
+// CHECK:STDOUT:   %.loc7_14.1: file.%.loc4 (%.1) = value_of_initializer %F.call
+// CHECK:STDOUT:   %.loc7_14.2: file.%.loc4 (%.1) = converted %F.call, %.loc7_14.1
 // CHECK:STDOUT:   return %.loc7_14.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -199,7 +199,7 @@ fn F(U:! type, T:! type) -> U* {
 // CHECK:STDOUT:     generic [%T: type, %U: type] {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F]
-// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T.ref (constants.%T)]
+// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %F.call: init <unexpected instref inst+32> (%.1) = call %F.ref(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
@@ -268,7 +268,7 @@ fn F(U:! type, T:! type) -> U* {
 // CHECK:STDOUT:     generic [%U: type, %T: type] {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F]
-// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T.ref (constants.%T.2)]
+// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T (constants.%T.2)]
 // CHECK:STDOUT:   %F.call: init %.1 = call %F.ref(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
@@ -337,7 +337,7 @@ fn F(U:! type, T:! type) -> U* {
 // CHECK:STDOUT:     generic [%U: type, %T: type] {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F]
-// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T.ref (constants.%T.2)]
+// CHECK:STDOUT:   %T.ref: type = name_ref T, %T [symbolic = %T (constants.%T.2)]
 // CHECK:STDOUT:   %F.call: init %.1 = call %F.ref(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }

+ 7 - 2
toolchain/check/testdata/impl/fail_extend_impl_forall.carbon

@@ -58,7 +58,7 @@ class C {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @GenericInterface
 // CHECK:STDOUT:     generic [file.%T.loc11_28.2: type] {
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+22> (%.2) = bind_symbolic_name Self 1 [symbolic = %Self (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 = %T.ref (constants.%T)]
 // CHECK:STDOUT:     %x.loc12_8.1: @GenericInterface.%T.ref (%T) = param x
@@ -102,7 +102,7 @@ class C {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc12_8.2: @GenericInterface.%T.ref (%T))
-// CHECK:STDOUT:     generic [file.%T.loc11_28.2: type, @GenericInterface.%Self: %.2];
+// CHECK:STDOUT:     generic [file.%T.loc11_28.2: type, @GenericInterface.%Self: <unexpected instref inst+22> (%.2)];
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.2(@impl.%x.loc20_10.2: @impl.%T.ref (%T))
 // CHECK:STDOUT:     generic [@C.%T.loc19_23.2: type] {
@@ -120,6 +120,11 @@ class C {
 // CHECK:STDOUT:   @GenericInterface.%T.ref => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%GenericInterface.decl(file.%T.loc11_28.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc11_28.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @impl.%F.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   @impl.%T.ref => constants.%T

+ 5 - 5
toolchain/check/testdata/interface/no_prelude/as_type_of_type.carbon

@@ -49,11 +49,11 @@ fn F(T:! Empty) {
 // CHECK:STDOUT: fn @F(%T: %.1)
 // CHECK:STDOUT:     generic [%T: %.1] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %T.ref: %.1 = name_ref T, %T [symbolic = %T.ref (constants.%T)]
-// CHECK:STDOUT:   %.loc14_10.1: type = facet_type_access %T.ref [symbolic = %T.ref (constants.%T)]
-// CHECK:STDOUT:   %.loc14_10.2: type = converted %T.ref, %.loc14_10.1 [symbolic = %T.ref (constants.%T)]
-// CHECK:STDOUT:   %x.var: ref @F.%T.ref (%T) = var x
-// CHECK:STDOUT:   %x: ref @F.%T.ref (%T) = bind_name x, %x.var
+// CHECK:STDOUT:   %T.ref: %.1 = name_ref T, %T [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %.loc14_10.1: type = facet_type_access %T.ref [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %.loc14_10.2: type = converted %T.ref, %.loc14_10.1 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %x.var: ref @F.%T (%T) = var x
+// CHECK:STDOUT:   %x: ref @F.%T (%T) = bind_name x, %x.var
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 3 - 0
toolchain/check/testdata/interface/no_prelude/fail_add_member_outside_definition.carbon

@@ -103,6 +103,9 @@ interface Outer {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Outer.%Inner.decl(constants.%Self.2) {
 // CHECK:STDOUT: declaration:
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   @Inner.%Self => constants.%Self.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Inner.%.decl(constants.%Self.2, constants.%Self.3) {

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

@@ -92,7 +92,7 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @.1
 // CHECK:STDOUT:     generic [file.%T.loc19_22.2: type] {
-// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.1)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+13> (%.4) = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -115,7 +115,7 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @.3
 // CHECK:STDOUT:     generic [file.%T.loc38_27.2: %.2] {
-// CHECK:STDOUT:   %Self: %.7 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.3)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+39> (%.7) = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.3)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -127,6 +127,11 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:   file.%T.loc19_22.2 => constants.%T.1
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%.decl.loc19(file.%T.loc19_22.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc19_22.2 => constants.%T.1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Generic.decl(constants.%T.1) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc21_19.2 => constants.%T.1
@@ -142,3 +147,8 @@ interface DifferentParams(T:! ()) {}
 // CHECK:STDOUT:   file.%T.loc38_27.2 => constants.%T.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%.decl.loc38(file.%T.loc38_27.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc38_27.2 => constants.%T.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 2 - 2
toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon

@@ -83,7 +83,7 @@ fn CallFacet(T:! Interface, x: T) {
 // CHECK:STDOUT: fn @CallStatic(%T: %.1)
 // CHECK:STDOUT:     generic [%T: %.1] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %T.ref: %.1 = name_ref T, %T [symbolic = %T.ref (constants.%T)]
+// CHECK:STDOUT:   %T.ref: %.1 = name_ref T, %T [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %F.ref: %.3 = name_ref F, @Interface.%.loc11 [template = constants.%.4]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -91,7 +91,7 @@ fn CallFacet(T:! Interface, x: T) {
 // CHECK:STDOUT: fn @CallFacet(%T: %.1, %x: @CallFacet.%T (%T))
 // CHECK:STDOUT:     generic [%T: %.1] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %x.ref: %T = name_ref x, %x
+// CHECK:STDOUT:   %x.ref: @CallFacet.%T (%T) = name_ref x, %x
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 42 - 32
toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon

@@ -29,11 +29,12 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %I: %I.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: type = interface_type @I, file.%I.decl(%T) [symbolic]
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %Self.1: %.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:   %.3: type = assoc_entity_type @I, %F.type [template]
 // CHECK:STDOUT:   %.4: %.3 = assoc_entity element0, @I.%F.decl [template]
+// CHECK:STDOUT:   %Self.2: <unexpected instref inst+28> (%.2) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
 // CHECK:STDOUT:   %.5: %.type = struct_value () [template]
 // CHECK:STDOUT: }
@@ -49,35 +50,35 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
 // 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 = %T.loc22_6.2 (constants.%T)]
-// CHECK:STDOUT:     %.loc22_24.1: <unexpected instref inst+42> (%.2) = specific_constant @I.%Self, %I.decl(constants.%T) [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     %Self.ref.loc22_24: <unexpected instref inst+42> (%.2) = name_ref Self, %.loc22_24.1 [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc22_24.2: type = facet_type_access %Self.ref.loc22_24 [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc22_24.3: type = converted %Self.ref.loc22_24, %.loc22_24.2 [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     %self.loc22_18.1: file.%.loc22_24.1 (%Self) = param self
-// CHECK:STDOUT:     @.1.%self: file.%.loc22_24.1 (%Self) = bind_name self, %self.loc22_18.1
-// CHECK:STDOUT:     %.loc22_35.1: <unexpected instref inst+42> (%.2) = specific_constant @I.%Self, %I.decl(constants.%T) [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     %Self.ref.loc22_35: <unexpected instref inst+42> (%.2) = name_ref Self, %.loc22_35.1 [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc22_35.2: type = facet_type_access %Self.ref.loc22_35 [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc22_35.3: type = converted %Self.ref.loc22_35, %.loc22_35.2 [symbolic = %.loc22_24.1 (constants.%Self)]
-// CHECK:STDOUT:     @.1.%return: ref %Self = var <return slot>
+// CHECK:STDOUT:     %.loc22_24.1: <unexpected instref inst+44> (%.2) = specific_constant @I.%Self, %I.decl(constants.%T) [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     %Self.ref.loc22_24: <unexpected instref inst+44> (%.2) = name_ref Self, %.loc22_24.1 [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     %.loc22_24.2: type = facet_type_access %Self.ref.loc22_24 [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     %.loc22_24.3: type = converted %Self.ref.loc22_24, %.loc22_24.2 [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     %self.loc22_18.1: file.%.loc22_24.1 (%Self.2) = param self
+// CHECK:STDOUT:     @.1.%self: file.%.loc22_24.1 (%Self.2) = bind_name self, %self.loc22_18.1
+// CHECK:STDOUT:     %.loc22_35.1: <unexpected instref inst+44> (%.2) = specific_constant @I.%Self, %I.decl(constants.%T) [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     %Self.ref.loc22_35: <unexpected instref inst+44> (%.2) = name_ref Self, %.loc22_35.1 [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     %.loc22_35.2: type = facet_type_access %Self.ref.loc22_35 [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     %.loc22_35.3: type = converted %Self.ref.loc22_35, %.loc22_35.2 [symbolic = %.loc22_24.1 (constants.%Self.2)]
+// CHECK:STDOUT:     @.1.%return: ref %Self.2 = 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: %.2 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+28> (%.2) = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
-// CHECK:STDOUT:     %.loc13_14.1: %.2 = specific_constant %Self, file.%I.decl(constants.%T) [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %Self.ref.loc13_14: %.2 = name_ref Self, %.loc13_14.1 [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc13_14.2: type = facet_type_access %Self.ref.loc13_14 [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc13_14.3: type = converted %Self.ref.loc13_14, %.loc13_14.2 [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %self.loc13_8.1: @I.%.loc13_14.1 (%Self) = param self
-// CHECK:STDOUT:     %self.loc13_8.2: @I.%.loc13_14.1 (%Self) = bind_name self, %self.loc13_8.1
-// CHECK:STDOUT:     %.loc13_25.1: %.2 = specific_constant %Self, file.%I.decl(constants.%T) [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %Self.ref.loc13_25: %.2 = name_ref Self, %.loc13_25.1 [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc13_25.2: type = facet_type_access %Self.ref.loc13_25 [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %.loc13_25.3: type = converted %Self.ref.loc13_25, %.loc13_25.2 [symbolic = %.loc13_14.1 (constants.%Self)]
-// CHECK:STDOUT:     %return.var: ref %Self = var <return slot>
+// CHECK:STDOUT:     %.loc13_14.1: %.2 = specific_constant %Self, file.%I.decl(constants.%T) [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %Self.ref.loc13_14: %.2 = name_ref Self, %.loc13_14.1 [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %.loc13_14.2: type = facet_type_access %Self.ref.loc13_14 [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %.loc13_14.3: type = converted %Self.ref.loc13_14, %.loc13_14.2 [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %self.loc13_8.1: @I.%.loc13_14.1 (%Self.1) = param self
+// CHECK:STDOUT:     %self.loc13_8.2: @I.%.loc13_14.1 (%Self.1) = bind_name self, %self.loc13_8.1
+// CHECK:STDOUT:     %.loc13_25.1: %.2 = specific_constant %Self, file.%I.decl(constants.%T) [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %Self.ref.loc13_25: %.2 = name_ref Self, %.loc13_25.1 [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %.loc13_25.2: type = facet_type_access %Self.ref.loc13_25 [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %.loc13_25.3: type = converted %Self.ref.loc13_25, %.loc13_25.2 [symbolic = %.loc13_14.1 (constants.%Self.1)]
+// CHECK:STDOUT:     %return.var: ref %Self.1 = var <return slot>
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc13_29: %.3 = assoc_entity element0, %F.decl [template = constants.%.4]
 // CHECK:STDOUT:
@@ -87,24 +88,33 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @F[@I.%self.loc13_8.2: @I.%.loc13_14.1 (%Self)]() -> %Self
-// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type, @I.%Self: %.2];
+// CHECK:STDOUT: fn @F[@I.%self.loc13_8.2: @I.%.loc13_14.1 (%Self.1)]() -> %Self.1
+// CHECK:STDOUT:     generic [file.%T.loc11_13.2: type, @I.%Self: <unexpected instref inst+28> (%.2)];
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @.1[%self: file.%.loc22_24.1 (%Self)]() -> %Self
+// CHECK:STDOUT: fn @.1[%self: file.%.loc22_24.1 (%Self.2)]() -> %Self.2
 // CHECK:STDOUT:     generic [file.%T.loc22_6.2: type] {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %self.ref: %Self = name_ref self, %self
+// CHECK:STDOUT:   %self.ref: file.%.loc22_24.1 (%Self.2) = name_ref self, %self
 // CHECK:STDOUT:   return %self.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%I.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: definition:
+// CHECK:STDOUT:   <unexpected instref inst+28> => constants.%.2
+// CHECK:STDOUT:   @I.%Self => constants.%Self.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @I.%F.decl(constants.%T, constants.%Self) {
+// CHECK:STDOUT: specific @I.%F.decl(constants.%T, constants.%Self.1) {
 // CHECK:STDOUT: declaration:
-// CHECK:STDOUT:   @I.%.loc13_14.1 => constants.%Self
+// CHECK:STDOUT:   @I.%.loc13_14.1 => constants.%Self.1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%I.decl(file.%T.loc11_13.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc11_13.2 => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%I.decl(file.%T.loc22_6.2) {
@@ -115,7 +125,7 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
 // CHECK:STDOUT: specific file.%.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc22_6.2 => constants.%T
-// CHECK:STDOUT:   <unexpected instref inst+42> => constants.%.2
-// CHECK:STDOUT:   file.%.loc22_24.1 => constants.%Self
+// CHECK:STDOUT:   <unexpected instref inst+44> => constants.%.2
+// CHECK:STDOUT:   file.%.loc22_24.1 => constants.%Self.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 21 - 6
toolchain/check/testdata/interface/no_prelude/generic.carbon

@@ -145,7 +145,7 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Simple
 // CHECK:STDOUT:     generic [file.%T.loc4_18.2: type] {
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.1)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+11> (%.2) = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -154,7 +154,7 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @WithAssocFn
 // CHECK:STDOUT:     generic [file.%T.loc8_23.2: type] {
-// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+31> (%.4) = bind_symbolic_name Self 1 [symbolic = %Self (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>
@@ -215,7 +215,7 @@ 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: %.4];
+// CHECK:STDOUT:     generic [file.%T.loc8_23.2: type, @WithAssocFn.%Self: <unexpected instref inst+31> (%.4)];
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.2() -> @impl.2.%return.var: %X {
 // CHECK:STDOUT: !entry:
@@ -232,7 +232,7 @@ fn G(T:! Generic(B)) {
 // 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: %.7 = name_ref T, %T [symbolic = %T.ref (constants.%T.2)]
+// CHECK:STDOUT:   %T.ref: %.7 = name_ref T, %T [symbolic = %T (constants.%T.2)]
 // CHECK:STDOUT:   %Receive.call: init %.1 = call %Receive.ref(%T.ref)
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -242,6 +242,11 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   file.%T.loc4_18.2 => constants.%T.1
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%Simple.decl(file.%T.loc4_18.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc4_18.2 => constants.%T.1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%WithAssocFn.decl(constants.%T.1) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc8_23.2 => constants.%T.1
@@ -251,6 +256,11 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%WithAssocFn.decl(file.%T.loc8_23.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc8_23.2 => constants.%T.1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Simple.decl(constants.%C) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc4_18.2 => constants.%C
@@ -335,7 +345,7 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Generic
 // CHECK:STDOUT:     generic [file.%T.loc4_19.2: type] {
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+11> (%.2) = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -359,7 +369,7 @@ fn G(T:! Generic(B)) {
 // 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: %.5 = name_ref T, %T [symbolic = %T.ref (constants.%T.3)]
+// CHECK:STDOUT:   %T.ref: %.5 = name_ref T, %T [symbolic = %T (constants.%T.3)]
 // CHECK:STDOUT:   %F.call: init %.1 = call %F.ref(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -369,6 +379,11 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   file.%T.loc4_19.2 => constants.%T.1
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%Generic.decl(file.%T.loc4_19.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc4_19.2 => constants.%T.1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%Generic.decl(constants.%A) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT:   file.%T.loc4_19.2 => constants.%A

+ 7 - 2
toolchain/check/testdata/interface/no_prelude/generic_import.carbon

@@ -54,7 +54,7 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @AddWith
 // CHECK:STDOUT:     generic [file.%T.loc4_19.2: type] {
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self: <unexpected instref inst+17> (%.2) = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {}
 // CHECK:STDOUT:   %.loc5: %.3 = assoc_entity element0, %F.decl [template = constants.%.4]
 // CHECK:STDOUT:
@@ -65,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: %.2];
+// CHECK:STDOUT:     generic [file.%T.loc4_19.2: type, @AddWith.%Self: <unexpected instref inst+17> (%.2)];
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific file.%AddWith.decl(constants.%T) {
 // CHECK:STDOUT: declaration:
@@ -76,6 +76,11 @@ impl C as AddWith(C) {
 // CHECK:STDOUT: declaration:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific file.%AddWith.decl(file.%T.loc4_19.2) {
+// CHECK:STDOUT: declaration:
+// CHECK:STDOUT:   file.%T.loc4_19.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- b.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {

+ 3 - 1
toolchain/sem_ir/constant.cpp

@@ -29,7 +29,9 @@ auto ConstantStore::GetOrAdd(Inst inst, bool is_symbolic) -> ConstantId {
     return const_id;
   });
   CARBON_CHECK(result.value() != ConstantId::Invalid);
-  CARBON_CHECK(result.value().is_symbolic() == is_symbolic);
+  CARBON_CHECK(result.value().is_symbolic() == is_symbolic)
+      << "Constant " << inst
+      << " registered as both symbolic and template constant.";
   return result.value();
 }
 

+ 21 - 5
toolchain/sem_ir/generic.cpp

@@ -53,8 +53,7 @@ auto GenericInstanceStore::CollectMemUsage(MemUsage& mem_usage,
                 KeyContext(generic_instances_.array_ref()));
 }
 
-auto GetConstantInInstance(const File& sem_ir,
-                           GenericInstanceId /*instance_id*/,
+auto GetConstantInInstance(const File& sem_ir, GenericInstanceId instance_id,
                            ConstantId const_id) -> ConstantId {
   if (!const_id.is_symbolic()) {
     // Type does not depend on a generic parameter.
@@ -67,9 +66,26 @@ auto GetConstantInInstance(const File& sem_ir,
     return const_id;
   }
 
-  // TODO: Look up the value in the generic instance. For now, return the
-  // canonical constant value.
-  return sem_ir.constant_values().Get(symbolic.inst_id);
+  if (!instance_id.is_valid()) {
+    // TODO: We have a generic constant but no instance. Investigate whether we
+    // can CHECK-fail here. For now, produce the canonical value of the
+    // constant.
+    return sem_ir.constant_values().Get(symbolic.inst_id);
+  }
+
+  const auto& specific = sem_ir.generic_instances().Get(instance_id);
+  if (specific.generic_id != symbolic.generic_id) {
+    // TODO: Given an instance for the wrong generic. If the symbolic constant
+    // is from an enclosing generic, take the value from the corresponding
+    // instance. Otherwise, CHECK-fail.
+    return sem_ir.constant_values().Get(symbolic.inst_id);
+  }
+
+  auto value_block_id = specific.GetValueBlock(symbolic.index.region());
+  CARBON_CHECK(value_block_id.is_valid())
+      << "Queried region of " << instance_id << " before it was resolved.";
+  return sem_ir.constant_values().Get(
+      sem_ir.inst_blocks().Get(value_block_id)[symbolic.index.index()]);
 }
 
 auto GetConstantValueInInstance(const File& sem_ir,