Introduce TypeInstId (#5288)

TypeInstId is an InstId whose constant value has a type of TypeType.
This includes:
- Type value instructions, the `ClassType` or `IntLiteralType`
instructions.
- Constraint value instructions, which are the `FacetType` and
`TypeType` instructions, each of which also have type TypeType.

TypeInstId encodes in the type system that it is safe to convert the
instruction's value to a TypeId, and CHECKs at construction that this
invariant is maintained.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Dana Jansens
2025-04-10 22:59:02 +00:00
committed by GitHub
co-authored by Richard Smith
parent 03a31bd0de
commit cf57c85545
27 changed files with 202 additions and 111 deletions
+7 -7
View File
@@ -1076,16 +1076,16 @@ static auto PerformBuiltinConversion(
// `FacetValue`, which requires an instruction of type `TypeType`. So if
// we are converting from a facet value, we get its `type` via an extra
// `FacetAccessType` instruction.
auto type_inst_id = SemIR::InstId::None;
auto type_inst_id = SemIR::TypeInstId::None;
if (sem_ir.types().Is<SemIR::FacetType>(value_type_id)) {
type_inst_id =
type_inst_id = context.types().GetAsTypeInstId(
AddInst(context, loc_id,
SemIR::FacetAccessType{
.type_id = SemIR::TypeType::SingletonTypeId,
.facet_value_inst_id = const_value_id,
});
}));
} else {
type_inst_id = const_value_id;
type_inst_id = context.types().GetAsTypeInstId(const_value_id);
}
return AddInst<SemIR::FacetValue>(
context, loc_id,
@@ -1470,7 +1470,7 @@ auto ExprAsType(Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
auto type_inst_id = ConvertToValueOfType(context, loc_id, value_id,
SemIR::TypeType::SingletonTypeId);
if (type_inst_id == SemIR::ErrorInst::SingletonInstId) {
return {.inst_id = type_inst_id,
return {.inst_id = SemIR::ErrorInst::SingletonTypeInstId,
.type_id = SemIR::ErrorInst::SingletonTypeId};
}
@@ -1481,11 +1481,11 @@ auto ExprAsType(Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
"cannot evaluate type expression");
context.emitter().Emit(loc_id, TypeExprEvaluationFailure);
}
return {.inst_id = SemIR::ErrorInst::SingletonInstId,
return {.inst_id = SemIR::ErrorInst::SingletonTypeInstId,
.type_id = SemIR::ErrorInst::SingletonTypeId};
}
return {.inst_id = type_inst_id,
return {.inst_id = context.types().GetAsTypeInstId(type_inst_id),
.type_id = context.types().GetTypeIdForTypeConstantId(type_const_id)};
}
+1 -1
View File
@@ -120,7 +120,7 @@ auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id,
// A type that has been converted for use as a type expression.
struct TypeExpr {
// The converted expression of type `type`, or `ErrorInst::SingletonInstId`.
SemIR::InstId inst_id;
SemIR::TypeInstId inst_id;
// The corresponding type, or `ErrorInst::SingletonTypeId`.
SemIR::TypeId type_id;
};
+4
View File
@@ -130,6 +130,10 @@ class DeductionWorklist {
Add(inst_id, SemIR::InstId(arg), needs_substitution);
break;
}
case CARBON_KIND(SemIR::TypeInstId inst_id): {
Add(inst_id, SemIR::InstId(arg), needs_substitution);
break;
}
case CARBON_KIND(SemIR::StructTypeFieldsId fields_id): {
AddAll(fields_id, SemIR::StructTypeFieldsId(arg), needs_substitution);
break;
+10
View File
@@ -421,6 +421,16 @@ static auto GetConstantValue(EvalContext& eval_context,
return inst_id;
}
static auto GetConstantValue(EvalContext& eval_context,
SemIR::TypeInstId inst_id, Phase* phase)
-> SemIR::TypeInstId {
// The input instruction is a TypeInstId, and eval does not change concrete
// types (like TypeType which TypeInstId implies), so the result is also a
// valid TypeInstId.
return SemIR::TypeInstId::UnsafeMake(GetConstantValue(
eval_context, static_cast<SemIR::InstId>(inst_id), phase));
}
// Explicitly discard a `DestInstId`, because we should not be using the
// destination as part of evaluation.
static auto GetConstantValue(EvalContext& /*eval_context*/,
+4 -4
View File
@@ -39,7 +39,7 @@ static auto WitnessAccessMatchesInterface(
}
static auto IncompleteFacetTypeDiagnosticBuilder(
Context& context, SemIRLoc loc, SemIR::InstId facet_type_inst_id,
Context& context, SemIRLoc loc, SemIR::TypeInstId facet_type_inst_id,
bool is_definition) -> DiagnosticBuilder {
if (is_definition) {
CARBON_DIAGNOSTIC(ImplAsIncompleteFacetTypeDefinition, Error,
@@ -59,7 +59,7 @@ static auto IncompleteFacetTypeDiagnosticBuilder(
auto InitialFacetTypeImplWitness(
Context& context, SemIR::LocId witness_loc_id,
SemIR::InstId facet_type_inst_id, SemIR::InstId self_type_inst_id,
SemIR::TypeInstId facet_type_inst_id, SemIR::TypeInstId self_type_inst_id,
const SemIR::SpecificInterface& interface_to_witness,
SemIR::SpecificId self_specific_id, bool is_definition) -> SemIR::InstId {
// TODO: Finish facet type resolution. This code currently only handles
@@ -233,8 +233,8 @@ auto InitialFacetTypeImplWitness(
return witness_inst_id;
}
auto RequireCompleteFacetTypeForImplDefinition(Context& context, SemIRLoc loc,
SemIR::InstId facet_type_inst_id)
auto RequireCompleteFacetTypeForImplDefinition(
Context& context, SemIRLoc loc, SemIR::TypeInstId facet_type_inst_id)
-> bool {
auto facet_type_id =
context.types().GetTypeIdForTypeInstId(facet_type_inst_id);
+3 -3
View File
@@ -41,14 +41,14 @@ auto FacetTypeFromInterface(Context& context, SemIR::InterfaceId interface_id,
// `Self` type.
auto InitialFacetTypeImplWitness(
Context& context, SemIR::LocId witness_loc_id,
SemIR::InstId facet_type_inst_id, SemIR::InstId self_type_inst_id,
SemIR::TypeInstId facet_type_inst_id, SemIR::TypeInstId self_type_inst_id,
const SemIR::SpecificInterface& interface_to_witness,
SemIR::SpecificId self_specific_id, bool is_definition) -> SemIR::InstId;
// Returns `true` if the facet type is complete. Otherwise issues a diagnostic
// and returns `false`.
auto RequireCompleteFacetTypeForImplDefinition(Context& context, SemIRLoc loc,
SemIR::InstId facet_type_inst_id)
auto RequireCompleteFacetTypeForImplDefinition(
Context& context, SemIRLoc loc, SemIR::TypeInstId facet_type_inst_id)
-> bool;
// Replaces the placeholder created by `InitialFacetTypeImplWitness` with an
+1 -1
View File
@@ -143,7 +143,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
cast_type_id);
});
if (cast_type_id == SemIR::ErrorInst::SingletonTypeId) {
cast_type_inst_id = SemIR::ErrorInst::SingletonInstId;
cast_type_inst_id = SemIR::ErrorInst::SingletonTypeInstId;
}
auto binding_id =
context.parse_tree().As<Parse::VarBindingPatternId>(node_id);
+9 -9
View File
@@ -370,7 +370,7 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
return true;
}
auto [adapted_inst_id, adapted_type_id] =
auto [adapted_type_inst_id, adapted_type_id] =
ExprAsType(context, node_id, adapted_type_expr_id);
adapted_type_id = AsConcreteType(
context, adapted_type_id, node_id,
@@ -379,26 +379,26 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
"adapted type {0} is an incomplete type",
InstIdAsType);
return context.emitter().Build(node_id, IncompleteTypeInAdaptDecl,
adapted_inst_id);
adapted_type_inst_id);
},
[&] {
CARBON_DIAGNOSTIC(AbstractTypeInAdaptDecl, Error,
"adapted type {0} is an abstract type", InstIdAsType);
return context.emitter().Build(node_id, AbstractTypeInAdaptDecl,
adapted_inst_id);
adapted_type_inst_id);
});
if (adapted_type_id == SemIR::ErrorInst::SingletonTypeId) {
adapted_inst_id = SemIR::ErrorInst::SingletonInstId;
adapted_type_inst_id = SemIR::ErrorInst::SingletonTypeInstId;
}
// Build a SemIR representation for the declaration.
class_info.adapt_id = AddInst<SemIR::AdaptDecl>(
context, node_id, {.adapted_type_inst_id = adapted_inst_id});
context, node_id, {.adapted_type_inst_id = adapted_type_inst_id});
// Extend the class scope with the adapted type's scope if requested.
if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
auto& class_scope = context.name_scopes().Get(class_info.scope_id);
class_scope.AddExtendedScope(adapted_inst_id);
class_scope.AddExtendedScope(adapted_type_inst_id);
}
return true;
}
@@ -422,17 +422,17 @@ struct BaseInfo {
SemIR::TypeId type_id;
SemIR::NameScopeId scope_id;
SemIR::InstId inst_id;
SemIR::TypeInstId inst_id;
};
constexpr BaseInfo BaseInfo::Error = {
.type_id = SemIR::ErrorInst::SingletonTypeId,
.scope_id = SemIR::NameScopeId::None,
.inst_id = SemIR::ErrorInst::SingletonInstId};
.inst_id = SemIR::ErrorInst::SingletonTypeInstId};
} // namespace
// Diagnoses an attempt to derive from a final type.
static auto DiagnoseBaseIsFinal(Context& context, Parse::NodeId node_id,
SemIR::InstId base_type_inst_id) -> void {
SemIR::TypeInstId base_type_inst_id) -> void {
CARBON_DIAGNOSTIC(BaseIsFinal, Error,
"deriving from final type {0}; base type must be an "
"`abstract` or `base` class",
+4 -3
View File
@@ -53,7 +53,7 @@ auto HandleParseNode(Context& context, Parse::FunctionIntroducerId node_id)
auto HandleParseNode(Context& context, Parse::ReturnTypeId node_id) -> bool {
// Propagate the type expression.
auto [type_node_id, type_inst_id] = context.node_stack().PopExprWithNodeId();
auto type_id = ExprAsType(context, type_node_id, type_inst_id).type_id;
auto as_type = ExprAsType(context, type_node_id, type_inst_id);
// If the previous node was `IdentifierNameBeforeParams`, then it would have
// caused these entries to be pushed to the pattern stacks. But it's possible
@@ -69,10 +69,11 @@ auto HandleParseNode(Context& context, Parse::ReturnTypeId node_id) -> bool {
}
auto return_slot_pattern_id = AddPatternInst<SemIR::ReturnSlotPattern>(
context, node_id, {.type_id = type_id, .type_inst_id = type_inst_id});
context, node_id,
{.type_id = as_type.type_id, .type_inst_id = as_type.inst_id});
auto param_pattern_id = AddPatternInst<SemIR::OutParamPattern>(
context, node_id,
{.type_id = type_id,
{.type_id = as_type.type_id,
.subpattern_id = return_slot_pattern_id,
.index = SemIR::CallParamIndex::None});
context.node_stack().Push(node_id, param_pattern_id);
+26 -26
View File
@@ -55,14 +55,14 @@ auto HandleParseNode(Context& context, Parse::ForallId /*node_id*/) -> bool {
auto HandleParseNode(Context& context, Parse::TypeImplAsId node_id) -> bool {
auto [self_node, self_id] = context.node_stack().PopExprWithNodeId();
self_id = ExprAsType(context, self_node, self_id).inst_id;
context.node_stack().Push(node_id, self_id);
auto self_type_inst_id = ExprAsType(context, self_node, self_id).inst_id;
context.node_stack().Push(node_id, self_type_inst_id);
// Introduce `Self`. Note that we add this name lexically rather than adding
// to the `NameScopeId` of the `impl`, because this happens before we enter
// the `impl` scope or even identify which `impl` we're declaring.
// TODO: Revisit this once #3714 is resolved.
AddNameToLookup(context, SemIR::NameId::SelfType, self_id);
AddNameToLookup(context, SemIR::NameId::SelfType, self_type_inst_id);
return true;
}
@@ -109,11 +109,11 @@ auto HandleParseNode(Context& context, Parse::DefaultSelfImplAsId node_id)
// is a class and found its `Self`, so additionally performing an unqualified
// name lookup would be redundant work, but would avoid duplicating the
// handling of the `Self` expression.
auto self_inst_id = AddInst(
auto self_inst_id = context.types().GetAsTypeInstId(AddInst(
context, node_id,
SemIR::NameRef{.type_id = SemIR::TypeType::SingletonTypeId,
.name_id = SemIR::NameId::SelfType,
.value_id = context.types().GetInstId(self_type_id)});
.value_id = context.types().GetInstId(self_type_id)}));
// There's no need to push `Self` into scope here, because we can find it in
// the parent class scope.
@@ -135,8 +135,8 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node,
Parse::AnyImplDeclId node_id, SemIR::ImplId impl_id,
Parse::NodeId self_type_node, SemIR::TypeId self_type_id,
Parse::NodeId params_node,
SemIR::InstId constraint_inst_id,
SemIR::TypeId constraint_id) -> bool {
SemIR::TypeInstId constraint_type_inst_id,
SemIR::TypeId constraint_type_id) -> bool {
auto parent_scope_id = context.decl_name_stack().PeekParentScopeId();
if (!parent_scope_id.has_value()) {
DiagnoseExtendImplOutsideClass(context, node_id);
@@ -188,14 +188,14 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node,
parent_scope.set_has_error();
} else {
bool is_complete = RequireCompleteType(
context, constraint_id, context.insts().GetLocId(constraint_inst_id),
[&] {
context, constraint_type_id,
context.insts().GetLocId(constraint_type_inst_id), [&] {
CARBON_DIAGNOSTIC(ExtendImplAsIncomplete, Error,
"`extend impl as` incomplete facet type {0}",
InstIdAsType);
return context.emitter().Build(impl.latest_decl_id(),
ExtendImplAsIncomplete,
constraint_inst_id);
constraint_type_inst_id);
});
if (!is_complete) {
parent_scope.set_has_error();
@@ -203,7 +203,7 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node,
}
}
parent_scope.AddExtendedScope(constraint_inst_id);
parent_scope.AddExtendedScope(constraint_type_inst_id);
return true;
}
@@ -318,7 +318,7 @@ static auto IsValidImplRedecl(Context& context, SemIR::Impl& new_impl,
// and returns `None`.
static auto CheckConstraintIsInterface(Context& context,
SemIR::InstId impl_decl_id,
SemIR::InstId constraint_id)
SemIR::TypeInstId constraint_id)
-> SemIR::SpecificInterface {
auto facet_type_id = context.types().GetTypeIdForTypeInstId(constraint_id);
if (facet_type_id == SemIR::ErrorInst::SingletonTypeId) {
@@ -351,15 +351,15 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
-> std::pair<SemIR::ImplId, SemIR::InstId> {
auto [constraint_node, constraint_id] =
context.node_stack().PopExprWithNodeId();
auto [self_type_node, self_inst_id] =
auto [self_type_node, self_type_inst_id] =
context.node_stack().PopWithNodeId<Parse::NodeCategory::ImplAs>();
auto self_type_id = context.types().GetTypeIdForTypeInstId(self_inst_id);
auto self_type_id = context.types().GetTypeIdForTypeInstId(self_type_inst_id);
// Pop the `impl` introducer and any `forall` parameters as a "name".
auto name = PopImplIntroducerAndParamsAsNameComponent(context, node_id);
auto decl_block_id = context.inst_block_stack().Pop();
// Convert the constraint expression to a type.
auto [constraint_inst_id, constraint_type_id] =
auto [constraint_type_inst_id, constraint_type_id] =
ExprAsType(context, constraint_node, constraint_id);
// Process modifiers.
@@ -385,10 +385,10 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
SemIR::Impl impl_info = {name_context.MakeEntityWithParamsBase(
name, impl_decl_id,
/*is_extern=*/false, SemIR::LibraryNameId::None),
{.self_id = self_inst_id,
.constraint_id = constraint_inst_id,
{.self_id = self_type_inst_id,
.constraint_id = constraint_type_inst_id,
.interface = CheckConstraintIsInterface(
context, impl_decl_id, constraint_inst_id),
context, impl_decl_id, constraint_type_inst_id),
.is_final = is_final}};
// Add the impl declaration.
bool invalid_redeclaration = false;
@@ -486,17 +486,17 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
auto extend_node = introducer.modifier_node_id(ModifierOrder::Decl);
if (impl_info.generic_id.has_value()) {
SemIR::TypeId type_id = context.insts().Get(constraint_inst_id).type_id();
constraint_inst_id = AddInst<SemIR::SpecificConstant>(
context, context.insts().GetLocId(constraint_inst_id),
{.type_id = type_id,
.inst_id = constraint_inst_id,
.specific_id =
context.generics().GetSelfSpecific(impl_info.generic_id)});
constraint_type_inst_id =
context.types().GetAsTypeInstId(AddInst<SemIR::SpecificConstant>(
context, context.insts().GetLocId(constraint_type_inst_id),
{.type_id = SemIR::TypeType::SingletonTypeId,
.inst_id = constraint_type_inst_id,
.specific_id =
context.generics().GetSelfSpecific(impl_info.generic_id)}));
}
if (!ExtendImpl(context, extend_node, node_id, impl_decl.impl_id,
self_type_node, self_type_id, name.implicit_params_loc_id,
constraint_inst_id, constraint_type_id)) {
constraint_type_inst_id, constraint_type_id)) {
// Don't allow the invalid impl to be used.
FillImplWitnessWithErrors(context, impl_info);
context.impls().Get(impl_decl.impl_id).witness_id =
+1 -1
View File
@@ -111,7 +111,7 @@ auto HandleParseNode(Context& context, Parse::RequirementImplsId node_id)
ImplsOnNonFacetType, Error,
"right argument of `impls` requirement must be a facet type");
context.emitter().Emit(rhs_node, ImplsOnNonFacetType);
rhs_as_type.inst_id = SemIR::ErrorInst::SingletonInstId;
rhs_as_type.inst_id = SemIR::ErrorInst::SingletonTypeInstId;
}
// TODO: Require that at least one side uses a designator.
// TODO: For things like `HashSet(.T) as type`, add an implied constraint
+6
View File
@@ -80,6 +80,12 @@ static auto FindAssociatedImportIRs(Context& context,
}
break;
}
case CARBON_KIND(SemIR::TypeInstId inst_id): {
if (inst_id.has_value()) {
worklist.push_back(inst_id);
}
break;
}
case CARBON_KIND(SemIR::InstBlockId inst_block_id): {
push_block(inst_block_id);
break;
+1 -1
View File
@@ -272,7 +272,7 @@ static auto MapType(Context& context, clang::QualType type) -> TypeExpr {
context.ast_context().getTypeSize(type) == 32) {
return MakeIntType(context, context.ints().Add(32));
}
return {.inst_id = SemIR::ErrorInst::SingletonInstId,
return {.inst_id = SemIR::ErrorInst::SingletonTypeInstId,
.type_id = SemIR::ErrorInst::SingletonTypeId};
}
+24 -15
View File
@@ -699,6 +699,15 @@ static auto GetLocalConstantInstId(ImportRefResolver& resolver,
return resolver.local_constant_values().GetInstIdIfValid(const_id);
}
// Returns the local constant InstId for an imported InstId.
static auto GetLocalTypeInstId(ImportRefResolver& resolver,
SemIR::TypeInstId inst_id) -> SemIR::TypeInstId {
// The input instruction is a TypeInstId, and import does not change the type
// of instructions, so the result is also a valid TypeInstId.
return SemIR::TypeInstId::UnsafeMake(
GetLocalConstantInstId(resolver, static_cast<SemIR::InstId>(inst_id)));
}
// Returns the ConstantId for a TypeId. Adds unresolved constants to
// work_stack_.
static auto GetLocalConstantId(ImportRefResolver& resolver,
@@ -1165,7 +1174,7 @@ static auto GetLocalReturnSlotPatternId(
MakeImportedLocIdAndInst<SemIR::ReturnSlotPattern>(
context.local_context(),
AddImportIRInst(context, param_pattern.subpattern_id),
{.type_id = type_id, .type_inst_id = SemIR::InstId::None}));
{.type_id = type_id, .type_inst_id = SemIR::TypeInstId::None}));
return AddInstInNoBlock(
context.local_context(),
MakeImportedLocIdAndInst<SemIR::OutParamPattern>(
@@ -1400,9 +1409,9 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
return ResolveResult::Retry();
}
auto adapted_type_inst_id =
auto adapted_type_inst_id = resolver.local_ir().types().GetAsTypeInstId(
AddLoadedImportRef(resolver, SemIR::TypeType::SingletonTypeId,
inst.adapted_type_inst_id, adapted_type_const_id);
inst.adapted_type_inst_id, adapted_type_const_id));
// Create a corresponding instruction to represent the declaration.
auto inst_id = AddInstInNoBlock(
@@ -1418,7 +1427,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
SemIR::ArrayType inst) -> ResolveResult {
CARBON_CHECK(inst.type_id == SemIR::TypeType::SingletonTypeId);
auto element_type_inst_id =
GetLocalConstantInstId(resolver, inst.element_type_inst_id);
GetLocalTypeInstId(resolver, inst.element_type_inst_id);
auto bound_id = GetLocalConstantInstId(resolver, inst.bound_id);
if (resolver.HasNewWork()) {
return ResolveResult::Retry();
@@ -1559,9 +1568,9 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
return ResolveResult::Retry();
}
auto base_type_inst_id =
auto base_type_inst_id = resolver.local_ir().types().GetAsTypeInstId(
AddLoadedImportRef(resolver, SemIR::TypeType::SingletonTypeId,
inst.base_type_inst_id, base_type_const_id);
inst.base_type_inst_id, base_type_const_id));
// Create a corresponding instruction to represent the declaration.
auto inst_id = AddInstInNoBlock(
@@ -2130,8 +2139,8 @@ static auto MakeImplDeclaration(ImportContext& context,
AddImportIRInst(context, import_impl.latest_decl_id()), impl_decl));
impl_decl.impl_id = context.local_impls().Add(
{GetIncompleteLocalEntityBase(context, impl_decl_id, import_impl),
{.self_id = SemIR::InstId::None,
.constraint_id = SemIR::InstId::None,
{.self_id = SemIR::TypeInstId::None,
.constraint_id = SemIR::TypeInstId::None,
.interface = SemIR::SpecificInterface::None,
.witness_id = witness_id}});
@@ -2226,12 +2235,12 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
// Create instructions for self and constraint to hold the symbolic constant
// value for a generic impl.
new_impl.self_id =
new_impl.self_id = resolver.local_ir().types().GetAsTypeInstId(
AddLoadedImportRef(resolver, SemIR::TypeType::SingletonTypeId,
import_impl.self_id, self_const_id);
new_impl.constraint_id =
import_impl.self_id, self_const_id));
new_impl.constraint_id = resolver.local_ir().types().GetAsTypeInstId(
AddLoadedImportRef(resolver, SemIR::TypeType::SingletonTypeId,
import_impl.constraint_id, constraint_const_id);
import_impl.constraint_id, constraint_const_id));
new_impl.interface = GetLocalSpecificInterface(
resolver, import_impl.interface, specific_interface_data);
if (import_impl.is_complete()) {
@@ -2499,7 +2508,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
static auto TryResolveTypedInst(ImportRefResolver& resolver,
SemIR::FacetValue inst) -> ResolveResult {
auto type_id = GetLocalConstantId(resolver, inst.type_id);
auto type_inst_id = GetLocalConstantInstId(resolver, inst.type_inst_id);
auto type_inst_id = GetLocalTypeInstId(resolver, inst.type_inst_id);
auto witnesses = GetLocalInstBlockContents(resolver, inst.witnesses_block_id);
if (resolver.HasNewWork()) {
return ResolveResult::Retry();
@@ -2808,9 +2817,9 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
-> ResolveResult {
CARBON_CHECK(inst.type_id == SemIR::TypeType::SingletonTypeId);
auto class_const_inst_id =
GetLocalConstantInstId(resolver, inst.class_type_inst_id);
GetLocalTypeInstId(resolver, inst.class_type_inst_id);
auto elem_const_inst_id =
GetLocalConstantInstId(resolver, inst.element_type_inst_id);
GetLocalTypeInstId(resolver, inst.element_type_inst_id);
if (resolver.HasNewWork()) {
return ResolveResult::Retry();
}
+1 -1
View File
@@ -384,7 +384,7 @@ class NodeStack {
Parse::NodeCategory::MemberName | Parse::NodeCategory::NonExprName,
Id::KindFor<SemIR::NameId>());
set_id_if_category_is(Parse::NodeCategory::ImplAs,
Id::KindFor<SemIR::InstId>());
Id::KindFor<SemIR::TypeInstId>());
set_id_if_category_is(Parse::NodeCategory::Decl |
Parse::NodeCategory::Statement |
Parse::NodeCategory::Modifier,
+12
View File
@@ -89,6 +89,12 @@ static auto PushOperand(Context& context, Worklist& worklist,
}
break;
}
case CARBON_KIND(SemIR::TypeInstId inst_id): {
if (inst_id.has_value()) {
worklist.Push(inst_id);
}
break;
}
case CARBON_KIND(SemIR::InstBlockId inst_block_id): {
push_block(inst_block_id);
break;
@@ -175,6 +181,12 @@ static auto PopOperand(Context& context, Worklist& worklist,
}
return worklist.Pop().index;
}
case CARBON_KIND(SemIR::TypeInstId inst_id): {
if (!inst_id.has_value()) {
return arg.value();
}
return worklist.Pop().index;
}
case CARBON_KIND(SemIR::InstBlockId inst_block_id): {
return pop_block_id(inst_block_id).index;
}
+2 -2
View File
@@ -157,8 +157,8 @@ auto GetPointerType(Context& context, SemIR::InstId pointee_type_id)
return GetTypeImpl<SemIR::PointerType>(context, pointee_type_id);
}
auto GetUnboundElementType(Context& context, SemIR::InstId class_type_id,
SemIR::InstId element_type_id) -> SemIR::TypeId {
auto GetUnboundElementType(Context& context, SemIR::TypeInstId class_type_id,
SemIR::TypeInstId element_type_id) -> SemIR::TypeId {
return GetTypeImpl<SemIR::UnboundElementType>(context, class_type_id,
element_type_id);
}
+2 -2
View File
@@ -83,8 +83,8 @@ auto GetTupleType(Context& context, llvm::ArrayRef<SemIR::InstId> type_inst_ids)
-> SemIR::TypeId;
// Returns an unbound element type.
auto GetUnboundElementType(Context& context, SemIR::InstId class_type_id,
SemIR::InstId element_type_id) -> SemIR::TypeId;
auto GetUnboundElementType(Context& context, SemIR::TypeInstId class_type_id,
SemIR::TypeInstId element_type_id) -> SemIR::TypeId;
} // namespace Carbon::Check
@@ -63,12 +63,12 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: inst25: {kind: Converted, arg0: inst21, arg1: inst15, type: type(TypeType)}
// CHECK:STDOUT: inst26: {kind: Converted, arg0: inst22, arg1: inst15, type: type(TypeType)}
// CHECK:STDOUT: inst27: {kind: Converted, arg0: inst24, arg1: inst23, type: type(TypeType)}
// CHECK:STDOUT: inst28: {kind: ReturnSlotPattern, arg0: inst24, type: type(inst23)}
// CHECK:STDOUT: inst28: {kind: ReturnSlotPattern, arg0: inst27, type: type(inst23)}
// CHECK:STDOUT: inst29: {kind: OutParamPattern, arg0: inst28, arg1: call_param1, type: type(inst23)}
// CHECK:STDOUT: inst30: {kind: ValueParam, arg0: call_param0, arg1: name1, type: type(inst15)}
// CHECK:STDOUT: inst31: {kind: SpliceBlock, arg0: inst_block4, arg1: inst17, type: type(TypeType)}
// CHECK:STDOUT: inst32: {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(inst23)}
// CHECK:STDOUT: inst33: {kind: ReturnSlot, arg0: inst24, arg1: inst32, type: type(inst23)}
// CHECK:STDOUT: inst33: {kind: ReturnSlot, arg0: inst27, arg1: inst32, type: type(inst23)}
// CHECK:STDOUT: inst34: {kind: FunctionDecl, arg0: function0, arg1: inst_block11, type: type(inst35)}
// CHECK:STDOUT: inst35: {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
// CHECK:STDOUT: inst36: {kind: StructValue, arg0: inst_block_empty, type: type(inst35)}
+2 -2
View File
@@ -77,11 +77,11 @@ fn Foo[T:! type](n: T) -> (T, ()) {
// CHECK:STDOUT: inst28: {kind: Converted, arg0: inst25, arg1: inst24, type: type(TypeType)}
// CHECK:STDOUT: inst29: {kind: TupleType, arg0: inst_block11, type: type(TypeType)}
// CHECK:STDOUT: inst30: {kind: Converted, arg0: inst27, arg1: inst29, type: type(TypeType)}
// CHECK:STDOUT: inst31: {kind: ReturnSlotPattern, arg0: inst27, type: type(symbolic_constant5)}
// CHECK:STDOUT: inst31: {kind: ReturnSlotPattern, arg0: inst30, type: type(symbolic_constant5)}
// CHECK:STDOUT: inst32: {kind: OutParamPattern, arg0: inst31, arg1: call_param1, type: type(symbolic_constant5)}
// CHECK:STDOUT: inst33: {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(symbolic_constant3)}
// CHECK:STDOUT: inst34: {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(symbolic_constant5)}
// CHECK:STDOUT: inst35: {kind: ReturnSlot, arg0: inst27, arg1: inst34, type: type(symbolic_constant5)}
// CHECK:STDOUT: inst35: {kind: ReturnSlot, arg0: inst30, arg1: inst34, type: type(symbolic_constant5)}
// CHECK:STDOUT: inst36: {kind: FunctionDecl, arg0: function0, arg1: inst_block14, type: type(inst40)}
// CHECK:STDOUT: inst37: {kind: BindSymbolicName, arg0: entity_name0, arg1: inst<none>, type: type(TypeType)}
// CHECK:STDOUT: inst38: {kind: SymbolicBindingPattern, arg0: entity_name0, type: type(TypeType)}
+4
View File
@@ -1398,6 +1398,10 @@ class FormatterImpl {
}
}
auto FormatName(TypeInstId id) -> void {
FormatName(static_cast<InstId>(id));
}
auto FormatLabel(InstBlockId id) -> void {
out_ << inst_namer_->GetLabelFor(scope_, id);
}
+2 -1
View File
@@ -179,7 +179,8 @@ using IdKind = TypeEnum<
NameScopeId,
SpecificId,
SpecificInterfaceId,
StructTypeFieldsId>;
StructTypeFieldsId,
TypeInstId>;
// clang-format on
} // namespace Carbon::SemIR
+20
View File
@@ -52,6 +52,26 @@ struct InstId : public IdBase<InstId> {
constexpr InstId InstId::InitTombstone = InstId(NoneIndex - 1);
// And InstId whose value is a type. The fact it's a type is CHECKed on
// construction, and this allows that check to be represented in the type
// system.
struct TypeInstId : public InstId {
static const TypeInstId None;
using InstId::InstId;
static constexpr auto UnsafeMake(InstId id) -> TypeInstId {
return TypeInstId(UnsafeCtor(), id);
}
private:
struct UnsafeCtor {};
explicit constexpr TypeInstId(UnsafeCtor /*unsafe*/, InstId id)
: InstId(id) {}
};
constexpr TypeInstId TypeInstId::None = TypeInstId::UnsafeMake(InstId::None);
// An ID of an instruction that is referenced absolutely by another instruction.
// This should only be used as the type of a field within a typed instruction
// class.
+2 -2
View File
@@ -17,9 +17,9 @@ struct ImplFields {
// This following members always have values and do not change.
// The type for which the impl is implementing a constraint.
InstId self_id;
TypeInstId self_id;
// The constraint that the impl implements.
InstId constraint_id;
TypeInstId constraint_id;
// The single interface to implement from `constraint_id`.
// The members are `None` if `constraint_id` isn't complete or doesn't
+32 -15
View File
@@ -8,28 +8,45 @@
namespace Carbon::SemIR {
auto TypeStore::GetTypeIdForTypeConstantId(SemIR::ConstantId constant_id) const
-> SemIR::TypeId {
// Verify that the constant value's type is `TypeType` (or an error).
static void CheckTypeOfConstantIsTypeType(File& file, ConstantId constant_id) {
CARBON_CHECK(constant_id.is_constant(),
"Canonicalizing non-constant type: {0}", constant_id);
auto type_id = file_->insts()
.Get(file_->constant_values().GetInstId(constant_id))
.type_id();
CARBON_CHECK(type_id == SemIR::TypeType::SingletonTypeId ||
constant_id == SemIR::ErrorInst::SingletonConstantId,
auto type_id =
file.insts().Get(file.constant_values().GetInstId(constant_id)).type_id();
CARBON_CHECK(type_id == TypeType::SingletonTypeId ||
constant_id == ErrorInst::SingletonConstantId,
"Forming type ID for non-type constant of type {0}",
GetAsInst(type_id));
return SemIR::TypeId::ForTypeConstant(constant_id);
file.types().GetAsInst(type_id));
}
auto TypeStore::GetTypeIdForTypeInstId(SemIR::InstId inst_id) const
-> SemIR::TypeId {
return GetTypeIdForTypeConstantId(file_->constant_values().Get(inst_id));
auto TypeStore::GetTypeIdForTypeConstantId(ConstantId constant_id) const
-> TypeId {
CheckTypeOfConstantIsTypeType(*file_, constant_id);
return TypeId::ForTypeConstant(constant_id);
}
auto TypeStore::GetInstId(TypeId type_id) const -> InstId {
return file_->constant_values().GetInstId(GetConstantId(type_id));
auto TypeStore::GetTypeIdForTypeInstId(InstId inst_id) const -> TypeId {
auto constant_id = file_->constant_values().Get(inst_id);
CheckTypeOfConstantIsTypeType(*file_, constant_id);
return TypeId::ForTypeConstant(constant_id);
}
auto TypeStore::GetTypeIdForTypeInstId(TypeInstId inst_id) const -> TypeId {
auto constant_id = file_->constant_values().Get(inst_id);
return TypeId::ForTypeConstant(constant_id);
}
auto TypeStore::GetAsTypeInstId(InstId inst_id) const -> TypeInstId {
auto constant_id = file_->constant_values().Get(inst_id);
CheckTypeOfConstantIsTypeType(*file_, constant_id);
return TypeInstId::UnsafeMake(inst_id);
}
auto TypeStore::GetInstId(TypeId type_id) const -> TypeInstId {
// The instruction for a TypeId has a value of that TypeId.
return TypeInstId::UnsafeMake(
file_->constant_values().GetInstId(GetConstantId(type_id)));
}
auto TypeStore::GetAsInst(TypeId type_id) const -> Inst {
+9 -4
View File
@@ -39,8 +39,7 @@ class TypeStore : public Yaml::Printable<TypeStore> {
// Facet values are of the same typishness as types, but are not themselves
// types, so they can not be passed here. They should be converted to a type
// through an `as type` conversion, that is, to a value of type `TypeType`.
auto GetTypeIdForTypeConstantId(SemIR::ConstantId constant_id) const
-> SemIR::TypeId;
auto GetTypeIdForTypeConstantId(ConstantId constant_id) const -> TypeId;
// Returns the type ID for an instruction whose constant value is a type
// value, i.e. it is a value of type `TypeType`.
@@ -50,10 +49,16 @@ class TypeStore : public Yaml::Printable<TypeStore> {
// so they can not be passed here. They should be converted to a type through
// an `as type` conversion, such as to a `FacetAccessType` instruction whose
// value is of type `TypeType`.
auto GetTypeIdForTypeInstId(SemIR::InstId inst_id) const -> SemIR::TypeId;
auto GetTypeIdForTypeInstId(InstId inst_id) const -> TypeId;
auto GetTypeIdForTypeInstId(TypeInstId inst_id) const -> TypeId;
// Converts an `InstId` to a `TypeInstId` of the same id value. This process
// involves checking that the type of the instruction's value is `TypeType`,
// and then this check is encoded in the type system via `TypeInstId`.
auto GetAsTypeInstId(InstId inst_id) const -> TypeInstId;
// Returns the ID of the instruction used to define the specified type.
auto GetInstId(TypeId type_id) const -> InstId;
auto GetInstId(TypeId type_id) const -> TypeInstId;
// Returns the instruction used to define the specified type.
auto GetAsInst(TypeId type_id) const -> Inst;
+11 -9
View File
@@ -81,7 +81,7 @@ struct AnyFoundationDecl {
static constexpr InstKind Kinds[] = {InstKind::AdaptDecl, InstKind::BaseDecl};
InstKind kind;
InstId foundation_type_inst_id;
TypeInstId foundation_type_inst_id;
// Kind-specific data.
AnyRawId arg1;
};
@@ -94,7 +94,7 @@ struct AdaptDecl {
.is_lowered = false});
// No type_id; this is not a value.
InstId adapted_type_inst_id;
TypeInstId adapted_type_inst_id;
};
// Takes the address of a reference expression, such as for the `&` address-of
@@ -193,7 +193,7 @@ struct ArrayType {
TypeId type_id;
InstId bound_id;
InstId element_type_inst_id;
TypeInstId element_type_inst_id;
};
// Perform a no-op conversion to a compatible type.
@@ -287,7 +287,7 @@ struct BaseDecl {
{.ir_name = "base_decl", .constant_kind = InstConstantKind::Unique});
TypeId type_id;
InstId base_type_inst_id;
TypeInstId base_type_inst_id;
ElementIndex index;
};
@@ -665,6 +665,8 @@ struct ErrorInst {
ConstantId::ForConcreteConstant(SingletonInstId);
static constexpr auto SingletonTypeId =
TypeId::ForTypeConstant(SingletonConstantId);
static constexpr auto SingletonTypeInstId =
TypeInstId::UnsafeMake(SingletonInstId);
TypeId type_id;
};
@@ -736,7 +738,7 @@ struct FacetValue {
// A `FacetType`.
TypeId type_id;
// The type that you will get if you cast this value to `type`.
InstId type_inst_id;
TypeInstId type_inst_id;
// The set of `ImplWitness` instructions for a `FacetType`. The witnesses are
// in the same order as the set of `required_interfaces` in the
// `IdentifiedFacetType` of the `FacetType` from `type_id`, so that an index
@@ -1387,7 +1389,7 @@ struct ReturnSlot {
// The function return type as originally written by the user. For diagnostics
// only; this has no semantic significance, and is not preserved across
// imports.
InstId type_inst_id;
TypeInstId type_inst_id;
// The storage that will be initialized by the function.
InstId storage_id;
@@ -1410,7 +1412,7 @@ struct ReturnSlotPattern {
// The function return type as originally written by the user. For diagnostics
// only; this has no semantic significance, and is not preserved across
// imports.
InstId type_inst_id;
TypeInstId type_inst_id;
};
// An `expr == expr` clause in a `where` expression or `require` declaration.
@@ -1782,9 +1784,9 @@ struct UnboundElementType {
TypeId type_id;
// The `ClassType` that a value of this type is an element of.
InstId class_type_inst_id;
TypeInstId class_type_inst_id;
// The type of the element.
InstId element_type_inst_id;
TypeInstId element_type_inst_id;
};
// Converts from a value expression to an ephemeral reference expression, in