Bläddra i källkod

Rename "generic instance" to "specific" throughout the toolchain. (#4165)

As discussed in toolchain meeting, we want to avoid overloading the
meaning of "instance", and "specific" was the best name we found. It's a
little unorthodox and inventive, but hopefully over time will become as
unsurprising as the term "generic" is.
Richard Smith 1 år sedan
förälder
incheckning
3cb769a053
41 ändrade filer med 372 tillägg och 398 borttagningar
  1. 6 6
      toolchain/check/call.cpp
  2. 1 2
      toolchain/check/check.cpp
  3. 18 19
      toolchain/check/context.cpp
  4. 9 11
      toolchain/check/context.h
  5. 4 4
      toolchain/check/convert.cpp
  6. 1 1
      toolchain/check/convert.h
  7. 12 13
      toolchain/check/decl_name_stack.cpp
  8. 1 1
      toolchain/check/decl_name_stack.h
  9. 42 46
      toolchain/check/eval.cpp
  10. 1 2
      toolchain/check/eval.h
  11. 2 2
      toolchain/check/function.cpp
  12. 1 1
      toolchain/check/function.h
  13. 36 38
      toolchain/check/generic.cpp
  14. 11 12
      toolchain/check/generic.h
  15. 4 4
      toolchain/check/handle_class.cpp
  16. 1 1
      toolchain/check/handle_function.cpp
  17. 4 4
      toolchain/check/handle_interface.cpp
  18. 5 5
      toolchain/check/handle_name.cpp
  19. 24 24
      toolchain/check/import_ref.cpp
  20. 9 9
      toolchain/check/member_access.cpp
  21. 4 5
      toolchain/check/operator.cpp
  22. 11 11
      toolchain/check/scope_stack.cpp
  23. 10 11
      toolchain/check/scope_stack.h
  24. 11 11
      toolchain/check/subst.cpp
  25. 1 1
      toolchain/check/testdata/basics/builtin_insts.carbon
  26. 5 5
      toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon
  27. 5 5
      toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon
  28. 2 2
      toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon
  29. 3 3
      toolchain/check/testdata/basics/no_prelude/raw_ir.carbon
  30. 1 1
      toolchain/parse/node_ids.h
  31. 2 3
      toolchain/sem_ir/file.cpp
  32. 4 8
      toolchain/sem_ir/file.h
  33. 14 15
      toolchain/sem_ir/formatter.cpp
  34. 4 5
      toolchain/sem_ir/function.cpp
  35. 5 5
      toolchain/sem_ir/function.h
  36. 31 34
      toolchain/sem_ir/generic.cpp
  37. 44 45
      toolchain/sem_ir/generic.h
  38. 3 3
      toolchain/sem_ir/id_kind.h
  39. 12 11
      toolchain/sem_ir/ids.h
  40. 7 8
      toolchain/sem_ir/typed_insts.h
  41. 1 1
      toolchain/sem_ir/yaml_test.cpp

+ 6 - 6
toolchain/check/call.cpp

@@ -27,7 +27,7 @@ static auto PerformCallToGenericClass(Context& context, Parse::NodeId node_id,
   // TODO: Pass in information about the specific in which the generic class
   // name was found.
   // TODO: Perform argument deduction.
-  auto specific_id = SemIR::GenericInstanceId::Invalid;
+  auto specific_id = SemIR::SpecificId::Invalid;
 
   // Convert the arguments to match the parameters.
   auto converted_args_id = ConvertCallArgs(
@@ -53,7 +53,7 @@ static auto PerformCallToGenericInterface(Context& context,
   // TODO: Pass in information about the specific in which the generic interface
   // name was found.
   // TODO: Perform argument deduction.
-  auto specific_id = SemIR::GenericInstanceId::Invalid;
+  auto specific_id = SemIR::SpecificId::Invalid;
 
   // Convert the arguments to match the parameters.
   auto converted_args_id = ConvertCallArgs(
@@ -101,15 +101,15 @@ auto PerformCall(Context& context, Parse::NodeId node_id,
   // TODO: Properly determine the generic argument values for the call. For now,
   // we do so only if the function introduces no generic parameters beyond those
   // of the enclosing context.
-  auto specific_id = SemIR::GenericInstanceId::Invalid;
-  if (callee_function.instance_id.is_valid()) {
+  auto specific_id = SemIR::SpecificId::Invalid;
+  if (callee_function.specific_id.is_valid()) {
     auto enclosing_args_id =
-        context.generic_instances().Get(callee_function.instance_id).args_id;
+        context.specifics().Get(callee_function.specific_id).args_id;
     auto fn_params_id = context.generics().Get(callable.generic_id).bindings_id;
     if (context.inst_blocks().Get(fn_params_id).size() ==
         context.inst_blocks().Get(enclosing_args_id).size()) {
       specific_id =
-          MakeGenericInstance(context, callable.generic_id, enclosing_args_id);
+          MakeSpecific(context, callable.generic_id, enclosing_args_id);
     }
   }
 

+ 1 - 2
toolchain/check/check.cpp

@@ -206,8 +206,7 @@ static auto ImportCurrentPackage(Context& context, UnitInfo& unit_info,
                                /*api_imports=*/nullptr, total_ir_count));
 
   context.scope_stack().Push(
-      package_inst_id, SemIR::NameScopeId::Package,
-      SemIR::GenericInstanceId::Invalid,
+      package_inst_id, SemIR::NameScopeId::Package, SemIR::SpecificId::Invalid,
       context.name_scopes().Get(SemIR::NameScopeId::Package).has_error);
 }
 

+ 18 - 19
toolchain/check/context.cpp

@@ -275,11 +275,11 @@ auto Context::LookupUnqualifiedName(Parse::NodeId node_id,
       scope_stack().LookupInLexicalScopes(name_id);
 
   // Walk the non-lexical scopes and perform lookups into each of them.
-  for (auto [index, lookup_scope_id, instance_id] :
+  for (auto [index, lookup_scope_id, specific_id] :
        llvm::reverse(non_lexical_scopes)) {
     if (auto non_lexical_result = LookupQualifiedName(
             node_id, name_id,
-            {.name_scope_id = lookup_scope_id, .instance_id = instance_id},
+            {.name_scope_id = lookup_scope_id, .specific_id = specific_id},
             /*required=*/false);
         non_lexical_result.inst_id.is_valid()) {
       return non_lexical_result;
@@ -287,16 +287,16 @@ auto Context::LookupUnqualifiedName(Parse::NodeId node_id,
   }
 
   if (lexical_result.is_valid()) {
-    // A lexical scope never needs an associated generic instance. If there's a
+    // A lexical scope never needs an associated specific. If there's a
     // lexically enclosing generic, then it also encloses the point of use of
     // the name.
-    return {.instance_id = SemIR::GenericInstanceId::Invalid,
+    return {.specific_id = SemIR::SpecificId::Invalid,
             .inst_id = lexical_result};
   }
 
   // We didn't find anything at all.
   DiagnoseNameNotFound(node_id, name_id);
-  return {.instance_id = SemIR::GenericInstanceId::Invalid,
+  return {.specific_id = SemIR::SpecificId::Invalid,
           .inst_id = SemIR::InstId::BuiltinError};
 }
 
@@ -320,13 +320,13 @@ auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id,
                                   LookupScope scope, bool required)
     -> LookupResult {
   llvm::SmallVector<LookupScope> scopes = {scope};
-  LookupResult result = {.instance_id = SemIR::GenericInstanceId::Invalid,
+  LookupResult result = {.specific_id = SemIR::SpecificId::Invalid,
                          .inst_id = SemIR::InstId::Invalid};
   bool has_error = false;
 
   // Walk this scope and, if nothing is found here, the scopes it extends.
   while (!scopes.empty()) {
-    auto [scope_id, instance_id] = scopes.pop_back_val();
+    auto [scope_id, specific_id] = scopes.pop_back_val();
     const auto& name_scope = name_scopes().Get(scope_id);
     has_error |= name_scope.has_error;
 
@@ -338,9 +338,9 @@ auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id,
       scopes.reserve(scopes.size() + extended.size());
       for (auto extended_id : llvm::reverse(extended)) {
         // TODO: Track a constant describing the extended scope, and substitute
-        // into it to determine its corresponding generic instance.
+        // into it to determine its corresponding specific.
         scopes.push_back({.name_scope_id = extended_id,
-                          .instance_id = SemIR::GenericInstanceId::Invalid});
+                          .specific_id = SemIR::SpecificId::Invalid});
       }
       continue;
     }
@@ -356,19 +356,19 @@ auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id,
           SemIR::NameId);
       emitter_->Emit(node_id, NameAmbiguousDueToExtend, name_id);
       // TODO: Add notes pointing to the scopes.
-      return {.instance_id = SemIR::GenericInstanceId::Invalid,
+      return {.specific_id = SemIR::SpecificId::Invalid,
               .inst_id = SemIR::InstId::BuiltinError};
     }
 
     result.inst_id = scope_result_id;
-    result.instance_id = instance_id;
+    result.specific_id = specific_id;
   }
 
   if (required && !result.inst_id.is_valid()) {
     if (!has_error) {
       DiagnoseNameNotFound(node_id, name_id);
     }
-    return {.instance_id = SemIR::GenericInstanceId::Invalid,
+    return {.specific_id = SemIR::SpecificId::Invalid,
             .inst_id = SemIR::InstId::BuiltinError};
   }
 
@@ -715,8 +715,8 @@ class TypeCompleter {
           }
           return false;
         }
-        if (inst.instance_id.is_valid()) {
-          ResolveSpecificDefinition(context_, inst.instance_id);
+        if (inst.specific_id.is_valid()) {
+          ResolveSpecificDefinition(context_, inst.specific_id);
         }
         Push(class_info.object_repr_id);
         break;
@@ -1012,8 +1012,8 @@ auto Context::TryToDefineType(
       return false;
     }
 
-    if (interface->instance_id.is_valid()) {
-      ResolveSpecificDefinition(*this, interface->instance_id);
+    if (interface->specific_id.is_valid()) {
+      ResolveSpecificDefinition(*this, interface->specific_id);
     }
   }
 
@@ -1085,9 +1085,8 @@ auto Context::GetBuiltinType(SemIR::BuiltinInstKind kind) -> SemIR::TypeId {
 }
 
 auto Context::GetFunctionType(SemIR::FunctionId fn_id,
-                              SemIR::GenericInstanceId instance_id)
-    -> SemIR::TypeId {
-  return GetCompleteTypeImpl<SemIR::FunctionType>(*this, fn_id, instance_id);
+                              SemIR::SpecificId specific_id) -> SemIR::TypeId {
+  return GetCompleteTypeImpl<SemIR::FunctionType>(*this, fn_id, specific_id);
 }
 
 auto Context::GetGenericClassType(SemIR::ClassId class_id) -> SemIR::TypeId {

+ 9 - 11
toolchain/check/context.h

@@ -30,16 +30,16 @@ namespace Carbon::Check {
 struct LookupScope {
   // The name scope in which names are searched.
   SemIR::NameScopeId name_scope_id;
-  // The generic instance for the name scope, or `Invalid` if the name scope is
-  // not an instance of a generic.
-  SemIR::GenericInstanceId instance_id;
+  // The specific for the name scope, or `Invalid` if the name scope is not
+  // defined by a generic or we should perform lookup into the generic itself.
+  SemIR::SpecificId specific_id;
 };
 
 // A result produced by name lookup.
 struct LookupResult {
-  // The generic instance in which the lookup result was found. `Invalid` if the
-  // result was not found in a generic instance.
-  SemIR::GenericInstanceId instance_id;
+  // The specific in which the lookup result was found. `Invalid` if the result
+  // was not found in a specific.
+  SemIR::SpecificId specific_id;
   // The declaration that was found by name lookup.
   SemIR::InstId inst_id;
 };
@@ -288,8 +288,8 @@ class Context {
   auto GetBuiltinType(SemIR::BuiltinInstKind kind) -> SemIR::TypeId;
 
   // Gets a function type. The returned type will be complete.
-  auto GetFunctionType(SemIR::FunctionId fn_id,
-                       SemIR::GenericInstanceId instance_id) -> SemIR::TypeId;
+  auto GetFunctionType(SemIR::FunctionId fn_id, SemIR::SpecificId specific_id)
+      -> SemIR::TypeId;
 
   // Gets a generic class type, which is the type of a name of a generic class,
   // such as the type of `Vector` given `class Vector(T:! type)`. The returned
@@ -423,9 +423,7 @@ class Context {
   }
   auto impls() -> SemIR::ImplStore& { return sem_ir().impls(); }
   auto generics() -> SemIR::GenericStore& { return sem_ir().generics(); }
-  auto generic_instances() -> SemIR::GenericInstanceStore& {
-    return sem_ir().generic_instances();
-  }
+  auto specifics() -> SemIR::SpecificStore& { return sem_ir().specifics(); }
   auto import_irs() -> ValueStore<SemIR::ImportIRId>& {
     return sem_ir().import_irs();
   }

+ 4 - 4
toolchain/check/convert.cpp

@@ -1119,7 +1119,7 @@ CARBON_DIAGNOSTIC(InCallToFunction, Note, "Calling function declared here.");
 // Convert the object argument in a method call to match the `self` parameter.
 static auto ConvertSelf(Context& context, SemIR::LocId call_loc_id,
                         SemIR::InstId callee_id,
-                        SemIR::GenericInstanceId callee_specific_id,
+                        SemIR::SpecificId callee_specific_id,
                         std::optional<SemIR::AddrPattern> addr_pattern,
                         SemIR::InstId self_param_id, SemIR::Param self_param,
                         SemIR::InstId self_id) -> SemIR::InstId {
@@ -1168,7 +1168,7 @@ static auto ConvertSelf(Context& context, SemIR::LocId call_loc_id,
 
   return ConvertToValueOfType(
       context, call_loc_id, self_or_addr_id,
-      SemIR::GetTypeInInstance(context.sem_ir(), callee_specific_id,
+      SemIR::GetTypeInSpecific(context.sem_ir(), callee_specific_id,
                                self_param.type_id));
 }
 
@@ -1177,7 +1177,7 @@ auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id,
                      llvm::ArrayRef<SemIR::InstId> arg_refs,
                      SemIR::InstId return_storage_id,
                      const SemIR::EntityWithParamsBase& callee,
-                     SemIR::GenericInstanceId callee_specific_id)
+                     SemIR::SpecificId callee_specific_id)
     -> SemIR::InstBlockId {
   auto implicit_param_refs =
       context.inst_blocks().GetOrEmpty(callee.implicit_param_refs_id);
@@ -1238,7 +1238,7 @@ auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id,
     diag_param_index = i;
 
     auto param_type_id =
-        SemIR::GetTypeInInstance(context.sem_ir(), callee_specific_id,
+        SemIR::GetTypeInSpecific(context.sem_ir(), callee_specific_id,
                                  context.insts().Get(param_id).type_id());
     // TODO: Convert to the proper expression category. For now, we assume
     // parameters are all `let` bindings.

+ 1 - 1
toolchain/check/convert.h

@@ -97,7 +97,7 @@ auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id,
                      llvm::ArrayRef<SemIR::InstId> arg_refs,
                      SemIR::InstId return_storage_id,
                      const SemIR::EntityWithParamsBase& callee,
-                     SemIR::GenericInstanceId callee_specific_id)
+                     SemIR::SpecificId callee_specific_id)
     -> SemIR::InstBlockId;
 
 // Converts an expression for use as a type.

+ 12 - 13
toolchain/check/decl_name_stack.cpp

@@ -200,18 +200,18 @@ auto DeclNameStack::LookupOrAddName(NameContext name_context,
 static auto PushNameQualifierScope(Context& context,
                                    SemIR::InstId scope_inst_id,
                                    SemIR::NameScopeId scope_id,
-                                   SemIR::GenericInstanceId instance_id,
+                                   SemIR::SpecificId specific_id,
                                    bool has_error = false) -> void {
   // If the qualifier has no parameters, we don't need to keep around a
   // parameter scope.
   context.scope_stack().PopIfEmpty();
 
   // When declaring a member of a generic, resolve the self specific.
-  if (instance_id.is_valid()) {
-    ResolveSpecificDefinition(context, instance_id);
+  if (specific_id.is_valid()) {
+    ResolveSpecificDefinition(context, specific_id);
   }
 
-  context.scope_stack().Push(scope_inst_id, scope_id, instance_id, has_error);
+  context.scope_stack().Push(scope_inst_id, scope_id, specific_id, has_error);
 
   // An interface also introduces its 'Self' parameter into scope, despite it
   // not being redeclared as part of the qualifier.
@@ -232,10 +232,10 @@ auto DeclNameStack::ApplyNameQualifier(const NameComponent& name) -> void {
   name_context.has_qualifiers = true;
 
   // Resolve the qualifier as a scope and enter the new scope.
-  auto [scope_id, instance_id] = ResolveAsScope(name_context, name);
+  auto [scope_id, specific_id] = ResolveAsScope(name_context, name);
   if (scope_id.is_valid()) {
     PushNameQualifierScope(*context_, name_context.resolved_inst_id, scope_id,
-                           instance_id,
+                           specific_id,
                            context_->name_scopes().Get(scope_id).has_error);
     name_context.parent_scope_id = scope_id;
   } else {
@@ -366,10 +366,9 @@ static auto DiagnoseQualifiedDeclInNonScope(Context& context, SemIRLoc use_loc,
 
 auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
                                    const NameComponent& name) const
-    -> std::pair<SemIR::NameScopeId, SemIR::GenericInstanceId> {
-  constexpr std::pair<SemIR::NameScopeId, SemIR::GenericInstanceId>
-      InvalidResult = {SemIR::NameScopeId::Invalid,
-                       SemIR::GenericInstanceId::Invalid};
+    -> std::pair<SemIR::NameScopeId, SemIR::SpecificId> {
+  constexpr std::pair<SemIR::NameScopeId, SemIR::SpecificId> InvalidResult = {
+      SemIR::NameScopeId::Invalid, SemIR::SpecificId::Invalid};
 
   if (!CheckQualifierIsResolved(*context_, name_context)) {
     return InvalidResult;
@@ -396,7 +395,7 @@ auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
         return InvalidResult;
       }
       return {class_info.scope_id,
-              context_->generics().GetSelfInstance(class_info.generic_id)};
+              context_->generics().GetSelfSpecific(class_info.generic_id)};
     }
     case CARBON_KIND(SemIR::InterfaceDecl interface_decl): {
       const auto& interface_info =
@@ -412,7 +411,7 @@ auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
         return InvalidResult;
       }
       return {interface_info.scope_id,
-              context_->generics().GetSelfInstance(interface_info.generic_id)};
+              context_->generics().GetSelfSpecific(interface_info.generic_id)};
     }
     case CARBON_KIND(SemIR::Namespace resolved_inst): {
       auto scope_id = resolved_inst.name_scope_id;
@@ -432,7 +431,7 @@ auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
         // be used as a name qualifier.
         scope.is_closed_import = false;
       }
-      return {scope_id, SemIR::GenericInstanceId::Invalid};
+      return {scope_id, SemIR::SpecificId::Invalid};
     }
     default: {
       DiagnoseQualifiedDeclInNonScope(*context_, name_context.loc_id,

+ 1 - 1
toolchain/check/decl_name_stack.h

@@ -253,7 +253,7 @@ class DeclNameStack {
   // the name doesn't resolve to a scope.
   auto ResolveAsScope(const NameContext& name_context,
                       const NameComponent& name) const
-      -> std::pair<SemIR::NameScopeId, SemIR::GenericInstanceId>;
+      -> std::pair<SemIR::NameScopeId, SemIR::SpecificId>;
 
   // The linked context.
   Context* context_;

+ 42 - 46
toolchain/check/eval.cpp

@@ -31,7 +31,7 @@ class EvalContext {
  public:
   explicit EvalContext(
       Context& context,
-      SemIR::GenericInstanceId specific_id = SemIR::GenericInstanceId::Invalid,
+      SemIR::SpecificId specific_id = SemIR::SpecificId::Invalid,
       std::optional<SpecificEvalInfo> specific_eval_info = std::nullopt)
       : context_(context),
         specific_id_(specific_id),
@@ -45,7 +45,7 @@ class EvalContext {
       return SemIR::ConstantId::Invalid;
     }
 
-    const auto& specific = generic_instances().Get(specific_id_);
+    const auto& specific = specifics().Get(specific_id_);
     auto args = inst_blocks().Get(specific.args_id);
 
     // Bindings past the ones with known arguments can appear as local
@@ -67,14 +67,14 @@ class EvalContext {
 
     // While resolving a specific, map from previous instructions in the eval
     // block into their evaluated values. These values won't be present on the
-    // instance itself yet, so `GetConstantInInstance` won't be able to find
+    // specific itself yet, so `GetConstantInSpecific` won't be able to find
     // them.
     if (specific_eval_info_) {
       const auto& symbolic_info =
           constant_values().GetSymbolicConstant(const_id);
       if (symbolic_info.index.is_valid() &&
           symbolic_info.generic_id ==
-              generic_instances().Get(specific_id_).generic_id &&
+              specifics().Get(specific_id_).generic_id &&
           symbolic_info.index.region() == specific_eval_info_->region) {
         auto inst_id = specific_eval_info_->values[symbolic_info.index.index()];
         CARBON_CHECK(inst_id.is_valid())
@@ -85,7 +85,7 @@ class EvalContext {
     }
 
     // Map from a specific constant value to the canonical value.
-    return GetConstantInInstance(sem_ir(), specific_id_, const_id);
+    return GetConstantInSpecific(sem_ir(), specific_id_, const_id);
   }
 
   // Gets the constant value of the specified instruction in this context.
@@ -124,8 +124,8 @@ class EvalContext {
   auto interfaces() -> const ValueStore<SemIR::InterfaceId>& {
     return sem_ir().interfaces();
   }
-  auto generic_instances() -> const SemIR::GenericInstanceStore& {
-    return sem_ir().generic_instances();
+  auto specifics() -> const SemIR::SpecificStore& {
+    return sem_ir().specifics();
   }
   auto type_blocks() -> SemIR::BlockValueStore<SemIR::TypeBlockId>& {
     return sem_ir().type_blocks();
@@ -157,7 +157,7 @@ class EvalContext {
   // The type-checking context in which we're performing evaluation.
   Context& context_;
   // The specific that we are evaluating within.
-  SemIR::GenericInstanceId specific_id_;
+  SemIR::SpecificId specific_id_;
   // If we are currently evaluating an eval block for `specific_id_`,
   // information about that evaluation.
   std::optional<SpecificEvalInfo> specific_eval_info_;
@@ -320,26 +320,25 @@ static auto GetConstantValue(EvalContext& eval_context,
   return type_block_id;
 }
 
-// The constant value of a generic instance is the generic instance with the
-// corresponding constant values for its arguments.
+// The constant value of a specific is the specific with the corresponding
+// constant values for its arguments.
 static auto GetConstantValue(EvalContext& eval_context,
-                             SemIR::GenericInstanceId instance_id, Phase* phase)
-    -> SemIR::GenericInstanceId {
-  if (!instance_id.is_valid()) {
-    return SemIR::GenericInstanceId::Invalid;
+                             SemIR::SpecificId specific_id, Phase* phase)
+    -> SemIR::SpecificId {
+  if (!specific_id.is_valid()) {
+    return SemIR::SpecificId::Invalid;
   }
 
-  const auto& instance = eval_context.generic_instances().Get(instance_id);
-  auto args_id = GetConstantValue(eval_context, instance.args_id, phase);
+  const auto& specific = eval_context.specifics().Get(specific_id);
+  auto args_id = GetConstantValue(eval_context, specific.args_id, phase);
   if (!args_id.is_valid()) {
-    return SemIR::GenericInstanceId::Invalid;
+    return SemIR::SpecificId::Invalid;
   }
 
-  if (args_id == instance.args_id) {
-    return instance_id;
+  if (args_id == specific.args_id) {
+    return specific_id;
   }
-  return MakeGenericInstance(eval_context.context(), instance.generic_id,
-                             args_id);
+  return MakeSpecific(eval_context.context(), specific.generic_id, args_id);
 }
 
 // Replaces the specified field of the given typed instruction with its constant
@@ -1095,7 +1094,7 @@ static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc,
       eval_context.insts().Get(call.callee_id).type_id());
   CARBON_KIND_SWITCH(type_inst) {
     case CARBON_KIND(SemIR::GenericClassType generic_class): {
-      auto instance_id = MakeGenericInstance(
+      auto specific_id = MakeSpecific(
           eval_context.context(),
           eval_context.classes().Get(generic_class.class_id).generic_id,
           call.args_id);
@@ -1103,21 +1102,20 @@ static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc,
           eval_context.context(),
           SemIR::ClassType{.type_id = call.type_id,
                            .class_id = generic_class.class_id,
-                           .instance_id = instance_id},
+                           .specific_id = specific_id},
           phase);
     }
     case CARBON_KIND(SemIR::GenericInterfaceType generic_interface): {
-      auto instance_id =
-          MakeGenericInstance(eval_context.context(),
-                              eval_context.interfaces()
-                                  .Get(generic_interface.interface_id)
-                                  .generic_id,
-                              call.args_id);
+      auto specific_id = MakeSpecific(eval_context.context(),
+                                      eval_context.interfaces()
+                                          .Get(generic_interface.interface_id)
+                                          .generic_id,
+                                      call.args_id);
       return MakeConstantResult(
           eval_context.context(),
           SemIR::InterfaceType{.type_id = call.type_id,
                                .interface_id = generic_interface.interface_id,
-                               .instance_id = instance_id},
+                               .specific_id = specific_id},
           phase);
     }
     default: {
@@ -1187,13 +1185,13 @@ auto TryEvalInstInContext(EvalContext& eval_context, SemIR::InstId inst_id,
           &SemIR::BoundMethod::object_id, &SemIR::BoundMethod::function_id);
     case SemIR::ClassType::Kind:
       return RebuildIfFieldsAreConstant(eval_context, inst,
-                                        &SemIR::ClassType::instance_id);
+                                        &SemIR::ClassType::specific_id);
     case SemIR::FunctionType::Kind:
       return RebuildIfFieldsAreConstant(eval_context, inst,
-                                        &SemIR::FunctionType::instance_id);
+                                        &SemIR::FunctionType::specific_id);
     case SemIR::InterfaceType::Kind:
       return RebuildIfFieldsAreConstant(eval_context, inst,
-                                        &SemIR::InterfaceType::instance_id);
+                                        &SemIR::InterfaceType::specific_id);
     case SemIR::InterfaceWitness::Kind:
       return RebuildIfFieldsAreConstant(eval_context, inst,
                                         &SemIR::InterfaceWitness::elements_id);
@@ -1288,7 +1286,7 @@ auto TryEvalInstInContext(EvalContext& eval_context, SemIR::InstId inst_id,
           eval_context.context(),
           SemIR::ClassType{.type_id = SemIR::TypeId::TypeType,
                            .class_id = class_decl.class_id,
-                           .instance_id = SemIR::GenericInstanceId::Invalid},
+                           .specific_id = SemIR::SpecificId::Invalid},
           Phase::Template);
     }
     case CARBON_KIND(SemIR::InterfaceDecl interface_decl): {
@@ -1309,17 +1307,16 @@ auto TryEvalInstInContext(EvalContext& eval_context, SemIR::InstId inst_id,
       // A non-generic interface declaration evaluates to the interface type.
       return MakeConstantResult(
           eval_context.context(),
-          SemIR::InterfaceType{
-              .type_id = SemIR::TypeId::TypeType,
-              .interface_id = interface_decl.interface_id,
-              .instance_id = SemIR::GenericInstanceId::Invalid},
+          SemIR::InterfaceType{.type_id = SemIR::TypeId::TypeType,
+                               .interface_id = interface_decl.interface_id,
+                               .specific_id = SemIR::SpecificId::Invalid},
           Phase::Template);
     }
 
-    case CARBON_KIND(SemIR::SpecificConstant instance): {
+    case CARBON_KIND(SemIR::SpecificConstant specific): {
       // Pull the constant value out of the specific.
-      return SemIR::GetConstantValueInInstance(
-          eval_context.sem_ir(), instance.instance_id, instance.inst_id);
+      return SemIR::GetConstantValueInSpecific(
+          eval_context.sem_ir(), specific.specific_id, specific.inst_id);
     }
 
     // These cases are treated as being the unique canonical definition of the
@@ -1371,8 +1368,8 @@ auto TryEvalInstInContext(EvalContext& eval_context, SemIR::InstId inst_id,
       const auto& bind_name =
           eval_context.entity_names().Get(bind.entity_name_id);
 
-      // If we know which instance we're evaluating within and this is an
-      // argument of that instance, its constant value is the corresponding
+      // If we know which specific we're evaluating within and this is an
+      // argument of that specific, its constant value is the corresponding
       // argument value.
       if (auto value =
               eval_context.GetCompileTimeBindValue(bind_name.bind_index);
@@ -1482,11 +1479,10 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
   return TryEvalInstInContext(eval_context, inst_id, inst);
 }
 
-auto TryEvalBlockForSpecific(Context& context,
-                             SemIR::GenericInstanceId specific_id,
+auto TryEvalBlockForSpecific(Context& context, SemIR::SpecificId specific_id,
                              SemIR::GenericInstIndex::Region region)
     -> SemIR::InstBlockId {
-  auto generic_id = context.generic_instances().Get(specific_id).generic_id;
+  auto generic_id = context.specifics().Get(specific_id).generic_id;
   auto eval_block_id = context.generics().Get(generic_id).GetEvalBlock(region);
   auto eval_block = context.inst_blocks().Get(eval_block_id);
 

+ 1 - 2
toolchain/check/eval.h

@@ -20,8 +20,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
 // Evaluates the eval block for a region of a specific. Produces a block
 // containing the evaluated constant values of the instructions in the eval
 // block.
-auto TryEvalBlockForSpecific(Context& context,
-                             SemIR::GenericInstanceId specific_id,
+auto TryEvalBlockForSpecific(Context& context, SemIR::SpecificId specific_id,
                              SemIR::GenericInstIndex::Region region)
     -> SemIR::InstBlockId;
 

+ 2 - 2
toolchain/check/function.cpp

@@ -26,7 +26,7 @@ auto CheckFunctionTypeMatches(Context& context,
   auto new_return_type_id =
       new_function.GetDeclaredReturnType(context.sem_ir());
   auto prev_return_type_id = prev_function.GetDeclaredReturnType(
-      context.sem_ir(), SemIR::GenericInstanceId::Invalid);
+      context.sem_ir(), SemIR::SpecificId::Invalid);
   if (new_return_type_id == SemIR::TypeId::Error ||
       prev_return_type_id == SemIR::TypeId::Error) {
     return false;
@@ -72,7 +72,7 @@ auto CheckFunctionTypeMatches(Context& context,
 
 auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
                              SemIR::Function& function,
-                             SemIR::GenericInstanceId specific_id)
+                             SemIR::SpecificId specific_id)
     -> SemIR::Function::ReturnSlot {
   // If we have already checked the return type, we have nothing to do.
   if (function.return_slot != SemIR::Function::ReturnSlot::NotComputed &&

+ 1 - 1
toolchain/check/function.h

@@ -40,7 +40,7 @@ auto CheckFunctionTypeMatches(Context& context,
 // necessary.
 auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
                              SemIR::Function& function,
-                             SemIR::GenericInstanceId specific_id)
+                             SemIR::SpecificId specific_id)
     -> SemIR::Function::ReturnSlot;
 
 }  // namespace Carbon::Check

+ 36 - 38
toolchain/check/generic.cpp

@@ -30,9 +30,8 @@ auto StartGenericDefinition(Context& context) -> void {
 // Adds an instruction `generic_inst_id` to the eval block for a generic region,
 // which is the current instruction block. The instruction `generic_inst_id` is
 // expected to compute the value of the constant described by `const_inst_id` in
-// each instance of the generic. Forms and returns a corresponding symbolic
-// constant ID that refers to the substituted value of that instruction in each
-// instance of the generic.
+// each specific. Forms and returns a corresponding symbolic constant ID that
+// refers to the substituted value of that instruction in each specific.
 static auto AddGenericConstantInstToEvalBlock(
     Context& context, SemIR::GenericId generic_id,
     SemIR::GenericInstIndex::Region region, SemIR::InstId const_inst_id,
@@ -124,9 +123,9 @@ class RebuildGenericConstantInEvalBlockCallbacks final
 }  // namespace
 
 // Adds instructions to compute the substituted version of `type_id` in each
-// instance of a generic into the eval block for the generic, which is the
-// current instruction block. Returns a symbolic type ID that refers to the
-// substituted type in each instance of the generic.
+// specific into the eval block for the generic, which is the current
+// instruction block. Returns a symbolic type ID that refers to the substituted
+// type in each specific.
 static auto AddGenericTypeToEvalBlock(
     Context& context, SemIR::GenericId generic_id,
     SemIR::GenericInstIndex::Region region,
@@ -142,9 +141,9 @@ static auto AddGenericTypeToEvalBlock(
 }
 
 // Adds instructions to compute the substituted value of `inst_id` in each
-// instance of a generic into the eval block for the generic, which is the
-// current instruction block. Returns a symbolic constant instruction ID that
-// refers to the substituted constant value in each instance of the generic.
+// specific into the eval block for the generic, which is the current
+// instruction block. Returns a symbolic constant instruction ID that refers to
+// the substituted constant value in each specific.
 static auto AddGenericConstantToEvalBlock(
     Context& context, SemIR::GenericId generic_id,
     SemIR::GenericInstIndex::Region region,
@@ -164,7 +163,7 @@ static auto AddGenericConstantToEvalBlock(
 }
 
 // Builds and returns a block of instructions whose constant values need to be
-// evaluated in order to resolve a generic instance.
+// evaluated in order to resolve a generic to a specific.
 static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id,
                                  SemIR::GenericInstIndex::Region region)
     -> SemIR::InstBlockId {
@@ -209,7 +208,7 @@ static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id,
     }
 
     // If the instruction has a symbolic constant value, then make a note that
-    // we'll need to evaluate this instruction in the generic instance. Update
+    // we'll need to evaluate this instruction when forming the specific. Update
     // the constant value of the instruction to refer to the result of that
     // eventual evaluation.
     if ((dep_kind & GenericRegionStack::DependencyKind::SymbolicConstant) !=
@@ -253,15 +252,15 @@ auto FinishGenericDecl(Context& context, SemIR::InstId decl_id)
   auto generic_id = context.generics().Add(
       SemIR::Generic{.decl_id = decl_id,
                      .bindings_id = bindings_id,
-                     .self_instance_id = SemIR::GenericInstanceId::Invalid});
+                     .self_specific_id = SemIR::SpecificId::Invalid});
 
   auto decl_block_id = MakeGenericEvalBlock(
       context, generic_id, SemIR::GenericInstIndex::Region::Declaration);
   context.generic_region_stack().Pop();
   context.generics().Get(generic_id).decl_block_id = decl_block_id;
 
-  auto self_instance_id = MakeGenericSelfInstance(context, generic_id);
-  context.generics().Get(generic_id).self_instance_id = self_instance_id;
+  auto self_specific_id = MakeSelfSpecific(context, generic_id);
+  context.generics().Get(generic_id).self_specific_id = self_specific_id;
   return generic_id;
 }
 
@@ -290,33 +289,32 @@ auto FinishGenericDefinition(Context& context, SemIR::GenericId generic_id)
   context.generic_region_stack().Pop();
 }
 
-auto MakeGenericInstance(Context& context, SemIR::GenericId generic_id,
-                         SemIR::InstBlockId args_id)
-    -> SemIR::GenericInstanceId {
-  auto instance_id = context.generic_instances().GetOrAdd(generic_id, args_id);
+auto MakeSpecific(Context& context, SemIR::GenericId generic_id,
+                  SemIR::InstBlockId args_id) -> SemIR::SpecificId {
+  auto specific_id = context.specifics().GetOrAdd(generic_id, args_id);
 
   // TODO: Remove this once we import generics properly.
   if (!generic_id.is_valid()) {
-    return instance_id;
+    return specific_id;
   }
 
-  // If this is the first time we've formed this instance, evaluate its decl
-  // block to form information about the instance.
-  if (!context.generic_instances().Get(instance_id).decl_block_id.is_valid()) {
+  // If this is the first time we've formed this specific, evaluate its decl
+  // block to form information about the specific.
+  if (!context.specifics().Get(specific_id).decl_block_id.is_valid()) {
     auto decl_block_id = TryEvalBlockForSpecific(
-        context, instance_id, SemIR::GenericInstIndex::Region::Declaration);
-    // Note that TryEvalBlockForSpecific may reallocate the list of generic
-    // instances, so re-lookup the instance here.
-    context.generic_instances().Get(instance_id).decl_block_id = decl_block_id;
+        context, specific_id, SemIR::GenericInstIndex::Region::Declaration);
+    // Note that TryEvalBlockForSpecific may reallocate the list of specifics,
+    // so re-lookup the specific here.
+    context.specifics().Get(specific_id).decl_block_id = decl_block_id;
   }
 
-  return instance_id;
+  return specific_id;
 }
 
-auto MakeGenericSelfInstance(Context& context, SemIR::GenericId generic_id)
-    -> SemIR::GenericInstanceId {
+auto MakeSelfSpecific(Context& context, SemIR::GenericId generic_id)
+    -> SemIR::SpecificId {
   if (!generic_id.is_valid()) {
-    return SemIR::GenericInstanceId::Invalid;
+    return SemIR::SpecificId::Invalid;
   }
 
   auto& generic = context.generics().Get(generic_id);
@@ -330,16 +328,16 @@ auto MakeGenericSelfInstance(Context& context, SemIR::GenericId generic_id)
   }
   auto args_id = context.inst_blocks().AddCanonical(arg_ids);
 
-  // Build a corresponding instance.
+  // Build a corresponding specific.
   // TODO: This could be made more efficient. We don't need to perform
   // substitution here; we know we want identity mappings for all constants and
   // types. We could also consider not storing the mapping at all in this case.
-  return MakeGenericInstance(context, generic_id, args_id);
+  return MakeSpecific(context, generic_id, args_id);
 }
 
-auto ResolveSpecificDefinition(Context& context,
-                               SemIR::GenericInstanceId specific_id) -> bool {
-  auto& specific = context.generic_instances().Get(specific_id);
+auto ResolveSpecificDefinition(Context& context, SemIR::SpecificId specific_id)
+    -> bool {
+  auto& specific = context.specifics().Get(specific_id);
   auto generic_id = specific.generic_id;
 
   // TODO: Remove this once we import generics properly.
@@ -356,9 +354,9 @@ auto ResolveSpecificDefinition(Context& context,
     }
     auto definition_block_id = TryEvalBlockForSpecific(
         context, specific_id, SemIR::GenericInstIndex::Region::Definition);
-    // Note that TryEvalBlockForSpecific may reallocate the list of generic
-    // instances, so re-lookup the instance here.
-    context.generic_instances().Get(specific_id).definition_block_id =
+    // Note that TryEvalBlockForSpecific may reallocate the list of specifics,
+    // so re-lookup the specific here.
+    context.specifics().Get(specific_id).definition_block_id =
         definition_block_id;
   }
   return true;

+ 11 - 12
toolchain/check/generic.h

@@ -31,26 +31,25 @@ auto FinishGenericRedecl(Context& context, SemIR::InstId decl_id,
 auto FinishGenericDefinition(Context& context, SemIR::GenericId generic_id)
     -> void;
 
-// Builds a new generic instance, or finds an existing one if this instance of
-// this generic has already been referenced. Performs substitution into the
+// Builds a new specific, or finds an existing one if this generic has already
+// been referenced with these arguments. Performs substitution into the
 // declaration, but not the definition, of the generic.
 //
 // `args_id` should be a canonical instruction block referring to constants.
-auto MakeGenericInstance(Context& context, SemIR::GenericId generic_id,
-                         SemIR::InstBlockId args_id)
-    -> SemIR::GenericInstanceId;
+auto MakeSpecific(Context& context, SemIR::GenericId generic_id,
+                  SemIR::InstBlockId args_id) -> SemIR::SpecificId;
 
-// Builds the generic instance corresponding to the generic itself. For example,
-// for a generic `G(T:! type)`, this is `G(T)`. For an invalid `generic_id`,
-// returns an invalid instance ID.
-auto MakeGenericSelfInstance(Context& context, SemIR::GenericId generic_id)
-    -> SemIR::GenericInstanceId;
+// Builds the specific that describes how the generic should refer to itself.
+// For example, for a generic `G(T:! type)`, this is the specific `G(T)`. For an
+// invalid `generic_id`, returns an invalid specific ID.
+auto MakeSelfSpecific(Context& context, SemIR::GenericId generic_id)
+    -> SemIR::SpecificId;
 
 // Attempts to resolve the definition of the given specific, by evaluating the
 // eval block of the corresponding generic and storing a corresponding value
 // block in the specific. Returns false if a definition is not available.
-auto ResolveSpecificDefinition(Context& context,
-                               SemIR::GenericInstanceId specific_id) -> bool;
+auto ResolveSpecificDefinition(Context& context, SemIR::SpecificId specific_id)
+    -> bool;
 
 }  // namespace Carbon::Check
 

+ 4 - 4
toolchain/check/handle_class.cpp

@@ -252,13 +252,13 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
     // declaration.
     auto& class_info = context.classes().Get(class_decl.class_id);
     if (class_info.is_generic()) {
-      auto instance_id =
-          context.generics().GetSelfInstance(class_info.generic_id);
+      auto specific_id =
+          context.generics().GetSelfSpecific(class_info.generic_id);
       class_info.self_type_id = context.GetTypeIdForTypeConstant(
           TryEvalInst(context, SemIR::InstId::Invalid,
                       SemIR::ClassType{.type_id = SemIR::TypeId::TypeType,
                                        .class_id = class_decl.class_id,
-                                       .instance_id = instance_id}));
+                                       .specific_id = specific_id}));
     } else {
       class_info.self_type_id = context.GetTypeIdForTypeInst(class_decl_id);
     }
@@ -293,7 +293,7 @@ auto HandleParseNode(Context& context, Parse::ClassDefinitionStartId node_id)
   // Enter the class scope.
   context.scope_stack().Push(
       class_decl_id, class_info.scope_id,
-      context.generics().GetSelfInstance(class_info.generic_id));
+      context.generics().GetSelfSpecific(class_info.generic_id));
   StartGenericDefinition(context);
 
   // Introduce `Self`.

+ 1 - 1
toolchain/check/handle_function.cpp

@@ -335,7 +335,7 @@ static auto HandleFunctionDefinitionAfterSignature(
 
   // Check the return type is complete.
   CheckFunctionReturnType(context, function.return_storage_id, function,
-                          SemIR::GenericInstanceId::Invalid);
+                          SemIR::SpecificId::Invalid);
 
   // Check the parameter types are complete.
   for (auto param_id : llvm::concat<const SemIR::InstId>(

+ 4 - 4
toolchain/check/handle_interface.cpp

@@ -144,7 +144,7 @@ auto HandleParseNode(Context& context,
   // Enter the interface scope.
   context.scope_stack().Push(
       interface_decl_id, interface_info.scope_id,
-      context.generics().GetSelfInstance(interface_info.generic_id));
+      context.generics().GetSelfSpecific(interface_info.generic_id));
   StartGenericDefinition(context);
 
   context.inst_block_stack().Push();
@@ -157,13 +157,13 @@ auto HandleParseNode(Context& context,
   if (!interface_info.is_defined()) {
     SemIR::TypeId self_type_id = SemIR::TypeId::Invalid;
     if (interface_info.is_generic()) {
-      auto instance_id =
-          context.generics().GetSelfInstance(interface_info.generic_id);
+      auto specific_id =
+          context.generics().GetSelfSpecific(interface_info.generic_id);
       self_type_id = context.GetTypeIdForTypeConstant(
           TryEvalInst(context, SemIR::InstId::Invalid,
                       SemIR::InterfaceType{.type_id = SemIR::TypeId::TypeType,
                                            .interface_id = interface_id,
-                                           .instance_id = instance_id}));
+                                           .specific_id = specific_id}));
     } else {
       self_type_id = context.GetTypeIdForTypeInst(interface_decl_id);
     }

+ 5 - 5
toolchain/check/handle_name.cpp

@@ -81,18 +81,18 @@ static auto HandleNameAsExpr(Context& context, Parse::NodeId node_id,
                              SemIR::NameId name_id) -> bool {
   auto result = context.LookupUnqualifiedName(node_id, name_id);
   auto value = context.insts().Get(result.inst_id);
-  auto type_id = SemIR::GetTypeInInstance(context.sem_ir(), result.instance_id,
+  auto type_id = SemIR::GetTypeInSpecific(context.sem_ir(), result.specific_id,
                                           value.type_id());
   CARBON_CHECK(type_id.is_valid()) << "Missing type for " << value;
 
-  // If the named entity has a constant value that depends on its generic
-  // instance, store the instance too.
-  if (result.instance_id.is_valid() &&
+  // If the named entity has a constant value that depends on its specific,
+  // store the specific too.
+  if (result.specific_id.is_valid() &&
       context.constant_values().Get(result.inst_id).is_symbolic()) {
     result.inst_id = context.AddInst<SemIR::SpecificConstant>(
         node_id, {.type_id = type_id,
                   .inst_id = result.inst_id,
-                  .instance_id = result.instance_id});
+                  .specific_id = result.specific_id});
   }
 
   context.AddInstAndPush<SemIR::NameRef>(

+ 24 - 24
toolchain/check/import_ref.cpp

@@ -422,30 +422,30 @@ class ImportRefResolver {
   }
 
   // Gets a local argument list corresponding to the arguments of an imported
-  // generic instance.
-  auto GetLocalGenericInstanceArgs(SemIR::GenericInstanceId instance_id)
+  // specific.
+  auto GetLocalSpecificArgs(SemIR::SpecificId specific_id)
       -> llvm::SmallVector<SemIR::InstId> {
-    if (!instance_id.is_valid()) {
+    if (!specific_id.is_valid()) {
       return {};
     }
     return GetLocalInstBlockContents(
-        import_ir_.generic_instances().Get(instance_id).args_id);
+        import_ir_.specifics().Get(specific_id).args_id);
   }
 
-  // Gets a local generic instance whose arguments were already imported by
-  // GetLocalGenericInstanceArgs. Does not add any new work.
-  auto GetLocalGenericInstance(SemIR::GenericInstanceId instance_id,
-                               llvm::ArrayRef<SemIR::InstId> args)
-      -> SemIR::GenericInstanceId {
-    if (!instance_id.is_valid()) {
-      return SemIR::GenericInstanceId::Invalid;
+  // Gets a local specific whose arguments were already imported by
+  // GetLocalSpecificArgs. Does not add any new work.
+  auto GetLocalSpecific(SemIR::SpecificId specific_id,
+                        llvm::ArrayRef<SemIR::InstId> args)
+      -> SemIR::SpecificId {
+    if (!specific_id.is_valid()) {
+      return SemIR::SpecificId::Invalid;
     }
-    const auto& instance = import_ir_.generic_instances().Get(instance_id);
+    const auto& specific = import_ir_.specifics().Get(specific_id);
     // TODO: Import the generic.
     auto generic_id = SemIR::GenericId::Invalid;
-    auto args_id = GetLocalCanonicalInstBlockId(instance.args_id, args);
-    // TODO: Also import the generic instance.
-    return context_.generic_instances().GetOrAdd(generic_id, args_id);
+    auto args_id = GetLocalCanonicalInstBlockId(specific.args_id, args);
+    // TODO: Also import the specific.
+    return context_.specifics().GetOrAdd(generic_id, args_id);
   }
 
   // Returns the ConstantId for each parameter's type. Adds unresolved constants
@@ -1046,7 +1046,7 @@ class ImportRefResolver {
     CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
     auto class_const_id =
         GetLocalConstantId(import_ir_.classes().Get(inst.class_id).decl_id);
-    auto args = GetLocalGenericInstanceArgs(inst.instance_id);
+    auto args = GetLocalSpecificArgs(inst.specific_id);
     if (HasNewWork(initial_work)) {
       return ResolveResult::Retry();
     }
@@ -1061,11 +1061,11 @@ class ImportRefResolver {
     } else {
       auto generic_class_type = context_.types().GetAs<SemIR::GenericClassType>(
           class_const_inst.type_id());
-      auto instance_id = GetLocalGenericInstance(inst.instance_id, args);
+      auto specific_id = GetLocalSpecific(inst.specific_id, args);
       return ResolveAs<SemIR::ClassType>(
           {.type_id = SemIR::TypeId::TypeType,
            .class_id = generic_class_type.class_id,
-           .instance_id = instance_id});
+           .specific_id = specific_id});
     }
   }
 
@@ -1164,7 +1164,7 @@ class ImportRefResolver {
           .return_slot = function.return_slot,
           .builtin_function_kind = function.builtin_function_kind}});
     // TODO: Import this or recompute it.
-    auto specific_id = SemIR::GenericInstanceId::Invalid;
+    auto specific_id = SemIR::SpecificId::Invalid;
     function_decl.type_id =
         context_.GetFunctionType(function_decl.function_id, specific_id);
     // Write the function ID into the FunctionDecl.
@@ -1182,8 +1182,8 @@ class ImportRefResolver {
     }
     auto fn_val = context_.insts().Get(fn_val_id);
     CARBON_CHECK(context_.types().Is<SemIR::FunctionType>(fn_val.type_id()));
-    // TODO: Import the correct generic instance and build a function type
-    // constant using it.
+    // TODO: Import the correct specific and build a function type constant
+    // using it.
     return {.const_id = context_.types().GetConstantId(fn_val.type_id())};
   }
 
@@ -1355,7 +1355,7 @@ class ImportRefResolver {
     CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
     auto interface_const_id = GetLocalConstantId(
         import_ir_.interfaces().Get(inst.interface_id).decl_id);
-    auto args = GetLocalGenericInstanceArgs(inst.instance_id);
+    auto args = GetLocalSpecificArgs(inst.specific_id);
     if (HasNewWork(initial_work)) {
       return ResolveResult::Retry();
     }
@@ -1372,11 +1372,11 @@ class ImportRefResolver {
       auto generic_interface_type =
           context_.types().GetAs<SemIR::GenericInterfaceType>(
               interface_const_inst.type_id());
-      auto instance_id = GetLocalGenericInstance(inst.instance_id, args);
+      auto specific_id = GetLocalSpecific(inst.specific_id, args);
       return ResolveAs<SemIR::InterfaceType>(
           {.type_id = SemIR::TypeId::TypeType,
            .interface_id = generic_interface_type.interface_id,
-           .instance_id = instance_id});
+           .specific_id = specific_id});
     }
   }
 

+ 9 - 9
toolchain/check/member_access.cpp

@@ -27,7 +27,7 @@ static auto GetAsLookupScope(Context& context, Parse::NodeId node_id,
   auto base = context.insts().Get(base_id);
   if (auto base_as_namespace = base.TryAs<SemIR::Namespace>()) {
     return LookupScope{.name_scope_id = base_as_namespace->name_scope_id,
-                       .instance_id = SemIR::GenericInstanceId::Invalid};
+                       .specific_id = SemIR::SpecificId::Invalid};
   }
   // TODO: Consider refactoring the near-identical class and interface support
   // below.
@@ -43,7 +43,7 @@ static auto GetAsLookupScope(Context& context, Parse::NodeId node_id,
         });
     auto& class_info = context.classes().Get(base_as_class->class_id);
     return LookupScope{.name_scope_id = class_info.scope_id,
-                       .instance_id = base_as_class->instance_id};
+                       .specific_id = base_as_class->specific_id};
   }
   if (auto base_as_interface = base.TryAs<SemIR::InterfaceType>()) {
     context.TryToDefineType(
@@ -58,7 +58,7 @@ static auto GetAsLookupScope(Context& context, Parse::NodeId node_id,
     auto& interface_info =
         context.interfaces().Get(base_as_interface->interface_id);
     return LookupScope{.name_scope_id = interface_info.scope_id,
-                       .instance_id = base_as_interface->instance_id};
+                       .specific_id = base_as_interface->specific_id};
   }
   // TODO: Per the design, if `base_id` is any kind of type, then lookup should
   // treat it as a name scope, even if it doesn't have members. For example,
@@ -218,7 +218,7 @@ static auto LookupMemberNameInScope(Context& context, Parse::NodeId node_id,
                                     SemIR::NameId name_id,
                                     SemIR::ConstantId name_scope_const_id,
                                     LookupScope lookup_scope) -> SemIR::InstId {
-  LookupResult result = {.instance_id = SemIR::GenericInstanceId::Invalid,
+  LookupResult result = {.specific_id = SemIR::SpecificId::Invalid,
                          .inst_id = SemIR::InstId::BuiltinError};
   if (lookup_scope.name_scope_id.is_valid()) {
     result = context.LookupQualifiedName(node_id, name_id, lookup_scope);
@@ -226,18 +226,18 @@ static auto LookupMemberNameInScope(Context& context, Parse::NodeId node_id,
 
   // TODO: This duplicates the work that HandleNameAsExpr does. Factor this out.
   auto inst = context.insts().Get(result.inst_id);
-  auto type_id = SemIR::GetTypeInInstance(context.sem_ir(), result.instance_id,
+  auto type_id = SemIR::GetTypeInSpecific(context.sem_ir(), result.specific_id,
                                           inst.type_id());
   CARBON_CHECK(type_id.is_valid()) << "Missing type for member " << inst;
 
-  // If the named entity has a constant value that depends on its generic
-  // instance, store the instance too.
-  if (result.instance_id.is_valid() &&
+  // If the named entity has a constant value that depends on its specific,
+  // store the specific too.
+  if (result.specific_id.is_valid() &&
       context.constant_values().Get(result.inst_id).is_symbolic()) {
     result.inst_id = context.AddInst<SemIR::SpecificConstant>(
         node_id, {.type_id = type_id,
                   .inst_id = result.inst_id,
-                  .instance_id = result.instance_id});
+                  .specific_id = result.specific_id});
   }
 
   // TODO: Use a different kind of instruction that also references the

+ 4 - 5
toolchain/check/operator.cpp

@@ -38,10 +38,9 @@ static auto GetOperatorOpFunction(Context& context, Parse::AnyExprId node_id,
     return SemIR::InstId::Invalid;
   }
 
-  // TODO: For a parameterized interface, find the corresponding generic
-  // instance.
+  // TODO: For a parameterized interface, find the corresponding specific.
   LookupScope scope = {.name_scope_id = interface_scope_id,
-                       .instance_id = SemIR::GenericInstanceId::Invalid};
+                       .specific_id = SemIR::SpecificId::Invalid};
 
   // Lookup `Interface.Op`.
   auto op_ident_id = context.identifiers().Add(op.op_name);
@@ -53,8 +52,8 @@ static auto GetOperatorOpFunction(Context& context, Parse::AnyExprId node_id,
   }
 
   // Look through import_refs and aliases.
-  auto op_const_id = GetConstantValueInInstance(
-      context.sem_ir(), op_result.instance_id, op_result.inst_id);
+  auto op_const_id = GetConstantValueInSpecific(
+      context.sem_ir(), op_result.specific_id, op_result.inst_id);
   auto op_id = context.constant_values().GetInstId(op_const_id);
 
   // We expect it to be an associated function.

+ 11 - 11
toolchain/check/scope_stack.cpp

@@ -14,13 +14,13 @@ auto ScopeStack::VerifyOnFinish() -> void {
 }
 
 auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
-                      SemIR::GenericInstanceId instance_id,
+                      SemIR::SpecificId specific_id,
                       bool lexical_lookup_has_load_error) -> void {
   // If this scope doesn't have a specific of its own, it lives in the enclosing
   // scope's specific, if any.
-  auto enclosing_instance_id = instance_id;
-  if (!instance_id.is_valid() && !scope_stack_.empty()) {
-    enclosing_instance_id = PeekSpecificId();
+  auto enclosing_specific_id = specific_id;
+  if (!specific_id.is_valid() && !scope_stack_.empty()) {
+    enclosing_specific_id = PeekSpecificId();
   }
 
   compile_time_binding_stack_.PushArray();
@@ -28,7 +28,7 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
       {.index = next_scope_index_,
        .scope_inst_id = scope_inst_id,
        .scope_id = scope_id,
-       .instance_id = enclosing_instance_id,
+       .specific_id = enclosing_specific_id,
        .next_compile_time_bind_index = SemIR::CompileTimeBindIndex(
            compile_time_binding_stack_.all_values_size()),
        .lexical_lookup_has_load_error =
@@ -36,13 +36,13 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
   if (scope_id.is_valid()) {
     non_lexical_scope_stack_.push_back({.scope_index = next_scope_index_,
                                         .name_scope_id = scope_id,
-                                        .instance_id = enclosing_instance_id});
+                                        .specific_id = enclosing_specific_id});
   } else {
     // For lexical lookups, unqualified lookup doesn't know how to find the
-    // associated generic instance, so if we start adding lexical scopes with
-    // generic instances, we'll need to somehow track them in lookup.
-    CARBON_CHECK(!instance_id.is_valid())
-        << "Lexical scope should not have an associated generic instance.";
+    // associated specific, so if we start adding lexical scopes associated with
+    // specifics, we'll need to somehow track them in lookup.
+    CARBON_CHECK(!specific_id.is_valid())
+        << "Lexical scope should not have an associated specific.";
   }
 
   // TODO: Handle this case more gracefully.
@@ -226,7 +226,7 @@ auto ScopeStack::Restore(SuspendedScope scope) -> void {
     non_lexical_scope_stack_.push_back(
         {.scope_index = scope.entry.index,
          .name_scope_id = scope.entry.scope_id,
-         .instance_id = scope.entry.instance_id});
+         .specific_id = scope.entry.specific_id});
   }
   scope_stack_.push_back(std::move(scope.entry));
 }

+ 10 - 11
toolchain/check/scope_stack.h

@@ -47,8 +47,8 @@ class ScopeStack {
     // The corresponding name scope.
     SemIR::NameScopeId name_scope_id;
 
-    // The corresponding generic instance.
-    SemIR::GenericInstanceId instance_id;
+    // The corresponding specific.
+    SemIR::SpecificId specific_id;
   };
 
   // Information about a scope that has been temporarily removed from the stack.
@@ -58,11 +58,10 @@ class ScopeStack {
   // scopes. lexical_lookup_has_load_error is used to limit diagnostics when a
   // given namespace may contain a mix of both successful and failed name
   // imports.
-  auto Push(
-      SemIR::InstId scope_inst_id = SemIR::InstId::Invalid,
-      SemIR::NameScopeId scope_id = SemIR::NameScopeId::Invalid,
-      SemIR::GenericInstanceId instance_id = SemIR::GenericInstanceId::Invalid,
-      bool lexical_lookup_has_load_error = false) -> void;
+  auto Push(SemIR::InstId scope_inst_id = SemIR::InstId::Invalid,
+            SemIR::NameScopeId scope_id = SemIR::NameScopeId::Invalid,
+            SemIR::SpecificId specific_id = SemIR::SpecificId::Invalid,
+            bool lexical_lookup_has_load_error = false) -> void;
 
   // Pops the top scope from scope_stack_, cleaning up names from
   // lexical_lookup_.
@@ -92,8 +91,8 @@ class ScopeStack {
   // associated with a specific. This will generally be the self specific of the
   // innermost enclosing generic, as there is no way to enter any other specific
   // scope.
-  auto PeekSpecificId() const -> SemIR::GenericInstanceId {
-    return Peek().instance_id;
+  auto PeekSpecificId() const -> SemIR::SpecificId {
+    return Peek().specific_id;
   }
 
   // Returns the current scope, if it is of the specified kind. Otherwise,
@@ -181,8 +180,8 @@ class ScopeStack {
     // The name scope associated with this entry, if any.
     SemIR::NameScopeId scope_id;
 
-    // The generic instance associated with this entry, if any.
-    SemIR::GenericInstanceId instance_id;
+    // The specific associated with this entry, if any.
+    SemIR::SpecificId specific_id;
 
     // The next compile-time binding index to allocate in this scope.
     SemIR::CompileTimeBindIndex next_compile_time_bind_index;

+ 11 - 11
toolchain/check/subst.cpp

@@ -82,11 +82,11 @@ static auto PushOperand(Context& context, Worklist& worklist,
         worklist.Push(context.types().GetInstId(type_id));
       }
       break;
-    case SemIR::IdKind::For<SemIR::GenericInstanceId>:
-      if (auto instance_id = static_cast<SemIR::GenericInstanceId>(arg);
-          instance_id.is_valid()) {
+    case SemIR::IdKind::For<SemIR::SpecificId>:
+      if (auto specific_id = static_cast<SemIR::SpecificId>(arg);
+          specific_id.is_valid()) {
         PushOperand(context, worklist, SemIR::IdKind::For<SemIR::InstBlockId>,
-                    context.generic_instances().Get(instance_id).args_id.index);
+                    context.specifics().Get(specific_id).args_id.index);
       }
       break;
     default:
@@ -145,17 +145,17 @@ static auto PopOperand(Context& context, Worklist& worklist, SemIR::IdKind kind,
       }
       return new_type_block.GetCanonical().index;
     }
-    case SemIR::IdKind::For<SemIR::GenericInstanceId>: {
-      auto instance_id = SemIR::GenericInstanceId(arg);
-      if (!instance_id.is_valid()) {
+    case SemIR::IdKind::For<SemIR::SpecificId>: {
+      auto specific_id = SemIR::SpecificId(arg);
+      if (!specific_id.is_valid()) {
         return arg;
       }
-      auto& instance = context.generic_instances().Get(instance_id);
+      auto& specific = context.specifics().Get(specific_id);
       auto args_id =
           PopOperand(context, worklist, SemIR::IdKind::For<SemIR::InstBlockId>,
-                     instance.args_id.index);
-      return MakeGenericInstance(context, instance.generic_id,
-                                 SemIR::InstBlockId(args_id))
+                     specific.args_id.index);
+      return MakeSpecific(context, specific.generic_id,
+                          SemIR::InstBlockId(args_id))
           .index;
     }
     default:

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

@@ -22,7 +22,7 @@
 // CHECK:STDOUT:   functions:       {}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
-// CHECK:STDOUT:   generic_instances: {}
+// CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}

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

@@ -39,7 +39,7 @@ fn B() {
 // CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [block4]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
-// CHECK:STDOUT:   generic_instances: {}
+// CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -51,7 +51,7 @@ fn B() {
 // CHECK:STDOUT:   insts:
 // CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
 // CHECK:STDOUT:     'inst+1':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+2)}
-// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+3':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
 // CHECK:STDOUT:     'inst+4':          {kind: StructValue, arg0: empty, type: type(inst+2)}
 // CHECK:STDOUT:     'inst+5':          {kind: Return}
@@ -114,7 +114,7 @@ fn B() {
 // CHECK:STDOUT:     function1:       {name: name1, parent_scope: name_scope1}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
-// CHECK:STDOUT:   generic_instances: {}
+// CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -129,13 +129,13 @@ fn B() {
 // CHECK:STDOUT:     'inst+1':          {kind: ImportDecl, arg0: name1}
 // CHECK:STDOUT:     'inst+2':          {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(instNamespaceType)}
 // CHECK:STDOUT:     'inst+3':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+4)}
-// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+5':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
 // CHECK:STDOUT:     'inst+6':          {kind: StructValue, arg0: empty, type: type(inst+4)}
 // CHECK:STDOUT:     'inst+7':          {kind: NameRef, arg0: name1, arg1: inst+2, type: type(instNamespaceType)}
 // CHECK:STDOUT:     'inst+8':          {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: entity_name0, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+9':          {kind: FunctionDecl, arg0: function1, arg1: empty, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+11':         {kind: StructValue, arg0: empty, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+12':         {kind: NameRef, arg0: name1, arg1: inst+8, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+13':         {kind: Call, arg0: inst+12, arg1: block5, type: type(inst+5)}

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

@@ -39,7 +39,7 @@ fn B() {
 // CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, body: [block4]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
-// CHECK:STDOUT:   generic_instances: {}
+// CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -51,7 +51,7 @@ fn B() {
 // CHECK:STDOUT:   insts:
 // CHECK:STDOUT:     'inst+0':          {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
 // CHECK:STDOUT:     'inst+1':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+2)}
-// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+2':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+3':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
 // CHECK:STDOUT:     'inst+4':          {kind: StructValue, arg0: empty, type: type(inst+2)}
 // CHECK:STDOUT:     'inst+5':          {kind: Return}
@@ -93,7 +93,7 @@ fn B() {
 // CHECK:STDOUT:     function1:       {name: name1, parent_scope: name_scope1}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
-// CHECK:STDOUT:   generic_instances: {}
+// CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -108,13 +108,13 @@ fn B() {
 // CHECK:STDOUT:     'inst+1':          {kind: ImportDecl, arg0: name1}
 // CHECK:STDOUT:     'inst+2':          {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(instNamespaceType)}
 // CHECK:STDOUT:     'inst+3':          {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+4)}
-// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+4':          {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+5':          {kind: TupleType, arg0: type_block0, type: typeTypeType}
 // CHECK:STDOUT:     'inst+6':          {kind: StructValue, arg0: empty, type: type(inst+4)}
 // CHECK:STDOUT:     'inst+7':          {kind: NameRef, arg0: name1, arg1: inst+2, type: type(instNamespaceType)}
 // CHECK:STDOUT:     'inst+8':          {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: entity_name0, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+9':          {kind: FunctionDecl, arg0: function1, arg1: empty, type: type(inst+10)}
-// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+10':         {kind: FunctionType, arg0: function1, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+11':         {kind: StructValue, arg0: empty, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+12':         {kind: NameRef, arg0: name1, arg1: inst+8, type: type(inst+10)}
 // CHECK:STDOUT:     'inst+13':         {kind: Call, arg0: inst+12, arg1: block5, type: type(inst+5)}

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

@@ -30,7 +30,7 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, return_storage: inst+13, return_slot: present, body: [block7]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
-// CHECK:STDOUT:   generic_instances: {}
+// CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -60,7 +60,7 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:     'inst+12':         {kind: Converted, arg0: inst+9, arg1: inst+8, type: typeTypeType}
 // CHECK:STDOUT:     'inst+13':         {kind: VarStorage, arg0: nameReturnSlot, type: type(inst+8)}
 // CHECK:STDOUT:     'inst+14':         {kind: FunctionDecl, arg0: function0, arg1: block6, type: type(inst+15)}
-// CHECK:STDOUT:     'inst+15':         {kind: FunctionType, arg0: function0, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+15':         {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+16':         {kind: StructValue, arg0: empty, type: type(inst+15)}
 // CHECK:STDOUT:     'inst+17':         {kind: PointerType, arg0: type(inst+8), type: typeTypeType}
 // CHECK:STDOUT:     'inst+18':         {kind: NameRef, arg0: name1, arg1: inst+5, type: type(inst+1)}

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

@@ -32,8 +32,8 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:
 // CHECK:STDOUT:     generic0:        {decl: inst+16, bindings: block8}
-// CHECK:STDOUT:   generic_instances:
-// CHECK:STDOUT:     genericInstance0: {generic: generic0, args: block10}
+// CHECK:STDOUT:   specifics:
+// CHECK:STDOUT:     specific0:       {generic: generic0, args: block10}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -77,7 +77,7 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:     'inst+17':         {kind: BindSymbolicName, arg0: entity_name0, arg1: inst<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+18':         {kind: TupleType, arg0: type_block3, type: typeTypeType}
 // CHECK:STDOUT:     'inst+19':         {kind: TupleType, arg0: type_block3, type: typeTypeType}
-// CHECK:STDOUT:     'inst+20':         {kind: FunctionType, arg0: function0, arg1: genericInstance<invalid>, type: typeTypeType}
+// CHECK:STDOUT:     'inst+20':         {kind: FunctionType, arg0: function0, arg1: specific<invalid>, type: typeTypeType}
 // CHECK:STDOUT:     'inst+21':         {kind: StructValue, arg0: empty, type: type(inst+20)}
 // CHECK:STDOUT:     'inst+22':         {kind: PointerType, arg0: type(symbolicConstant1), type: typeTypeType}
 // CHECK:STDOUT:     'inst+23':         {kind: NameRef, arg0: name2, arg1: inst+6, type: type(symbolicConstant2)}

+ 1 - 1
toolchain/parse/node_ids.h

@@ -20,7 +20,7 @@ struct InvalidNodeId {};
 // contain any of the information about the node, and serve as a handle that
 // can be used with the underlying tree to query for detailed information.
 struct NodeId : public IdBase {
-  // An explicitly invalid instance.
+  // An explicitly invalid node ID.
   static constexpr InvalidNodeId Invalid;
 
   using IdBase::IdBase;

+ 2 - 3
toolchain/sem_ir/file.cpp

@@ -152,7 +152,7 @@ auto File::OutputYaml(bool include_builtins) const -> Yaml::OutputMapping {
           map.Add("functions", functions_.OutputYaml());
           map.Add("classes", classes_.OutputYaml());
           map.Add("generics", generics_.OutputYaml());
-          map.Add("generic_instances", generic_instances_.OutputYaml());
+          map.Add("specifics", specifics_.OutputYaml());
           map.Add("types", types_.OutputYaml());
           map.Add("type_blocks", type_blocks_.OutputYaml());
           map.Add(
@@ -201,8 +201,7 @@ auto File::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
   mem_usage.Collect(MemUsage::ConcatLabel(label, "interfaces_"), interfaces_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "impls_"), impls_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "generics_"), generics_);
-  mem_usage.Collect(MemUsage::ConcatLabel(label, "generic_instances_"),
-                    generic_instances_);
+  mem_usage.Collect(MemUsage::ConcatLabel(label, "specifics_"), specifics_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "import_irs_"), import_irs_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "import_ir_insts_"),
                     import_ir_insts_);

+ 4 - 8
toolchain/sem_ir/file.h

@@ -125,12 +125,8 @@ class File : public Printable<File> {
   auto impls() const -> const ImplStore& { return impls_; }
   auto generics() -> GenericStore& { return generics_; }
   auto generics() const -> const GenericStore& { return generics_; }
-  auto generic_instances() -> GenericInstanceStore& {
-    return generic_instances_;
-  }
-  auto generic_instances() const -> const GenericInstanceStore& {
-    return generic_instances_;
-  }
+  auto specifics() -> SpecificStore& { return specifics_; }
+  auto specifics() const -> const SpecificStore& { return specifics_; }
   auto import_irs() -> ValueStore<ImportIRId>& { return import_irs_; }
   auto import_irs() const -> const ValueStore<ImportIRId>& {
     return import_irs_;
@@ -215,8 +211,8 @@ class File : public Printable<File> {
   // Storage for generics.
   GenericStore generics_;
 
-  // Storage for instances of generics.
-  GenericInstanceStore generic_instances_;
+  // Storage for specifics.
+  SpecificStore specifics_;
 
   // Related IRs. There are some fixed entries at the start; see ImportIRId.
   ValueStore<ImportIRId> import_irs_;

+ 14 - 15
toolchain/sem_ir/formatter.cpp

@@ -69,8 +69,8 @@ class FormatterImpl {
       FormatFunction(FunctionId(i));
     }
 
-    for (int i : llvm::seq(sem_ir_.generic_instances().size())) {
-      FormatSpecific(GenericInstanceId(i));
+    for (int i : llvm::seq(sem_ir_.specifics().size())) {
+      FormatSpecific(SpecificId(i));
     }
 
     // End-of-file newline.
@@ -370,8 +370,7 @@ class FormatterImpl {
     out_ << '\n';
   }
 
-  auto FormatSpecificRegion(const Generic& generic,
-                            const GenericInstance& specific,
+  auto FormatSpecificRegion(const Generic& generic, const Specific& specific,
                             GenericInstIndex::Region region,
                             llvm::StringRef region_name) -> void {
     if (!specific.GetValueBlock(region).is_valid()) {
@@ -409,8 +408,8 @@ class FormatterImpl {
     }
   }
 
-  auto FormatSpecific(GenericInstanceId id) -> void {
-    const auto& specific = sem_ir_.generic_instances().Get(id);
+  auto FormatSpecific(SpecificId id) -> void {
+    const auto& specific = sem_ir_.specifics().Get(id);
 
     out_ << "\n";
 
@@ -764,8 +763,8 @@ class FormatterImpl {
   }
 
   auto FormatInstRHS(FunctionType inst) -> void {
-    if (inst.instance_id.is_valid()) {
-      FormatArgs(inst.function_id, inst.instance_id);
+    if (inst.specific_id.is_valid()) {
+      FormatArgs(inst.function_id, inst.specific_id);
     } else {
       FormatArgs(inst.function_id);
     }
@@ -777,8 +776,8 @@ class FormatterImpl {
   }
 
   auto FormatInstRHS(ClassType inst) -> void {
-    if (inst.instance_id.is_valid()) {
-      FormatArgs(inst.class_id, inst.instance_id);
+    if (inst.specific_id.is_valid()) {
+      FormatArgs(inst.class_id, inst.specific_id);
     } else {
       FormatArgs(inst.class_id);
     }
@@ -795,8 +794,8 @@ class FormatterImpl {
   }
 
   auto FormatInstRHS(InterfaceType inst) -> void {
-    if (inst.instance_id.is_valid()) {
-      FormatArgs(inst.interface_id, inst.instance_id);
+    if (inst.specific_id.is_valid()) {
+      FormatArgs(inst.interface_id, inst.specific_id);
     } else {
       FormatArgs(inst.interface_id);
     }
@@ -949,7 +948,7 @@ class FormatterImpl {
     out_ << ')';
   }
 
-  auto FormatArg(GenericInstanceId id) -> void { FormatName(id); }
+  auto FormatArg(SpecificId id) -> void { FormatName(id); }
 
   auto FormatArg(RealId id) -> void {
     // TODO: Format with a `.` when the exponent is near zero.
@@ -997,8 +996,8 @@ class FormatterImpl {
     out_ << inst_namer_->GetNameFor(id);
   }
 
-  auto FormatName(GenericInstanceId id) -> void {
-    const auto& specific = sem_ir_.generic_instances().Get(id);
+  auto FormatName(SpecificId id) -> void {
+    const auto& specific = sem_ir_.specifics().Get(id);
     FormatName(specific.generic_id);
     FormatArg(specific.args_id);
   }

+ 4 - 5
toolchain/sem_ir/function.cpp

@@ -12,7 +12,7 @@ namespace Carbon::SemIR {
 
 auto GetCalleeFunction(const File& sem_ir, InstId callee_id) -> CalleeFunction {
   CalleeFunction result = {.function_id = FunctionId::Invalid,
-                           .instance_id = GenericInstanceId::Invalid,
+                           .specific_id = SpecificId::Invalid,
                            .self_id = InstId::Invalid,
                            .is_error = false};
 
@@ -38,17 +38,16 @@ auto GetCalleeFunction(const File& sem_ir, InstId callee_id) -> CalleeFunction {
   }
 
   result.function_id = fn_type->function_id;
-  result.instance_id = fn_type->instance_id;
+  result.specific_id = fn_type->specific_id;
   return result;
 }
 
 auto Function::GetDeclaredReturnType(const File& file,
-                                     GenericInstanceId specific_id) const
-    -> TypeId {
+                                     SpecificId specific_id) const -> TypeId {
   if (!return_storage_id.is_valid()) {
     return TypeId::Invalid;
   }
-  return GetTypeInInstance(file, specific_id,
+  return GetTypeInSpecific(file, specific_id,
                            file.insts().Get(return_storage_id).type_id());
 }
 

+ 5 - 5
toolchain/sem_ir/function.h

@@ -98,13 +98,13 @@ struct Function : public EntityWithParamsBase,
   static auto GetParamFromParamRefId(const File& sem_ir, InstId param_ref_id)
       -> std::pair<InstId, Param>;
 
-  // Gets the declared return type for a specific instance of this function, or
+  // Gets the declared return type for a specific version of this function, or
   // the canonical return type for the original declaration no specific is
   // specified.  Returns `Invalid` if no return type was specified, in which
   // case the effective return type is an empty tuple.
   auto GetDeclaredReturnType(const File& file,
-                             GenericInstanceId specific_id =
-                                 GenericInstanceId::Invalid) const -> TypeId;
+                             SpecificId specific_id = SpecificId::Invalid) const
+      -> TypeId;
 
   // Returns whether the function has a return slot. Can only be called for a
   // function that has either been called or defined, otherwise this is not
@@ -126,8 +126,8 @@ class File;
 struct CalleeFunction {
   // The function. Invalid if not a function.
   SemIR::FunctionId function_id;
-  // The generic instance that contains the function.
-  SemIR::GenericInstanceId instance_id;
+  // The specific that contains the function.
+  SemIR::SpecificId specific_id;
   // The bound `self` parameter. Invalid if not a method.
   SemIR::InstId self_id;
   // True if an error instruction was found.

+ 31 - 34
toolchain/sem_ir/generic.cpp

@@ -8,10 +8,9 @@
 
 namespace Carbon::SemIR {
 
-class GenericInstanceStore::KeyContext
-    : public TranslatingKeyContext<KeyContext> {
+class SpecificStore::KeyContext : public TranslatingKeyContext<KeyContext> {
  public:
-  // A lookup key for a generic instance.
+  // A lookup key for a specific.
   struct Key {
     GenericId generic_id;
     InstBlockId args_id;
@@ -19,41 +18,39 @@ class GenericInstanceStore::KeyContext
     friend auto operator==(const Key&, const Key&) -> bool = default;
   };
 
-  explicit KeyContext(llvm::ArrayRef<GenericInstance> instances)
-      : instances_(instances) {}
+  explicit KeyContext(llvm::ArrayRef<Specific> specifics)
+      : specifics_(specifics) {}
 
-  auto TranslateKey(GenericInstanceId id) const -> Key {
-    const auto& instance = instances_[id.index];
-    return {.generic_id = instance.generic_id, .args_id = instance.args_id};
+  auto TranslateKey(SpecificId id) const -> Key {
+    const auto& specific = specifics_[id.index];
+    return {.generic_id = specific.generic_id, .args_id = specific.args_id};
   }
 
  private:
-  llvm::ArrayRef<GenericInstance> instances_;
+  llvm::ArrayRef<Specific> specifics_;
 };
 
-auto GenericInstanceStore::GetOrAdd(GenericId generic_id, InstBlockId args_id)
-    -> GenericInstanceId {
+auto SpecificStore::GetOrAdd(GenericId generic_id, InstBlockId args_id)
+    -> SpecificId {
   return lookup_table_
       .Insert(
           KeyContext::Key{.generic_id = generic_id, .args_id = args_id},
           [&] {
-            return generic_instances_.Add(
+            return specifics_.Add(
                 {.generic_id = generic_id, .args_id = args_id});
           },
-          KeyContext(generic_instances_.array_ref()))
+          KeyContext(specifics_.array_ref()))
       .key();
 }
 
-auto GenericInstanceStore::CollectMemUsage(MemUsage& mem_usage,
-                                           llvm::StringRef label) const
-    -> void {
-  mem_usage.Collect(MemUsage::ConcatLabel(label, "generic_instances_"),
-                    generic_instances_);
+auto SpecificStore::CollectMemUsage(MemUsage& mem_usage,
+                                    llvm::StringRef label) const -> void {
+  mem_usage.Collect(MemUsage::ConcatLabel(label, "specifics_"), specifics_);
   mem_usage.Add(MemUsage::ConcatLabel(label, "lookup_table_"), lookup_table_,
-                KeyContext(generic_instances_.array_ref()));
+                KeyContext(specifics_.array_ref()));
 }
 
-auto GetConstantInInstance(const File& sem_ir, GenericInstanceId instance_id,
+auto GetConstantInSpecific(const File& sem_ir, SpecificId specific_id,
                            ConstantId const_id) -> ConstantId {
   if (!const_id.is_symbolic()) {
     // Type does not depend on a generic parameter.
@@ -62,43 +59,43 @@ auto GetConstantInInstance(const File& sem_ir, GenericInstanceId instance_id,
 
   const auto& symbolic = sem_ir.constant_values().GetSymbolicConstant(const_id);
   if (!symbolic.generic_id.is_valid()) {
-    // Constant is an abstract symbolic constant, not an instance-specific one.
+    // Constant is an abstract symbolic constant, not associated with some
+    // particular generic.
     return const_id;
   }
 
-  if (!instance_id.is_valid()) {
-    // TODO: We have a generic constant but no instance. Investigate whether we
+  if (!specific_id.is_valid()) {
+    // TODO: We have a generic constant but no specific. Investigate whether we
     // can CHECK-fail here. For now, produce the canonical value of the
     // constant.
     return sem_ir.constant_values().Get(symbolic.inst_id);
   }
 
-  const auto& specific = sem_ir.generic_instances().Get(instance_id);
+  const auto& specific = sem_ir.specifics().Get(specific_id);
   if (specific.generic_id != symbolic.generic_id) {
-    // TODO: Given an instance for the wrong generic. If the symbolic constant
+    // TODO: Given an specific for the wrong generic. If the symbolic constant
     // is from an enclosing generic, take the value from the corresponding
-    // instance. Otherwise, CHECK-fail.
+    // specific. Otherwise, CHECK-fail.
     return sem_ir.constant_values().Get(symbolic.inst_id);
   }
 
   auto value_block_id = specific.GetValueBlock(symbolic.index.region());
   CARBON_CHECK(value_block_id.is_valid())
-      << "Queried region of " << instance_id << " before it was resolved.";
+      << "Queried region of " << specific_id << " before it was resolved.";
   return sem_ir.constant_values().Get(
       sem_ir.inst_blocks().Get(value_block_id)[symbolic.index.index()]);
 }
 
-auto GetConstantValueInInstance(const File& sem_ir,
-                                GenericInstanceId instance_id, InstId inst_id)
-    -> ConstantId {
-  return GetConstantInInstance(sem_ir, instance_id,
+auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id,
+                                InstId inst_id) -> ConstantId {
+  return GetConstantInSpecific(sem_ir, specific_id,
                                sem_ir.constant_values().Get(inst_id));
 }
 
-auto GetTypeInInstance(const File& sem_ir, GenericInstanceId instance_id,
+auto GetTypeInSpecific(const File& sem_ir, SpecificId specific_id,
                        TypeId type_id) -> TypeId {
-  return TypeId::ForTypeConstant(GetConstantInInstance(
-      sem_ir, instance_id, sem_ir.types().GetConstantId(type_id)));
+  return TypeId::ForTypeConstant(GetConstantInSpecific(
+      sem_ir, specific_id, sem_ir.types().GetConstantId(type_id)));
 }
 
 }  // namespace Carbon::SemIR

+ 44 - 45
toolchain/sem_ir/generic.h

@@ -37,10 +37,10 @@ struct Generic : public Printable<Generic> {
   // The index in this block will match the `bind_index` in the name binding
   // instruction's `EntityName`.
   InstBlockId bindings_id;
-  // The self instance of this generic, which is an instance where every generic
-  // parameter's argument is that same parameter. For example, the self instance
+  // The self specific of this generic, which is a specific where every generic
+  // parameter's argument is that same parameter. For example, the self specific
   // of `Vector(T:! type)` is `Vector(T)`.
-  GenericInstanceId self_instance_id;
+  SpecificId self_specific_id;
 
   // The following members are set at the end of the corresponding region of the
   // generic.
@@ -54,19 +54,18 @@ struct Generic : public Printable<Generic> {
 // Provides storage for generics.
 class GenericStore : public ValueStore<GenericId> {
  public:
-  // Get the self-instance for a generic, or an invalid instance for an invalid
+  // Get the self specific for a generic, or an invalid specific for an invalid
   // generic ID.
-  auto GetSelfInstance(GenericId id) -> GenericInstanceId {
-    return id.is_valid() ? Get(id).self_instance_id
-                         : GenericInstanceId::Invalid;
+  auto GetSelfSpecific(GenericId id) -> SpecificId {
+    return id.is_valid() ? Get(id).self_specific_id : SpecificId::Invalid;
   }
 };
 
-// An instance of a generic entity, such as an instance of a generic function.
-// For each construct that depends on a compile-time parameter in the generic
-// entity, this contains the corresponding non-generic value. This includes
+// A specific, which is the combination of a generic and specified generic
+// arguments. For each construct that depends on a compile-time parameter in the
+// generic entity, this contains the corresponding specific value. This includes
 // values for the compile-time parameters themselves.
-struct GenericInstance : Printable<GenericInstance> {
+struct Specific : Printable<Specific> {
   auto Print(llvm::raw_ostream& out) const -> void {
     out << "{generic: " << generic_id << ", args: " << args_id << "}";
   }
@@ -82,7 +81,7 @@ struct GenericInstance : Printable<GenericInstance> {
                : definition_block_id;
   }
 
-  // The generic that this is an instance of.
+  // The generic that this is a specific version of.
   GenericId generic_id;
   // Argument values, corresponding to the bindings in `Generic::bindings_id`.
   InstBlockId args_id;
@@ -96,64 +95,64 @@ struct GenericInstance : Printable<GenericInstance> {
   InstBlockId definition_block_id = InstBlockId::Invalid;
 };
 
-// Provides storage for deduplicated instances of generics.
-class GenericInstanceStore : public Yaml::Printable<GenericInstanceStore> {
+// Provides storage for deduplicated specifics, which represent generics plus
+// their associated generic argument list.
+class SpecificStore : public Yaml::Printable<SpecificStore> {
  public:
-  // Adds a new generic instance, or gets the existing generic instance for a
-  // specified generic and argument list. Returns the ID of the generic
-  // instance. The argument IDs must be for instructions in the constant block,
-  // and must be a canonical instruction block ID.
-  auto GetOrAdd(GenericId generic_id, InstBlockId args_id) -> GenericInstanceId;
-
-  // Gets the specified generic instance.
-  auto Get(GenericInstanceId instance_id) const -> const GenericInstance& {
-    return generic_instances_.Get(instance_id);
+  // Adds a new specific, or gets the existing specific for a specified generic
+  // and argument list. Returns the ID of the specific. The argument IDs must be
+  // for instructions in the constant block, and must be a canonical instruction
+  // block ID.
+  auto GetOrAdd(GenericId generic_id, InstBlockId args_id) -> SpecificId;
+
+  // Gets the specific with the given ID.
+  auto Get(SpecificId specific_id) const -> const Specific& {
+    return specifics_.Get(specific_id);
   }
 
-  // Gets the specified generic instance.
-  auto Get(GenericInstanceId instance_id) -> GenericInstance& {
-    return generic_instances_.Get(instance_id);
+  // Gets the specific with the given ID.
+  auto Get(SpecificId specific_id) -> Specific& {
+    return specifics_.Get(specific_id);
   }
 
   // These are to support printable structures, and are not guaranteed.
   auto OutputYaml() const -> Yaml::OutputMapping {
-    return generic_instances_.OutputYaml();
+    return specifics_.OutputYaml();
   }
 
   // Collects memory usage of members.
   auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
       -> void;
 
-  auto array_ref() const -> llvm::ArrayRef<GenericInstance> {
-    return generic_instances_.array_ref();
+  auto array_ref() const -> llvm::ArrayRef<Specific> {
+    return specifics_.array_ref();
   }
-  auto size() const -> size_t { return generic_instances_.size(); }
+  auto size() const -> size_t { return specifics_.size(); }
 
  private:
   // Context for hashing keys.
   class KeyContext;
 
-  ValueStore<GenericInstanceId> generic_instances_;
-  Carbon::Set<GenericInstanceId, 0, KeyContext> lookup_table_;
+  ValueStore<SpecificId> specifics_;
+  Carbon::Set<SpecificId, 0, KeyContext> lookup_table_;
 };
 
-// Gets the substituted value of a constant within a specified instance of a
-// generic. Note that this does not perform substitution, and will return
+// Gets the substituted value of a potentially generic constant within a
+// specific. Note that this does not perform substitution, and will return
 // `Invalid` if the substituted constant value is not yet known.
-auto GetConstantInInstance(const File& sem_ir, GenericInstanceId instance_id,
+auto GetConstantInSpecific(const File& sem_ir, SpecificId specific_id,
                            ConstantId const_id) -> ConstantId;
 
-// Gets the substituted constant value of an instruction within a specified
-// instance of a generic. Note that this does not perform substitution, and will
+// Gets the substituted constant value of a potentially generic instruction
+// within a specific. Note that this does not perform substitution, and will
 // return `Invalid` if the substituted constant value is not yet known.
-auto GetConstantValueInInstance(const File& sem_ir,
-                                GenericInstanceId instance_id, InstId inst_id)
-    -> ConstantId;
-
-// Gets the substituted value of a type within a specified instance of a
-// generic. Note that this does not perform substitution, and will return
-// `Invalid` if the substituted type is not yet known.
-auto GetTypeInInstance(const File& sem_ir, GenericInstanceId instance_id,
+auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id,
+                                InstId inst_id) -> ConstantId;
+
+// Gets the substituted value of a potentially generic type within a specific.
+// Note that this does not perform substitution, and will return `Invalid` if
+// the substituted type is not yet known.
+auto GetTypeInSpecific(const File& sem_ir, SpecificId specific_id,
                        TypeId type_id) -> TypeId;
 
 }  // namespace Carbon::SemIR

+ 3 - 3
toolchain/sem_ir/id_kind.h

@@ -121,9 +121,9 @@ using IdKind = TypeEnum<
     IntId, RealId, FloatId, StringLiteralValueId,
     // From sem_ir/id.h.
     InstId, ConstantId, EntityNameId, CompileTimeBindIndex, FunctionId, ClassId,
-    InterfaceId, ImplId, GenericId, GenericInstanceId, ImportIRId,
-    ImportIRInstId, LocId, BoolValue, IntKind, NameId, NameScopeId, InstBlockId,
-    TypeId, TypeBlockId, ElementIndex, FloatKind>;
+    InterfaceId, ImplId, GenericId, SpecificId, ImportIRId, ImportIRInstId,
+    LocId, BoolValue, IntKind, NameId, NameScopeId, InstBlockId, TypeId,
+    TypeBlockId, ElementIndex, FloatKind>;
 
 }  // namespace Carbon::SemIR
 

+ 12 - 11
toolchain/sem_ir/ids.h

@@ -22,7 +22,7 @@ struct EntityName;
 struct Class;
 struct Function;
 struct Generic;
-struct GenericInstance;
+struct Specific;
 struct ImportIR;
 struct ImportIRInst;
 struct Interface;
@@ -319,27 +319,28 @@ struct GenericId : public IdBase, public Printable<GenericId> {
 
 constexpr GenericId GenericId::Invalid = GenericId(InvalidIndex);
 
-// The ID of an instance of a generic.
-struct GenericInstanceId : public IdBase, public Printable<GenericInstanceId> {
-  using ValueType = GenericInstance;
+// The ID of a specific, which is the result of specifying the generic arguments
+// for a generic.
+struct SpecificId : public IdBase, public Printable<SpecificId> {
+  using ValueType = Specific;
 
   // An explicitly invalid ID. This is typically used to represent a non-generic
-  // instance.
-  static const GenericInstanceId Invalid;
+  // entity.
+  static const SpecificId Invalid;
 
   using IdBase::IdBase;
   auto Print(llvm::raw_ostream& out) const -> void {
-    out << "genericInstance";
+    out << "specific";
     IdBase::Print(out);
   }
 };
 
-constexpr GenericInstanceId GenericInstanceId::Invalid =
-    GenericInstanceId(InvalidIndex);
+constexpr SpecificId SpecificId::Invalid = SpecificId(InvalidIndex);
 
 // The index of an instruction that depends on generic parameters within a
-// generic, and the value of that instruction within the instances of that
-// generic. This is a pair of a region and an index, stored in 32 bits.
+// region of a generic. A corresponding specific version of the instruction can
+// be found in each specific corresponding to that generic. This is a pair of a
+// region and an index, stored in 32 bits.
 struct GenericInstIndex : public IndexBase, public Printable<GenericInstIndex> {
   // Where the value is first used within the generic.
   enum Region : uint8_t {

+ 7 - 8
toolchain/sem_ir/typed_insts.h

@@ -450,7 +450,7 @@ struct ClassInit {
   InstId dest_id;
 };
 
-// The type for a class, either non-generic or parameterized generic instance.
+// The type for a class, either non-generic or specific.
 struct ClassType {
   static constexpr auto Kind = InstKind::ClassType.Define<Parse::NodeId>(
       {.ir_name = "class_type",
@@ -459,7 +459,7 @@ struct ClassType {
 
   TypeId type_id;
   ClassId class_id;
-  GenericInstanceId instance_id;
+  SpecificId specific_id;
 };
 
 // Indicates `const` on a type, such as `var x: const i32`.
@@ -575,7 +575,7 @@ struct FunctionType {
 
   TypeId type_id;
   FunctionId function_id;
-  GenericInstanceId instance_id;
+  SpecificId specific_id;
 };
 
 // The type of the name of a generic class. The corresponding value is an empty
@@ -690,8 +690,7 @@ struct InterfaceDecl {
   InstBlockId decl_block_id;
 };
 
-// The type for an interface, either non-generic or parameterized generic
-// instance.
+// The type for an interface, either non-generic or specific.
 struct InterfaceType {
   static constexpr auto Kind = InstKind::InterfaceType.Define<Parse::NodeId>(
       {.ir_name = "interface_type",
@@ -700,7 +699,7 @@ struct InterfaceType {
 
   TypeId type_id;
   InterfaceId interface_id;
-  GenericInstanceId instance_id;
+  SpecificId specific_id;
 };
 
 // A witness that a type implements an interface.
@@ -823,7 +822,7 @@ struct ReturnExpr {
 };
 
 // Given an instruction with a constant value that depends on a generic
-// parameter, selects an instance of that instruction with the constant value
+// parameter, selects a version of that instruction with the constant value
 // corresponding to a particular specific.
 //
 // TODO: We only form these as the instruction referenced by a `NameRef`.
@@ -835,7 +834,7 @@ struct SpecificConstant {
 
   TypeId type_id;
   InstId inst_id;
-  GenericInstanceId instance_id;
+  SpecificId specific_id;
 };
 
 // Splices a block into the location where this appears. This may be an

+ 1 - 1
toolchain/sem_ir/yaml_test.cpp

@@ -62,7 +62,7 @@ TEST(SemIRTest, YAML) {
       Pair("functions", Yaml::Mapping(SizeIs(1))),
       Pair("classes", Yaml::Mapping(SizeIs(0))),
       Pair("generics", Yaml::Mapping(SizeIs(0))),
-      Pair("generic_instances", Yaml::Mapping(SizeIs(0))),
+      Pair("specifics", Yaml::Mapping(SizeIs(0))),
       Pair("types", Yaml::Mapping(Each(type_builtin))),
       Pair("type_blocks", Yaml::Mapping(SizeIs(Ge(1)))),
       Pair("insts",