mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 11:21:05 +01:00
Restructure handling of expressions in patterns (#7445)
Instead of maintaining a stack of pending subpatterns which might or might not contain expressions, we mark non-nesting regions during pattern handling that might contain an expression. The implementation remains largely the same; the difference is that callers are expected to end a pending expression region as soon as possible, rather than wait for the end of the subpattern. This makes it possible to emit non-pattern insts during pattern handling, without the risk that they will get caught in a pending expression region further up the stack.
This commit is contained in:
@@ -17,14 +17,14 @@
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
auto BeginSubpattern(Context& context) -> void {
|
||||
auto BeginExprRegionForPattern(Context& context) -> void {
|
||||
context.inst_block_stack().Push();
|
||||
// TODO: This allocates an InstBlockId even in the case where the pattern has
|
||||
// no associated expression. Find a way to avoid this.
|
||||
context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
|
||||
}
|
||||
|
||||
static auto PopSubpatternExpr(Context& context, SemIR::InstId result_id)
|
||||
static auto PopExprRegion(Context& context, SemIR::InstId result_id)
|
||||
-> SemIR::ExprRegionId {
|
||||
if (context.region_stack().PeekRegion().size() > 1) {
|
||||
// End the exit block with a branch to a successor block, whose contents
|
||||
@@ -46,16 +46,16 @@ static auto PopSubpatternExpr(Context& context, SemIR::InstId result_id)
|
||||
.result_id = result_id});
|
||||
}
|
||||
|
||||
auto ConsumeSubpatternExpr(Context& context, SemIR::InstId result_id)
|
||||
auto ConsumeExprRegionForPattern(Context& context, SemIR::InstId result_id)
|
||||
-> SemIR::ExprRegionId {
|
||||
auto region_id = PopSubpatternExpr(context, result_id);
|
||||
auto region_id = PopExprRegion(context, result_id);
|
||||
// Push an empty, unreachable region so that we can later detect the region
|
||||
// has been consumed.
|
||||
context.region_stack().PushUnreachableRegion();
|
||||
return region_id;
|
||||
}
|
||||
|
||||
auto EndEmptySubpattern(Context& context) -> void {
|
||||
auto EndEmptyExprRegionForPattern(Context& context) -> void {
|
||||
if (!context.region_stack().PeekRegion().empty()) {
|
||||
CARBON_CHECK(context.inst_block_stack().PeekCurrentBlockContents().empty());
|
||||
auto block_id = context.inst_block_stack().Pop();
|
||||
@@ -65,13 +65,13 @@ auto EndEmptySubpattern(Context& context) -> void {
|
||||
context.region_stack().PopAndDiscardRegion();
|
||||
}
|
||||
|
||||
auto EndSubpattern(Context& context, NodeStack& node_stack) -> void {
|
||||
auto EndExprRegionForPattern(Context& context, NodeStack& node_stack) -> void {
|
||||
auto [node_id, maybe_expr_id] =
|
||||
node_stack.PopWithNodeIdIf<Parse::NodeCategory::Expr>();
|
||||
if (maybe_expr_id) {
|
||||
// We formed an expression, not a pattern, so convert it to an expression
|
||||
// pattern now.
|
||||
auto expr_region_id = PopSubpatternExpr(context, *maybe_expr_id);
|
||||
auto expr_region_id = PopExprRegion(context, *maybe_expr_id);
|
||||
auto pattern_type_id =
|
||||
GetPatternType(context, context.insts().Get(*maybe_expr_id).type_id());
|
||||
node_stack.Push(node_id, AddInst<SemIR::ExprPattern>(
|
||||
@@ -81,10 +81,16 @@ auto EndSubpattern(Context& context, NodeStack& node_stack) -> void {
|
||||
} else {
|
||||
// The expression region should have been consumed when forming the pattern
|
||||
// instruction, so should now effectively be empty.
|
||||
EndEmptySubpattern(context);
|
||||
EndEmptyExprRegionForPattern(context);
|
||||
}
|
||||
}
|
||||
|
||||
auto MakeEmptyRegion(Context& context, SemIR::InstId result_id)
|
||||
-> SemIR::ExprRegionId {
|
||||
return context.sem_ir().expr_regions().Add(
|
||||
{.block_ids = {SemIR::InstBlockId::Empty}, .result_id = result_id});
|
||||
}
|
||||
|
||||
auto AddBindingEntityName(Context& context, SemIR::NameId name_id,
|
||||
SemIR::InstId form_id, bool is_unused,
|
||||
BindingPhase phase) -> SemIR::EntityNameId {
|
||||
|
||||
Reference in New Issue
Block a user