From d96f2c6338af6aac63e36579c3ccbdb921087b09 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 19 Nov 2024 12:41:07 -0800 Subject: [PATCH] Remove labels from the builtin inst kind macro --- toolchain/lower/mangler.cpp | 7 +- toolchain/sem_ir/builtin_inst_kind.cpp | 10 +- toolchain/sem_ir/builtin_inst_kind.h | 12 +- toolchain/sem_ir/file.cpp | 2 +- toolchain/sem_ir/formatter.cpp | 2 - toolchain/sem_ir/ids.h | 7 +- toolchain/sem_ir/inst_kind.def | 71 +++------- toolchain/sem_ir/inst_namer.cpp | 2 +- toolchain/sem_ir/stringify_type.cpp | 34 +++-- toolchain/sem_ir/typed_insts.h | 182 +++++++++++++++++++++++-- 10 files changed, 216 insertions(+), 113 deletions(-) diff --git a/toolchain/lower/mangler.cpp b/toolchain/lower/mangler.cpp index f4e44879888c..fb910e135533 100644 --- a/toolchain/lower/mangler.cpp +++ b/toolchain/lower/mangler.cpp @@ -56,8 +56,9 @@ auto Mangler::MangleInverseQualifiedNameScope(llvm::raw_ostream& os, names_to_render.push_back( {.name_scope_id = interface.scope_id, .prefix = ':'}); - auto self_inst_id = constant_values().GetConstantInstId(impl.self_id); - CARBON_KIND_SWITCH(insts().Get(self_inst_id)) { + auto self_inst = + insts().Get(constant_values().GetConstantInstId(impl.self_id)); + CARBON_KIND_SWITCH(self_inst) { case CARBON_KIND(SemIR::ClassType class_type): { auto next_name_scope_id = sem_ir().classes().Get(class_type.class_id).scope_id; @@ -76,7 +77,7 @@ auto Mangler::MangleInverseQualifiedNameScope(llvm::raw_ostream& os, case SemIR::TypeType::Kind: case SemIR::VtableType::Kind: case SemIR::WitnessType::Kind: { - os << self_inst_id.builtin_inst_kind().label(); + os << self_inst.kind().ir_name(); break; } case CARBON_KIND(SemIR::IntType int_type): { diff --git a/toolchain/sem_ir/builtin_inst_kind.cpp b/toolchain/sem_ir/builtin_inst_kind.cpp index 381af317f64e..1a12cb292300 100644 --- a/toolchain/sem_ir/builtin_inst_kind.cpp +++ b/toolchain/sem_ir/builtin_inst_kind.cpp @@ -7,17 +7,9 @@ namespace Carbon::SemIR { CARBON_DEFINE_ENUM_CLASS_NAMES(BuiltinInstKind) = { -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \ +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \ CARBON_ENUM_CLASS_NAME_STRING(Name) #include "toolchain/sem_ir/inst_kind.def" }; -auto BuiltinInstKind::label() -> llvm::StringRef { - static constexpr llvm::StringLiteral Labels[] = { -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, Label) Label, -#include "toolchain/sem_ir/inst_kind.def" - }; - return Labels[AsInt()]; -} - } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/builtin_inst_kind.h b/toolchain/sem_ir/builtin_inst_kind.h index 733899a68f98..407d445af53d 100644 --- a/toolchain/sem_ir/builtin_inst_kind.h +++ b/toolchain/sem_ir/builtin_inst_kind.h @@ -12,22 +12,18 @@ namespace Carbon::SemIR { CARBON_DEFINE_RAW_ENUM_CLASS(BuiltinInstKind, uint8_t) { -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \ - CARBON_RAW_ENUM_ENUMERATOR(Name) +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) CARBON_RAW_ENUM_ENUMERATOR(Name) #include "toolchain/sem_ir/inst_kind.def" }; class BuiltinInstKind : public CARBON_ENUM_BASE(BuiltinInstKind) { public: -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \ - CARBON_ENUM_CONSTANT_DECL(Name) +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) CARBON_ENUM_CONSTANT_DECL(Name) #include "toolchain/sem_ir/inst_kind.def" - auto label() -> llvm::StringRef; - // The count of enum values excluding Invalid. static constexpr uint8_t ValidCount = 0 -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) +1 +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) +1 #include "toolchain/sem_ir/inst_kind.def" ; @@ -36,7 +32,7 @@ class BuiltinInstKind : public CARBON_ENUM_BASE(BuiltinInstKind) { using EnumBase::FromInt; }; -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \ +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \ CARBON_ENUM_CONSTANT_DEFINITION(BuiltinInstKind, Name) #include "toolchain/sem_ir/inst_kind.def" diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index e58a82016ac0..86dea10fce8e 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -43,7 +43,7 @@ File::File(CheckIRId check_ir_id, IdentifierId package_id, // Error uses a self-referential type so that it's not accidentally treated as // a normal type. Every other builtin is a type, including the // self-referential TypeType. -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \ +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \ insts_.AddInNoBlock(LocIdAndInst::NoLoc( \ {.type_id = BuiltinInstKind::Name == BuiltinInstKind::ErrorInst \ ? TypeId::Error \ diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index e2489445289e..c7eea04a60e6 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -1021,8 +1021,6 @@ class FormatterImpl { auto FormatArg(BoolValue v) -> void { out_ << v; } - auto FormatArg(BuiltinInstKind kind) -> void { out_ << kind.label(); } - auto FormatArg(EntityNameId id) -> void { const auto& info = sem_ir_.entity_names().Get(id); FormatName(info.name_id); diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 1381329d6457..664b743c39c8 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -40,8 +40,7 @@ struct InstId : public IdBase, public Printable { static const InstId Invalid; // Builtin inst IDs. -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \ - static const InstId Builtin##Name; +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) static const InstId Builtin##Name; #include "toolchain/sem_ir/inst_kind.def" // The namespace for a `package` expression. @@ -83,8 +82,8 @@ struct InstId : public IdBase, public Printable { constexpr InstId InstId::Invalid = InstId(InvalidIndex); -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \ - constexpr InstId InstId::Builtin##Name = \ +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \ + constexpr InstId InstId::Builtin##Name = \ InstId::ForBuiltin(BuiltinInstKind::Name); #include "toolchain/sem_ir/inst_kind.def" diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 4e151245ad37..503409117388 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -13,9 +13,9 @@ // // Temporarily, we have CARBON_SEM_IR_BUILTIN_INST_KIND too: // -// - CARBON_SEM_IR_BUILTIN_INST_KIND(Name, Label) -// Defines a non-Invalid builtin type. The label is used for stringifying -// types. Falls back to CARBON_SEM_IR_INST_KIND if not defined. +// - CARBON_SEM_IR_BUILTIN_INST_KIND(Name) +// Defines a non-Invalid builtin type. Falls back to CARBON_SEM_IR_INST_KIND +// if not defined. // // TODO: Merge builtin instructions into the standard CARBON_SEM_IR_INST_KIND, // tracking the "builtin" annotation separately. This approach is used for @@ -25,7 +25,7 @@ // CARBON_SEM_IR_INST_KIND. However, if it's provided, make // CARBON_SEM_IR_INST_KIND optional. Per the above TODO, this is temporary. #ifndef CARBON_SEM_IR_BUILTIN_INST_KIND -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) CARBON_SEM_IR_INST_KIND(Name) +#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) CARBON_SEM_IR_INST_KIND(Name) #else #ifndef CARBON_SEM_IR_INST_KIND #define CARBON_SEM_IR_INST_KIND(Name) @@ -36,57 +36,18 @@ #error "Must define the x-macro to use this file." #endif -// Tracks expressions which are valid as types. -// This has a deliberately self-referential type. -CARBON_SEM_IR_BUILTIN_INST_KIND(TypeType, "type") - -// Used when a semantic error has been detected, and a SemIR InstId is still -// required. For example, when there is a type checking issue, this will be used -// in the type_id. It's typically used as a cue that semantic checking doesn't -// need to issue further diagnostics. -CARBON_SEM_IR_BUILTIN_INST_KIND(ErrorInst, "") - -// Used for the type of patterns that do not match a fixed type. -CARBON_SEM_IR_BUILTIN_INST_KIND(AutoType, "auto") - -// ----------------------------------------------------------------------------- -// TODO: Below CARBON_SEM_IR_BUILTIN_INST_KIND types are all placeholders. While -// the above may last, the below are expected to need to change in order to -// better reflect Carbon's design. Keeping distinct placeholders can help find -// usages for later fixes. -// ----------------------------------------------------------------------------- - -// The type of bool literals and branch conditions, bool. -CARBON_SEM_IR_BUILTIN_INST_KIND(BoolType, "bool") - -// 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 -// runtime. -CARBON_SEM_IR_BUILTIN_INST_KIND(IntLiteralType, "Core.IntLiteral") - -// 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`. -CARBON_SEM_IR_BUILTIN_INST_KIND(LegacyFloatType, "f64") - -// The type of string values and String literals. -CARBON_SEM_IR_BUILTIN_INST_KIND(StringType, "String") - -// The type of bound method values. -CARBON_SEM_IR_BUILTIN_INST_KIND(BoundMethodType, "") - -// The type of specific functions. -CARBON_SEM_IR_BUILTIN_INST_KIND(SpecificFunctionType, "") - -// The type of namespace and imported package names. -CARBON_SEM_IR_BUILTIN_INST_KIND(NamespaceType, "") - -// The type of witnesses. -CARBON_SEM_IR_BUILTIN_INST_KIND(WitnessType, "") - -// The type of virtual function tables -CARBON_SEM_IR_BUILTIN_INST_KIND(VtableType, "") +CARBON_SEM_IR_BUILTIN_INST_KIND(TypeType) +CARBON_SEM_IR_BUILTIN_INST_KIND(ErrorInst) +CARBON_SEM_IR_BUILTIN_INST_KIND(AutoType) +CARBON_SEM_IR_BUILTIN_INST_KIND(BoolType) +CARBON_SEM_IR_BUILTIN_INST_KIND(IntLiteralType) +CARBON_SEM_IR_BUILTIN_INST_KIND(LegacyFloatType) +CARBON_SEM_IR_BUILTIN_INST_KIND(StringType) +CARBON_SEM_IR_BUILTIN_INST_KIND(BoundMethodType) +CARBON_SEM_IR_BUILTIN_INST_KIND(SpecificFunctionType) +CARBON_SEM_IR_BUILTIN_INST_KIND(NamespaceType) +CARBON_SEM_IR_BUILTIN_INST_KIND(WitnessType) +CARBON_SEM_IR_BUILTIN_INST_KIND(VtableType) // For each instruction kind declared here there is a matching definition in // `typed_insts.h`. diff --git a/toolchain/sem_ir/inst_namer.cpp b/toolchain/sem_ir/inst_namer.cpp index f9bda5b49d33..cccf4686ef65 100644 --- a/toolchain/sem_ir/inst_namer.cpp +++ b/toolchain/sem_ir/inst_namer.cpp @@ -146,7 +146,7 @@ auto InstNamer::GetNameFor(ScopeId scope_id, InstId inst_id) const // Check for a builtin. if (inst_id.is_builtin()) { - return inst_id.builtin_inst_kind().label().str(); + return sem_ir_.insts().Get(inst_id).kind().ir_name().str(); } if (inst_id == InstId::PackageNamespace) { diff --git a/toolchain/sem_ir/stringify_type.cpp b/toolchain/sem_ir/stringify_type.cpp index 98eafccf7569..23bd81a34e2c 100644 --- a/toolchain/sem_ir/stringify_type.cpp +++ b/toolchain/sem_ir/stringify_type.cpp @@ -76,12 +76,6 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) continue; } - // Builtins have designated labels. - if (step.inst_id.is_builtin()) { - out << step.inst_id.builtin_inst_kind().label(); - continue; - } - const auto& sem_ir = step.sem_ir; // Helper for instructions with the current sem_ir. auto push_inst_id = [&](InstId inst_id) { @@ -120,6 +114,22 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) auto untyped_inst = sem_ir.insts().Get(step.inst_id); CARBON_KIND_SWITCH(untyped_inst) { + case SemIR::AutoType::Kind: + case SemIR::BoolType::Kind: + case SemIR::BoundMethodType::Kind: + case SemIR::ErrorInst::Kind: + case SemIR::IntLiteralType::Kind: + case SemIR::LegacyFloatType::Kind: + case SemIR::NamespaceType::Kind: + case SemIR::SpecificFunctionType::Kind: + case SemIR::StringType::Kind: + case SemIR::TypeType::Kind: + case SemIR::VtableType::Kind: + case SemIR::WitnessType::Kind: { + // Builtin instructions use their IR name as a label. + out << untyped_inst.kind().ir_name(); + break; + } case CARBON_KIND(ArrayType inst): { if (step.index == 0) { out << "["; @@ -339,16 +349,13 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) case Assign::Kind: case AssociatedConstantDecl::Kind: case AssociatedEntity::Kind: - case AutoType::Kind: case BaseDecl::Kind: case BindName::Kind: case BindValue::Kind: case BindingPattern::Kind: case BlockArg::Kind: case BoolLiteral::Kind: - case BoolType::Kind: case BoundMethod::Kind: - case BoundMethodType::Kind: case Branch::Kind: case BranchIf::Kind: case BranchWithArg::Kind: @@ -359,7 +366,6 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) case CompleteTypeWitness::Kind: case Converted::Kind: case Deref::Kind: - case ErrorInst::Kind: case FieldDecl::Kind: case FloatLiteral::Kind: case FunctionDecl::Kind: @@ -368,14 +374,11 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) case ImportRefLoaded::Kind: case ImportRefUnloaded::Kind: case InitializeFrom::Kind: - case IntLiteralType::Kind: case IntValue::Kind: case InterfaceDecl::Kind: case InterfaceWitness::Kind: case InterfaceWitnessAccess::Kind: - case LegacyFloatType::Kind: case Namespace::Kind: - case NamespaceType::Kind: case OutParam::Kind: case OutParamPattern::Kind: case RequirementEquivalent::Kind: @@ -387,10 +390,8 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) case ReturnSlotPattern::Kind: case SpecificConstant::Kind: case SpecificFunction::Kind: - case SpecificFunctionType::Kind: case SpliceBlock::Kind: case StringLiteral::Kind: - case StringType::Kind: case StructAccess::Kind: case StructInit::Kind: case StructLiteral::Kind: @@ -402,15 +403,12 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) case TupleInit::Kind: case TupleLiteral::Kind: case TupleValue::Kind: - case TypeType::Kind: case UnaryOperatorNot::Kind: case ValueAsRef::Kind: case ValueOfInitializer::Kind: case ValueParam::Kind: case ValueParamPattern::Kind: case VarStorage::Kind: - case VtableType::Kind: - case WitnessType::Kind: // We don't know how to print this instruction, but it might have a // constant value that we can print. auto const_inst_id = diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index fab9f5653c47..2cee638de491 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -45,19 +45,32 @@ namespace Carbon::SemIR { -// A builtin instruction, corresponding to instructions like -// InstId::BuiltinTypeType. +// Used for the type of patterns that do not match a fixed type. // -// Builtins don't have a parse node associated with them. -#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, Label) \ - struct Name { \ - static constexpr auto Kind = InstKind::Name.Define( \ - {.ir_name = Label, \ - .is_type = InstIsType::Always, \ - .constant_kind = InstConstantKind::Always}); \ - TypeId type_id; \ - }; -#include "toolchain/sem_ir/inst_kind.def" +// TODO: Annotate as a builtin. +struct AutoType { + static constexpr auto Kind = InstKind::AutoType.Define( + {.ir_name = "auto", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + +// The type of bool literals and branch conditions, bool. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +// +// TODO: Annotate as a builtin. +struct BoolType { + static constexpr auto Kind = InstKind::BoolType.Define( + {.ir_name = "bool", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; // An adapted type declaration in a class, of the form `adapt T;`. struct AdaptDecl { @@ -370,6 +383,20 @@ struct BoundMethod { InstId function_id; }; +// The type of bound method values. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct BoundMethodType { + static constexpr auto Kind = + InstKind::BoundMethodType.Define( + {.ir_name = "", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // Common representation for all kinds of `Branch*` node. struct AnyBranch { static constexpr InstKind Kinds[] = {InstKind::Branch, InstKind::BranchIf, @@ -535,6 +562,21 @@ struct Deref { InstId pointer_id; }; +// Used when a semantic error has been detected, and a SemIR InstId is still +// required. For example, when there is a type checking issue, this will be used +// in the type_id. It's typically used as a cue that semantic checking doesn't +// need to issue further diagnostics. +// +// TODO: Annotate as a builtin. +struct ErrorInst { + static constexpr auto Kind = InstKind::ErrorInst.Define( + {.ir_name = "", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // An `export bind_name` declaration. struct ExportDecl { static constexpr auto Kind = @@ -603,6 +645,22 @@ 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`. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct LegacyFloatType { + static constexpr auto Kind = + InstKind::LegacyFloatType.Define( + {.ir_name = "f64", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // A function declaration. struct FunctionDecl { static constexpr auto Kind = @@ -780,6 +838,23 @@ struct IntValue { 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 +// runtime. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct IntLiteralType { + static constexpr auto Kind = + InstKind::IntLiteralType.Define( + {.ir_name = "Core.IntLiteral", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // An integer type. struct IntType { static constexpr auto Kind = InstKind::IntType.Define( @@ -819,6 +894,20 @@ struct Namespace { AbsoluteInstId import_id; }; +// The type of namespace and imported package names. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct NamespaceType { + static constexpr auto Kind = + InstKind::NamespaceType.Define( + {.ir_name = "", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // A parameter for a function or other parameterized block, as exposed in the // SemIR calling convention. The sub-kinds differ only in their expression // category. @@ -1036,6 +1125,20 @@ struct SpecificFunction { SpecificId specific_id; }; +// The type of specific functions. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct SpecificFunctionType { + static constexpr auto Kind = + InstKind::SpecificFunctionType.Define( + {.ir_name = "", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // Splices a block into the location where this appears. This may be an // expression, producing a result with a given type. For example, when // constructing from aggregates we may figure out which conversions are required @@ -1060,6 +1163,20 @@ struct StringLiteral { StringLiteralValueId string_literal_id; }; +// The type of string values and String literals. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct StringType { + static constexpr auto Kind = + InstKind::StringType.Define( + {.ir_name = "String", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // Access to a struct type, with the index into the struct_id representation. struct StructAccess { // TODO: Make Parse::NodeId more specific. @@ -1187,6 +1304,19 @@ struct TupleValue { InstBlockId elements_id; }; +// Tracks expressions which are valid as types. This has a deliberately +// self-referential type. +// +// TODO: Annotate as a builtin. +struct TypeType { + static constexpr auto Kind = InstKind::TypeType.Define( + {.ir_name = "type", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // The `not` operator, such as `not operand`. struct UnaryOperatorNot { // TODO: Make Parse::NodeId more specific. @@ -1249,6 +1379,20 @@ struct VarStorage { NameId name_id; }; +// The type of virtual function tables. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct VtableType { + static constexpr auto Kind = + InstKind::VtableType.Define( + {.ir_name = "", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // An `expr where requirements` expression. struct WhereExpr { static constexpr auto Kind = InstKind::WhereExpr.Define( @@ -1263,6 +1407,20 @@ struct WhereExpr { InstBlockId requirements_id; }; +// The type of witnesses. +// +// Although this is a builtin, it may still evolve to a more standard type and +// be removed. +struct WitnessType { + static constexpr auto Kind = + InstKind::WitnessType.Define( + {.ir_name = "", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::Always}); + + TypeId type_id; +}; + // These concepts are an implementation detail of the library, not public API. namespace Internal {