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

Alphabetize typed_insts.h (#5401)

As requested
[here](https://github.com/carbon-language/carbon-lang/pull/5400#discussion_r2070631805).

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Geoff Romer 10 месяцев назад
Родитель
Сommit
0b3edee177

+ 1 - 0
toolchain/check/eval.cpp

@@ -26,6 +26,7 @@
 #include "toolchain/sem_ir/generic.h"
 #include "toolchain/sem_ir/id_kind.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/inst_categories.h"
 #include "toolchain/sem_ir/inst_kind.h"
 #include "toolchain/sem_ir/typed_insts.h"
 

+ 1 - 0
toolchain/lower/file_context.cpp

@@ -30,6 +30,7 @@
 #include "toolchain/sem_ir/generic.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/inst.h"
+#include "toolchain/sem_ir/inst_categories.h"
 #include "toolchain/sem_ir/inst_kind.h"
 #include "toolchain/sem_ir/pattern.h"
 #include "toolchain/sem_ir/typed_insts.h"

+ 1 - 0
toolchain/sem_ir/BUILD

@@ -27,6 +27,7 @@ cc_library(
     hdrs = [
         "id_kind.h",
         "ids.h",
+        "inst_categories.h",
         "inst_kind.h",
         "singleton_insts.h",
         "typed_insts.h",

+ 1 - 0
toolchain/sem_ir/function.h

@@ -9,6 +9,7 @@
 #include "toolchain/sem_ir/builtin_function_kind.h"
 #include "toolchain/sem_ir/entity_with_params_base.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/inst_categories.h"
 #include "toolchain/sem_ir/typed_insts.h"
 
 namespace Carbon::SemIR {

+ 58 - 7
toolchain/sem_ir/inst.h

@@ -24,12 +24,14 @@
 
 namespace Carbon::SemIR {
 
+template <typename... TypedInsts>
+struct CategoryOf;
+
 // InstLikeTypeInfo is an implementation detail, and not public API.
 namespace Internal {
 
 // Information about an instruction-like type, which is a type that an Inst can
-// be converted to and from. The `Enabled` parameter is used to check
-// requirements on the type in the specializations of this template.
+// be converted to and from.
 template <typename InstLikeType>
 struct InstLikeTypeInfo;
 
@@ -74,15 +76,60 @@ struct InstLikeTypeInfo<TypedInst> : InstLikeTypeInfoBase<TypedInst> {
   static auto DebugName() -> InstKind { return TypedInst::Kind; }
 };
 
+// If `TypedInst` has an Nth field, validates that `CategoryInst` has a
+// corresponding field with a compatible type.
+template <typename CategoryInst, typename TypedInst, size_t N>
+static consteval auto ValidateCategoryFieldForTypedInst() -> void {
+  if constexpr (InstLikeTypeInfoBase<TypedInst>::NumArgs > N) {
+    if constexpr (!std::is_same_v<typename InstLikeTypeInfoBase<
+                                      CategoryInst>::template ArgType<N>,
+                                  AnyRawId>) {
+      static_assert(
+          std::is_same_v<
+              typename InstLikeTypeInfoBase<CategoryInst>::template ArgType<N>,
+              typename InstLikeTypeInfoBase<TypedInst>::template ArgType<N>>,
+          "Inst category field should be the same type as the "
+          "corresponding fields of its typed insts, or AnyRawId if "
+          "they have different types");
+    }
+  }
+}
+
+// Validates that `CategoryInst` is compatible with `TypedInst`
+template <typename CategoryInst, typename TypedInst>
+static consteval auto ValidateCategoryForTypedInst() -> void {
+  static_assert(Internal::HasKindMemberAsField<CategoryInst>,
+                "Inst category should have an `InstKind` field");
+  static_assert(!HasTypeIdMember<TypedInst> || HasTypeIdMember<CategoryInst>,
+                "Inst category should have a `TypeId` field if any of its "
+                "typed insts do");
+
+  static_assert(InstLikeTypeInfoBase<CategoryInst>::NumArgs >=
+                    InstLikeTypeInfoBase<TypedInst>::NumArgs,
+                "Inst category should have as many fields as any of its typed "
+                "insts");
+
+  ValidateCategoryFieldForTypedInst<CategoryInst, TypedInst, 0>();
+  ValidateCategoryFieldForTypedInst<CategoryInst, TypedInst, 1>();
+}
+
+// Validates that `CategoryInst` is compatible with all of `TypedInsts`.
+// Always returns true; validation failure will cause build errors when
+// instantiating the function.
+template <typename CategoryInst, typename... TypedInsts>
+static consteval auto ValidateCategory(
+    CategoryOf<TypedInsts...> /*category_info*/) -> bool {
+  (ValidateCategoryForTypedInst<CategoryInst, TypedInsts>(), ...);
+  return true;
+}
+
 // An instruction category is instruction-like.
 template <typename InstCat>
-  requires std::same_as<const InstKind&, decltype(InstCat::Kinds[0])>
+  requires requires { typename InstCat::CategoryInfo; }
 struct InstLikeTypeInfo<InstCat> : InstLikeTypeInfoBase<InstCat> {
-  static_assert(HasKindMemberAsField<InstCat>,
-                "Instruction category should have a kind field");
   static auto GetKind(InstCat cat) -> InstKind { return cat.kind; }
   static constexpr auto IsKind(InstKind kind) -> bool {
-    for (InstKind k : InstCat::Kinds) {
+    for (InstKind k : InstCat::CategoryInfo::Kinds) {
       if (k == kind) {
         return true;
       }
@@ -94,12 +141,16 @@ struct InstLikeTypeInfo<InstCat> : InstLikeTypeInfoBase<InstCat> {
     RawStringOstream out;
     out << "{";
     llvm::ListSeparator sep;
-    for (auto kind : InstCat::Kinds) {
+    for (auto kind : InstCat::CategoryInfo::Kinds) {
       out << sep << kind;
     }
     out << "}";
     return out.TakeStr();
   }
+
+ private:
+  // Trigger validation of `InstCat`.
+  static_assert(ValidateCategory<InstCat>(typename InstCat::CategoryInfo()));
 };
 
 // HasInstCategory is true if T::Kind is an element of InstCat::Kinds.

+ 172 - 0
toolchain/sem_ir/inst_categories.h

@@ -0,0 +1,172 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEM_IR_INST_CATEGORIES_H_
+#define CARBON_TOOLCHAIN_SEM_IR_INST_CATEGORIES_H_
+
+#include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/inst_kind.h"
+#include "toolchain/sem_ir/typed_insts.h"
+
+// An inst category is a set of inst kinds that can be treated polymorphically.
+// Each inst category is represented by a C++ type, just like an inst kind,
+// which can losslessly represent any inst in the category. `CategoryOf`
+// is used to declare the typed insts that belong to the category.
+
+namespace Carbon::SemIR {
+
+// Declares a category consisting of `TypedInsts...`, which is a list of typed
+// insts (not kinds). Should only be used to define a public type alias member
+// of a category inst type:
+//
+// struct MyCategory {
+//   using CategoryInfo = CategoryOf<X, Y, Z>;
+//   InstKind kind;
+//   ...
+// }
+template <typename... TypedInsts>
+struct CategoryOf {
+  // The InstKinds that belong to the category.
+  static constexpr InstKind Kinds[] = {TypedInsts::Kind...};
+};
+
+// Common representation for aggregate access nodes, which access a fixed
+// element of an aggregate.
+struct AnyAggregateAccess {
+  using CategoryInfo =
+      CategoryOf<ClassElementAccess, StructAccess, TupleAccess>;
+
+  InstKind kind;
+  TypeId type_id;
+  InstId aggregate_id;
+  ElementIndex index;
+};
+
+// Common representation for all kinds of aggregate initialization.
+struct AnyAggregateInit {
+  using CategoryInfo = CategoryOf<ArrayInit, ClassInit, StructInit, TupleInit>;
+
+  InstKind kind;
+  TypeId type_id;
+  InstBlockId elements_id;
+  DestInstId dest_id;
+};
+
+// Common representation for all kinds of aggregate value.
+struct AnyAggregateValue {
+  using CategoryInfo = CategoryOf<StructValue, TupleValue>;
+
+  InstKind kind;
+  TypeId type_id;
+  InstBlockId elements_id;
+};
+
+// Common representation for various `*binding_pattern` nodes.
+struct AnyBindingPattern {
+  // TODO: Also handle TemplateBindingPattern once it exists.
+  using CategoryInfo = CategoryOf<BindingPattern, SymbolicBindingPattern>;
+
+  InstKind kind;
+
+  // Always a PatternType whose scrutinee type is the declared type of the
+  // binding.
+  TypeId type_id;
+
+  // The name declared by the binding pattern. `None` indicates that the
+  // pattern has `_` in the name position, and so does not truly declare
+  // a name.
+  EntityNameId entity_name_id;
+};
+
+// Common representation for various `bind*` nodes.
+struct AnyBindName {
+  // TODO: Also handle BindTemplateName once it exists.
+  using CategoryInfo = CategoryOf<BindAlias, BindName, BindSymbolicName>;
+
+  InstKind kind;
+  TypeId type_id;
+  EntityNameId entity_name_id;
+  InstId value_id;
+};
+
+// Common representation for various `bind*` nodes, and `export name`.
+struct AnyBindNameOrExportDecl {
+  // TODO: Also handle BindTemplateName once it exists.
+  using CategoryInfo =
+      CategoryOf<BindAlias, BindName, BindSymbolicName, ExportDecl>;
+
+  InstKind kind;
+  TypeId type_id;
+  EntityNameId entity_name_id;
+  InstId value_id;
+};
+
+// Common representation for all kinds of `Branch*` node.
+struct AnyBranch {
+  using CategoryInfo = CategoryOf<Branch, BranchIf, BranchWithArg>;
+
+  InstKind kind;
+  // Branches don't produce a value, so have no type.
+  LabelId target_id;
+  // Kind-specific data.
+  AnyRawId arg1;
+};
+
+// Common representation for declarations describing the foundation type of a
+// class -- either its adapted type or its base class.
+struct AnyFoundationDecl {
+  using CategoryInfo = CategoryOf<AdaptDecl, BaseDecl>;
+
+  InstKind kind;
+  TypeId type_id;
+  TypeInstId foundation_type_inst_id;
+  // Kind-specific data.
+  AnyRawId arg1;
+};
+
+// Common representation for all kinds of `ImportRef*` node.
+struct AnyImportRef {
+  using CategoryInfo = CategoryOf<ImportRefUnloaded, ImportRefLoaded>;
+
+  InstKind kind;
+  TypeId type_id;
+  ImportIRInstId import_ir_inst_id;
+  // A BindName is currently only set on directly imported names. It is not
+  // generically available.
+  EntityNameId entity_name_id;
+};
+
+// A `Call` parameter for a function or other parameterized block.
+struct AnyParam {
+  using CategoryInfo = CategoryOf<OutParam, RefParam, ValueParam>;
+
+  InstKind kind;
+  TypeId type_id;
+  CallParamIndex index;
+
+  // A name to associate with this Param in pretty-printed IR. This is not
+  // necessarily unique, and can even be `None`; it has no semantic
+  // significance.
+  NameId pretty_name_id;
+};
+
+// A pattern that represents a `Call` parameter. It delegates to subpattern_id
+// in pattern matching. The sub-kinds differ only in the expression category
+// of the corresponding parameter inst.
+struct AnyParamPattern {
+  using CategoryInfo =
+      CategoryOf<OutParamPattern, RefParamPattern, ValueParamPattern>;
+
+  InstKind kind;
+
+  // Always a PatternType that represents the same type as the type of
+  // `subpattern_id`.
+  TypeId type_id;
+  InstId subpattern_id;
+  CallParamIndex index;
+};
+
+}  // namespace Carbon::SemIR
+
+#endif  // CARBON_TOOLCHAIN_SEM_IR_INST_CATEGORIES_H_

+ 1 - 0
toolchain/sem_ir/inst_namer.h

@@ -11,6 +11,7 @@
 #include "toolchain/parse/tree.h"
 #include "toolchain/sem_ir/file.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/inst_categories.h"
 #include "toolchain/sem_ir/inst_fingerprinter.h"
 
 namespace Carbon::SemIR {

+ 168 - 306
toolchain/sem_ir/typed_insts.h

@@ -76,17 +76,6 @@ struct AccessOptionalMemberAction {
   NameId name_id;
 };
 
-// Common representation for declarations describing the foundation type of a
-// class -- either its adapted type or its base class.
-struct AnyFoundationDecl {
-  static constexpr InstKind Kinds[] = {InstKind::AdaptDecl, InstKind::BaseDecl};
-
-  InstKind kind;
-  TypeInstId foundation_type_inst_id;
-  // Kind-specific data.
-  AnyRawId arg1;
-};
-
 // An adapted type declaration in a class, of the form `adapt T;`.
 struct AdaptDecl {
   static constexpr auto Kind = InstKind::AdaptDecl.Define<Parse::AdaptDeclId>(
@@ -139,41 +128,6 @@ struct ArrayIndex {
   InstId index_id;
 };
 
-// Common representation for aggregate access nodes, which access a fixed
-// element of an aggregate.
-struct AnyAggregateAccess {
-  static constexpr InstKind Kinds[] = {InstKind::ClassElementAccess,
-                                       InstKind::StructAccess,
-                                       InstKind::TupleAccess};
-
-  InstKind kind;
-  TypeId type_id;
-  InstId aggregate_id;
-  ElementIndex index;
-};
-
-// Common representation for all kinds of aggregate initialization.
-struct AnyAggregateInit {
-  static constexpr InstKind Kinds[] = {InstKind::ArrayInit, InstKind::ClassInit,
-                                       InstKind::StructInit,
-                                       InstKind::TupleInit};
-
-  InstKind kind;
-  TypeId type_id;
-  InstBlockId elements_id;
-  DestInstId dest_id;
-};
-
-// Common representation for all kinds of aggregate value.
-struct AnyAggregateValue {
-  static constexpr InstKind Kinds[] = {InstKind::StructValue,
-                                       InstKind::TupleValue};
-
-  InstKind kind;
-  TypeId type_id;
-  InstBlockId elements_id;
-};
-
 // Initializes an array from a tuple. `tuple_id` is the source tuple
 // expression. `inits_id` contains one initializer per array element.
 // `dest_id` is the destination array object for the initialization.
@@ -296,31 +250,6 @@ struct BaseDecl {
   ElementIndex index;
 };
 
-// Common representation for various `bind*` nodes.
-struct AnyBindName {
-  // TODO: Also handle BindTemplateName once it exists.
-  static constexpr InstKind Kinds[] = {InstKind::BindAlias, InstKind::BindName,
-                                       InstKind::BindSymbolicName};
-
-  InstKind kind;
-  TypeId type_id;
-  EntityNameId entity_name_id;
-  InstId value_id;
-};
-
-// Common representation for various `bind*` nodes, and `export name`.
-struct AnyBindNameOrExportDecl {
-  // TODO: Also handle BindTemplateName once it exists.
-  static constexpr InstKind Kinds[] = {InstKind::BindAlias, InstKind::BindName,
-                                       InstKind::BindSymbolicName,
-                                       InstKind::ExportDecl};
-
-  InstKind kind;
-  TypeId type_id;
-  EntityNameId entity_name_id;
-  InstId value_id;
-};
-
 // Binds a name as an alias.
 struct BindAlias {
   static constexpr auto Kind =
@@ -366,25 +295,8 @@ struct BindValue {
   InstId value_id;
 };
 
-// Common representation for various `*binding_pattern` nodes.
-struct AnyBindingPattern {
-  // TODO: Also handle TemplateBindingPattern once it exists.
-  static constexpr InstKind Kinds[] = {InstKind::BindingPattern,
-                                       InstKind::SymbolicBindingPattern};
-
-  InstKind kind;
-
-  // Always a PatternType whose scrutinee type is the declared type of the
-  // binding.
-  TypeId type_id;
-
-  // The name declared by the binding pattern. `None` indicates that the
-  // pattern has `_` in the name position, and so does not truly declare
-  // a name.
-  EntityNameId entity_name_id;
-};
-
-// Represents a non-symbolic binding pattern.
+// Represents a non-symbolic binding pattern. See `AnyBindingPattern` for member
+// documentation.
 struct BindingPattern {
   static constexpr auto Kind = InstKind::BindingPattern.Define<Parse::NodeId>(
       {.ir_name = "binding_pattern",
@@ -395,19 +307,6 @@ struct BindingPattern {
   EntityNameId entity_name_id;
 };
 
-// Represents a symbolic binding pattern.
-struct SymbolicBindingPattern {
-  static constexpr auto Kind =
-      InstKind::SymbolicBindingPattern.Define<Parse::NodeId>({
-          .ir_name = "symbolic_binding_pattern",
-          .constant_kind = InstConstantKind::AlwaysUnique,
-          .is_lowered = false,
-      });
-
-  TypeId type_id;
-  EntityNameId entity_name_id;
-};
-
 // Reads an argument from `BranchWithArg`.
 struct BlockArg {
   static constexpr auto Kind = InstKind::BlockArg.Define<Parse::NodeId>(
@@ -471,18 +370,6 @@ struct BoundMethodType {
   TypeId type_id;
 };
 
-// Common representation for all kinds of `Branch*` node.
-struct AnyBranch {
-  static constexpr InstKind Kinds[] = {InstKind::Branch, InstKind::BranchIf,
-                                       InstKind::BranchWithArg};
-
-  InstKind kind;
-  // Branches don't produce a value, so have no type.
-  LabelId target_id;
-  // Kind-specific data.
-  AnyRawId arg1;
-};
-
 // Control flow to branch to the target block.
 struct Branch {
   // TODO: Make Parse::NodeId more specific.
@@ -625,6 +512,19 @@ struct ConstType {
   TypeInstId inner_id;
 };
 
+// Records that a type conversion `original as new_type` was done, producing the
+// result.
+struct Converted {
+  static constexpr auto Kind =
+      InstKind::Converted.Define<Parse::NodeId>({.ir_name = "converted"});
+
+  TypeId type_id;
+  // The operand prior to being converted. This is tracked only for tooling
+  // purposes and has no associated semantics.
+  AbsoluteInstId original_id;
+  InstId result_id;
+};
+
 // An action that performs simple conversion to a value expression of a given
 // type.
 struct ConvertToValueAction {
@@ -639,19 +539,6 @@ struct ConvertToValueAction {
   TypeInstId target_type_inst_id;
 };
 
-// Records that a type conversion `original as new_type` was done, producing the
-// result.
-struct Converted {
-  static constexpr auto Kind =
-      InstKind::Converted.Define<Parse::NodeId>({.ir_name = "converted"});
-
-  TypeId type_id;
-  // The operand prior to being converted. This is tracked only for tooling
-  // purposes and has no associated semantics.
-  AbsoluteInstId original_id;
-  InstId result_id;
-};
-
 // The `*` dereference operator, as in `*pointer`.
 struct Deref {
   static constexpr auto Kind =
@@ -774,22 +661,6 @@ struct FloatType {
   InstId bit_width_id;
 };
 
-// The legacy float type. This is currently used for real literals, and is
-// treated as f64. It's separate from `FloatType`, and should change to mirror
-// integers, likely replacing this with a `FloatLiteralType`.
-struct LegacyFloatType {
-  static constexpr auto Kind =
-      InstKind::LegacyFloatType.Define<Parse::NoneNodeId>(
-          {.ir_name = "f64",
-           .is_type = InstIsType::Always,
-           .constant_kind = InstConstantKind::Always});
-  // This is a singleton instruction. However, it may still evolve into a more
-  // standard type and be removed.
-  static constexpr auto TypeInstId = MakeSingletonTypeInstId<Kind>();
-
-  TypeId type_id;
-};
-
 // A function declaration.
 struct FunctionDecl {
   static constexpr auto Kind =
@@ -1017,19 +888,8 @@ struct ImportDecl {
   NameId package_id;
 };
 
-// Common representation for all kinds of `ImportRef*` node.
-struct AnyImportRef {
-  static constexpr InstKind Kinds[] = {InstKind::ImportRefUnloaded,
-                                       InstKind::ImportRefLoaded};
-
-  InstKind kind;
-  ImportIRInstId import_ir_inst_id;
-  // A BindName is currently only set on directly imported names. It is not
-  // generically available.
-  EntityNameId entity_name_id;
-};
-
-// An imported entity that is not yet been loaded.
+// An imported entity that is not yet been loaded. See `AnyImportRef` for
+// member documentation.
 struct ImportRefUnloaded {
   static constexpr auto Kind =
       InstKind::ImportRefUnloaded.Define<Parse::NodeId>(
@@ -1039,7 +899,8 @@ struct ImportRefUnloaded {
   EntityNameId entity_name_id;
 };
 
-// A imported entity that is loaded, and may be used.
+// A imported entity that is loaded, and may be used. See `AnyImportRef` for
+// member documentation.
 struct ImportRefLoaded {
   static constexpr auto Kind = InstKind::ImportRefLoaded.Define<Parse::NodeId>(
       {.ir_name = "import_ref", .is_lowered = false});
@@ -1103,16 +964,6 @@ struct InterfaceDecl {
   DeclInstBlockId decl_block_id;
 };
 
-// A literal integer value.
-struct IntValue {
-  // TODO: Make Parse::NodeId more specific.
-  static constexpr auto Kind = InstKind::IntValue.Define<Parse::NodeId>(
-      {.ir_name = "int_value", .constant_kind = InstConstantKind::Always});
-
-  TypeId type_id;
-  IntId int_id;
-};
-
 // An arbitrary-precision integer type, which is used as the type of integer
 // literals and as the parameter type of `Core.Int` and `Core.Float`. This type
 // only provides compile-time operations, and is represented as an empty type at
@@ -1148,6 +999,32 @@ struct IntType {
   InstId bit_width_id;
 };
 
+// A literal integer value.
+struct IntValue {
+  // TODO: Make Parse::NodeId more specific.
+  static constexpr auto Kind = InstKind::IntValue.Define<Parse::NodeId>(
+      {.ir_name = "int_value", .constant_kind = InstConstantKind::Always});
+
+  TypeId type_id;
+  IntId int_id;
+};
+
+// The legacy float type. This is currently used for real literals, and is
+// treated as f64. It's separate from `FloatType`, and should change to mirror
+// integers, likely replacing this with a `FloatLiteralType`.
+struct LegacyFloatType {
+  static constexpr auto Kind =
+      InstKind::LegacyFloatType.Define<Parse::NoneNodeId>(
+          {.ir_name = "f64",
+           .is_type = InstIsType::Always,
+           .constant_kind = InstConstantKind::Always});
+  // This is a singleton instruction. However, it may still evolve into a more
+  // standard type and be removed.
+  static constexpr auto TypeInstId = MakeSingletonTypeInstId<Kind>();
+
+  TypeId type_id;
+};
+
 // A symbolic instruction that takes the place of an `ImplWitness` when the
 // result is not fully known. When evaluated it does an impl lookup query, based
 // on the stored query arguments, that a type implements an interface. The query
@@ -1230,21 +1107,6 @@ struct NamespaceType {
   TypeId type_id;
 };
 
-// A `Call` parameter for a function or other parameterized block.
-struct AnyParam {
-  static constexpr InstKind Kinds[] = {InstKind::OutParam, InstKind::RefParam,
-                                       InstKind::ValueParam};
-
-  InstKind kind;
-  TypeId type_id;
-  CallParamIndex index;
-
-  // A name to associate with this Param in pretty-printed IR. This is not
-  // necessarily unique, and can even be `None`; it has no semantic
-  // significance.
-  NameId pretty_name_id;
-};
-
 // An output `Call` parameter. See AnyParam for member documentation.
 struct OutParam {
   // TODO: Make Parse::NodeId more specific.
@@ -1256,46 +1118,8 @@ struct OutParam {
   NameId pretty_name_id;
 };
 
-// A by-reference `Call` parameter. See AnyParam for member documentation.
-struct RefParam {
-  // TODO: Make Parse::NodeId more specific.
-  static constexpr auto Kind = InstKind::RefParam.Define<Parse::NodeId>(
-      {.ir_name = "ref_param", .constant_kind = InstConstantKind::Never});
-
-  TypeId type_id;
-  CallParamIndex index;
-  NameId pretty_name_id;
-};
-
-// A by-value `Call` parameter. See AnyParam for member documentation.
-struct ValueParam {
-  // TODO: Make Parse::NodeId more specific.
-  static constexpr auto Kind = InstKind::ValueParam.Define<Parse::NodeId>(
-      {.ir_name = "value_param", .constant_kind = InstConstantKind::Never});
-
-  TypeId type_id;
-  CallParamIndex index;
-  NameId pretty_name_id;
-};
-
-// A pattern that represents a `Call` parameter. It delegates to subpattern_id
-// in pattern matching. The sub-kinds differ only in the expression category
-// of the corresponding parameter inst.
-struct AnyParamPattern {
-  static constexpr InstKind Kinds[] = {InstKind::OutParamPattern,
-                                       InstKind::RefParamPattern,
-                                       InstKind::ValueParamPattern};
-
-  InstKind kind;
-
-  // Always a PatternType that represents the same type as the type of
-  // `subpattern_id`.
-  TypeId type_id;
-  InstId subpattern_id;
-  CallParamIndex index;
-};
-
-// A pattern that represents an output `Call` parameter.
+// A pattern that represents an output `Call` parameter. See `AnyParamPattern`
+// for member documentation.
 struct OutParamPattern {
   static constexpr auto Kind =
       InstKind::OutParamPattern.Define<Parse::ReturnTypeId>(
@@ -1308,33 +1132,6 @@ struct OutParamPattern {
   CallParamIndex index;
 };
 
-// A pattern that represents a by-reference `Call` parameter.
-struct RefParamPattern {
-  // TODO: Make Parse::NodeId more specific.
-  static constexpr auto Kind = InstKind::RefParamPattern.Define<Parse::NodeId>(
-      {.ir_name = "ref_param_pattern",
-       .constant_kind = InstConstantKind::AlwaysUnique,
-       .is_lowered = false});
-
-  TypeId type_id;
-  InstId subpattern_id;
-  CallParamIndex index;
-};
-
-// A pattern that represents a by-value `Call` parameter.
-struct ValueParamPattern {
-  // TODO: Make Parse::NodeId more specific.
-  static constexpr auto Kind =
-      InstKind::ValueParamPattern.Define<Parse::NodeId>(
-          {.ir_name = "value_param_pattern",
-           .constant_kind = InstConstantKind::AlwaysUnique,
-           .is_lowered = false});
-
-  TypeId type_id;
-  InstId subpattern_id;
-  CallParamIndex index;
-};
-
 // The type of a pattern that matches scrutinees of type
 // `scrutinee_type_inst_id`.
 struct PatternType {
@@ -1375,6 +1172,31 @@ struct RefineTypeAction {
   TypeInstId inst_type_inst_id;
 };
 
+// A by-reference `Call` parameter. See AnyParam for member documentation.
+struct RefParam {
+  // TODO: Make Parse::NodeId more specific.
+  static constexpr auto Kind = InstKind::RefParam.Define<Parse::NodeId>(
+      {.ir_name = "ref_param", .constant_kind = InstConstantKind::Never});
+
+  TypeId type_id;
+  CallParamIndex index;
+  NameId pretty_name_id;
+};
+
+// A pattern that represents a by-reference `Call` parameter. See
+// `AnyParamPattern` for member documentation.
+struct RefParamPattern {
+  // TODO: Make Parse::NodeId more specific.
+  static constexpr auto Kind = InstKind::RefParamPattern.Define<Parse::NodeId>(
+      {.ir_name = "ref_param_pattern",
+       .constant_kind = InstConstantKind::AlwaysUnique,
+       .is_lowered = false});
+
+  TypeId type_id;
+  InstId subpattern_id;
+  CallParamIndex index;
+};
+
 // Requires a type to be complete. This is only created for generic types and
 // produces a witness that the type is complete.
 //
@@ -1395,6 +1217,45 @@ struct RequireCompleteType {
   TypeInstId complete_type_inst_id;
 };
 
+// An `expr == expr` clause in a `where` expression or `require` declaration.
+struct RequirementEquivalent {
+  static constexpr auto Kind =
+      InstKind::RequirementEquivalent.Define<Parse::RequirementEqualEqualId>(
+          {.ir_name = "requirement_equivalent",
+           .constant_kind = InstConstantKind::Never,
+           .is_lowered = false});
+
+  // No type since not an expression
+  InstId lhs_id;
+  InstId rhs_id;
+};
+
+// An `expr impls expr` clause in a `where` expression or `require` declaration.
+struct RequirementImpls {
+  static constexpr auto Kind =
+      InstKind::RequirementImpls.Define<Parse::RequirementImplsId>(
+          {.ir_name = "requirement_impls",
+           .constant_kind = InstConstantKind::Never,
+           .is_lowered = false});
+
+  // No type since not an expression
+  InstId lhs_id;
+  InstId rhs_id;
+};
+
+// A `.M = expr` clause in a `where` expression or `require` declaration.
+struct RequirementRewrite {
+  static constexpr auto Kind =
+      InstKind::RequirementRewrite.Define<Parse::RequirementEqualId>(
+          {.ir_name = "requirement_rewrite",
+           .constant_kind = InstConstantKind::Never,
+           .is_lowered = false});
+
+  // No type since not an expression
+  InstId lhs_id;
+  InstId rhs_id;
+};
+
 struct Return {
   static constexpr auto Kind = InstKind::Return.Define<Parse::NodeId>(
       {.ir_name = "return",
@@ -1457,45 +1318,6 @@ struct ReturnSlotPattern {
   TypeInstId type_inst_id;
 };
 
-// An `expr == expr` clause in a `where` expression or `require` declaration.
-struct RequirementEquivalent {
-  static constexpr auto Kind =
-      InstKind::RequirementEquivalent.Define<Parse::RequirementEqualEqualId>(
-          {.ir_name = "requirement_equivalent",
-           .constant_kind = InstConstantKind::Never,
-           .is_lowered = false});
-
-  // No type since not an expression
-  InstId lhs_id;
-  InstId rhs_id;
-};
-
-// An `expr impls expr` clause in a `where` expression or `require` declaration.
-struct RequirementImpls {
-  static constexpr auto Kind =
-      InstKind::RequirementImpls.Define<Parse::RequirementImplsId>(
-          {.ir_name = "requirement_impls",
-           .constant_kind = InstConstantKind::Never,
-           .is_lowered = false});
-
-  // No type since not an expression
-  InstId lhs_id;
-  InstId rhs_id;
-};
-
-// A `.M = expr` clause in a `where` expression or `require` declaration.
-struct RequirementRewrite {
-  static constexpr auto Kind =
-      InstKind::RequirementRewrite.Define<Parse::RequirementEqualId>(
-          {.ir_name = "requirement_rewrite",
-           .constant_kind = InstConstantKind::Never,
-           .is_lowered = false});
-
-  // No type since not an expression
-  InstId lhs_id;
-  InstId rhs_id;
-};
-
 // Given an instruction with a constant value that depends on a generic
 // parameter, selects a version of that instruction with the constant value
 // corresponding to a particular specific.
@@ -1682,6 +1504,20 @@ struct StructValue {
   InstBlockId elements_id;
 };
 
+// Represents a symbolic binding pattern. See `AnyBindingPattern` for member
+// documentation.
+struct SymbolicBindingPattern {
+  static constexpr auto Kind =
+      InstKind::SymbolicBindingPattern.Define<Parse::NodeId>({
+          .ir_name = "symbolic_binding_pattern",
+          .constant_kind = InstConstantKind::AlwaysUnique,
+          .is_lowered = false,
+      });
+
+  TypeId type_id;
+  EntityNameId entity_name_id;
+};
+
 // A temporary value.
 struct Temporary {
   static constexpr auto Kind =
@@ -1858,6 +1694,32 @@ struct ValueOfInitializer {
   InstId init_id;
 };
 
+// A by-value `Call` parameter. See AnyParam for member documentation.
+struct ValueParam {
+  // TODO: Make Parse::NodeId more specific.
+  static constexpr auto Kind = InstKind::ValueParam.Define<Parse::NodeId>(
+      {.ir_name = "value_param", .constant_kind = InstConstantKind::Never});
+
+  TypeId type_id;
+  CallParamIndex index;
+  NameId pretty_name_id;
+};
+
+// A pattern that represents a by-value `Call` parameter. See `AnyParamPattern`
+// for member documentation.
+struct ValueParamPattern {
+  // TODO: Make Parse::NodeId more specific.
+  static constexpr auto Kind =
+      InstKind::ValueParamPattern.Define<Parse::NodeId>(
+          {.ir_name = "value_param_pattern",
+           .constant_kind = InstConstantKind::AlwaysUnique,
+           .is_lowered = false});
+
+  TypeId type_id;
+  InstId subpattern_id;
+  CallParamIndex index;
+};
+
 // A `var` pattern.
 struct VarPattern {
   static constexpr auto Kind =
@@ -1887,17 +1749,14 @@ struct VarStorage {
   AbsoluteInstId pattern_id;
 };
 
-// The type of virtual function tables.
-struct VtableType {
-  static constexpr auto Kind = InstKind::VtableType.Define<Parse::NoneNodeId>(
-      {.ir_name = "<vtable>",
-       .is_type = InstIsType::Always,
-       .constant_kind = InstConstantKind::Always});
-  // This is a singleton instruction. However, it may still evolve into a more
-  // standard type and be removed.
-  static constexpr auto TypeInstId = MakeSingletonTypeInstId<Kind>();
-
+// Definition of ABI-neutral vtable information for a dynamic class.
+struct Vtable {
+  static constexpr auto Kind = InstKind::Vtable.Define<Parse::NodeId>(
+      {.ir_name = "vtable",
+       .constant_kind = InstConstantKind::Always,
+       .is_lowered = false});
   TypeId type_id;
+  InstBlockId virtual_functions_id;
 };
 
 // Initializer for virtual function table pointers in object initialization.
@@ -1908,14 +1767,17 @@ struct VtablePtr {
   InstId vtable_id;
 };
 
-// Definition of ABI-neutral vtable information for a dynamic class.
-struct Vtable {
-  static constexpr auto Kind = InstKind::Vtable.Define<Parse::NodeId>(
-      {.ir_name = "vtable",
-       .constant_kind = InstConstantKind::Always,
-       .is_lowered = false});
+// The type of virtual function tables.
+struct VtableType {
+  static constexpr auto Kind = InstKind::VtableType.Define<Parse::NoneNodeId>(
+      {.ir_name = "<vtable>",
+       .is_type = InstIsType::Always,
+       .constant_kind = InstConstantKind::Always});
+  // This is a singleton instruction. However, it may still evolve into a more
+  // standard type and be removed.
+  static constexpr auto TypeInstId = MakeSingletonTypeInstId<Kind>();
+
   TypeId type_id;
-  InstBlockId virtual_functions_id;
 };
 
 // An `expr where requirements` expression.