Basic support for symbolic forms (#7408)

This commit is contained in:
Geoff Romer
2026-06-25 22:46:48 +00:00
committed by GitHub
parent 5aae6a1ca5
commit 8158d4ffd4
24 changed files with 836 additions and 204 deletions
+42 -10
View File
@@ -22,8 +22,15 @@ static auto AsAnyInstId(IdAndKind arg) -> InstId {
return arg.As<SemIR::AbsoluteInstId>();
}
struct ExprCategoryResult {
ExprCategory category;
InstId inner_inst_id;
};
// Returns the expression category of `inst_id`, and the ID of the innermost
// inst visited while determining that category.
static auto GetExprCategoryImpl(const File* ir, InstId inst_id)
-> ExprCategory {
-> ExprCategoryResult {
// The overall expression category if the current instruction is a value
// expression.
ExprCategory value_category = ExprCategory::Value;
@@ -34,8 +41,10 @@ static auto GetExprCategoryImpl(const File* ir, InstId inst_id)
// If this instruction kind has a fixed category, return it.
if (auto fixed_category = category_from_kind.TryAsFixedCategory()) {
return *fixed_category == ExprCategory::Value ? value_category
: *fixed_category;
return {.category = *fixed_category == ExprCategory::Value
? value_category
: *fixed_category,
.inner_inst_id = inst_id};
}
// Handle any special cases that use
@@ -107,8 +116,10 @@ static auto GetExprCategoryImpl(const File* ir, InstId inst_id)
// operand.
switch (*category_from_kind.TryAsComputedCategory()) {
case ComputedExprCategory::ValueIfHasType: {
return untyped_inst.kind().has_type() ? value_category
: ExprCategory::NotExpr;
return {.category = untyped_inst.kind().has_type()
? value_category
: ExprCategory::NotExpr,
.inner_inst_id = inst_id};
}
case ComputedExprCategory::SameAsFirstOperand: {
@@ -127,7 +138,7 @@ static auto GetExprCategoryImpl(const File* ir, InstId inst_id)
case TypedInstT::Kind: { \
auto category = handle_special_case(untyped_inst.As<TypedInstT>()); \
if (category.has_value()) { \
return *category; \
return {.category = *category, .inner_inst_id = inst_id}; \
} \
break; \
}
@@ -139,7 +150,7 @@ static auto GetExprCategoryImpl(const File* ir, InstId inst_id)
}
auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
return GetExprCategoryImpl(&file, inst_id);
return GetExprCategoryImpl(&file, inst_id).category;
}
auto FindStorageArgForInitializer(const File& sem_ir, InstId init_id,
@@ -258,11 +269,11 @@ static auto GetDecomposedFormKindForType(const File& sem_ir, TypeId type_id)
return FormInfo::Primitive;
}
auto GetFormInfo(const File& sem_ir, InstId inst_id) -> FormInfo {
auto GetFormInfo(const File& sem_ir, SemIR::InstId inst_id) -> FormInfo {
auto inst = sem_ir.insts().Get(inst_id);
ExprCategory category = GetExprCategory(sem_ir, inst_id);
if (inst.type_id() == ErrorInst::TypeId) {
auto [category, inner_inst_id] = GetExprCategoryImpl(&sem_ir, inst_id);
if (inst.type_id() == SemIR::ErrorInst::TypeId) {
// TODO: Should `GetExprCategory` do this?
category = ExprCategory::Error;
}
@@ -275,10 +286,25 @@ auto GetFormInfo(const File& sem_ir, InstId inst_id) -> FormInfo {
sem_ir.types().GetAsInst(inst.type_id()));
}
auto form_inst_id = InstId::None;
if (category == ExprCategory::Dependent) {
kind = FormInfo::Dependent;
// TODO: Generalize this logic to handle other kinds of form-dependent insts
// besides references to `:?` bindings.
auto splice = sem_ir.insts().GetAs<SpliceInst>(inner_inst_id);
auto param_action =
sem_ir.insts().GetAs<CalleePatternMatchAction>(splice.inst_id);
auto args = sem_ir.bundles().Get(param_action.args_id);
splice = sem_ir.insts().GetAs<SpliceInst>(args.pattern_id);
auto pattern = sem_ir.insts().GetAs<FormParamPatternAction>(splice.inst_id);
form_inst_id = pattern.form_id;
}
return {.kind = kind,
.category = category,
.type_id = inst.type_id(),
.constant_id = sem_ir.constant_values().Get(inst_id),
.form_inst_id = form_inst_id,
.loc_id = LocId(inst_id),
.inst_id = inst_id};
}
@@ -324,12 +350,15 @@ auto VisitTupleElementForms(const File& sem_ir, FormInfo form,
for (auto [type_inst_id, const_inst_id] :
llvm::zip_longest(element_type_inst_ids, tuple_const_inst_ids)) {
// TODO: figure out how to update the category if it's `Mixed`, and
// how to populate `form_inst_id` if the updated category is `Dependent`.
visitor({.kind = FormInfo::Primitive,
.category = form.category,
.type_id = sem_ir.types().GetTypeIdForTypeInstId(*type_inst_id),
.constant_id = const_inst_id
? sem_ir.constant_values().Get(*const_inst_id)
: ConstantId::NotConstant,
.form_inst_id = InstId::None,
.loc_id = form.loc_id,
.inst_id = InstId::None});
}
@@ -357,6 +386,8 @@ auto VisitStructElementForms(const File& sem_ir, FormInfo form,
for (auto [field, const_inst_id] :
llvm::zip_longest(fields, struct_const_inst_ids)) {
// TODO: figure out how to update the category if it's `Mixed`, and
// how to populate `form_inst_id` if the updated category is `Dependent`.
visitor(
{.kind = FormInfo::Primitive,
.category = form.category,
@@ -364,6 +395,7 @@ auto VisitStructElementForms(const File& sem_ir, FormInfo form,
.constant_id = const_inst_id
? sem_ir.constant_values().Get(*const_inst_id)
: ConstantId::NotConstant,
.form_inst_id = InstId::None,
.loc_id = form.loc_id,
.inst_id = InstId::None});
}