Add facet type values and an instruction that produces them (#4460)

Still to do:
* Represent facet type values in a canonical form
* Produce & consume facet type values instead of interface values
* `type` should be associated with a canonical facet type value
* Support `&` on facet type values
* Type check and enforce requirements in facet types

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
This commit is contained in:
josh11b
2024-11-04 21:43:55 +00:00
committed by GitHub
co-authored by Josh L
parent 607522c7de
commit ea0b0b4b48
18 changed files with 495 additions and 253 deletions
+43 -4
View File
@@ -126,6 +126,9 @@ class EvalContext {
auto interfaces() -> const ValueStore<SemIR::InterfaceId>& {
return sem_ir().interfaces();
}
auto facet_types() -> CanonicalValueStore<SemIR::FacetTypeId>& {
return sem_ir().facet_types();
}
auto specifics() -> const SemIR::SpecificStore& {
return sem_ir().specifics();
}
@@ -1106,6 +1109,20 @@ static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc,
return SemIR::ConstantId::NotConstant;
}
// Creates a FacetType constant.
static auto MakeFacetTypeResult(Context& context,
SemIR::TypeId base_facet_type_id,
SemIR::InstBlockId requirement_block_id,
Phase phase) -> SemIR::ConstantId {
SemIR::FacetTypeId facet_type_id = context.sem_ir().facet_types().Add(
SemIR::FacetTypeInfo{.base_facet_type_id = base_facet_type_id,
.requirement_block_id = requirement_block_id});
return MakeConstantResult(context,
SemIR::FacetType{.type_id = SemIR::TypeId::TypeType,
.facet_type_id = facet_type_id},
phase);
}
// Implementation for `TryEvalInst`, wrapping `Context` with `EvalContext`.
static auto TryEvalInstInContext(EvalContext& eval_context,
SemIR::InstId inst_id, SemIR::Inst inst)
@@ -1287,6 +1304,23 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
Phase::Template);
}
case CARBON_KIND(SemIR::FacetType facet_type): {
SemIR::FacetTypeInfo info =
eval_context.facet_types().Get(facet_type.facet_type_id);
Phase phase = Phase::Template;
SemIR::TypeId base_facet_type_id =
GetConstantValue(eval_context, info.base_facet_type_id, &phase);
// TODO: process & canonicalize requirements
SemIR::InstBlockId requirement_block_id = info.requirement_block_id;
// If nothing changed, can reuse this instruction.
if (base_facet_type_id == info.base_facet_type_id &&
requirement_block_id == info.requirement_block_id) {
return MakeConstantResult(eval_context.context(), inst, phase);
}
return MakeFacetTypeResult(eval_context.context(), base_facet_type_id,
requirement_block_id, phase);
}
case CARBON_KIND(SemIR::InterfaceDecl interface_decl): {
// If the interface has generic parameters, we don't produce an interface
// type, but a callable whose return value is an interface type.
@@ -1445,10 +1479,15 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
return eval_context.GetConstantValue(typed_inst.facet_id);
}
case CARBON_KIND(SemIR::WhereExpr typed_inst): {
// TODO: This currently ignores the requirements and just produces the
// left-hand type argument to the `where`.
return eval_context.GetConstantValue(
eval_context.insts().Get(typed_inst.period_self_id).type_id());
SemIR::TypeId base_facet_type_id =
eval_context.insts().Get(typed_inst.period_self_id).type_id();
Phase phase = Phase::Template;
base_facet_type_id =
GetConstantValue(eval_context, base_facet_type_id, &phase);
SemIR::InstBlockId requirement_block_id = typed_inst.requirements_id;
// TODO: process & canonicalize requirements
return MakeFacetTypeResult(eval_context.context(), base_facet_type_id,
requirement_block_id, phase);
}
// `not true` -> `false`, `not false` -> `true`.