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

Track the type as written in `BaseDecl` and `AdaptDecl`. (#4564)

Represent the type as an `InstId` rather than as a `TypeId` to preserve
how it was written and better support tracking its value in a generic.
Add accessors to `Class` to get the base and adapted type to reduce code
duplication, and add `TypeStore::GetObjectRepr` to make it easier to map
from a type to its possibly-adapted object representation type. In
passing, also move `GetIntTypeInfo` and `GetUnqualifiedType` into
`TypeStore`.

This fixes specifics of generic adapters to properly look at the
specific adapted type, and also fixes importing of adapters.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Richard Smith 1 год назад
Родитель
Сommit
d6ec885eb3
51 измененных файлов с 1530 добавлено и 415 удалено
  1. 20 22
      toolchain/check/context.cpp
  2. 0 3
      toolchain/check/context.h
  3. 10 10
      toolchain/check/convert.cpp
  4. 7 5
      toolchain/check/eval.cpp
  5. 26 34
      toolchain/check/handle_class.cpp
  6. 42 7
      toolchain/check/import_ref.cpp
  7. 11 7
      toolchain/check/member_access.cpp
  8. 2 2
      toolchain/check/pointer_dereference.cpp
  9. 63 63
      toolchain/check/testdata/as/adapter_conversion.carbon
  10. 5 7
      toolchain/check/testdata/class/adapt.carbon
  11. 1 1
      toolchain/check/testdata/class/base.carbon
  12. 1 1
      toolchain/check/testdata/class/base_field.carbon
  13. 1 1
      toolchain/check/testdata/class/base_function_unqualified.carbon
  14. 1 1
      toolchain/check/testdata/class/base_method.carbon
  15. 1 1
      toolchain/check/testdata/class/base_method_qualified.carbon
  16. 3 3
      toolchain/check/testdata/class/base_method_shadow.carbon
  17. 1 1
      toolchain/check/testdata/class/compound_field.carbon
  18. 2 2
      toolchain/check/testdata/class/derived_to_base.carbon
  19. 9 12
      toolchain/check/testdata/class/extend_adapt.carbon
  20. 4 4
      toolchain/check/testdata/class/fail_abstract.carbon
  21. 4 4
      toolchain/check/testdata/class/fail_adapt_bad_decl.carbon
  22. 1 1
      toolchain/check/testdata/class/fail_adapt_bad_type.carbon
  23. 10 11
      toolchain/check/testdata/class/fail_adapt_modifiers.carbon
  24. 1 1
      toolchain/check/testdata/class/fail_adapt_with_base.carbon
  25. 6 6
      toolchain/check/testdata/class/fail_adapt_with_subobjects.carbon
  26. 1 1
      toolchain/check/testdata/class/fail_base_bad_type.carbon
  27. 1 1
      toolchain/check/testdata/class/fail_base_method_define.carbon
  28. 4 4
      toolchain/check/testdata/class/fail_base_modifiers.carbon
  29. 1 1
      toolchain/check/testdata/class/fail_base_no_extend.carbon
  30. 2 2
      toolchain/check/testdata/class/fail_base_repeated.carbon
  31. 1 1
      toolchain/check/testdata/class/fail_base_unbound.carbon
  32. 1 1
      toolchain/check/testdata/class/fail_derived_to_base.carbon
  33. 2 2
      toolchain/check/testdata/class/fail_extend_cycle.carbon
  34. 1008 0
      toolchain/check/testdata/class/generic/adapt.carbon
  35. 15 15
      toolchain/check/testdata/class/generic/base_is_generic.carbon
  36. 1 1
      toolchain/check/testdata/class/generic/init.carbon
  37. 8 8
      toolchain/check/testdata/class/import_base.carbon
  38. 9 9
      toolchain/check/testdata/class/inheritance_access.carbon
  39. 56 58
      toolchain/check/testdata/class/init_adapt.carbon
  40. 1 1
      toolchain/check/testdata/class/self_conversion.carbon
  41. 5 5
      toolchain/check/testdata/class/virtual_modifiers.carbon
  42. 3 3
      toolchain/check/testdata/impl/multiple_extend.carbon
  43. 30 39
      toolchain/lower/constant.cpp
  44. 1 4
      toolchain/lower/handle_aggregates.cpp
  45. 1 0
      toolchain/sem_ir/BUILD
  46. 24 0
      toolchain/sem_ir/class.cpp
  47. 8 0
      toolchain/sem_ir/class.h
  48. 1 25
      toolchain/sem_ir/file.h
  49. 66 0
      toolchain/sem_ir/type.cpp
  50. 30 21
      toolchain/sem_ir/type.h
  51. 18 3
      toolchain/sem_ir/typed_insts.h

+ 20 - 22
toolchain/check/context.cpp

@@ -390,18 +390,19 @@ static auto DiagnoseInvalidQualifiedNameAccess(Context& context, SemIRLoc loc,
   }
 
   // TODO: Support scoped entities other than just classes.
-  auto class_info = context.classes().Get(class_type->class_id);
+  const auto& class_info = context.classes().Get(class_type->class_id);
 
   auto parent_type_id = class_info.self_type_id;
 
   if (access_kind == SemIR::AccessKind::Private && is_parent_access) {
-    if (auto base_decl = context.insts().TryGetAsIfValid<SemIR::BaseDecl>(
-            class_info.base_id)) {
-      parent_type_id = base_decl->base_type_id;
-    } else if (auto adapt_decl =
-                   context.insts().TryGetAsIfValid<SemIR::AdaptDecl>(
-                       class_info.adapt_id)) {
-      parent_type_id = adapt_decl->adapted_type_id;
+    if (auto base_type_id =
+            class_info.GetBaseType(context.sem_ir(), class_type->specific_id);
+        base_type_id.is_valid()) {
+      parent_type_id = base_type_id;
+    } else if (auto adapted_type_id = class_info.GetAdaptedType(
+                   context.sem_ir(), class_type->specific_id);
+               adapted_type_id.is_valid()) {
+      parent_type_id = adapted_type_id;
     } else {
       CARBON_FATAL("Expected parent for parent access");
     }
@@ -957,7 +958,13 @@ class TypeCompleter {
         if (inst.specific_id.is_valid()) {
           ResolveSpecificDefinition(context_, inst.specific_id);
         }
-        Push(class_info.GetObjectRepr(context_.sem_ir(), inst.specific_id));
+        if (auto adapted_type_id =
+                class_info.GetAdaptedType(context_.sem_ir(), inst.specific_id);
+            adapted_type_id.is_valid()) {
+          Push(adapted_type_id);
+        } else {
+          Push(class_info.GetObjectRepr(context_.sem_ir(), inst.specific_id));
+        }
         break;
       }
       case CARBON_KIND(SemIR::ConstType inst): {
@@ -1127,12 +1134,10 @@ class TypeCompleter {
     auto& class_info = context_.classes().Get(inst.class_id);
     // The value representation of an adapter is the value representation of
     // its adapted type.
-    if (class_info.adapt_id.is_valid()) {
-      return GetNestedValueRepr(SemIR::GetTypeInSpecific(
-          context_.sem_ir(), inst.specific_id,
-          context_.insts()
-              .GetAs<SemIR::AdaptDecl>(class_info.adapt_id)
-              .adapted_type_id));
+    if (auto adapted_type_id =
+            class_info.GetAdaptedType(context_.sem_ir(), inst.specific_id);
+        adapted_type_id.is_valid()) {
+      return GetNestedValueRepr(adapted_type_id);
     }
     // Otherwise, the value representation for a class is a pointer to the
     // object representation.
@@ -1400,13 +1405,6 @@ auto Context::GetUnboundElementType(SemIR::TypeId class_type_id,
                                                 element_type_id);
 }
 
-auto Context::GetUnqualifiedType(SemIR::TypeId type_id) -> SemIR::TypeId {
-  if (auto const_type = types().TryGetAs<SemIR::ConstType>(type_id)) {
-    return const_type->inner_id;
-  }
-  return type_id;
-}
-
 auto Context::PrintForStackDump(llvm::raw_ostream& output) const -> void {
   output << "Check::Context\n";
 

+ 0 - 3
toolchain/check/context.h

@@ -431,9 +431,6 @@ class Context {
   auto GetUnboundElementType(SemIR::TypeId class_type_id,
                              SemIR::TypeId element_type_id) -> SemIR::TypeId;
 
-  // Removes any top-level `const` qualifiers from a type.
-  auto GetUnqualifiedType(SemIR::TypeId type_id) -> SemIR::TypeId;
-
   // Adds an exported name.
   auto AddExport(SemIR::InstId inst_id) -> void { exports_.push_back(inst_id); }
 

+ 10 - 10
toolchain/check/convert.cpp

@@ -607,15 +607,12 @@ static auto ComputeInheritancePath(Context& context, SemIR::TypeId derived_id,
       break;
     }
     auto& derived_class = context.classes().Get(derived_class_type->class_id);
-    if (!derived_class.base_id.is_valid()) {
+    auto base_type_id = derived_class.GetBaseType(
+        context.sem_ir(), derived_class_type->specific_id);
+    if (!base_type_id.is_valid()) {
       result = std::nullopt;
       break;
     }
-    auto base_decl =
-        context.insts().GetAs<SemIR::BaseDecl>(derived_class.base_id);
-    auto base_type_id = SemIR::GetTypeInSpecific(
-        context.sem_ir(), derived_class_type->specific_id,
-        base_decl.base_type_id);
     result->push_back({derived_class.base_id, base_type_id});
     derived_id = base_type_id;
   }
@@ -712,12 +709,15 @@ static auto GetCompatibleBaseType(Context& context, SemIR::TypeId type_id)
     -> SemIR::TypeId {
   // If the type is an adapter, its object representation type is its compatible
   // non-adapter type.
-  if (auto class_type = context.types().TryGetAs<SemIR::ClassType>(type_id)) {
+  while (auto class_type =
+             context.types().TryGetAs<SemIR::ClassType>(type_id)) {
     auto& class_info = context.classes().Get(class_type->class_id);
-    if (class_info.adapt_id.is_valid()) {
-      return class_info.GetObjectRepr(context.sem_ir(),
-                                      class_type->specific_id);
+    auto adapted_type_id =
+        class_info.GetAdaptedType(context.sem_ir(), class_type->specific_id);
+    if (!adapted_type_id.is_valid()) {
+      break;
     }
+    type_id = adapted_type_id;
   }
 
   // Otherwise, the type itself is a non-adapter type.

+ 7 - 5
toolchain/check/eval.cpp

@@ -676,7 +676,7 @@ static auto PerformCheckedIntConvert(Context& context, SemIRLoc loc,
   auto arg_val = context.ints().Get(arg.int_id);
 
   auto [is_signed, bit_width_id] =
-      context.sem_ir().GetIntTypeInfo(dest_type_id);
+      context.sem_ir().types().GetIntTypeInfo(dest_type_id);
   auto width = bit_width_id.is_valid()
                    ? context.ints().Get(bit_width_id).getZExtValue()
                    : arg_val.getBitWidth();
@@ -718,7 +718,8 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc,
                                      SemIR::InstId arg_id)
     -> SemIR::ConstantId {
   auto op = context.insts().GetAs<SemIR::IntValue>(arg_id);
-  auto [is_signed, bit_width_id] = context.sem_ir().GetIntTypeInfo(op.type_id);
+  auto [is_signed, bit_width_id] =
+      context.sem_ir().types().GetIntTypeInfo(op.type_id);
   CARBON_CHECK(bit_width_id != IntId::Invalid,
                "Cannot evaluate a generic bit width integer: {0}", op);
   llvm::APInt op_val = context.ints().GetAtWidth(op.int_id, bit_width_id);
@@ -771,7 +772,7 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc,
   }
 
   auto [lhs_is_signed, lhs_bit_width_id] =
-      context.sem_ir().GetIntTypeInfo(lhs.type_id);
+      context.sem_ir().types().GetIntTypeInfo(lhs.type_id);
   llvm::APInt lhs_val = context.ints().GetAtWidth(lhs.int_id, lhs_bit_width_id);
 
   llvm::APInt result_val;
@@ -916,7 +917,8 @@ static auto PerformBuiltinIntComparison(Context& context,
   CARBON_CHECK(lhs.type_id == rhs.type_id,
                "Builtin comparison with mismatched types!");
 
-  auto [is_signed, bit_width_id] = context.sem_ir().GetIntTypeInfo(lhs.type_id);
+  auto [is_signed, bit_width_id] =
+      context.sem_ir().types().GetIntTypeInfo(lhs.type_id);
   CARBON_CHECK(bit_width_id != IntId::Invalid,
                "Cannot evaluate a generic bit width integer: {0}", lhs);
   llvm::APInt lhs_val = context.ints().GetAtWidth(lhs.int_id, bit_width_id);
@@ -1497,6 +1499,7 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
     // TODO: This doesn't properly handle redeclarations. Consider adding a
     // corresponding `Value` inst for each of these cases, or returning the
     // first declaration.
+    case SemIR::AdaptDecl::Kind:
     case SemIR::AssociatedConstantDecl::Kind:
     case SemIR::BaseDecl::Kind:
     case SemIR::FieldDecl::Kind:
@@ -1699,7 +1702,6 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
     }
 
     // These cases are either not expressions or not constant.
-    case SemIR::AdaptDecl::Kind:
     case SemIR::AddrPattern::Kind:
     case SemIR::Assign::Kind:
     case SemIR::BindName::Kind:

+ 26 - 34
toolchain/check/handle_class.cpp

@@ -6,6 +6,7 @@
 #include "toolchain/check/context.h"
 #include "toolchain/check/convert.h"
 #include "toolchain/check/decl_name_stack.h"
+#include "toolchain/check/diagnostic_helpers.h"
 #include "toolchain/check/eval.h"
 #include "toolchain/check/generic.h"
 #include "toolchain/check/handle.h"
@@ -387,21 +388,23 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
       [&] {
         CARBON_DIAGNOSTIC(IncompleteTypeInAdaptDecl, Error,
                           "adapted type {0} is an incomplete type",
-                          SemIR::TypeId);
+                          InstIdAsType);
         return context.emitter().Build(node_id, IncompleteTypeInAdaptDecl,
-                                       adapted_type_id);
+                                       adapted_inst_id);
       },
       [&] {
         CARBON_DIAGNOSTIC(AbstractTypeInAdaptDecl, Error,
-                          "adapted type {0} is an abstract type",
-                          SemIR::TypeId);
+                          "adapted type {0} is an abstract type", InstIdAsType);
         return context.emitter().Build(node_id, AbstractTypeInAdaptDecl,
-                                       adapted_type_id);
+                                       adapted_inst_id);
       });
+  if (adapted_type_id == SemIR::TypeId::Error) {
+    adapted_inst_id = SemIR::InstId::BuiltinErrorInst;
+  }
 
   // Build a SemIR representation for the declaration.
   class_info.adapt_id = context.AddInst<SemIR::AdaptDecl>(
-      node_id, {.adapted_type_id = adapted_type_id});
+      node_id, {.adapted_type_inst_id = adapted_inst_id});
 
   // Extend the class scope with the adapted type's scope if requested.
   if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
@@ -432,9 +435,10 @@ struct BaseInfo {
   SemIR::NameScopeId scope_id;
   SemIR::InstId inst_id;
 };
-constexpr BaseInfo BaseInfo::Error = {.type_id = SemIR::TypeId::Error,
-                                      .scope_id = SemIR::NameScopeId::Invalid,
-                                      .inst_id = SemIR::InstId::Invalid};
+constexpr BaseInfo BaseInfo::Error = {
+    .type_id = SemIR::TypeId::Error,
+    .scope_id = SemIR::NameScopeId::Invalid,
+    .inst_id = SemIR::InstId::BuiltinErrorInst};
 }  // namespace
 
 // Diagnoses an attempt to derive from a final type.
@@ -531,7 +535,7 @@ auto HandleParseNode(Context& context, Parse::BaseDeclId node_id) -> bool {
       context.GetUnboundElementType(class_info.self_type_id, base_info.type_id);
   class_info.base_id = context.AddInst<SemIR::BaseDecl>(
       node_id, {.type_id = field_type_id,
-                .base_type_id = base_info.type_id,
+                .base_type_inst_id = base_info.inst_id,
                 .index = SemIR::ElementIndex::Invalid});
 
   if (base_info.type_id != SemIR::TypeId::Error) {
@@ -607,27 +611,17 @@ static auto CheckCompleteAdapterClassType(Context& context,
   }
 
   // The object representation of the adapter is the object representation
-  // of the adapted type. This is the adapted type itself unless it's a class
-  // type.
-  //
-  // TODO: The object representation of `const T` should also be the object
-  // representation of `T`.
-  auto adapted_type_id = context.insts()
-                             .GetAs<SemIR::AdaptDecl>(class_info.adapt_id)
-                             .adapted_type_id;
-  if (auto adapted_class =
-          context.types().TryGetAs<SemIR::ClassType>(adapted_type_id)) {
-    auto& adapted_class_info = context.classes().Get(adapted_class->class_id);
-    if (adapted_class_info.adapt_id.is_valid()) {
-      return adapted_class_info.complete_type_witness_id;
-    }
-  }
+  // of the adapted type.
+  auto adapted_type_id =
+      class_info.GetAdaptedType(context.sem_ir(), SemIR::SpecificId::Invalid);
+  auto object_repr_id = context.types().GetObjectRepr(adapted_type_id);
 
   return context.AddInst<SemIR::CompleteTypeWitness>(
       node_id,
       {.type_id = context.GetBuiltinType(SemIR::BuiltinInstKind::WitnessType),
-       .object_repr_id = adapted_type_id});
+       .object_repr_id = object_repr_id});
 }
+
 static auto AddStructTypeFields(
     Context& context,
     llvm::SmallVector<SemIR::StructTypeField>& struct_type_fields)
@@ -664,11 +658,12 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
   }
 
   bool defining_vptr = class_info.is_dynamic;
-  if (class_info.base_id.is_valid()) {
-    auto base_info = context.insts().GetAs<SemIR::BaseDecl>(class_info.base_id);
+  auto base_type_id =
+      class_info.GetBaseType(context.sem_ir(), SemIR::SpecificId::Invalid);
+  if (base_type_id.is_valid()) {
     // TODO: If the base class is template dependent, we will need to decide
     // whether to add a vptr as part of instantiation.
-    if (auto* base_class_info = TryGetAsClass(context, base_info.base_type_id);
+    if (auto* base_class_info = TryGetAsClass(context, base_type_id);
         base_class_info && base_class_info->is_dynamic) {
       defining_vptr = false;
     }
@@ -684,16 +679,13 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
          .type_id = context.GetPointerType(
              context.GetBuiltinType(SemIR::BuiltinInstKind::VtableType))});
   }
-  if (class_info.base_id.is_valid()) {
+  if (base_type_id.is_valid()) {
     auto base_decl = context.insts().GetAs<SemIR::BaseDecl>(class_info.base_id);
     base_decl.index =
         SemIR::ElementIndex{static_cast<int>(struct_type_fields.size())};
     context.ReplaceInstPreservingConstantValue(class_info.base_id, base_decl);
     struct_type_fields.push_back(
-        {.name_id = SemIR::NameId::Base,
-         .type_id = context.insts()
-                        .GetAs<SemIR::BaseDecl>(class_info.base_id)
-                        .base_type_id});
+        {.name_id = SemIR::NameId::Base, .type_id = base_type_id});
   }
 
   return context.AddInst<SemIR::CompleteTypeWitness>(

+ 42 - 7
toolchain/check/import_ref.cpp

@@ -1252,6 +1252,28 @@ static auto ResolveAs(ImportContext& context, InstT inst) -> ResolveResult {
   return ResolveAsUntyped(context, inst);
 }
 
+static auto TryResolveTypedInst(ImportRefResolver& resolver,
+                                SemIR::AdaptDecl inst,
+                                SemIR::InstId import_inst_id) -> ResolveResult {
+  auto adapted_type_const_id = GetLocalConstantId(
+      resolver,
+      resolver.import_constant_values().Get(inst.adapted_type_inst_id));
+  if (resolver.HasNewWork()) {
+    return ResolveResult::Retry();
+  }
+
+  auto adapted_type_inst_id =
+      AddLoadedImportRef(resolver, SemIR::TypeId::TypeType,
+                         inst.adapted_type_inst_id, adapted_type_const_id);
+
+  // Create a corresponding instruction to represent the declaration.
+  auto inst_id = resolver.local_context().AddInstInNoBlock(
+      resolver.local_context().MakeImportedLocAndInst<SemIR::AdaptDecl>(
+          AddImportIRInst(resolver, import_inst_id),
+          {.adapted_type_inst_id = adapted_type_inst_id}));
+  return ResolveResult::Done(resolver.local_constant_values().Get(inst_id));
+}
+
 static auto TryResolveTypedInst(ImportRefResolver& resolver,
                                 SemIR::AssociatedEntity inst) -> ResolveResult {
   auto type_const_id = GetLocalConstantId(resolver, inst.type_id);
@@ -1293,20 +1315,23 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
                                 SemIR::BaseDecl inst,
                                 SemIR::InstId import_inst_id) -> ResolveResult {
   auto type_const_id = GetLocalConstantId(resolver, inst.type_id);
-  auto base_type_const_id = GetLocalConstantId(resolver, inst.base_type_id);
+  auto base_type_const_id = GetLocalConstantId(
+      resolver, resolver.import_constant_values().Get(inst.base_type_inst_id));
   if (resolver.HasNewWork()) {
     return ResolveResult::Retry();
   }
 
-  // Import the instruction in order to update contained base_type_id and
-  // track the import location.
+  auto base_type_inst_id =
+      AddLoadedImportRef(resolver, SemIR::TypeId::TypeType,
+                         inst.base_type_inst_id, base_type_const_id);
+
+  // Create a corresponding instruction to represent the declaration.
   auto inst_id = resolver.local_context().AddInstInNoBlock(
       resolver.local_context().MakeImportedLocAndInst<SemIR::BaseDecl>(
           AddImportIRInst(resolver, import_inst_id),
           {.type_id =
                resolver.local_context().GetTypeIdForTypeConstant(type_const_id),
-           .base_type_id = resolver.local_context().GetTypeIdForTypeConstant(
-               base_type_const_id),
+           .base_type_inst_id = base_type_inst_id,
            .index = inst.index}));
   return ResolveResult::Done(resolver.local_constant_values().Get(inst_id));
 }
@@ -1397,7 +1422,8 @@ static auto AddClassDefinition(ImportContext& context,
                                const SemIR::Class& import_class,
                                SemIR::Class& new_class,
                                SemIR::InstId complete_type_witness_id,
-                               SemIR::InstId base_id) -> void {
+                               SemIR::InstId base_id, SemIR::InstId adapt_id)
+    -> void {
   new_class.definition_id = new_class.first_owning_decl_id;
 
   new_class.complete_type_witness_id = complete_type_witness_id;
@@ -1417,6 +1443,9 @@ static auto AddClassDefinition(ImportContext& context,
   if (import_class.base_id.is_valid()) {
     new_class.base_id = base_id;
   }
+  if (import_class.adapt_id.is_valid()) {
+    new_class.adapt_id = adapt_id;
+  }
 }
 
 static auto TryResolveTypedInst(ImportRefResolver& resolver,
@@ -1480,6 +1509,9 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
   auto base_id = import_class.base_id.is_valid()
                      ? GetLocalConstantInstId(resolver, import_class.base_id)
                      : SemIR::InstId::Invalid;
+  auto adapt_id = import_class.adapt_id.is_valid()
+                      ? GetLocalConstantInstId(resolver, import_class.adapt_id)
+                      : SemIR::InstId::Invalid;
 
   if (resolver.HasNewWork()) {
     return ResolveResult::Retry(class_const_id);
@@ -1498,7 +1530,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
 
   if (import_class.is_defined()) {
     AddClassDefinition(resolver, import_class, new_class,
-                       complete_type_witness_id, base_id);
+                       complete_type_witness_id, base_id, adapt_id);
   }
 
   return ResolveResult::Done(class_const_id);
@@ -2328,6 +2360,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
 
   auto untyped_inst = resolver.import_insts().Get(inst_id);
   CARBON_KIND_SWITCH(untyped_inst) {
+    case CARBON_KIND(SemIR::AdaptDecl inst): {
+      return TryResolveTypedInst(resolver, inst, inst_id);
+    }
     case CARBON_KIND(SemIR::AssociatedEntity inst): {
       return TryResolveTypedInst(resolver, inst);
     }

+ 11 - 7
toolchain/check/member_access.cpp

@@ -81,15 +81,19 @@ static auto GetHighestAllowedAccess(Context& context, SemIR::LocId loc_id,
 
     // If the `type_id` of `Self` does not match with the one we're currently
     // accessing, try checking if this class is of the parent type of `Self`.
-    if (auto base_decl = context.insts().TryGetAsIfValid<SemIR::BaseDecl>(
-            self_class_info.base_id)) {
-      if (base_decl->base_type_id == class_info.self_type_id) {
+    if (auto base_type_id = self_class_info.GetBaseType(
+            context.sem_ir(), self_class_type->specific_id);
+        base_type_id.is_valid()) {
+      if (context.types().GetConstantId(base_type_id) == name_scope_const_id) {
         return SemIR::AccessKind::Protected;
       }
-    } else if (auto adapt_decl =
-                   context.insts().TryGetAsIfValid<SemIR::AdaptDecl>(
-                       self_class_info.adapt_id)) {
-      if (adapt_decl->adapted_type_id == class_info.self_type_id) {
+      // TODO: Also check whether this base class has a base class of its own.
+    } else if (auto adapt_type_id = self_class_info.GetAdaptedType(
+                   context.sem_ir(), self_class_type->specific_id);
+               adapt_type_id.is_valid()) {
+      if (context.types().GetConstantId(adapt_type_id) == name_scope_const_id) {
+        // TODO: Should we be allowed to access protected fields of a type we
+        // are adapting? The design doesn't allow this.
         return SemIR::AccessKind::Protected;
       }
     }

+ 2 - 2
toolchain/check/pointer_dereference.cpp

@@ -23,8 +23,8 @@ auto PerformPointerDereference(
   //
   // to convert to a pointer value.
   base_id = ConvertToValueExpr(context, base_id);
-  auto type_id =
-      context.GetUnqualifiedType(context.insts().Get(base_id).type_id());
+  auto type_id = context.types().GetUnqualifiedType(
+      context.insts().Get(base_id).type_id());
   auto result_type_id = SemIR::TypeId::Error;
   if (auto pointer_type =
           context.types().TryGetAs<SemIR::PointerType>(type_id)) {

+ 63 - 63
toolchain/check/testdata/as/adapter_conversion.carbon

@@ -133,8 +133,7 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:   %.38: %i32 = int_value 2 [template]
 // CHECK:STDOUT:   %struct: %A = struct_value (%.35, %.38) [template]
 // CHECK:STDOUT:   %B: type = class_type @B [template]
-// CHECK:STDOUT:   %.39: <witness> = complete_type_witness %A [template]
-// CHECK:STDOUT:   %.40: type = ptr_type %B [template]
+// CHECK:STDOUT:   %.39: type = ptr_type %B [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -166,7 +165,7 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:   %A.ref.loc18: type = name_ref A, %A.decl [template = constants.%A]
 // CHECK:STDOUT:   %B.ref.loc21: type = name_ref B, %B.decl [template = constants.%B]
 // CHECK:STDOUT:   %B.ref.loc22: type = name_ref B, %B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc22: type = ptr_type %B [template = constants.%.40]
+// CHECK:STDOUT:   %.loc22: type = ptr_type %B [template = constants.%.39]
 // CHECK:STDOUT:   %B.ref.loc24: type = name_ref B, %B.decl [template = constants.%B]
 // CHECK:STDOUT:   %b_factory.var: ref %B = var b_factory
 // CHECK:STDOUT:   %b_factory: ref %B = bind_name b_factory, %b_factory.var
@@ -202,8 +201,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   adapt_decl %A
-// CHECK:STDOUT:   %.loc15: <witness> = complete_type_witness %A [template = constants.%.39]
+// CHECK:STDOUT:   adapt_decl %A.ref [template]
+// CHECK:STDOUT:   %.loc15: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%B
@@ -267,8 +266,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:   %B.ref.loc22: type = name_ref B, file.%B.decl [template = constants.%B]
 // CHECK:STDOUT:   %.loc22_25.1: ref %B = as_compatible %a_ref.ref.loc22
 // CHECK:STDOUT:   %.loc22_25.2: ref %B = converted %a_ref.ref.loc22, %.loc22_25.1
-// CHECK:STDOUT:   %.loc22_17: %.40 = addr_of %.loc22_25.2
-// CHECK:STDOUT:   %b_ptr: %.40 = bind_name b_ptr, %.loc22_17
+// CHECK:STDOUT:   %.loc22_17: %.39 = addr_of %.loc22_25.2
+// CHECK:STDOUT:   %b_ptr: %.39 = bind_name b_ptr, %.loc22_17
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
 // CHECK:STDOUT:   %Make.ref: %Make.type = name_ref Make, @A.%Make.decl [template = constants.%Make]
 // CHECK:STDOUT:   %.loc24_5: ref %B = splice_block file.%b_factory.var {}
@@ -329,7 +328,7 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc5_9) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc5_12.1: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
 // CHECK:STDOUT:   %.loc5_12.2: type = converted %int.make_type_signed, %.loc5_12.1 [template = constants.%i32]
-// CHECK:STDOUT:   adapt_decl %i32
+// CHECK:STDOUT:   adapt_decl %.loc5_12.2 [template]
 // CHECK:STDOUT:   %.loc6: <witness> = complete_type_witness %i32 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -403,7 +402,7 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT: class @A {
 // CHECK:STDOUT:   %.loc4_18: %.1 = struct_literal ()
 // CHECK:STDOUT:   %.loc4_19: type = converted %.loc4_18, constants.%.1 [template = constants.%.1]
-// CHECK:STDOUT:   adapt_decl %.1
+// CHECK:STDOUT:   adapt_decl %.loc4_19 [template]
 // CHECK:STDOUT:   %.loc4_21: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -412,7 +411,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   adapt_decl %A
+// CHECK:STDOUT:   adapt_decl %A.ref [template]
+// CHECK:STDOUT:   %.loc5: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%B
@@ -420,7 +420,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   adapt_decl %B
+// CHECK:STDOUT:   adapt_decl %B.ref [template]
+// CHECK:STDOUT:   %.loc6: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%C
@@ -428,7 +429,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @D {
 // CHECK:STDOUT:   %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
-// CHECK:STDOUT:   adapt_decl %C
+// CHECK:STDOUT:   adapt_decl %C.ref [template]
+// CHECK:STDOUT:   %.loc7: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%D
@@ -457,21 +459,20 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:   %.3: type = struct_type {.x: %i32, .y: %i32} [template]
 // CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
 // CHECK:STDOUT:   %B: type = class_type @B [template]
-// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %A [template]
-// CHECK:STDOUT:   %.7: Core.IntLiteral = int_value 1 [template]
-// CHECK:STDOUT:   %.8: Core.IntLiteral = int_value 2 [template]
-// CHECK:STDOUT:   %.9: type = struct_type {.x: Core.IntLiteral, .y: Core.IntLiteral} [template]
+// CHECK:STDOUT:   %.6: Core.IntLiteral = int_value 1 [template]
+// CHECK:STDOUT:   %.7: Core.IntLiteral = int_value 2 [template]
+// CHECK:STDOUT:   %.8: type = struct_type {.x: Core.IntLiteral, .y: Core.IntLiteral} [template]
 // CHECK:STDOUT:   %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
 // CHECK:STDOUT:   %Convert.type.14: type = fn_type @Convert.2, @impl.1(%.1) [template]
 // CHECK:STDOUT:   %Convert.14: %Convert.type.14 = struct_value () [template]
-// CHECK:STDOUT:   %.33: <witness> = interface_witness (%Convert.14) [template]
-// CHECK:STDOUT:   %.34: <bound method> = bound_method %.7, %Convert.14 [template]
-// CHECK:STDOUT:   %.35: <specific function> = specific_function %.34, @Convert.2(%.1) [template]
-// CHECK:STDOUT:   %.36: %i32 = int_value 1 [template]
-// CHECK:STDOUT:   %.37: <bound method> = bound_method %.8, %Convert.14 [template]
-// CHECK:STDOUT:   %.38: <specific function> = specific_function %.37, @Convert.2(%.1) [template]
-// CHECK:STDOUT:   %.39: %i32 = int_value 2 [template]
-// CHECK:STDOUT:   %struct: %A = struct_value (%.36, %.39) [template]
+// CHECK:STDOUT:   %.32: <witness> = interface_witness (%Convert.14) [template]
+// CHECK:STDOUT:   %.33: <bound method> = bound_method %.6, %Convert.14 [template]
+// CHECK:STDOUT:   %.34: <specific function> = specific_function %.33, @Convert.2(%.1) [template]
+// CHECK:STDOUT:   %.35: %i32 = int_value 1 [template]
+// CHECK:STDOUT:   %.36: <bound method> = bound_method %.7, %Convert.14 [template]
+// CHECK:STDOUT:   %.37: <specific function> = specific_function %.36, @Convert.2(%.1) [template]
+// CHECK:STDOUT:   %.38: %i32 = int_value 2 [template]
+// CHECK:STDOUT:   %struct: %A = struct_value (%.35, %.38) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -521,8 +522,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   adapt_decl %A
-// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %A [template = constants.%.6]
+// CHECK:STDOUT:   adapt_decl %A.ref [template]
+// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%B
@@ -530,25 +531,25 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc13_25: Core.IntLiteral = int_value 1 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc13_33: Core.IntLiteral = int_value 2 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc13_34.1: %.9 = struct_literal (%.loc13_25, %.loc13_33)
+// CHECK:STDOUT:   %.loc13_25: Core.IntLiteral = int_value 1 [template = constants.%.6]
+// CHECK:STDOUT:   %.loc13_33: Core.IntLiteral = int_value 2 [template = constants.%.7]
+// CHECK:STDOUT:   %.loc13_34.1: %.8 = struct_literal (%.loc13_25, %.loc13_33)
 // CHECK:STDOUT:   %A.ref.loc13: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc13_34.2: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc13_34.3: <bound method> = bound_method %.loc13_25, %.loc13_34.2 [template = constants.%.34]
-// CHECK:STDOUT:   %.loc13_34.4: <specific function> = specific_function %.loc13_34.3, @Convert.2(constants.%.1) [template = constants.%.35]
-// CHECK:STDOUT:   %int.convert_checked.loc13_34.1: init %i32 = call %.loc13_34.4(%.loc13_25) [template = constants.%.36]
-// CHECK:STDOUT:   %.loc13_34.5: init %i32 = converted %.loc13_25, %int.convert_checked.loc13_34.1 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc13_34.2: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc13_34.3: <bound method> = bound_method %.loc13_25, %.loc13_34.2 [template = constants.%.33]
+// CHECK:STDOUT:   %.loc13_34.4: <specific function> = specific_function %.loc13_34.3, @Convert.2(constants.%.1) [template = constants.%.34]
+// CHECK:STDOUT:   %int.convert_checked.loc13_34.1: init %i32 = call %.loc13_34.4(%.loc13_25) [template = constants.%.35]
+// CHECK:STDOUT:   %.loc13_34.5: init %i32 = converted %.loc13_25, %int.convert_checked.loc13_34.1 [template = constants.%.35]
 // CHECK:STDOUT:   %.loc13_34.6: ref %A = temporary_storage
 // CHECK:STDOUT:   %.loc13_34.7: ref %i32 = class_element_access %.loc13_34.6, element0
-// CHECK:STDOUT:   %.loc13_34.8: init %i32 = initialize_from %.loc13_34.5 to %.loc13_34.7 [template = constants.%.36]
-// CHECK:STDOUT:   %.loc13_34.9: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc13_34.10: <bound method> = bound_method %.loc13_33, %.loc13_34.9 [template = constants.%.37]
-// CHECK:STDOUT:   %.loc13_34.11: <specific function> = specific_function %.loc13_34.10, @Convert.2(constants.%.1) [template = constants.%.38]
-// CHECK:STDOUT:   %int.convert_checked.loc13_34.2: init %i32 = call %.loc13_34.11(%.loc13_33) [template = constants.%.39]
-// CHECK:STDOUT:   %.loc13_34.12: init %i32 = converted %.loc13_33, %int.convert_checked.loc13_34.2 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc13_34.8: init %i32 = initialize_from %.loc13_34.5 to %.loc13_34.7 [template = constants.%.35]
+// CHECK:STDOUT:   %.loc13_34.9: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc13_34.10: <bound method> = bound_method %.loc13_33, %.loc13_34.9 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc13_34.11: <specific function> = specific_function %.loc13_34.10, @Convert.2(constants.%.1) [template = constants.%.37]
+// CHECK:STDOUT:   %int.convert_checked.loc13_34.2: init %i32 = call %.loc13_34.11(%.loc13_33) [template = constants.%.38]
+// CHECK:STDOUT:   %.loc13_34.12: init %i32 = converted %.loc13_33, %int.convert_checked.loc13_34.2 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc13_34.13: ref %i32 = class_element_access %.loc13_34.6, element1
-// CHECK:STDOUT:   %.loc13_34.14: init %i32 = initialize_from %.loc13_34.12 to %.loc13_34.13 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc13_34.14: init %i32 = initialize_from %.loc13_34.12 to %.loc13_34.13 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc13_34.15: init %A = class_init (%.loc13_34.8, %.loc13_34.14), %.loc13_34.6 [template = constants.%struct]
 // CHECK:STDOUT:   %.loc13_34.16: ref %A = temporary %.loc13_34.6, %.loc13_34.15
 // CHECK:STDOUT:   %.loc13_36: ref %A = converted %.loc13_34.1, %.loc13_34.16
@@ -557,25 +558,25 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:   %.loc13_42.2: ref %B = converted %.loc13_36, %.loc13_42.1
 // CHECK:STDOUT:   %.loc13_42.3: %B = bind_value %.loc13_42.2
 // CHECK:STDOUT:   %b_value: %B = bind_name b_value, %.loc13_42.3
-// CHECK:STDOUT:   %.loc24_24: Core.IntLiteral = int_value 1 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc24_32: Core.IntLiteral = int_value 2 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc24_33.1: %.9 = struct_literal (%.loc24_24, %.loc24_32)
+// CHECK:STDOUT:   %.loc24_24: Core.IntLiteral = int_value 1 [template = constants.%.6]
+// CHECK:STDOUT:   %.loc24_32: Core.IntLiteral = int_value 2 [template = constants.%.7]
+// CHECK:STDOUT:   %.loc24_33.1: %.8 = struct_literal (%.loc24_24, %.loc24_32)
 // CHECK:STDOUT:   %A.ref.loc24: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc24_33.2: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc24_33.3: <bound method> = bound_method %.loc24_24, %.loc24_33.2 [template = constants.%.34]
-// CHECK:STDOUT:   %.loc24_33.4: <specific function> = specific_function %.loc24_33.3, @Convert.2(constants.%.1) [template = constants.%.35]
-// CHECK:STDOUT:   %int.convert_checked.loc24_33.1: init %i32 = call %.loc24_33.4(%.loc24_24) [template = constants.%.36]
-// CHECK:STDOUT:   %.loc24_33.5: init %i32 = converted %.loc24_24, %int.convert_checked.loc24_33.1 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc24_33.2: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc24_33.3: <bound method> = bound_method %.loc24_24, %.loc24_33.2 [template = constants.%.33]
+// CHECK:STDOUT:   %.loc24_33.4: <specific function> = specific_function %.loc24_33.3, @Convert.2(constants.%.1) [template = constants.%.34]
+// CHECK:STDOUT:   %int.convert_checked.loc24_33.1: init %i32 = call %.loc24_33.4(%.loc24_24) [template = constants.%.35]
+// CHECK:STDOUT:   %.loc24_33.5: init %i32 = converted %.loc24_24, %int.convert_checked.loc24_33.1 [template = constants.%.35]
 // CHECK:STDOUT:   %.loc24_33.6: ref %A = temporary_storage
 // CHECK:STDOUT:   %.loc24_33.7: ref %i32 = class_element_access %.loc24_33.6, element0
-// CHECK:STDOUT:   %.loc24_33.8: init %i32 = initialize_from %.loc24_33.5 to %.loc24_33.7 [template = constants.%.36]
-// CHECK:STDOUT:   %.loc24_33.9: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc24_33.10: <bound method> = bound_method %.loc24_32, %.loc24_33.9 [template = constants.%.37]
-// CHECK:STDOUT:   %.loc24_33.11: <specific function> = specific_function %.loc24_33.10, @Convert.2(constants.%.1) [template = constants.%.38]
-// CHECK:STDOUT:   %int.convert_checked.loc24_33.2: init %i32 = call %.loc24_33.11(%.loc24_32) [template = constants.%.39]
-// CHECK:STDOUT:   %.loc24_33.12: init %i32 = converted %.loc24_32, %int.convert_checked.loc24_33.2 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc24_33.8: init %i32 = initialize_from %.loc24_33.5 to %.loc24_33.7 [template = constants.%.35]
+// CHECK:STDOUT:   %.loc24_33.9: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc24_33.10: <bound method> = bound_method %.loc24_32, %.loc24_33.9 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc24_33.11: <specific function> = specific_function %.loc24_33.10, @Convert.2(constants.%.1) [template = constants.%.37]
+// CHECK:STDOUT:   %int.convert_checked.loc24_33.2: init %i32 = call %.loc24_33.11(%.loc24_32) [template = constants.%.38]
+// CHECK:STDOUT:   %.loc24_33.12: init %i32 = converted %.loc24_32, %int.convert_checked.loc24_33.2 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc24_33.13: ref %i32 = class_element_access %.loc24_33.6, element1
-// CHECK:STDOUT:   %.loc24_33.14: init %i32 = initialize_from %.loc24_33.12 to %.loc24_33.13 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc24_33.14: init %i32 = initialize_from %.loc24_33.12 to %.loc24_33.13 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc24_33.15: init %A = class_init (%.loc24_33.8, %.loc24_33.14), %.loc24_33.6 [template = constants.%struct]
 // CHECK:STDOUT:   %.loc24_33.16: ref %A = temporary %.loc24_33.6, %.loc24_33.15
 // CHECK:STDOUT:   %.loc24_35: ref %A = converted %.loc24_33.1, %.loc24_33.16
@@ -599,9 +600,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:   %.3: type = struct_type {.x: %i32} [template]
 // CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
 // CHECK:STDOUT:   %B: type = class_type @B [template]
-// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %A [template]
-// CHECK:STDOUT:   %.7: Core.IntLiteral = int_value 1 [template]
-// CHECK:STDOUT:   %.8: type = struct_type {.x: Core.IntLiteral} [template]
+// CHECK:STDOUT:   %.6: Core.IntLiteral = int_value 1 [template]
+// CHECK:STDOUT:   %.7: type = struct_type {.x: Core.IntLiteral} [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -643,8 +643,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   adapt_decl %A
-// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %A [template = constants.%.6]
+// CHECK:STDOUT:   adapt_decl %A.ref [template]
+// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%B
@@ -652,8 +652,8 @@ var b: B = {.x = 1} as B;
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc21_18: Core.IntLiteral = int_value 1 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc21_19: %.8 = struct_literal (%.loc21_18)
+// CHECK:STDOUT:   %.loc21_18: Core.IntLiteral = int_value 1 [template = constants.%.6]
+// CHECK:STDOUT:   %.loc21_19: %.7 = struct_literal (%.loc21_18)
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
 // CHECK:STDOUT:   %.loc21_21: %B = converted %.loc21_19, <error> [template = <error>]
 // CHECK:STDOUT:   assign file.%b.var, <error>

+ 5 - 7
toolchain/check/testdata/class/adapt.carbon

@@ -57,7 +57,6 @@ fn F(a: AdaptNotExtend) {
 // CHECK:STDOUT:   %.3: type = struct_type {.a: %i32, .b: %i32} [template]
 // CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
 // CHECK:STDOUT:   %SomeClassAdapter: type = class_type @SomeClassAdapter [template]
-// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %SomeClass [template]
 // CHECK:STDOUT:   %StructAdapter: type = class_type @StructAdapter [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -103,8 +102,8 @@ fn F(a: AdaptNotExtend) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @SomeClassAdapter {
 // CHECK:STDOUT:   %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
-// CHECK:STDOUT:   adapt_decl %SomeClass
-// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %SomeClass [template = constants.%.6]
+// CHECK:STDOUT:   adapt_decl %SomeClass.ref [template]
+// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%SomeClassAdapter
@@ -120,7 +119,7 @@ fn F(a: AdaptNotExtend) {
 // CHECK:STDOUT:   %.loc14_23.2: type = value_of_initializer %int.make_type_signed.loc14_23 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc14_23.3: type = converted %int.make_type_signed.loc14_23, %.loc14_23.2 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc14_26: type = struct_type {.a: %i32, .b: %i32} [template = constants.%.3]
-// CHECK:STDOUT:   adapt_decl %.3
+// CHECK:STDOUT:   adapt_decl %.loc14_26 [template]
 // CHECK:STDOUT:   %.loc15: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -136,7 +135,6 @@ fn F(a: AdaptNotExtend) {
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
 // CHECK:STDOUT:   %AdaptNotExtend: type = class_type @AdaptNotExtend [template]
-// CHECK:STDOUT:   %.4: <witness> = complete_type_witness %Adapted [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
 // CHECK:STDOUT: }
@@ -179,8 +177,8 @@ fn F(a: AdaptNotExtend) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @AdaptNotExtend {
 // CHECK:STDOUT:   %Adapted.ref: type = name_ref Adapted, file.%Adapted.decl [template = constants.%Adapted]
-// CHECK:STDOUT:   adapt_decl %Adapted
-// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %Adapted [template = constants.%.4]
+// CHECK:STDOUT:   adapt_decl %Adapted.ref [template]
+// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AdaptNotExtend

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

@@ -151,7 +151,7 @@ class Derived {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc8: %.6 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc8: %.6 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %.loc10_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc10_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc10_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]

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

@@ -112,7 +112,7 @@ fn Access(p: Derived*) -> i32* {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc18: %.6 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc18: %.6 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %.loc20_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed.loc20: init type = call constants.%Int(%.loc20_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc20_10.2: type = value_of_initializer %int.make_type_signed.loc20 [template = constants.%i32]

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

@@ -72,7 +72,7 @@ fn Derived.H() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc16: %.4 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc16: %.4 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {} {}
 // CHECK:STDOUT:   %H.decl: %H.type = fn_decl @H [template = constants.%H] {} {}
 // CHECK:STDOUT:   %.loc20: <witness> = complete_type_witness %.5 [template = constants.%.6]

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

@@ -124,7 +124,7 @@ fn Call(p: Derived*) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc22: %.35 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc22: %.35 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %.loc23: <witness> = complete_type_witness %.36 [template = constants.%.37]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

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

@@ -163,7 +163,7 @@ fn PassDerivedToBaseIndirect(p: Derived*) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc19: %.5 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc19: %.5 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %self.patt: %Derived = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %Derived = value_param_pattern %self.patt, runtime_param0

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

@@ -134,7 +134,7 @@ fn Call(a: A*, b: B*, c: C*, d: D*) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc16: %.5 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc16: %.5 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %self.patt: %.6 = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %.6 = value_param_pattern %self.patt, runtime_param0
@@ -156,7 +156,7 @@ fn Call(a: A*, b: B*, c: C*, d: D*) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc21: %.11 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc21: %.11 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.3 = fn_decl @F.3 [template = constants.%F.3] {
 // CHECK:STDOUT:     %self.patt: %.12 = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %.12 = value_param_pattern %self.patt, runtime_param0
@@ -178,7 +178,7 @@ fn Call(a: A*, b: B*, c: C*, d: D*) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @D {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc26: %.15 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc26: %.15 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc27: <witness> = complete_type_witness %.13 [template = constants.%.14]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

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

@@ -183,7 +183,7 @@ fn AccessBaseIndirect(p: Derived*) -> i32* {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc18: %.6 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc18: %.6 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %.loc20_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed.loc20: init type = call constants.%Int(%.loc20_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc20_10.2: type = value_of_initializer %int.make_type_signed.loc20 [template = constants.%i32]

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

@@ -210,7 +210,7 @@ fn ConvertInit() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc16: %.6 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc16: %.6 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %.loc17_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc17_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc17_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
@@ -227,7 +227,7 @@ fn ConvertInit() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc21: %.13 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc21: %.13 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc22_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc22_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc22_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]

+ 9 - 12
toolchain/check/testdata/class/extend_adapt.carbon

@@ -154,7 +154,6 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:   %AdapterMethod: %AdapterMethod.type = struct_value () [template]
 // CHECK:STDOUT:   %.3: type = struct_type {.a: %i32, .b: %i32} [template]
 // CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
-// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %SomeClass [template]
 // CHECK:STDOUT:   %TestStaticMemberFunction.type: type = fn_type @TestStaticMemberFunction [template]
 // CHECK:STDOUT:   %TestStaticMemberFunction: %TestStaticMemberFunction.type = struct_value () [template]
 // CHECK:STDOUT:   %TestAdapterMethod.type: type = fn_type @TestAdapterMethod [template]
@@ -201,8 +200,8 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @SomeClassAdapter {
 // CHECK:STDOUT:   %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
-// CHECK:STDOUT:   adapt_decl %SomeClass
-// CHECK:STDOUT:   %.loc17: <witness> = complete_type_witness %SomeClass [template = constants.%.6]
+// CHECK:STDOUT:   adapt_decl %SomeClass.ref [template]
+// CHECK:STDOUT:   %.loc17: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%SomeClassAdapter
@@ -270,7 +269,6 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
 // CHECK:STDOUT:   %SomeClassAdapter: type = class_type @SomeClassAdapter [template]
-// CHECK:STDOUT:   %.4: <witness> = complete_type_witness %SomeClass [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
 // CHECK:STDOUT: }
@@ -321,8 +319,8 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @SomeClassAdapter {
 // CHECK:STDOUT:   %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
-// CHECK:STDOUT:   adapt_decl %SomeClass
-// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %SomeClass [template = constants.%.4]
+// CHECK:STDOUT:   adapt_decl %SomeClass.ref [template]
+// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%SomeClassAdapter
@@ -353,7 +351,6 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:   %.3: type = struct_type {.a: %i32, .b: %i32} [template]
 // CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
 // CHECK:STDOUT:   %SomeClassAdapter: type = class_type @SomeClassAdapter [template]
-// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %SomeClass [template]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
 // CHECK:STDOUT: }
@@ -416,8 +413,8 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @SomeClassAdapter {
 // CHECK:STDOUT:   %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
-// CHECK:STDOUT:   adapt_decl %SomeClass
-// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %SomeClass [template = constants.%.6]
+// CHECK:STDOUT:   adapt_decl %SomeClass.ref [template]
+// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%SomeClassAdapter
@@ -491,7 +488,7 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:   %.loc5_30.2: type = value_of_initializer %int.make_type_signed.loc5_30 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc5_30.3: type = converted %int.make_type_signed.loc5_30, %.loc5_30.2 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc5_33: type = struct_type {.a: %i32, .b: %i32} [template = constants.%.2]
-// CHECK:STDOUT:   adapt_decl %.2
+// CHECK:STDOUT:   adapt_decl %.loc5_33 [template]
 // CHECK:STDOUT:   %.loc6: <witness> = complete_type_witness %.2 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -567,7 +564,7 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:   %.loc5_26.3: type = value_of_initializer %int.make_type_signed.loc5_22 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc5_26.4: type = converted %int.make_type_signed.loc5_22, %.loc5_26.3 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc5_26.5: type = converted %.loc5_25, constants.%tuple.type.2 [template = constants.%tuple.type.2]
-// CHECK:STDOUT:   adapt_decl %tuple.type.2
+// CHECK:STDOUT:   adapt_decl %.loc5_26.5 [template]
 // CHECK:STDOUT:   %.loc6: <witness> = complete_type_witness %tuple.type.2 [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -658,7 +655,7 @@ fn F(a: IntAdapter) -> i32 {
 // CHECK:STDOUT:   %int.make_type_signed: init type = call %MakeInt.ref(%.loc7_24) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc7_27.1: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
 // CHECK:STDOUT:   %.loc7_27.2: type = converted %int.make_type_signed, %.loc7_27.1 [template = constants.%i32]
-// CHECK:STDOUT:   adapt_decl %i32
+// CHECK:STDOUT:   adapt_decl %.loc7_27.2 [template]
 // CHECK:STDOUT:   %.loc8: <witness> = complete_type_witness %i32 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 4 - 4
toolchain/check/testdata/class/fail_abstract.carbon

@@ -361,7 +361,7 @@ fn CallReturnAbstract() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Adapter {
 // CHECK:STDOUT:   %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract]
-// CHECK:STDOUT:   adapt_decl <error>
+// CHECK:STDOUT:   adapt_decl <error> [template]
 // CHECK:STDOUT:   %.loc17: <witness> = complete_type_witness <error> [template = <error>]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -492,7 +492,7 @@ fn CallReturnAbstract() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract]
-// CHECK:STDOUT:   %.loc8: %.4 = base_decl %Abstract, element0 [template]
+// CHECK:STDOUT:   %.loc8: %.4 = base_decl %Abstract.ref, element0 [template]
 // CHECK:STDOUT:   %.loc10_10.1: Core.IntLiteral = int_value 32 [template = constants.%.5]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc10_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc10_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
@@ -577,7 +577,7 @@ fn CallReturnAbstract() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract]
-// CHECK:STDOUT:   %.loc8: %.4 = base_decl %Abstract, element0 [template]
+// CHECK:STDOUT:   %.loc8: %.4 = base_decl %Abstract.ref, element0 [template]
 // CHECK:STDOUT:   %.loc10_10.1: Core.IntLiteral = int_value 32 [template = constants.%.5]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc10_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc10_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
@@ -669,7 +669,7 @@ fn CallReturnAbstract() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract]
-// CHECK:STDOUT:   %.loc9: %.6 = base_decl %Abstract, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.6 = base_decl %Abstract.ref, element0 [template]
 // CHECK:STDOUT:   %.loc11_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc11_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc11_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]

+ 4 - 4
toolchain/check/testdata/class/fail_adapt_bad_decl.carbon

@@ -140,7 +140,7 @@ class C {
 // CHECK:STDOUT: class @Bad {
 // CHECK:STDOUT:   %.loc12_9: Core.IntLiteral = int_value 100 [template = constants.%.1]
 // CHECK:STDOUT:   %.loc12_12: type = converted %.loc12_9, <error> [template = <error>]
-// CHECK:STDOUT:   adapt_decl <error>
+// CHECK:STDOUT:   adapt_decl <error> [template]
 // CHECK:STDOUT:   %.loc13: <witness> = complete_type_witness <error> [template = <error>]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -192,7 +192,7 @@ class C {
 // CHECK:STDOUT: class @Bad {
 // CHECK:STDOUT:   %.loc12_16: Core.IntLiteral = int_value 100 [template = constants.%.1]
 // CHECK:STDOUT:   %.loc12_19: type = converted %.loc12_16, <error> [template = <error>]
-// CHECK:STDOUT:   adapt_decl <error>
+// CHECK:STDOUT:   adapt_decl <error> [template]
 // CHECK:STDOUT:   %.loc13: <witness> = complete_type_witness <error> [template = <error>]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -238,7 +238,7 @@ class C {
 // CHECK:STDOUT: class @MultipleAdapts {
 // CHECK:STDOUT:   %.loc5_10: %empty_tuple.type = tuple_literal ()
 // CHECK:STDOUT:   %.loc5_11: type = converted %.loc5_10, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:   adapt_decl %empty_tuple.type
+// CHECK:STDOUT:   adapt_decl %.loc5_11 [template]
 // CHECK:STDOUT:   %.loc13: %.1 = struct_literal ()
 // CHECK:STDOUT:   %.loc14: <witness> = complete_type_witness %empty_tuple.type [template = constants.%.2]
 // CHECK:STDOUT:
@@ -249,7 +249,7 @@ class C {
 // CHECK:STDOUT: class @MultipleAdaptsSameType {
 // CHECK:STDOUT:   %.loc17_10: %empty_tuple.type = tuple_literal ()
 // CHECK:STDOUT:   %.loc17_11: type = converted %.loc17_10, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:   adapt_decl %empty_tuple.type
+// CHECK:STDOUT:   adapt_decl %.loc17_11 [template]
 // CHECK:STDOUT:   %.loc25: %empty_tuple.type = tuple_literal ()
 // CHECK:STDOUT:   %.loc26: <witness> = complete_type_witness %empty_tuple.type [template = constants.%.2]
 // CHECK:STDOUT:

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

@@ -53,7 +53,7 @@ class AdaptIncomplete {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @AdaptIncomplete {
 // CHECK:STDOUT:   %Incomplete.ref: type = name_ref Incomplete, file.%Incomplete.decl [template = constants.%Incomplete]
-// CHECK:STDOUT:   adapt_decl <error>
+// CHECK:STDOUT:   adapt_decl <error> [template]
 // CHECK:STDOUT:   %.loc14: <witness> = complete_type_witness <error> [template = <error>]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 10 - 11
toolchain/check/testdata/class/fail_adapt_modifiers.carbon

@@ -62,7 +62,6 @@ class C5 {
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
 // CHECK:STDOUT:   %C1: type = class_type @C1 [template]
-// CHECK:STDOUT:   %.4: <witness> = complete_type_witness %B [template]
 // CHECK:STDOUT:   %C2: type = class_type @C2 [template]
 // CHECK:STDOUT:   %C3: type = class_type @C3 [template]
 // CHECK:STDOUT:   %C4: type = class_type @C4 [template]
@@ -104,8 +103,8 @@ class C5 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C1 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   adapt_decl %B
-// CHECK:STDOUT:   %.loc19: <witness> = complete_type_witness %B [template = constants.%.4]
+// CHECK:STDOUT:   adapt_decl %B.ref [template]
+// CHECK:STDOUT:   %.loc19: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%C1
@@ -113,8 +112,8 @@ class C5 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C2 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   adapt_decl %B
-// CHECK:STDOUT:   %.loc27: <witness> = complete_type_witness %B [template = constants.%.4]
+// CHECK:STDOUT:   adapt_decl %B.ref [template]
+// CHECK:STDOUT:   %.loc27: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%C2
@@ -122,8 +121,8 @@ class C5 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C3 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   adapt_decl %B
-// CHECK:STDOUT:   %.loc35: <witness> = complete_type_witness %B [template = constants.%.4]
+// CHECK:STDOUT:   adapt_decl %B.ref [template]
+// CHECK:STDOUT:   %.loc35: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%C3
@@ -131,8 +130,8 @@ class C5 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C4 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   adapt_decl %B
-// CHECK:STDOUT:   %.loc46: <witness> = complete_type_witness %B [template = constants.%.4]
+// CHECK:STDOUT:   adapt_decl %B.ref [template]
+// CHECK:STDOUT:   %.loc46: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%C4
@@ -141,8 +140,8 @@ class C5 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C5 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   adapt_decl %B
-// CHECK:STDOUT:   %.loc56: <witness> = complete_type_witness %B [template = constants.%.4]
+// CHECK:STDOUT:   adapt_decl %B.ref [template]
+// CHECK:STDOUT:   %.loc56: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%C5

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

@@ -58,7 +58,7 @@ base class AdaptWithVirtual {
 // CHECK:STDOUT: class @AdaptWithVirtual {
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
 // CHECK:STDOUT:   %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%Simple]
-// CHECK:STDOUT:   adapt_decl %Simple
+// CHECK:STDOUT:   adapt_decl %Simple.ref [template]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AdaptWithVirtual

+ 6 - 6
toolchain/check/testdata/class/fail_adapt_with_subobjects.carbon

@@ -119,9 +119,9 @@ class AdaptWithBaseAndFields {
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc10_9) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc10_12.1: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
 // CHECK:STDOUT:   %.loc10_12.2: type = converted %int.make_type_signed, %.loc10_12.1 [template = constants.%i32]
-// CHECK:STDOUT:   adapt_decl %i32
+// CHECK:STDOUT:   adapt_decl %.loc10_12.2 [template]
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc15: %.5 = base_decl %Base, element<invalid> [template]
+// CHECK:STDOUT:   %.loc15: %.5 = base_decl %Base.ref, element<invalid> [template]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AdaptWithBase
@@ -166,7 +166,7 @@ class AdaptWithBaseAndFields {
 // CHECK:STDOUT:   %int.make_type_signed.loc8: init type = call constants.%Int(%.loc8_9) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc8_12.1: type = value_of_initializer %int.make_type_signed.loc8 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc8_12.2: type = converted %int.make_type_signed.loc8, %.loc8_12.1 [template = constants.%i32]
-// CHECK:STDOUT:   adapt_decl %i32
+// CHECK:STDOUT:   adapt_decl %.loc8_12.2 [template]
 // CHECK:STDOUT:   %.loc13_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed.loc13: init type = call constants.%Int(%.loc13_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc13_10.2: type = value_of_initializer %int.make_type_signed.loc13 [template = constants.%i32]
@@ -183,7 +183,7 @@ class AdaptWithBaseAndFields {
 // CHECK:STDOUT:   %int.make_type_signed.loc20: init type = call constants.%Int(%.loc20_9) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc20_12.1: type = value_of_initializer %int.make_type_signed.loc20 [template = constants.%i32]
 // CHECK:STDOUT:   %.loc20_12.2: type = converted %int.make_type_signed.loc20, %.loc20_12.1 [template = constants.%i32]
-// CHECK:STDOUT:   adapt_decl %i32
+// CHECK:STDOUT:   adapt_decl %.loc20_12.2 [template]
 // CHECK:STDOUT:   %.loc25_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed.loc25: init type = call constants.%Int(%.loc25_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc25_10.2: type = value_of_initializer %int.make_type_signed.loc25 [template = constants.%i32]
@@ -250,7 +250,7 @@ class AdaptWithBaseAndFields {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @AdaptWithBaseAndFields {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc7: %.4 = base_decl %Base, element<invalid> [template]
+// CHECK:STDOUT:   %.loc7: %.4 = base_decl %Base.ref, element<invalid> [template]
 // CHECK:STDOUT:   %.loc8_10.1: Core.IntLiteral = int_value 32 [template = constants.%.5]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc8_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc8_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
@@ -258,7 +258,7 @@ class AdaptWithBaseAndFields {
 // CHECK:STDOUT:   %.loc8_8: %.6 = field_decl n, element<invalid> [template]
 // CHECK:STDOUT:   %.loc15_10: %.1 = struct_literal ()
 // CHECK:STDOUT:   %.loc15_11: type = converted %.loc15_10, constants.%.1 [template = constants.%.1]
-// CHECK:STDOUT:   adapt_decl %.1
+// CHECK:STDOUT:   adapt_decl %.loc15_11 [template]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AdaptWithBaseAndFields

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

@@ -847,7 +847,7 @@ fn AccessMemberWithInvalidBaseFinal_NoMember(p: DeriveFromFinal*) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @DeriveFromFinal {
 // CHECK:STDOUT:   %Final.ref: type = name_ref Final, file.%Final.decl [template = constants.%Final]
-// CHECK:STDOUT:   %.loc11: %.6 = base_decl %Final, element0 [template]
+// CHECK:STDOUT:   %.loc11: %.6 = base_decl %Final.ref, element0 [template]
 // CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.7 [template = constants.%.8]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

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

@@ -94,7 +94,7 @@ fn D.C.F() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @D {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc20: %.4 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc20: %.4 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc21: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 4 - 4
toolchain/check/testdata/class/fail_base_modifiers.carbon

@@ -102,7 +102,7 @@ class C4 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C1 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc18: %.4 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc18: %.4 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc19: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -113,7 +113,7 @@ class C4 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C2 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc30: %.7 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc30: %.7 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc31: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -123,7 +123,7 @@ class C4 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C3 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc41: %.8 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc41: %.8 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc42: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -134,7 +134,7 @@ class C4 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C4 {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc51: %.9 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc51: %.9 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc52: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

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

@@ -56,7 +56,7 @@ class C {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc17: %.4 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc17: %.4 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc18: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

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

@@ -88,7 +88,7 @@ class D {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B1.ref: type = name_ref B1, file.%B1.decl [template = constants.%B1]
-// CHECK:STDOUT:   %.loc15: %.4 = base_decl %B1, element0 [template]
+// CHECK:STDOUT:   %.loc15: %.4 = base_decl %B1.ref, element0 [template]
 // CHECK:STDOUT:   %B2.ref: type = name_ref B2, file.%B2.decl [template = constants.%B2]
 // CHECK:STDOUT:   %.loc24: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
@@ -100,7 +100,7 @@ class D {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @D {
 // CHECK:STDOUT:   %B1.ref.loc28: type = name_ref B1, file.%B1.decl [template = constants.%B1]
-// CHECK:STDOUT:   %.loc28: %.7 = base_decl %B1, element0 [template]
+// CHECK:STDOUT:   %.loc28: %.7 = base_decl %B1.ref.loc28, element0 [template]
 // CHECK:STDOUT:   %B1.ref.loc35: type = name_ref B1, file.%B1.decl [template = constants.%B1]
 // CHECK:STDOUT:   %.loc36: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:

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

@@ -60,7 +60,7 @@ let b: B = C.base;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc14: %.4 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc14: %.4 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %.loc15: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

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

@@ -153,7 +153,7 @@ fn ConvertIncomplete(p: Incomplete*) -> A2* { return p; }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B2 {
 // CHECK:STDOUT:   %A2.ref: type = name_ref A2, file.%A2.decl [template = constants.%A2]
-// CHECK:STDOUT:   %.loc20: %.7 = base_decl %A2, element0 [template]
+// CHECK:STDOUT:   %.loc20: %.7 = base_decl %A2.ref, element0 [template]
 // CHECK:STDOUT:   %.loc21_10.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
 // CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc21_10.1) [template = constants.%i32]
 // CHECK:STDOUT:   %.loc21_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]

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

@@ -73,7 +73,7 @@ base class A {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc16: %.4 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc16: %.4 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %.loc17: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -84,7 +84,7 @@ base class A {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @.1 {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc27: %.8 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc27: %.8 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %C.ref: <error> = name_ref C, <error> [template = <error>]
 // CHECK:STDOUT:   %.loc31: <error> = field_decl c, element1 [template]
 // CHECK:STDOUT:   %.loc32: <witness> = complete_type_witness <error> [template = <error>]

+ 1008 - 0
toolchain/check/testdata/class/generic/adapt.carbon

@@ -0,0 +1,1008 @@
+// 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/adapt.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic/adapt.carbon
+
+// --- adapt_specific_type.carbon
+
+library "[[@TEST_NAME]]";
+
+class C(T:! type) {
+  var x: T;
+}
+
+class Adapter {
+  adapt C(i32);
+}
+
+fn Access(a: Adapter) -> i32 {
+  return (a as C(i32)).x;
+}
+
+// --- import_adapt_specific_type.carbon
+
+library "[[@TEST_NAME]]";
+
+import library "adapt_specific_type";
+
+fn ImportedAccess(a: Adapter) -> i32 {
+  return (a as C(i32)).x;
+}
+
+// --- fail_todo_extend_adapt_specific_type.carbon
+
+library "[[@TEST_NAME]]";
+
+class C(T:! type) {
+  var x: T;
+}
+
+class Adapter {
+  extend adapt C(i32);
+}
+
+fn Access(a: Adapter) -> i32 {
+  // TODO: This should presumably work, but the design doesn't say how yet.
+  // CHECK:STDERR: fail_todo_extend_adapt_specific_type.carbon:[[@LINE+7]]:10: error: cannot implicitly convert from `Adapter` to `C(i32)` [ImplicitAsConversionFailure]
+  // CHECK:STDERR:   return a.x;
+  // CHECK:STDERR:          ^~~
+  // CHECK:STDERR: fail_todo_extend_adapt_specific_type.carbon:[[@LINE+4]]:10: note: type `Adapter` does not implement interface `ImplicitAs(C(i32))` [MissingImplInMemberAccessNote]
+  // CHECK:STDERR:   return a.x;
+  // CHECK:STDERR:          ^~~
+  // CHECK:STDERR:
+  return a.x;
+}
+
+// --- extend_adapt_specific_type_library.carbon
+
+// TODO: Delete this file and change the next file to instead import the
+// previous file once the previous file can be successfully type-checked.
+
+library "[[@TEST_NAME]]";
+
+class C(T:! type) {
+  var x: T;
+}
+
+class Adapter {
+  extend adapt C(i32);
+}
+
+// --- fail_todo_import_extend_adapt_specific_type.carbon
+
+library "[[@TEST_NAME]]";
+
+import library "extend_adapt_specific_type_library";
+
+fn ImportedAccess(a: Adapter) -> i32 {
+  // TODO: This should presumably work, but the design doesn't say how yet.
+  // CHECK:STDERR: fail_todo_import_extend_adapt_specific_type.carbon:[[@LINE+6]]:10: error: cannot implicitly convert from `Adapter` to `C(i32)` [ImplicitAsConversionFailure]
+  // CHECK:STDERR:   return a.x;
+  // CHECK:STDERR:          ^~~
+  // CHECK:STDERR: fail_todo_import_extend_adapt_specific_type.carbon:[[@LINE+3]]:10: note: type `Adapter` does not implement interface `ImplicitAs(C(i32))` [MissingImplInMemberAccessNote]
+  // CHECK:STDERR:   return a.x;
+  // CHECK:STDERR:          ^~~
+  return a.x;
+}
+
+// --- adapt_generic_type.carbon
+
+library "[[@TEST_NAME]]";
+
+class Adapter(T:! type) {
+  adapt T;
+}
+
+fn Convert(a: Adapter(i32)) -> i32 {
+  return a as i32;
+}
+
+// --- import_adapt_generic_type.carbon
+
+library "[[@TEST_NAME]]";
+
+import library "adapt_generic_type";
+
+fn ImportedConvert(a: Adapter(i32)) -> i32 {
+  return a as i32;
+}
+
+class C {
+  var n: i32;
+}
+
+fn ImportedConvertLocal(a: Adapter(C)) -> i32 {
+  return (a as C).n;
+}
+
+// CHECK:STDOUT: --- adapt_specific_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 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, @C(%T) [symbolic]
+// CHECK:STDOUT:   %.1: type = unbound_element_type %C.2, %T [symbolic]
+// CHECK:STDOUT:   %.2: type = struct_type {.x: %T} [symbolic]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [symbolic]
+// CHECK:STDOUT:   %Adapter: type = class_type @Adapter [template]
+// CHECK:STDOUT:   %.4: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %Int.type: type = fn_type @Int [template]
+// CHECK:STDOUT:   %Int: %Int.type = struct_value () [template]
+// CHECK:STDOUT:   %i32: type = int_type signed, %.4 [template]
+// CHECK:STDOUT:   %C.3: type = class_type @C, @C(%i32) [template]
+// CHECK:STDOUT:   %.5: type = unbound_element_type %C.3, %i32 [template]
+// CHECK:STDOUT:   %.6: type = struct_type {.x: %i32} [template]
+// CHECK:STDOUT:   %.7: <witness> = complete_type_witness %.6 [template]
+// CHECK:STDOUT:   %Access.type: type = fn_type @Access [template]
+// CHECK:STDOUT:   %Access: %Access.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int = %import_ref
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Adapter = %Adapter.decl
+// CHECK:STDOUT:     .Access = %Access.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: %C.type = class_decl @C [template = constants.%C.1] {
+// CHECK:STDOUT:     %T.patt.loc4_9.1: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:     %T.param_patt: type = value_param_pattern %T.patt.loc4_9.1, runtime_param<invalid> [symbolic = %T.patt.loc4_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = value_param runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc4_9.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_9.2 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Adapter.decl: type = class_decl @Adapter [template = constants.%Adapter] {} {}
+// CHECK:STDOUT:   %Access.decl: %Access.type = fn_decl @Access [template = constants.%Access] {
+// CHECK:STDOUT:     %a.patt: %Adapter = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %Adapter = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Adapter.ref: type = name_ref Adapter, file.%Adapter.decl [template = constants.%Adapter]
+// CHECK:STDOUT:     %.loc12_26.1: Core.IntLiteral = int_value 32 [template = constants.%.4]
+// CHECK:STDOUT:     %int.make_type_signed.loc12: init type = call constants.%Int(%.loc12_26.1) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc12_26.2: type = value_of_initializer %int.make_type_signed.loc12 [template = constants.%i32]
+// CHECK:STDOUT:     %.loc12_26.3: type = converted %int.make_type_signed.loc12, %.loc12_26.2 [template = constants.%i32]
+// CHECK:STDOUT:     %a.param: %Adapter = value_param runtime_param0
+// CHECK:STDOUT:     %a: %Adapter = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @C(%T.loc4_9.1: type) {
+// CHECK:STDOUT:   %T.loc4_9.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_9.2 (constants.%T)]
+// CHECK:STDOUT:   %T.patt.loc4_9.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C: type = class_type @C, @C(%T.loc4_9.2) [symbolic = %C (constants.%C.2)]
+// CHECK:STDOUT:   %.loc5_8.2: type = unbound_element_type @C.%C (%C.2), @C.%T.loc4_9.2 (%T) [symbolic = %.loc5_8.2 (constants.%.1)]
+// CHECK:STDOUT:   %.loc6_1.2: type = struct_type {.x: @C.%T.loc4_9.2 (%T)} [symbolic = %.loc6_1.2 (constants.%.2)]
+// CHECK:STDOUT:   %.loc6_1.3: <witness> = complete_type_witness @C.%.loc6_1.2 (%.2) [symbolic = %.loc6_1.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc4_9.1 [symbolic = %T.loc4_9.2 (constants.%T)]
+// CHECK:STDOUT:     %.loc5_8.1: @C.%.loc5_8.2 (%.1) = field_decl x, element0 [template]
+// CHECK:STDOUT:     %.loc6_1.1: <witness> = complete_type_witness %.2 [symbolic = %.loc6_1.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = constants.%C.2
+// CHECK:STDOUT:     .x = %.loc5_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Adapter {
+// CHECK:STDOUT:   %C.ref: %C.type = name_ref C, file.%C.decl [template = constants.%C.1]
+// CHECK:STDOUT:   %.loc9_11: Core.IntLiteral = int_value 32 [template = constants.%.4]
+// CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc9_11) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc9_10.1: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
+// CHECK:STDOUT:   %.loc9_10.2: type = converted %int.make_type_signed, %.loc9_10.1 [template = constants.%i32]
+// CHECK:STDOUT:   %C: type = class_type @C, @C(constants.%i32) [template = constants.%C.3]
+// CHECK:STDOUT:   adapt_decl %C [template]
+// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %.6 [template = constants.%.7]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Adapter
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Access(%a.param_patt: %Adapter) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %Adapter = name_ref a, %a
+// CHECK:STDOUT:   %C.ref: %C.type = name_ref C, file.%C.decl [template = constants.%C.1]
+// CHECK:STDOUT:   %.loc13_18: Core.IntLiteral = int_value 32 [template = constants.%.4]
+// CHECK:STDOUT:   %int.make_type_signed.loc13: init type = call constants.%Int(%.loc13_18) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc13_17.1: type = value_of_initializer %int.make_type_signed.loc13 [template = constants.%i32]
+// CHECK:STDOUT:   %.loc13_17.2: type = converted %int.make_type_signed.loc13, %.loc13_17.1 [template = constants.%i32]
+// CHECK:STDOUT:   %C: type = class_type @C, @C(constants.%i32) [template = constants.%C.3]
+// CHECK:STDOUT:   %.loc13_13.1: %C.3 = as_compatible %a.ref
+// CHECK:STDOUT:   %.loc13_13.2: %C.3 = converted %a.ref, %.loc13_13.1
+// CHECK:STDOUT:   %x.ref: %.5 = name_ref x, @C.%.loc5_8.1 [template = @C.%.loc5_8.1]
+// CHECK:STDOUT:   %.loc13_23.1: ref %i32 = class_element_access %.loc13_13.2, element0
+// CHECK:STDOUT:   %.loc13_23.2: %i32 = bind_value %.loc13_23.1
+// CHECK:STDOUT:   return %.loc13_23.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%T) {
+// CHECK:STDOUT:   %T.loc4_9.2 => constants.%T
+// CHECK:STDOUT:   %T.patt.loc4_9.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(%T.loc4_9.2) {
+// CHECK:STDOUT:   %T.loc4_9.2 => constants.%T
+// CHECK:STDOUT:   %T.patt.loc4_9.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%i32) {
+// CHECK:STDOUT:   %T.loc4_9.2 => constants.%i32
+// CHECK:STDOUT:   %T.patt.loc4_9.2 => constants.%i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C => constants.%C.3
+// CHECK:STDOUT:   %.loc5_8.2 => constants.%.5
+// CHECK:STDOUT:   %.loc6_1.2 => constants.%.6
+// CHECK:STDOUT:   %.loc6_1.3 => constants.%.7
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- import_adapt_specific_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Adapter: type = class_type @Adapter [template]
+// CHECK:STDOUT:   %.1: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %i32: type = int_type signed, %.1 [template]
+// CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
+// CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = struct_type {.x: %T} [symbolic]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, @C(%T) [symbolic]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
+// CHECK:STDOUT:   %C.3: type = class_type @C, @C(%i32) [template]
+// CHECK:STDOUT:   %.4: type = struct_type {.x: %i32} [template]
+// CHECK:STDOUT:   %.5: <witness> = complete_type_witness %.4 [template]
+// CHECK:STDOUT:   %.6: type = unbound_element_type %C.2, %T [symbolic]
+// CHECK:STDOUT:   %.7: type = unbound_element_type %C.3, %i32 [template]
+// CHECK:STDOUT:   %Int.type: type = fn_type @Int [template]
+// CHECK:STDOUT:   %Int: %Int.type = struct_value () [template]
+// CHECK:STDOUT:   %ImportedAccess.type: type = fn_type @ImportedAccess [template]
+// CHECK:STDOUT:   %ImportedAccess: %ImportedAccess.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: %C.type = import_ref Main//adapt_specific_type, inst+9, loaded [template = constants.%C.1]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//adapt_specific_type, inst+26, loaded [template = constants.%Adapter]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//adapt_specific_type, inst+65, unloaded
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int = %import_ref.8
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//adapt_specific_type, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.5: @C.%.1 (%.6) = import_ref Main//adapt_specific_type, inst+18, loaded [template = %.1]
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//adapt_specific_type, inst+27, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .Adapter = imports.%import_ref.2
+// CHECK:STDOUT:     .Access = imports.%import_ref.3
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .ImportedAccess = %ImportedAccess.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %default.import = import <invalid>
+// CHECK:STDOUT:   %ImportedAccess.decl: %ImportedAccess.type = fn_decl @ImportedAccess [template = constants.%ImportedAccess] {
+// CHECK:STDOUT:     %a.patt: %Adapter = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %Adapter = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Adapter.ref: type = name_ref Adapter, imports.%import_ref.2 [template = constants.%Adapter]
+// CHECK:STDOUT:     %.loc6_34.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
+// CHECK:STDOUT:     %int.make_type_signed.loc6: init type = call constants.%Int(%.loc6_34.1) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_34.2: type = value_of_initializer %int.make_type_signed.loc6 [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_34.3: type = converted %int.make_type_signed.loc6, %.loc6_34.2 [template = constants.%i32]
+// CHECK:STDOUT:     %a.param: %Adapter = value_param runtime_param0
+// CHECK:STDOUT:     %a: %Adapter = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Adapter {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.7
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @C(constants.%T: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C: type = class_type @C, @C(%T) [symbolic = %C (constants.%C.2)]
+// CHECK:STDOUT:   %.1: type = unbound_element_type @C.%C (%C.2), @C.%T (%T) [symbolic = %.1 (constants.%.6)]
+// CHECK:STDOUT:   %.2: type = struct_type {.x: @C.%T (%T)} [symbolic = %.2 (constants.%.2)]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness @C.%.2 (%.2) [symbolic = %.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = imports.%import_ref.4
+// CHECK:STDOUT:     .x = imports.%import_ref.5
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @ImportedAccess(%a.param_patt: %Adapter) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %Adapter = name_ref a, %a
+// CHECK:STDOUT:   %C.ref: %C.type = name_ref C, imports.%import_ref.1 [template = constants.%C.1]
+// CHECK:STDOUT:   %.loc7_18: Core.IntLiteral = int_value 32 [template = constants.%.1]
+// CHECK:STDOUT:   %int.make_type_signed.loc7: init type = call constants.%Int(%.loc7_18) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc7_17.1: type = value_of_initializer %int.make_type_signed.loc7 [template = constants.%i32]
+// CHECK:STDOUT:   %.loc7_17.2: type = converted %int.make_type_signed.loc7, %.loc7_17.1 [template = constants.%i32]
+// CHECK:STDOUT:   %C: type = class_type @C, @C(constants.%i32) [template = constants.%C.3]
+// CHECK:STDOUT:   %.loc7_13.1: %C.3 = as_compatible %a.ref
+// CHECK:STDOUT:   %.loc7_13.2: %C.3 = converted %a.ref, %.loc7_13.1
+// CHECK:STDOUT:   %x.ref: %.7 = name_ref x, imports.%import_ref.5 [template = imports.%.1]
+// CHECK:STDOUT:   %.loc7_23.1: ref %i32 = class_element_access %.loc7_13.2, element0
+// CHECK:STDOUT:   %.loc7_23.2: %i32 = bind_value %.loc7_23.1
+// CHECK:STDOUT:   return %.loc7_23.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %T.patt => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%i32) {
+// CHECK:STDOUT:   %T => constants.%i32
+// CHECK:STDOUT:   %T.patt => constants.%i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C => constants.%C.3
+// CHECK:STDOUT:   %.1 => constants.%.7
+// CHECK:STDOUT:   %.2 => constants.%.4
+// CHECK:STDOUT:   %.3 => constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %T.patt => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_todo_extend_adapt_specific_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 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, @C(%T) [symbolic]
+// CHECK:STDOUT:   %.1: type = unbound_element_type %C.2, %T [symbolic]
+// CHECK:STDOUT:   %.2: type = struct_type {.x: %T} [symbolic]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [symbolic]
+// CHECK:STDOUT:   %Adapter: type = class_type @Adapter [template]
+// CHECK:STDOUT:   %.4: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %Int.type: type = fn_type @Int [template]
+// CHECK:STDOUT:   %Int: %Int.type = struct_value () [template]
+// CHECK:STDOUT:   %i32: type = int_type signed, %.4 [template]
+// CHECK:STDOUT:   %C.3: type = class_type @C, @C(%i32) [template]
+// CHECK:STDOUT:   %.5: type = unbound_element_type %C.3, %i32 [template]
+// CHECK:STDOUT:   %.6: type = struct_type {.x: %i32} [template]
+// CHECK:STDOUT:   %.7: <witness> = complete_type_witness %.6 [template]
+// CHECK:STDOUT:   %Access.type: type = fn_type @Access [template]
+// CHECK:STDOUT:   %Access: %Access.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int = %import_ref.1
+// CHECK:STDOUT:     .ImplicitAs = %import_ref.2
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Adapter = %Adapter.decl
+// CHECK:STDOUT:     .Access = %Access.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: %C.type = class_decl @C [template = constants.%C.1] {
+// CHECK:STDOUT:     %T.patt.loc4_9.1: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:     %T.param_patt: type = value_param_pattern %T.patt.loc4_9.1, runtime_param<invalid> [symbolic = %T.patt.loc4_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = value_param runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc4_9.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_9.2 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Adapter.decl: type = class_decl @Adapter [template = constants.%Adapter] {} {}
+// CHECK:STDOUT:   %Access.decl: %Access.type = fn_decl @Access [template = constants.%Access] {
+// CHECK:STDOUT:     %a.patt: %Adapter = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %Adapter = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Adapter.ref: type = name_ref Adapter, file.%Adapter.decl [template = constants.%Adapter]
+// CHECK:STDOUT:     %.loc12_26.1: Core.IntLiteral = int_value 32 [template = constants.%.4]
+// CHECK:STDOUT:     %int.make_type_signed: init type = call constants.%Int(%.loc12_26.1) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc12_26.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
+// CHECK:STDOUT:     %.loc12_26.3: type = converted %int.make_type_signed, %.loc12_26.2 [template = constants.%i32]
+// CHECK:STDOUT:     %a.param: %Adapter = value_param runtime_param0
+// CHECK:STDOUT:     %a: %Adapter = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @C(%T.loc4_9.1: type) {
+// CHECK:STDOUT:   %T.loc4_9.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_9.2 (constants.%T)]
+// CHECK:STDOUT:   %T.patt.loc4_9.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C: type = class_type @C, @C(%T.loc4_9.2) [symbolic = %C (constants.%C.2)]
+// CHECK:STDOUT:   %.loc5_8.2: type = unbound_element_type @C.%C (%C.2), @C.%T.loc4_9.2 (%T) [symbolic = %.loc5_8.2 (constants.%.1)]
+// CHECK:STDOUT:   %.loc6_1.2: type = struct_type {.x: @C.%T.loc4_9.2 (%T)} [symbolic = %.loc6_1.2 (constants.%.2)]
+// CHECK:STDOUT:   %.loc6_1.3: <witness> = complete_type_witness @C.%.loc6_1.2 (%.2) [symbolic = %.loc6_1.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc4_9.1 [symbolic = %T.loc4_9.2 (constants.%T)]
+// CHECK:STDOUT:     %.loc5_8.1: @C.%.loc5_8.2 (%.1) = field_decl x, element0 [template]
+// CHECK:STDOUT:     %.loc6_1.1: <witness> = complete_type_witness %.2 [symbolic = %.loc6_1.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = constants.%C.2
+// CHECK:STDOUT:     .x = %.loc5_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Adapter {
+// CHECK:STDOUT:   %C.ref: %C.type = name_ref C, file.%C.decl [template = constants.%C.1]
+// CHECK:STDOUT:   %.loc9_18: Core.IntLiteral = int_value 32 [template = constants.%.4]
+// CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc9_18) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc9_17.1: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
+// CHECK:STDOUT:   %.loc9_17.2: type = converted %int.make_type_signed, %.loc9_17.1 [template = constants.%i32]
+// CHECK:STDOUT:   %C: type = class_type @C, @C(constants.%i32) [template = constants.%C.3]
+// CHECK:STDOUT:   adapt_decl %C [template]
+// CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %.6 [template = constants.%.7]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Adapter
+// CHECK:STDOUT:   extend %C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Access(%a.param_patt: %Adapter) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %Adapter = name_ref a, %a
+// CHECK:STDOUT:   %x.ref: %.5 = name_ref x, @C.%.loc5_8.1 [template = @C.%.loc5_8.1]
+// CHECK:STDOUT:   %.loc21_11.1: %C.3 = converted %a.ref, <error> [template = <error>]
+// CHECK:STDOUT:   %.loc21_11.2: %i32 = class_element_access <error>, element0 [template = <error>]
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%T) {
+// CHECK:STDOUT:   %T.loc4_9.2 => constants.%T
+// CHECK:STDOUT:   %T.patt.loc4_9.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(%T.loc4_9.2) {
+// CHECK:STDOUT:   %T.loc4_9.2 => constants.%T
+// CHECK:STDOUT:   %T.patt.loc4_9.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%i32) {
+// CHECK:STDOUT:   %T.loc4_9.2 => constants.%i32
+// CHECK:STDOUT:   %T.patt.loc4_9.2 => constants.%i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C => constants.%C.3
+// CHECK:STDOUT:   %.loc5_8.2 => constants.%.5
+// CHECK:STDOUT:   %.loc6_1.2 => constants.%.6
+// CHECK:STDOUT:   %.loc6_1.3 => constants.%.7
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- extend_adapt_specific_type_library.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 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, @C(%T) [symbolic]
+// CHECK:STDOUT:   %.1: type = unbound_element_type %C.2, %T [symbolic]
+// CHECK:STDOUT:   %.2: type = struct_type {.x: %T} [symbolic]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [symbolic]
+// CHECK:STDOUT:   %Adapter: type = class_type @Adapter [template]
+// CHECK:STDOUT:   %.4: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %Int.type: type = fn_type @Int [template]
+// CHECK:STDOUT:   %Int: %Int.type = struct_value () [template]
+// CHECK:STDOUT:   %i32: type = int_type signed, %.4 [template]
+// CHECK:STDOUT:   %C.3: type = class_type @C, @C(%i32) [template]
+// CHECK:STDOUT:   %.5: type = unbound_element_type %C.3, %i32 [template]
+// CHECK:STDOUT:   %.6: type = struct_type {.x: %i32} [template]
+// CHECK:STDOUT:   %.7: <witness> = complete_type_witness %.6 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int = %import_ref
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Adapter = %Adapter.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: %C.type = class_decl @C [template = constants.%C.1] {
+// CHECK:STDOUT:     %T.patt.loc7_9.1: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc7_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:     %T.param_patt: type = value_param_pattern %T.patt.loc7_9.1, runtime_param<invalid> [symbolic = %T.patt.loc7_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = value_param runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc7_9.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc7_9.2 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Adapter.decl: type = class_decl @Adapter [template = constants.%Adapter] {} {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @C(%T.loc7_9.1: type) {
+// CHECK:STDOUT:   %T.loc7_9.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc7_9.2 (constants.%T)]
+// CHECK:STDOUT:   %T.patt.loc7_9.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc7_9.2 (constants.%T.patt)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C: type = class_type @C, @C(%T.loc7_9.2) [symbolic = %C (constants.%C.2)]
+// CHECK:STDOUT:   %.loc8_8.2: type = unbound_element_type @C.%C (%C.2), @C.%T.loc7_9.2 (%T) [symbolic = %.loc8_8.2 (constants.%.1)]
+// CHECK:STDOUT:   %.loc9_1.2: type = struct_type {.x: @C.%T.loc7_9.2 (%T)} [symbolic = %.loc9_1.2 (constants.%.2)]
+// CHECK:STDOUT:   %.loc9_1.3: <witness> = complete_type_witness @C.%.loc9_1.2 (%.2) [symbolic = %.loc9_1.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc7_9.1 [symbolic = %T.loc7_9.2 (constants.%T)]
+// CHECK:STDOUT:     %.loc8_8.1: @C.%.loc8_8.2 (%.1) = field_decl x, element0 [template]
+// CHECK:STDOUT:     %.loc9_1.1: <witness> = complete_type_witness %.2 [symbolic = %.loc9_1.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = constants.%C.2
+// CHECK:STDOUT:     .x = %.loc8_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Adapter {
+// CHECK:STDOUT:   %C.ref: %C.type = name_ref C, file.%C.decl [template = constants.%C.1]
+// CHECK:STDOUT:   %.loc12_18: Core.IntLiteral = int_value 32 [template = constants.%.4]
+// CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc12_18) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc12_17.1: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
+// CHECK:STDOUT:   %.loc12_17.2: type = converted %int.make_type_signed, %.loc12_17.1 [template = constants.%i32]
+// CHECK:STDOUT:   %C: type = class_type @C, @C(constants.%i32) [template = constants.%C.3]
+// CHECK:STDOUT:   adapt_decl %C [template]
+// CHECK:STDOUT:   %.loc13: <witness> = complete_type_witness %.6 [template = constants.%.7]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Adapter
+// CHECK:STDOUT:   extend %C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%T) {
+// CHECK:STDOUT:   %T.loc7_9.2 => constants.%T
+// CHECK:STDOUT:   %T.patt.loc7_9.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(%T.loc7_9.2) {
+// CHECK:STDOUT:   %T.loc7_9.2 => constants.%T
+// CHECK:STDOUT:   %T.patt.loc7_9.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%i32) {
+// CHECK:STDOUT:   %T.loc7_9.2 => constants.%i32
+// CHECK:STDOUT:   %T.patt.loc7_9.2 => constants.%i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C => constants.%C.3
+// CHECK:STDOUT:   %.loc8_8.2 => constants.%.5
+// CHECK:STDOUT:   %.loc9_1.2 => constants.%.6
+// CHECK:STDOUT:   %.loc9_1.3 => constants.%.7
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_todo_import_extend_adapt_specific_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Adapter: type = class_type @Adapter [template]
+// CHECK:STDOUT:   %.1: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %i32: type = int_type signed, %.1 [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = struct_type {.x: %T} [symbolic]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [symbolic]
+// CHECK:STDOUT:   %C.2: type = class_type @C, @C(%T) [symbolic]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
+// CHECK:STDOUT:   %C.3: type = class_type @C, @C(%i32) [template]
+// CHECK:STDOUT:   %.4: type = struct_type {.x: %i32} [template]
+// CHECK:STDOUT:   %.5: <witness> = complete_type_witness %.4 [template]
+// CHECK:STDOUT:   %.6: type = unbound_element_type %C.2, %T [symbolic]
+// CHECK:STDOUT:   %.7: type = unbound_element_type %C.3, %i32 [template]
+// CHECK:STDOUT:   %Int.type: type = fn_type @Int [template]
+// CHECK:STDOUT:   %Int: %Int.type = struct_value () [template]
+// CHECK:STDOUT:   %ImportedAccess.type: type = fn_type @ImportedAccess [template]
+// CHECK:STDOUT:   %ImportedAccess: %ImportedAccess.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1 = import_ref Main//extend_adapt_specific_type_library, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//extend_adapt_specific_type_library, inst+26, loaded [template = constants.%Adapter]
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int = %import_ref.8
+// CHECK:STDOUT:     .ImplicitAs = %import_ref.9
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//extend_adapt_specific_type_library, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.4: @C.%.1 (%.6) = import_ref Main//extend_adapt_specific_type_library, inst+18, loaded [template = %.1]
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//extend_adapt_specific_type_library, inst+27, unloaded
+// CHECK:STDOUT:   %import_ref.7: type = import_ref Main//extend_adapt_specific_type_library, inst+44, loaded [template = constants.%C.3]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .Adapter = imports.%import_ref.2
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .ImportedAccess = %ImportedAccess.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %default.import = import <invalid>
+// CHECK:STDOUT:   %ImportedAccess.decl: %ImportedAccess.type = fn_decl @ImportedAccess [template = constants.%ImportedAccess] {
+// CHECK:STDOUT:     %a.patt: %Adapter = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %Adapter = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Adapter.ref: type = name_ref Adapter, imports.%import_ref.2 [template = constants.%Adapter]
+// CHECK:STDOUT:     %.loc6_34.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
+// CHECK:STDOUT:     %int.make_type_signed: init type = call constants.%Int(%.loc6_34.1) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_34.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_34.3: type = converted %int.make_type_signed, %.loc6_34.2 [template = constants.%i32]
+// CHECK:STDOUT:     %a.param: %Adapter = value_param runtime_param0
+// CHECK:STDOUT:     %a: %Adapter = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Adapter {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.6
+// CHECK:STDOUT:   extend imports.%import_ref.7
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @C(constants.%T: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C: type = class_type @C, @C(%T) [symbolic = %C (constants.%C.2)]
+// CHECK:STDOUT:   %.1: type = unbound_element_type @C.%C (%C.2), @C.%T (%T) [symbolic = %.1 (constants.%.6)]
+// CHECK:STDOUT:   %.2: type = struct_type {.x: @C.%T (%T)} [symbolic = %.2 (constants.%.2)]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness @C.%.2 (%.2) [symbolic = %.3 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = imports.%import_ref.3
+// CHECK:STDOUT:     .x = imports.%import_ref.4
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @ImportedAccess(%a.param_patt: %Adapter) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %Adapter = name_ref a, %a
+// CHECK:STDOUT:   %x.ref: %.7 = name_ref x, imports.%import_ref.4 [template = imports.%.1]
+// CHECK:STDOUT:   %.loc14_11.1: %C.3 = converted %a.ref, <error> [template = <error>]
+// CHECK:STDOUT:   %.loc14_11.2: %i32 = class_element_access <error>, element0 [template = <error>]
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %T.patt => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%i32) {
+// CHECK:STDOUT:   %T => constants.%i32
+// CHECK:STDOUT:   %T.patt => constants.%i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %C => constants.%C.3
+// CHECK:STDOUT:   %.1 => constants.%.7
+// CHECK:STDOUT:   %.2 => constants.%.4
+// CHECK:STDOUT:   %.3 => constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %T.patt => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- adapt_generic_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
+// CHECK:STDOUT:   %Adapter.type: type = generic_class_type @Adapter [template]
+// CHECK:STDOUT:   %Adapter.1: %Adapter.type = struct_value () [template]
+// CHECK:STDOUT:   %Adapter.2: type = class_type @Adapter, @Adapter(%T) [symbolic]
+// CHECK:STDOUT:   %.1: <witness> = complete_type_witness %T [symbolic]
+// CHECK:STDOUT:   %.2: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %Int.type: type = fn_type @Int [template]
+// CHECK:STDOUT:   %Int: %Int.type = struct_value () [template]
+// CHECK:STDOUT:   %i32: type = int_type signed, %.2 [template]
+// CHECK:STDOUT:   %Adapter.3: type = class_type @Adapter, @Adapter(%i32) [template]
+// CHECK:STDOUT:   %Convert.type: type = fn_type @Convert [template]
+// CHECK:STDOUT:   %Convert: %Convert.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %i32 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int = %import_ref
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .Adapter = %Adapter.decl
+// CHECK:STDOUT:     .Convert = %Convert.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %Adapter.decl: %Adapter.type = class_decl @Adapter [template = constants.%Adapter.1] {
+// CHECK:STDOUT:     %T.patt.loc4_15.1: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_15.2 (constants.%T.patt)]
+// CHECK:STDOUT:     %T.param_patt: type = value_param_pattern %T.patt.loc4_15.1, runtime_param<invalid> [symbolic = %T.patt.loc4_15.2 (constants.%T.patt)]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = value_param runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc4_15.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_15.2 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Convert.decl: %Convert.type = fn_decl @Convert [template = constants.%Convert] {
+// CHECK:STDOUT:     %a.patt: %Adapter.3 = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %Adapter.3 = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Adapter.ref: %Adapter.type = name_ref Adapter, file.%Adapter.decl [template = constants.%Adapter.1]
+// CHECK:STDOUT:     %.loc8_23: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:     %int.make_type_signed.loc8_23: init type = call constants.%Int(%.loc8_23) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc8_22.1: type = value_of_initializer %int.make_type_signed.loc8_23 [template = constants.%i32]
+// CHECK:STDOUT:     %.loc8_22.2: type = converted %int.make_type_signed.loc8_23, %.loc8_22.1 [template = constants.%i32]
+// CHECK:STDOUT:     %Adapter: type = class_type @Adapter, @Adapter(constants.%i32) [template = constants.%Adapter.3]
+// CHECK:STDOUT:     %.loc8_32.1: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:     %int.make_type_signed.loc8_32: init type = call constants.%Int(%.loc8_32.1) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc8_32.2: type = value_of_initializer %int.make_type_signed.loc8_32 [template = constants.%i32]
+// CHECK:STDOUT:     %.loc8_32.3: type = converted %int.make_type_signed.loc8_32, %.loc8_32.2 [template = constants.%i32]
+// CHECK:STDOUT:     %a.param: %Adapter.3 = value_param runtime_param0
+// CHECK:STDOUT:     %a: %Adapter.3 = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @Adapter(%T.loc4_15.1: type) {
+// CHECK:STDOUT:   %T.loc4_15.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_15.2 (constants.%T)]
+// CHECK:STDOUT:   %T.patt.loc4_15.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_15.2 (constants.%T.patt)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.loc6_1.2: <witness> = complete_type_witness @Adapter.%T.loc4_15.2 (%T) [symbolic = %.loc6_1.2 (constants.%.1)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc4_15.1 [symbolic = %T.loc4_15.2 (constants.%T)]
+// CHECK:STDOUT:     adapt_decl %T.ref [template]
+// CHECK:STDOUT:     %.loc6_1.1: <witness> = complete_type_witness %T [symbolic = %.loc6_1.2 (constants.%.1)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = constants.%Adapter.2
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Convert(%a.param_patt: %Adapter.3) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %Adapter.3 = name_ref a, %a
+// CHECK:STDOUT:   %.loc9_15.1: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:   %int.make_type_signed.loc9: init type = call constants.%Int(%.loc9_15.1) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc9_15.2: type = value_of_initializer %int.make_type_signed.loc9 [template = constants.%i32]
+// CHECK:STDOUT:   %.loc9_15.3: type = converted %int.make_type_signed.loc9, %.loc9_15.2 [template = constants.%i32]
+// CHECK:STDOUT:   %.loc9_12.1: %i32 = as_compatible %a.ref
+// CHECK:STDOUT:   %.loc9_12.2: %i32 = converted %a.ref, %.loc9_12.1
+// CHECK:STDOUT:   return %.loc9_12.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Adapter(constants.%T) {
+// CHECK:STDOUT:   %T.loc4_15.2 => constants.%T
+// CHECK:STDOUT:   %T.patt.loc4_15.2 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Adapter(constants.%i32) {
+// CHECK:STDOUT:   %T.loc4_15.2 => constants.%i32
+// CHECK:STDOUT:   %T.patt.loc4_15.2 => constants.%i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.loc6_1.2 => constants.%.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- import_adapt_generic_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Adapter.type: type = generic_class_type @Adapter [template]
+// CHECK:STDOUT:   %Adapter.1: %Adapter.type = struct_value () [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %.1: <witness> = complete_type_witness %T [symbolic]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
+// CHECK:STDOUT:   %.2: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %Int.type: type = fn_type @Int [template]
+// CHECK:STDOUT:   %Int: %Int.type = struct_value () [template]
+// CHECK:STDOUT:   %i32: type = int_type signed, %.2 [template]
+// CHECK:STDOUT:   %Adapter.3: type = class_type @Adapter, @Adapter(%i32) [template]
+// CHECK:STDOUT:   %ImportedConvert.type: type = fn_type @ImportedConvert [template]
+// CHECK:STDOUT:   %ImportedConvert: %ImportedConvert.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %i32 [template]
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.4: type = unbound_element_type %C, %i32 [template]
+// CHECK:STDOUT:   %.5: type = struct_type {.n: %i32} [template]
+// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %.5 [template]
+// CHECK:STDOUT:   %Adapter.4: type = class_type @Adapter, @Adapter(%C) [template]
+// CHECK:STDOUT:   %ImportedConvertLocal.type: type = fn_type @ImportedConvertLocal [template]
+// CHECK:STDOUT:   %ImportedConvertLocal: %ImportedConvertLocal.type = struct_value () [template]
+// CHECK:STDOUT:   %.7: <witness> = complete_type_witness %C [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: %Adapter.type = import_ref Main//adapt_generic_type, inst+9, loaded [template = constants.%Adapter.1]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//adapt_generic_type, inst+51, unloaded
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int = %import_ref.5
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//adapt_generic_type, inst+15, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Adapter = imports.%import_ref.1
+// CHECK:STDOUT:     .Convert = imports.%import_ref.2
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .ImportedConvert = %ImportedConvert.decl
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .ImportedConvertLocal = %ImportedConvertLocal.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %default.import = import <invalid>
+// CHECK:STDOUT:   %ImportedConvert.decl: %ImportedConvert.type = fn_decl @ImportedConvert [template = constants.%ImportedConvert] {
+// CHECK:STDOUT:     %a.patt: %Adapter.3 = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %Adapter.3 = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Adapter.ref: %Adapter.type = name_ref Adapter, imports.%import_ref.1 [template = constants.%Adapter.1]
+// CHECK:STDOUT:     %.loc6_31: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:     %int.make_type_signed.loc6_31: init type = call constants.%Int(%.loc6_31) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_30.1: type = value_of_initializer %int.make_type_signed.loc6_31 [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_30.2: type = converted %int.make_type_signed.loc6_31, %.loc6_30.1 [template = constants.%i32]
+// CHECK:STDOUT:     %Adapter: type = class_type @Adapter, @Adapter(constants.%i32) [template = constants.%Adapter.3]
+// CHECK:STDOUT:     %.loc6_40.1: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:     %int.make_type_signed.loc6_40: init type = call constants.%Int(%.loc6_40.1) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_40.2: type = value_of_initializer %int.make_type_signed.loc6_40 [template = constants.%i32]
+// CHECK:STDOUT:     %.loc6_40.3: type = converted %int.make_type_signed.loc6_40, %.loc6_40.2 [template = constants.%i32]
+// CHECK:STDOUT:     %a.param: %Adapter.3 = value_param runtime_param0
+// CHECK:STDOUT:     %a: %Adapter.3 = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {} {}
+// CHECK:STDOUT:   %ImportedConvertLocal.decl: %ImportedConvertLocal.type = fn_decl @ImportedConvertLocal [template = constants.%ImportedConvertLocal] {
+// CHECK:STDOUT:     %a.patt: %Adapter.4 = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %Adapter.4 = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Adapter.ref: %Adapter.type = name_ref Adapter, imports.%import_ref.1 [template = constants.%Adapter.1]
+// CHECK:STDOUT:     %C.ref.loc14: type = name_ref C, file.%C.decl [template = constants.%C]
+// CHECK:STDOUT:     %Adapter: type = class_type @Adapter, @Adapter(constants.%C) [template = constants.%Adapter.4]
+// CHECK:STDOUT:     %.loc14_43.1: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:     %int.make_type_signed: init type = call constants.%Int(%.loc14_43.1) [template = constants.%i32]
+// CHECK:STDOUT:     %.loc14_43.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
+// CHECK:STDOUT:     %.loc14_43.3: type = converted %int.make_type_signed, %.loc14_43.2 [template = constants.%i32]
+// CHECK:STDOUT:     %a.param: %Adapter.4 = value_param runtime_param0
+// CHECK:STDOUT:     %a: %Adapter.4 = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @Adapter(constants.%T: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %T.patt: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: <witness> = complete_type_witness @Adapter.%T (%T) [symbolic = %.1 (constants.%.1)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = imports.%import_ref.4
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %.loc11_10.1: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:   %int.make_type_signed: init type = call constants.%Int(%.loc11_10.1) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc11_10.2: type = value_of_initializer %int.make_type_signed [template = constants.%i32]
+// CHECK:STDOUT:   %.loc11_10.3: type = converted %int.make_type_signed, %.loc11_10.2 [template = constants.%i32]
+// CHECK:STDOUT:   %.loc11_8: %.4 = field_decl n, element0 [template]
+// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.5 [template = constants.%.6]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .n = %.loc11_8
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @ImportedConvert(%a.param_patt: %Adapter.3) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %Adapter.3 = name_ref a, %a
+// CHECK:STDOUT:   %.loc7_15.1: Core.IntLiteral = int_value 32 [template = constants.%.2]
+// CHECK:STDOUT:   %int.make_type_signed.loc7: init type = call constants.%Int(%.loc7_15.1) [template = constants.%i32]
+// CHECK:STDOUT:   %.loc7_15.2: type = value_of_initializer %int.make_type_signed.loc7 [template = constants.%i32]
+// CHECK:STDOUT:   %.loc7_15.3: type = converted %int.make_type_signed.loc7, %.loc7_15.2 [template = constants.%i32]
+// CHECK:STDOUT:   %.loc7_12.1: %i32 = as_compatible %a.ref
+// CHECK:STDOUT:   %.loc7_12.2: %i32 = converted %a.ref, %.loc7_12.1
+// CHECK:STDOUT:   return %.loc7_12.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @ImportedConvertLocal(%a.param_patt: %Adapter.4) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %Adapter.4 = name_ref a, %a
+// CHECK:STDOUT:   %C.ref.loc15: type = name_ref C, file.%C.decl [template = constants.%C]
+// CHECK:STDOUT:   %.loc15_13.1: %C = as_compatible %a.ref
+// CHECK:STDOUT:   %.loc15_13.2: %C = converted %a.ref, %.loc15_13.1
+// CHECK:STDOUT:   %n.ref: %.4 = name_ref n, @C.%.loc11_8 [template = @C.%.loc11_8]
+// CHECK:STDOUT:   %.loc15_18.1: ref %i32 = class_element_access %.loc15_13.2, element0
+// CHECK:STDOUT:   %.loc15_18.2: %i32 = bind_value %.loc15_18.1
+// CHECK:STDOUT:   return %.loc15_18.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Adapter(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %T.patt => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Adapter(constants.%i32) {
+// CHECK:STDOUT:   %T => constants.%i32
+// CHECK:STDOUT:   %T.patt => constants.%i32
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Adapter(constants.%C) {
+// CHECK:STDOUT:   %T => constants.%C
+// CHECK:STDOUT:   %T.patt => constants.%C
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.7
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 15 - 15
toolchain/check/testdata/class/generic/base_is_generic.carbon

@@ -197,7 +197,7 @@ fn H() {
 // CHECK:STDOUT:   %Base.ref: %Base.type = name_ref Base, file.%Base.decl [template = constants.%Base.1]
 // CHECK:STDOUT:   %Param.ref: type = name_ref Param, file.%Param.decl [template = constants.%Param]
 // CHECK:STDOUT:   %Base: type = class_type @Base, @Base(constants.%Param) [template = constants.%Base.3]
-// CHECK:STDOUT:   %.loc13: %.14 = base_decl %Base.3, element0 [template]
+// CHECK:STDOUT:   %.loc13: %.14 = base_decl %Base, element0 [template]
 // CHECK:STDOUT:   %.loc14: <witness> = complete_type_witness %.15 [template = constants.%.16]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -270,7 +270,7 @@ fn H() {
 // CHECK:STDOUT:   %import_ref.3: type = import_ref Main//extend_generic_base, inst+48, loaded [template = constants.%Derived]
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//extend_generic_base, inst+78, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     .Int = %import_ref.12
+// CHECK:STDOUT:     .Int = %import_ref.13
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
@@ -278,9 +278,9 @@ fn H() {
 // CHECK:STDOUT:   %import_ref.6: %.17 = import_ref Main//extend_generic_base, inst+44, loaded [template = %.1]
 // CHECK:STDOUT:   %import_ref.7 = import_ref Main//extend_generic_base, inst+15, unloaded
 // CHECK:STDOUT:   %import_ref.8: @Base.%.1 (%.9) = import_ref Main//extend_generic_base, inst+18, loaded [template = %.2]
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//extend_generic_base, inst+49, unloaded
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//extend_generic_base, inst+61, unloaded
-// CHECK:STDOUT:   %import_ref.11: type = import_ref Main//extend_generic_base, inst+52, loaded [template = constants.%Base.3]
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//extend_generic_base, inst+49, unloaded
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//extend_generic_base, inst+61, unloaded
+// CHECK:STDOUT:   %import_ref.12: type = import_ref Main//extend_generic_base, inst+52, loaded [template = constants.%Base.3]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -314,9 +314,9 @@ fn H() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.9
-// CHECK:STDOUT:   .base = imports.%import_ref.10
-// CHECK:STDOUT:   extend imports.%import_ref.11
+// CHECK:STDOUT:   .Self = imports.%import_ref.10
+// CHECK:STDOUT:   .base = imports.%import_ref.11
+// CHECK:STDOUT:   extend imports.%import_ref.12
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Param {
@@ -586,7 +586,7 @@ fn H() {
 // CHECK:STDOUT:     %X.ref: %X.type = name_ref X, file.%X.decl [template = constants.%X.1]
 // CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc8_9.1 [symbolic = %T.loc8_9.2 (constants.%T)]
 // CHECK:STDOUT:     %X.loc9_17.1: type = class_type @X, @X(constants.%T) [symbolic = %X.loc9_17.2 (constants.%X.3)]
-// CHECK:STDOUT:     %.loc9_20.1: @C.%.loc9_20.2 (%.5) = base_decl %X.3, element0 [template]
+// CHECK:STDOUT:     %.loc9_20.1: @C.%.loc9_20.2 (%.5) = base_decl %X.loc9_17.1, element0 [template]
 // CHECK:STDOUT:     %.loc10_1.1: <witness> = complete_type_witness %.6 [symbolic = %.loc10_1.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -770,9 +770,9 @@ fn H() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//extend_generic_symbolic_base, inst+15, unloaded
 // CHECK:STDOUT:   %import_ref.6: @X.%G.type (%G.type.1) = import_ref Main//extend_generic_symbolic_base, inst+21, loaded [symbolic = @X.%G (constants.%G.1)]
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//extend_generic_symbolic_base, inst+52, unloaded
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//extend_generic_symbolic_base, inst+61, unloaded
-// CHECK:STDOUT:   %import_ref.9: type = import_ref Main//extend_generic_symbolic_base, inst+55, loaded [symbolic = @C.%X (constants.%X.3)]
+// CHECK:STDOUT:   %import_ref.8 = import_ref Main//extend_generic_symbolic_base, inst+52, unloaded
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//extend_generic_symbolic_base, inst+61, unloaded
+// CHECK:STDOUT:   %import_ref.10: type = import_ref Main//extend_generic_symbolic_base, inst+55, loaded [symbolic = @C.%X (constants.%X.3)]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -801,9 +801,9 @@ fn H() {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   class {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%import_ref.7
-// CHECK:STDOUT:     .base = imports.%import_ref.8
-// CHECK:STDOUT:     extend imports.%import_ref.9
+// CHECK:STDOUT:     .Self = imports.%import_ref.8
+// CHECK:STDOUT:     .base = imports.%import_ref.9
+// CHECK:STDOUT:     extend imports.%import_ref.10
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

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

@@ -332,7 +332,7 @@ fn InitFromAdaptedSpecific(x: i32) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   class {
 // CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc4_13.1 [symbolic = %T.loc4_13.2 (constants.%T)]
-// CHECK:STDOUT:     adapt_decl %T
+// CHECK:STDOUT:     adapt_decl %T.ref [template]
 // CHECK:STDOUT:     %.loc6_1.1: <witness> = complete_type_witness %T [symbolic = %.loc6_1.2 (constants.%.1)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:

+ 8 - 8
toolchain/check/testdata/class/import_base.carbon

@@ -115,7 +115,7 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Child {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc13: %.6 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc13: %.6 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %.loc14: <witness> = complete_type_witness %.7 [template = constants.%.8]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -167,7 +167,7 @@ fn Run() {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//a, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+47, loaded [template = constants.%Child]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     .ImplicitAs = %import_ref.11
+// CHECK:STDOUT:     .ImplicitAs = %import_ref.12
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
@@ -176,9 +176,9 @@ fn Run() {
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//a, inst+19, unloaded
 // CHECK:STDOUT:   %import_ref.6: %.44 = import_ref Main//a, inst+38, loaded [template = %.1]
 // CHECK:STDOUT:   %import_ref.7 = import_ref Main//a, inst+43, unloaded
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//a, inst+48, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//a, inst+52, unloaded
-// CHECK:STDOUT:   %import_ref.10: type = import_ref Main//a, inst+49, loaded [template = constants.%Base]
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//a, inst+48, unloaded
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//a, inst+52, unloaded
+// CHECK:STDOUT:   %import_ref.11: type = import_ref Main//a, inst+49, loaded [template = constants.%Base]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -195,9 +195,9 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Child {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.8
-// CHECK:STDOUT:   .base = imports.%import_ref.9
-// CHECK:STDOUT:   extend imports.%import_ref.10
+// CHECK:STDOUT:   .Self = imports.%import_ref.9
+// CHECK:STDOUT:   .base = imports.%import_ref.10
+// CHECK:STDOUT:   extend imports.%import_ref.11
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Base {

+ 9 - 9
toolchain/check/testdata/class/inheritance_access.carbon

@@ -287,7 +287,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Circle {
 // CHECK:STDOUT:   %Shape.ref: type = name_ref Shape, file.%Shape.decl [template = constants.%Shape]
-// CHECK:STDOUT:   %.loc10: %.6 = base_decl %Shape, element0 [template]
+// CHECK:STDOUT:   %.loc10: %.6 = base_decl %Shape.ref, element0 [template]
 // CHECK:STDOUT:   %GetPosition.decl: %GetPosition.type = fn_decl @GetPosition [template = constants.%GetPosition] {
 // CHECK:STDOUT:     %self.patt: %Circle = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %Circle = value_param_pattern %self.patt, runtime_param0
@@ -403,7 +403,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc9: %.4 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.4 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
 // CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param0
@@ -426,7 +426,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc14: %.10 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc14: %.10 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %C = value_param_pattern %self.patt, runtime_param0
@@ -550,7 +550,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc12: %.33 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc12: %.33 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
 // CHECK:STDOUT:     %return.patt: %i32 = return_slot_pattern
 // CHECK:STDOUT:     %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param0
@@ -665,7 +665,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Square {
 // CHECK:STDOUT:   %Shape.ref: type = name_ref Shape, file.%Shape.decl [template = constants.%Shape]
-// CHECK:STDOUT:   %.loc9: %.6 = base_decl %Shape, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.6 = base_decl %Shape.ref, element0 [template]
 // CHECK:STDOUT:   %GetPosition.decl: %GetPosition.type = fn_decl @GetPosition [template = constants.%GetPosition] {
 // CHECK:STDOUT:     %self.patt: %Square = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %Square = value_param_pattern %self.patt, runtime_param0
@@ -849,7 +849,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc9: %.4 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.4 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {} {}
 // CHECK:STDOUT:   %.loc18: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
@@ -918,7 +918,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc9: %.4 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.4 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {} {}
 // CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:
@@ -1157,7 +1157,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc9: %.6 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.6 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
 // CHECK:STDOUT:     %self.patt: %B = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %B = value_param_pattern %self.patt, runtime_param0
@@ -1236,7 +1236,7 @@ class B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
 // CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
-// CHECK:STDOUT:   %.loc9: %.6 = base_decl %A, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.6 = base_decl %A.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
 // CHECK:STDOUT:     %self.patt: %B = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %B = value_param_pattern %self.patt, runtime_param0

+ 56 - 58
toolchain/check/testdata/class/init_adapt.carbon

@@ -103,21 +103,20 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:   %.3: type = struct_type {.a: %i32, .b: %i32} [template]
 // CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
 // CHECK:STDOUT:   %AdaptC: type = class_type @AdaptC [template]
-// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %C [template]
-// CHECK:STDOUT:   %.7: Core.IntLiteral = int_value 1 [template]
-// CHECK:STDOUT:   %.8: Core.IntLiteral = int_value 2 [template]
-// CHECK:STDOUT:   %.9: type = struct_type {.a: Core.IntLiteral, .b: Core.IntLiteral} [template]
+// CHECK:STDOUT:   %.6: Core.IntLiteral = int_value 1 [template]
+// CHECK:STDOUT:   %.7: Core.IntLiteral = int_value 2 [template]
+// CHECK:STDOUT:   %.8: type = struct_type {.a: Core.IntLiteral, .b: Core.IntLiteral} [template]
 // CHECK:STDOUT:   %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
 // CHECK:STDOUT:   %Convert.type.14: type = fn_type @Convert.2, @impl.1(%.1) [template]
 // CHECK:STDOUT:   %Convert.14: %Convert.type.14 = struct_value () [template]
-// CHECK:STDOUT:   %.33: <witness> = interface_witness (%Convert.14) [template]
-// CHECK:STDOUT:   %.34: <bound method> = bound_method %.7, %Convert.14 [template]
-// CHECK:STDOUT:   %.35: <specific function> = specific_function %.34, @Convert.2(%.1) [template]
-// CHECK:STDOUT:   %.36: %i32 = int_value 1 [template]
-// CHECK:STDOUT:   %.37: <bound method> = bound_method %.8, %Convert.14 [template]
-// CHECK:STDOUT:   %.38: <specific function> = specific_function %.37, @Convert.2(%.1) [template]
-// CHECK:STDOUT:   %.39: %i32 = int_value 2 [template]
-// CHECK:STDOUT:   %struct: %C = struct_value (%.36, %.39) [template]
+// CHECK:STDOUT:   %.32: <witness> = interface_witness (%Convert.14) [template]
+// CHECK:STDOUT:   %.33: <bound method> = bound_method %.6, %Convert.14 [template]
+// CHECK:STDOUT:   %.34: <specific function> = specific_function %.33, @Convert.2(%.1) [template]
+// CHECK:STDOUT:   %.35: %i32 = int_value 1 [template]
+// CHECK:STDOUT:   %.36: <bound method> = bound_method %.7, %Convert.14 [template]
+// CHECK:STDOUT:   %.37: <specific function> = specific_function %.36, @Convert.2(%.1) [template]
+// CHECK:STDOUT:   %.38: %i32 = int_value 2 [template]
+// CHECK:STDOUT:   %struct: %C = struct_value (%.35, %.38) [template]
 // CHECK:STDOUT:   %MakeC.type: type = fn_type @MakeC [template]
 // CHECK:STDOUT:   %MakeC: %MakeC.type = struct_value () [template]
 // CHECK:STDOUT:   %MakeAdaptC.type: type = fn_type @MakeAdaptC [template]
@@ -197,8 +196,8 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @AdaptC {
 // CHECK:STDOUT:   %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
-// CHECK:STDOUT:   adapt_decl %C
-// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %C [template = constants.%.6]
+// CHECK:STDOUT:   adapt_decl %C.ref [template]
+// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AdaptC
@@ -210,24 +209,24 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc13_18: Core.IntLiteral = int_value 1 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc13_26: Core.IntLiteral = int_value 2 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc13_27.1: %.9 = struct_literal (%.loc13_18, %.loc13_26)
-// CHECK:STDOUT:   %.loc13_27.2: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc13_27.3: <bound method> = bound_method %.loc13_18, %.loc13_27.2 [template = constants.%.34]
-// CHECK:STDOUT:   %.loc13_27.4: <specific function> = specific_function %.loc13_27.3, @Convert.2(constants.%.1) [template = constants.%.35]
-// CHECK:STDOUT:   %int.convert_checked.loc13_27.1: init %i32 = call %.loc13_27.4(%.loc13_18) [template = constants.%.36]
-// CHECK:STDOUT:   %.loc13_27.5: init %i32 = converted %.loc13_18, %int.convert_checked.loc13_27.1 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc13_18: Core.IntLiteral = int_value 1 [template = constants.%.6]
+// CHECK:STDOUT:   %.loc13_26: Core.IntLiteral = int_value 2 [template = constants.%.7]
+// CHECK:STDOUT:   %.loc13_27.1: %.8 = struct_literal (%.loc13_18, %.loc13_26)
+// CHECK:STDOUT:   %.loc13_27.2: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc13_27.3: <bound method> = bound_method %.loc13_18, %.loc13_27.2 [template = constants.%.33]
+// CHECK:STDOUT:   %.loc13_27.4: <specific function> = specific_function %.loc13_27.3, @Convert.2(constants.%.1) [template = constants.%.34]
+// CHECK:STDOUT:   %int.convert_checked.loc13_27.1: init %i32 = call %.loc13_27.4(%.loc13_18) [template = constants.%.35]
+// CHECK:STDOUT:   %.loc13_27.5: init %i32 = converted %.loc13_18, %int.convert_checked.loc13_27.1 [template = constants.%.35]
 // CHECK:STDOUT:   %.loc13_27.6: ref %C = temporary_storage
 // CHECK:STDOUT:   %.loc13_27.7: ref %i32 = class_element_access %.loc13_27.6, element0
-// CHECK:STDOUT:   %.loc13_27.8: init %i32 = initialize_from %.loc13_27.5 to %.loc13_27.7 [template = constants.%.36]
-// CHECK:STDOUT:   %.loc13_27.9: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc13_27.10: <bound method> = bound_method %.loc13_26, %.loc13_27.9 [template = constants.%.37]
-// CHECK:STDOUT:   %.loc13_27.11: <specific function> = specific_function %.loc13_27.10, @Convert.2(constants.%.1) [template = constants.%.38]
-// CHECK:STDOUT:   %int.convert_checked.loc13_27.2: init %i32 = call %.loc13_27.11(%.loc13_26) [template = constants.%.39]
-// CHECK:STDOUT:   %.loc13_27.12: init %i32 = converted %.loc13_26, %int.convert_checked.loc13_27.2 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc13_27.8: init %i32 = initialize_from %.loc13_27.5 to %.loc13_27.7 [template = constants.%.35]
+// CHECK:STDOUT:   %.loc13_27.9: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc13_27.10: <bound method> = bound_method %.loc13_26, %.loc13_27.9 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc13_27.11: <specific function> = specific_function %.loc13_27.10, @Convert.2(constants.%.1) [template = constants.%.37]
+// CHECK:STDOUT:   %int.convert_checked.loc13_27.2: init %i32 = call %.loc13_27.11(%.loc13_26) [template = constants.%.38]
+// CHECK:STDOUT:   %.loc13_27.12: init %i32 = converted %.loc13_26, %int.convert_checked.loc13_27.2 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc13_27.13: ref %i32 = class_element_access %.loc13_27.6, element1
-// CHECK:STDOUT:   %.loc13_27.14: init %i32 = initialize_from %.loc13_27.12 to %.loc13_27.13 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc13_27.14: init %i32 = initialize_from %.loc13_27.12 to %.loc13_27.13 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc13_27.15: init %C = class_init (%.loc13_27.8, %.loc13_27.14), %.loc13_27.6 [template = constants.%struct]
 // CHECK:STDOUT:   %.loc13_27.16: ref %C = temporary %.loc13_27.6, %.loc13_27.15
 // CHECK:STDOUT:   %.loc13_28.1: ref %C = converted %.loc13_27.1, %.loc13_27.16
@@ -272,21 +271,20 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:   %.3: type = struct_type {.a: %i32, .b: %i32} [template]
 // CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
 // CHECK:STDOUT:   %AdaptC: type = class_type @AdaptC [template]
-// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %C [template]
-// CHECK:STDOUT:   %.7: Core.IntLiteral = int_value 1 [template]
-// CHECK:STDOUT:   %.8: Core.IntLiteral = int_value 2 [template]
-// CHECK:STDOUT:   %.9: type = struct_type {.a: Core.IntLiteral, .b: Core.IntLiteral} [template]
+// CHECK:STDOUT:   %.6: Core.IntLiteral = int_value 1 [template]
+// CHECK:STDOUT:   %.7: Core.IntLiteral = int_value 2 [template]
+// CHECK:STDOUT:   %.8: type = struct_type {.a: Core.IntLiteral, .b: Core.IntLiteral} [template]
 // CHECK:STDOUT:   %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
 // CHECK:STDOUT:   %Convert.type.14: type = fn_type @Convert.2, @impl.1(%.1) [template]
 // CHECK:STDOUT:   %Convert.14: %Convert.type.14 = struct_value () [template]
-// CHECK:STDOUT:   %.33: <witness> = interface_witness (%Convert.14) [template]
-// CHECK:STDOUT:   %.34: <bound method> = bound_method %.7, %Convert.14 [template]
-// CHECK:STDOUT:   %.35: <specific function> = specific_function %.34, @Convert.2(%.1) [template]
-// CHECK:STDOUT:   %.36: %i32 = int_value 1 [template]
-// CHECK:STDOUT:   %.37: <bound method> = bound_method %.8, %Convert.14 [template]
-// CHECK:STDOUT:   %.38: <specific function> = specific_function %.37, @Convert.2(%.1) [template]
-// CHECK:STDOUT:   %.39: %i32 = int_value 2 [template]
-// CHECK:STDOUT:   %struct: %C = struct_value (%.36, %.39) [template]
+// CHECK:STDOUT:   %.32: <witness> = interface_witness (%Convert.14) [template]
+// CHECK:STDOUT:   %.33: <bound method> = bound_method %.6, %Convert.14 [template]
+// CHECK:STDOUT:   %.34: <specific function> = specific_function %.33, @Convert.2(%.1) [template]
+// CHECK:STDOUT:   %.35: %i32 = int_value 1 [template]
+// CHECK:STDOUT:   %.36: <bound method> = bound_method %.7, %Convert.14 [template]
+// CHECK:STDOUT:   %.37: <specific function> = specific_function %.36, @Convert.2(%.1) [template]
+// CHECK:STDOUT:   %.38: %i32 = int_value 2 [template]
+// CHECK:STDOUT:   %struct: %C = struct_value (%.35, %.38) [template]
 // CHECK:STDOUT:   %MakeC.type: type = fn_type @MakeC [template]
 // CHECK:STDOUT:   %MakeC: %MakeC.type = struct_value () [template]
 // CHECK:STDOUT:   %MakeAdaptC.type: type = fn_type @MakeAdaptC [template]
@@ -366,8 +364,8 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @AdaptC {
 // CHECK:STDOUT:   %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
-// CHECK:STDOUT:   adapt_decl %C
-// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %C [template = constants.%.6]
+// CHECK:STDOUT:   adapt_decl %C.ref [template]
+// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AdaptC
@@ -379,24 +377,24 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc13_18: Core.IntLiteral = int_value 1 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc13_26: Core.IntLiteral = int_value 2 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc13_27.1: %.9 = struct_literal (%.loc13_18, %.loc13_26)
-// CHECK:STDOUT:   %.loc13_27.2: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc13_27.3: <bound method> = bound_method %.loc13_18, %.loc13_27.2 [template = constants.%.34]
-// CHECK:STDOUT:   %.loc13_27.4: <specific function> = specific_function %.loc13_27.3, @Convert.2(constants.%.1) [template = constants.%.35]
-// CHECK:STDOUT:   %int.convert_checked.loc13_27.1: init %i32 = call %.loc13_27.4(%.loc13_18) [template = constants.%.36]
-// CHECK:STDOUT:   %.loc13_27.5: init %i32 = converted %.loc13_18, %int.convert_checked.loc13_27.1 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc13_18: Core.IntLiteral = int_value 1 [template = constants.%.6]
+// CHECK:STDOUT:   %.loc13_26: Core.IntLiteral = int_value 2 [template = constants.%.7]
+// CHECK:STDOUT:   %.loc13_27.1: %.8 = struct_literal (%.loc13_18, %.loc13_26)
+// CHECK:STDOUT:   %.loc13_27.2: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc13_27.3: <bound method> = bound_method %.loc13_18, %.loc13_27.2 [template = constants.%.33]
+// CHECK:STDOUT:   %.loc13_27.4: <specific function> = specific_function %.loc13_27.3, @Convert.2(constants.%.1) [template = constants.%.34]
+// CHECK:STDOUT:   %int.convert_checked.loc13_27.1: init %i32 = call %.loc13_27.4(%.loc13_18) [template = constants.%.35]
+// CHECK:STDOUT:   %.loc13_27.5: init %i32 = converted %.loc13_18, %int.convert_checked.loc13_27.1 [template = constants.%.35]
 // CHECK:STDOUT:   %.loc13_27.6: ref %C = temporary_storage
 // CHECK:STDOUT:   %.loc13_27.7: ref %i32 = class_element_access %.loc13_27.6, element0
-// CHECK:STDOUT:   %.loc13_27.8: init %i32 = initialize_from %.loc13_27.5 to %.loc13_27.7 [template = constants.%.36]
-// CHECK:STDOUT:   %.loc13_27.9: %Convert.type.2 = interface_witness_access constants.%.33, element0 [template = constants.%Convert.14]
-// CHECK:STDOUT:   %.loc13_27.10: <bound method> = bound_method %.loc13_26, %.loc13_27.9 [template = constants.%.37]
-// CHECK:STDOUT:   %.loc13_27.11: <specific function> = specific_function %.loc13_27.10, @Convert.2(constants.%.1) [template = constants.%.38]
-// CHECK:STDOUT:   %int.convert_checked.loc13_27.2: init %i32 = call %.loc13_27.11(%.loc13_26) [template = constants.%.39]
-// CHECK:STDOUT:   %.loc13_27.12: init %i32 = converted %.loc13_26, %int.convert_checked.loc13_27.2 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc13_27.8: init %i32 = initialize_from %.loc13_27.5 to %.loc13_27.7 [template = constants.%.35]
+// CHECK:STDOUT:   %.loc13_27.9: %Convert.type.2 = interface_witness_access constants.%.32, element0 [template = constants.%Convert.14]
+// CHECK:STDOUT:   %.loc13_27.10: <bound method> = bound_method %.loc13_26, %.loc13_27.9 [template = constants.%.36]
+// CHECK:STDOUT:   %.loc13_27.11: <specific function> = specific_function %.loc13_27.10, @Convert.2(constants.%.1) [template = constants.%.37]
+// CHECK:STDOUT:   %int.convert_checked.loc13_27.2: init %i32 = call %.loc13_27.11(%.loc13_26) [template = constants.%.38]
+// CHECK:STDOUT:   %.loc13_27.12: init %i32 = converted %.loc13_26, %int.convert_checked.loc13_27.2 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc13_27.13: ref %i32 = class_element_access %.loc13_27.6, element1
-// CHECK:STDOUT:   %.loc13_27.14: init %i32 = initialize_from %.loc13_27.12 to %.loc13_27.13 [template = constants.%.39]
+// CHECK:STDOUT:   %.loc13_27.14: init %i32 = initialize_from %.loc13_27.12 to %.loc13_27.13 [template = constants.%.38]
 // CHECK:STDOUT:   %.loc13_27.15: init %C = class_init (%.loc13_27.8, %.loc13_27.14), %.loc13_27.6 [template = constants.%struct]
 // CHECK:STDOUT:   %.loc13_27.16: ref %C = temporary %.loc13_27.6, %.loc13_27.15
 // CHECK:STDOUT:   %.loc13_28.1: ref %C = converted %.loc13_27.1, %.loc13_27.16

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

@@ -145,7 +145,7 @@ fn Call(p: Derived*) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc16: %.6 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc16: %.6 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %SelfBase.decl: %SelfBase.type = fn_decl @SelfBase [template = constants.%SelfBase] {
 // CHECK:STDOUT:     %self.patt: %Base = binding_pattern self
 // CHECK:STDOUT:     %self.param_patt: %Base = value_param_pattern %self.patt, runtime_param0

+ 5 - 5
toolchain/check/testdata/class/virtual_modifiers.carbon

@@ -219,7 +219,7 @@ class Derived {
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
 // CHECK:STDOUT:   %Modifiers.ref: <namespace> = name_ref Modifiers, imports.%Modifiers [template = imports.%Modifiers]
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, imports.%import_ref.1 [template = constants.%Base]
-// CHECK:STDOUT:   %.loc8: %.5 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc8: %.5 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   %.loc9: <witness> = complete_type_witness %.6 [template = constants.%.7]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -336,7 +336,7 @@ class Derived {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @A2 {
 // CHECK:STDOUT:   %A1.ref: type = name_ref A1, file.%A1.decl [template = constants.%A1]
-// CHECK:STDOUT:   %.loc9: %.5 = base_decl %A1, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.5 = base_decl %A1.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.6 [template = constants.%.7]
 // CHECK:STDOUT:
@@ -405,7 +405,7 @@ class Derived {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B2 {
 // CHECK:STDOUT:   %B1.ref: type = name_ref B1, file.%B1.decl [template = constants.%B1]
-// CHECK:STDOUT:   %.loc9: %.5 = base_decl %B1, element0 [template]
+// CHECK:STDOUT:   %.loc9: %.5 = base_decl %B1.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.6 [template = constants.%.7]
 // CHECK:STDOUT:
@@ -418,7 +418,7 @@ class Derived {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %B2.ref: type = name_ref B2, file.%B2.decl [template = constants.%B2]
-// CHECK:STDOUT:   %.loc14: %.10 = base_decl %B2, element0 [template]
+// CHECK:STDOUT:   %.loc14: %.10 = base_decl %B2.ref, element0 [template]
 // CHECK:STDOUT:   %F.decl: %F.type.3 = fn_decl @F.3 [template = constants.%F.3] {} {}
 // CHECK:STDOUT:   %.loc16: <witness> = complete_type_witness %.11 [template = constants.%.12]
 // CHECK:STDOUT:
@@ -660,7 +660,7 @@ class Derived {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc8: %.4 = base_decl %Base, element1 [template]
+// CHECK:STDOUT:   %.loc8: %.4 = base_decl %Base.ref, element1 [template]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
 // CHECK:STDOUT:   %.loc10: <witness> = complete_type_witness %.6 [template = constants.%.7]
 // CHECK:STDOUT:

+ 3 - 3
toolchain/check/testdata/impl/multiple_extend.carbon

@@ -565,7 +565,7 @@ fn P(o: O) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @E {
 // CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
-// CHECK:STDOUT:   %.loc13: %.6 = base_decl %B, element0 [template]
+// CHECK:STDOUT:   %.loc13: %.6 = base_decl %B.ref, element0 [template]
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
 // CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%E [template = constants.%E]
 // CHECK:STDOUT:     %HasI.ref: type = name_ref HasI, file.%HasI.decl [template = constants.%HasI.type]
@@ -703,7 +703,7 @@ fn P(o: O) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @L {
 // CHECK:STDOUT:   %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
-// CHECK:STDOUT:   %.loc13: %.6 = base_decl %Base, element0 [template]
+// CHECK:STDOUT:   %.loc13: %.6 = base_decl %Base.ref, element0 [template]
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
 // CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%L [template = constants.%L]
 // CHECK:STDOUT:     %HasK.ref: type = name_ref HasK, file.%HasK.decl [template = constants.%HasK.type]
@@ -866,7 +866,7 @@ fn P(o: O) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @O {
 // CHECK:STDOUT:   %NBase.ref: type = name_ref NBase, file.%NBase.decl [template = constants.%NBase]
-// CHECK:STDOUT:   %.loc17: %.8 = base_decl %NBase, element0 [template]
+// CHECK:STDOUT:   %.loc17: %.8 = base_decl %NBase.ref, element0 [template]
 // CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
 // CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%O [template = constants.%O]
 // CHECK:STDOUT:     %HasN1.ref: type = name_ref HasN1, file.%HasN1.decl [template = constants.%HasN1.type]

+ 30 - 39
toolchain/lower/constant.cpp

@@ -99,30 +99,12 @@ static auto EmitAggregateConstant(ConstantContext& context,
   return ConstantType::get(llvm_type, elements);
 }
 
-// For each instruction InstT, there is a function below to convert it to an
-// `llvm::Constant*`:
+// For each instruction InstT that can be emitted as a constant, there is a
+// function below to convert it to an `llvm::Constant*`:
 //
 // auto EmitAsConstant(ConstantContext& context, SemIR::InstT inst)
 //     -> llvm::Constant*;
 
-template <typename InstT>
-  requires(InstT::Kind.constant_kind() == SemIR::InstConstantKind::Never ||
-           InstT::Kind.constant_kind() == SemIR::InstConstantKind::SymbolicOnly)
-static auto EmitAsConstant(ConstantContext& /*context*/, InstT inst)
-    -> llvm::Constant* {
-  CARBON_FATAL("Unexpected constant instruction kind {0}", inst);
-}
-
-// For constants that are always of type `type`, produce the trivial runtime
-// representation of type `type`.
-template <typename InstT>
-  requires(InstT::Kind.is_type() == SemIR::InstIsType::Always &&
-           InstT::Kind.constant_kind() != SemIR::InstConstantKind::SymbolicOnly)
-static auto EmitAsConstant(ConstantContext& context, InstT /*inst*/)
-    -> llvm::Constant* {
-  return context.GetTypeAsValue();
-}
-
 // Represent facet values the same as types.
 static auto EmitAsConstant(ConstantContext& context, SemIR::FacetValue /*inst*/)
     -> llvm::Constant* {
@@ -197,20 +179,6 @@ static auto EmitAsConstant(ConstantContext& context, SemIR::FloatLiteral inst)
   return llvm::ConstantFP::get(context.GetType(inst.type_id), value);
 }
 
-static auto EmitAsConstant(ConstantContext& context,
-                           SemIR::InterfaceWitness inst) -> llvm::Constant* {
-  // TODO: For dynamic dispatch, we might want to lower witness tables as
-  // constants.
-  return context.GetUnusedConstant(inst.type_id);
-}
-
-static auto EmitAsConstant(ConstantContext& /*context*/,
-                           SemIR::ImplDecl /*inst*/) -> llvm::Constant* {
-  // An ImplDecl isn't a value, so this constant value won't ever be used.
-  // It also doesn't even have a type, so we can't use GetUnusedConstant.
-  return nullptr;
-}
-
 static auto EmitAsConstant(ConstantContext& context, SemIR::IntValue inst)
     -> llvm::Constant* {
   auto* type = context.GetType(inst.type_id);
@@ -226,7 +194,8 @@ static auto EmitAsConstant(ConstantContext& context, SemIR::IntValue inst)
 
   auto val = context.sem_ir().ints().Get(inst.int_id);
   int bit_width = int_type->getBitWidth();
-  bool is_signed = context.sem_ir().GetIntTypeInfo(inst.type_id).is_signed;
+  bool is_signed =
+      context.sem_ir().types().GetIntTypeInfo(inst.type_id).is_signed;
   return llvm::ConstantInt::get(type, is_signed ? val.sextOrTrunc(bit_width)
                                                 : val.zextOrTrunc(bit_width));
 }
@@ -246,6 +215,28 @@ static auto EmitAsConstant(ConstantContext& /*context*/,
   CARBON_FATAL("TODO: Add support: {0}", inst);
 }
 
+// Tries to emit an LLVM constant value for this constant instruction. Centrally
+// handles some common cases and then dispatches to the relevant EmitAsConstant
+// overload based on the type of the instruction for the remaining cases.
+template <typename InstT>
+static auto MaybeEmitAsConstant(ConstantContext& context, InstT inst)
+    -> llvm::Constant* {
+  if constexpr (InstT::Kind.constant_kind() == SemIR::InstConstantKind::Never ||
+                InstT::Kind.constant_kind() ==
+                    SemIR::InstConstantKind::SymbolicOnly) {
+    CARBON_FATAL("Unexpected constant instruction kind {0}", inst);
+  } else if constexpr (!InstT::Kind.is_lowered()) {
+    // This instruction has a constant value, but that constant value will never
+    // be used by lowering.
+    return nullptr;
+  } else if constexpr (InstT::Kind.is_type() == SemIR::InstIsType::Always) {
+    // All types are lowered to the same value.
+    return context.GetTypeAsValue();
+  } else {
+    return EmitAsConstant(context, inst);
+  }
+}
+
 auto LowerConstants(FileContext& file_context,
                     llvm::MutableArrayRef<llvm::Constant*> constants) -> void {
   ConstantContext context(file_context, constants);
@@ -273,10 +264,10 @@ auto LowerConstants(FileContext& file_context,
     }
     llvm::Constant* value = nullptr;
     CARBON_KIND_SWITCH(inst) {
-#define CARBON_SEM_IR_INST_KIND(Name)            \
-  case CARBON_KIND(SemIR::Name const_inst): {    \
-    value = EmitAsConstant(context, const_inst); \
-    break;                                       \
+#define CARBON_SEM_IR_INST_KIND(Name)                 \
+  case CARBON_KIND(SemIR::Name const_inst): {         \
+    value = MaybeEmitAsConstant(context, const_inst); \
+    break;                                            \
   }
 #include "toolchain/sem_ir/inst_kind.def"
     }

+ 1 - 4
toolchain/lower/handle_aggregates.cpp

@@ -102,11 +102,8 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
                 SemIR::ClassElementAccess inst) -> void {
   // Find the class that we're performing access into.
   auto class_type_id = context.sem_ir().insts().Get(inst.base_id).type_id();
-  auto class_type =
-      context.sem_ir().types().GetAs<SemIR::ClassType>(class_type_id);
-  const auto& class_info = context.sem_ir().classes().Get(class_type.class_id);
   SemIR::TypeId object_repr_id =
-      class_info.GetObjectRepr(context.sem_ir(), class_type.specific_id);
+      context.sem_ir().types().GetObjectRepr(class_type_id);
 
   // Translate the class field access into a struct access on the object
   // representation.

+ 1 - 0
toolchain/sem_ir/BUILD

@@ -74,6 +74,7 @@ cc_library(
         "generic.cpp",
         "impl.cpp",
         "name.cpp",
+        "type.cpp",
         "type_info.cpp",
     ],
     hdrs = [

+ 24 - 0
toolchain/sem_ir/class.cpp

@@ -7,9 +7,33 @@
 #include "toolchain/sem_ir/file.h"
 #include "toolchain/sem_ir/generic.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/typed_insts.h"
 
 namespace Carbon::SemIR {
 
+static auto GetFoundationType(const File& file, SpecificId specific_id,
+                              InstId inst_id) -> TypeId {
+  if (!inst_id.is_valid()) {
+    return TypeId::Invalid;
+  }
+  if (inst_id == SemIR::InstId::BuiltinErrorInst) {
+    return TypeId::Error;
+  }
+  return TypeId::ForTypeConstant(GetConstantValueInSpecific(
+      file, specific_id,
+      file.insts().GetAs<AnyFoundationDecl>(inst_id).foundation_type_inst_id));
+}
+
+auto Class::GetAdaptedType(const File& file, SpecificId specific_id) const
+    -> TypeId {
+  return GetFoundationType(file, specific_id, adapt_id);
+}
+
+auto Class::GetBaseType(const File& file, SpecificId specific_id) const
+    -> TypeId {
+  return GetFoundationType(file, specific_id, base_id);
+}
+
 auto Class::GetObjectRepr(const File& file, SpecificId specific_id) const
     -> TypeId {
   if (!complete_type_witness_id.is_valid()) {

+ 8 - 0
toolchain/sem_ir/class.h

@@ -77,6 +77,14 @@ struct Class : public EntityWithParamsBase,
     return complete_type_witness_id.is_valid();
   }
 
+  // Gets the type that this class type adapts. Returns Invalid if there is no
+  // such type, or if the class is not yet defined.
+  auto GetAdaptedType(const File& file, SpecificId specific_id) const -> TypeId;
+
+  // Gets the base class for this class type. Returns Invalid if there is no
+  // such type, or if the class is not yet defined.
+  auto GetBaseType(const File& file, SpecificId specific_id) const -> TypeId;
+
   // Gets the object representation for this class. Returns Invalid if the class
   // is not yet defined.
   auto GetObjectRepr(const File& file, SpecificId specific_id) const -> TypeId;

+ 1 - 25
toolchain/sem_ir/file.h

@@ -37,12 +37,6 @@ namespace Carbon::SemIR {
 // Provides semantic analysis on a Parse::Tree.
 class File : public Printable<File> {
  public:
-  // Used to return information about an integer type in `GetIntTypeInfo`.
-  struct IntTypeInfo {
-    bool is_signed;
-    IntId bit_width;
-  };
-
   // Starts a new file for Check::CheckParseTree.
   explicit File(CheckIRId check_ir_id,
                 const std::optional<Parse::Tree::PackagingDecl>& packaging_decl,
@@ -79,24 +73,6 @@ class File : public Printable<File> {
     return types().GetAs<PointerType>(pointer_id).pointee_id;
   }
 
-  // Returns integer type information from a type ID. Abstracts away the
-  // difference between an `IntType` instruction defined type and a builtin
-  // instruction defined type. Uses IntId::Invalid for types that have an
-  // invalid width.
-  //
-  // TODO: Move this to TypeStore.
-  auto GetIntTypeInfo(TypeId int_type_id) const -> IntTypeInfo {
-    auto inst_id = types().GetInstId(int_type_id);
-    if (inst_id == InstId::BuiltinIntLiteralType) {
-      return {.is_signed = true, .bit_width = IntId::Invalid};
-    }
-    auto int_type = insts().GetAs<IntType>(inst_id);
-    auto bit_width_inst = insts().TryGetAs<IntValue>(int_type.bit_width_id);
-    return {
-        .is_signed = int_type.int_kind.is_signed(),
-        .bit_width = bit_width_inst ? bit_width_inst->int_id : IntId::Invalid};
-  }
-
   auto check_ir_id() const -> CheckIRId { return check_ir_id_; }
   auto package_id() const -> IdentifierId { return package_id_; }
   auto library_id() const -> SemIR::LibraryNameId { return library_id_; }
@@ -293,7 +269,7 @@ class File : public Printable<File> {
   StructTypeFieldsStore struct_type_fields_ = StructTypeFieldsStore(allocator_);
 
   // Descriptions of types used in this file.
-  TypeStore types_ = TypeStore(&insts_, &constant_values_);
+  TypeStore types_ = TypeStore(this);
 };
 
 // The expression category of a sem_ir instruction. See /docs/design/values.md

+ 66 - 0
toolchain/sem_ir/type.cpp

@@ -0,0 +1,66 @@
+// 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
+
+#include "toolchain/sem_ir/type.h"
+
+#include "toolchain/sem_ir/file.h"
+
+namespace Carbon::SemIR {
+
+auto TypeStore::GetInstId(TypeId type_id) const -> InstId {
+  return file_->constant_values().GetInstId(GetConstantId(type_id));
+}
+
+auto TypeStore::GetAsInst(TypeId type_id) const -> Inst {
+  return file_->insts().Get(GetInstId(type_id));
+}
+
+auto TypeStore::GetObjectRepr(TypeId type_id) const -> TypeId {
+  type_id = GetUnqualifiedType(type_id);
+  auto class_type = TryGetAs<ClassType>(type_id);
+  if (!class_type) {
+    return type_id;
+  }
+  const auto& class_info = file_->classes().Get(class_type->class_id);
+  if (!class_info.is_defined()) {
+    return TypeId::Invalid;
+  }
+  return class_info.GetObjectRepr(*file_, class_type->specific_id);
+}
+
+auto TypeStore::GetUnqualifiedType(TypeId type_id) const -> TypeId {
+  if (auto const_type = TryGetAs<ConstType>(type_id)) {
+    return const_type->inner_id;
+  }
+  return type_id;
+}
+
+auto TypeStore::IsSignedInt(TypeId int_type_id) const -> bool {
+  auto object_repr_id = GetObjectRepr(int_type_id);
+  if (!object_repr_id.is_valid()) {
+    return false;
+  }
+  auto inst_id = GetInstId(int_type_id);
+  if (inst_id == InstId::BuiltinIntLiteralType) {
+    return true;
+  }
+  auto int_type = file_->insts().TryGetAs<IntType>(inst_id);
+  return int_type && int_type->int_kind.is_signed();
+}
+
+auto TypeStore::GetIntTypeInfo(TypeId int_type_id) const -> IntTypeInfo {
+  auto object_repr_id = GetObjectRepr(int_type_id);
+  auto inst_id = GetInstId(object_repr_id);
+  if (inst_id == InstId::BuiltinIntLiteralType) {
+    return {.is_signed = true, .bit_width = IntId::Invalid};
+  }
+  auto int_type = file_->insts().GetAs<IntType>(inst_id);
+  auto bit_width_inst =
+      file_->insts().TryGetAs<IntValue>(int_type.bit_width_id);
+  return {
+      .is_signed = int_type.int_kind.is_signed(),
+      .bit_width = bit_width_inst ? bit_width_inst->int_id : IntId::Invalid};
+}
+
+}  // namespace Carbon::SemIR

+ 30 - 21
toolchain/sem_ir/type.h

@@ -16,8 +16,13 @@ namespace Carbon::SemIR {
 // Provides a ValueStore wrapper with an API specific to types.
 class TypeStore : public Yaml::Printable<TypeStore> {
  public:
-  explicit TypeStore(InstStore* insts, ConstantValueStore* constants)
-      : insts_(insts), constants_(constants) {}
+  // Used to return information about an integer type in `GetIntTypeInfo`.
+  struct IntTypeInfo {
+    bool is_signed;
+    IntId bit_width;
+  };
+
+  explicit TypeStore(File* file) : file_(file) {}
 
   // Returns the ID of the constant used to define the specified type.
   auto GetConstantId(TypeId type_id) const -> ConstantId {
@@ -29,14 +34,10 @@ class TypeStore : public Yaml::Printable<TypeStore> {
   }
 
   // Returns the ID of the instruction used to define the specified type.
-  auto GetInstId(TypeId type_id) const -> InstId {
-    return constants_->GetInstId(GetConstantId(type_id));
-  }
+  auto GetInstId(TypeId type_id) const -> InstId;
 
   // Returns the instruction used to define the specified type.
-  auto GetAsInst(TypeId type_id) const -> Inst {
-    return insts_->Get(GetInstId(type_id));
-  }
+  auto GetAsInst(TypeId type_id) const -> Inst;
 
   // Returns whether the specified kind of instruction was used to define the
   // type.
@@ -49,8 +50,7 @@ class TypeStore : public Yaml::Printable<TypeStore> {
   // to be a particular kind of instruction.
   template <typename InstT>
   auto GetAs(TypeId type_id) const -> InstT {
-    auto inst_id = constants_->GetInstId(GetConstantId(type_id));
-    return insts_->GetAs<InstT>(inst_id);
+    return GetAsInst(type_id).As<InstT>();
   }
 
   // Returns the instruction used to define the specified type, if it is of a
@@ -87,21 +87,31 @@ class TypeStore : public Yaml::Printable<TypeStore> {
     CARBON_CHECK(IsComplete(type_id));
   }
 
+  // Get the object representation associated with a type. For a non-class type,
+  // this is the type itself. An invalid TypeId is returned if the object
+  // representation cannot be determined because the type is not complete.
+  auto GetObjectRepr(TypeId type_id) const -> TypeId;
+
   // Determines whether the given type is known to be complete. This does not
   // determine whether the type could be completed, only whether it has been.
   auto IsComplete(TypeId type_id) const -> bool {
     return complete_type_info_.Contains(type_id);
   }
 
-  // Determines whether the given type is a signed integer type.
-  auto IsSignedInt(TypeId int_type_id) const -> bool {
-    auto inst_id = GetInstId(int_type_id);
-    if (inst_id == InstId::BuiltinIntLiteralType) {
-      return true;
-    }
-    auto int_type = insts_->TryGetAs<IntType>(inst_id);
-    return int_type && int_type->int_kind.is_signed();
-  }
+  // Removes any top-level `const` qualifiers from a type.
+  auto GetUnqualifiedType(TypeId type_id) const -> TypeId;
+
+  // Determines whether the given type is a signed integer type. This includes
+  // the case where the type is `Core.IntLiteral` or a class type whose object
+  // representation is a signed integer type.
+  auto IsSignedInt(TypeId int_type_id) const -> bool;
+
+  // Returns integer type information from a type ID that is known to represent
+  // an integer type. Abstracts away the difference between an `IntType`
+  // instruction defined type, a builtin instruction defined type, and a class
+  // adapting such a type. Uses IntId::Invalid for types that have a
+  // non-constant width and for IntLiteral.
+  auto GetIntTypeInfo(TypeId int_type_id) const -> IntTypeInfo;
 
   // Returns a list of types that were completed in this file, in the order in
   // which they were completed. Earlier types in this list cannot contain
@@ -128,8 +138,7 @@ class TypeStore : public Yaml::Printable<TypeStore> {
   }
 
  private:
-  InstStore* insts_;
-  ConstantValueStore* constants_;
+  File* file_;
   Map<TypeId, CompleteTypeInfo> complete_type_info_;
   llvm::SmallVector<TypeId> complete_types_;
 };

+ 18 - 3
toolchain/sem_ir/typed_insts.h

@@ -72,13 +72,26 @@ struct BoolType {
   TypeId type_id;
 };
 
+// Common representation for declarations describing the foundation type of a
+// class -- either its adapted type or its base class.
+struct AnyFoundationDecl {
+  static constexpr InstKind Kinds[] = {InstKind::AdaptDecl, InstKind::BaseDecl};
+
+  InstKind kind;
+  InstId foundation_type_inst_id;
+  // Kind-specific data.
+  int32_t arg1;
+};
+
 // An adapted type declaration in a class, of the form `adapt T;`.
 struct AdaptDecl {
   static constexpr auto Kind = InstKind::AdaptDecl.Define<Parse::AdaptDeclId>(
-      {.ir_name = "adapt_decl", .is_lowered = false});
+      {.ir_name = "adapt_decl",
+       .constant_kind = InstConstantKind::Always,
+       .is_lowered = false});
 
   // No type_id; this is not a value.
-  TypeId adapted_type_id;
+  InstId adapted_type_inst_id;
 };
 
 // Takes the address of a reference expression, such as for the `&` address-of
@@ -242,7 +255,7 @@ struct BaseDecl {
       {.ir_name = "base_decl", .constant_kind = InstConstantKind::Always});
 
   TypeId type_id;
-  TypeId base_type_id;
+  InstId base_type_inst_id;
   ElementIndex index;
 };
 
@@ -846,6 +859,8 @@ struct InterfaceWitness {
   static constexpr auto Kind = InstKind::InterfaceWitness.Define<Parse::NodeId>(
       {.ir_name = "interface_witness",
        .constant_kind = InstConstantKind::Conditional,
+       // TODO: For dynamic dispatch, we might want to lower witness tables as
+       // constants.
        .is_lowered = false});
 
   // Always the builtin witness type.