From 6d5a883d6d079d8d734331d482e0fabae359618f Mon Sep 17 00:00:00 2001 From: Geoff Romer Date: Fri, 15 May 2026 14:10:40 -0700 Subject: [PATCH] Restructure scrutinee type handling (#7216) This change avoids situations where a variable might be either a pattern type or a scrutinee type, depending on the pattern matching state, and makes it clear that the state only affects which specific is selected. --- toolchain/check/pattern_match.cpp | 66 ++++++++++++++++--------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/toolchain/check/pattern_match.cpp b/toolchain/check/pattern_match.cpp index 81831a2566bd..4d39b2135214 100644 --- a/toolchain/check/pattern_match.cpp +++ b/toolchain/check/pattern_match.cpp @@ -210,21 +210,15 @@ class MatchContext { return value_id; } - // Performs the core logic of matching a variable pattern whose type is - // `pattern_type_id`, but returns the scrutinee that its subpattern should be - // matched with, rather than pushing it onto the worklist. This is factored - // out so it can be reused by `VarParamPattern`, which needs to do the - // pre-work of both a `VarPattern` and a `RefParamPattern`. - auto DoVarPreWorkImpl(State state, SemIR::TypeId pattern_type_id, + // Performs the core logic of matching a variable pattern whose scrutinee + // type is `scrutinee_type_id`, but returns the scrutinee that its subpattern + // should be matched with, rather than pushing it onto the worklist. This is + // factored out so it can be reused by `VarParamPattern`, which needs to do + // the pre-work of both a `VarPattern` and a `RefParamPattern`. + auto DoVarPreWorkImpl(State state, SemIR::TypeId scrutinee_type_id, SemIR::InstId scrutinee_id, WorkItem entry) const -> SemIR::InstId; - // Returns the scrutinee type from `pattern_id` when passed a `CallerState`, - // and `param_pattern_type_id` otherwise. - auto GetSpecificPatternTypeId(State state, SemIR::InstId pattern_id, - SemIR::TypeId param_pattern_type_id) - -> SemIR::TypeId; - // The stack of work to be processed. llvm::SmallVector stack_; @@ -415,34 +409,41 @@ static auto ParamKindFor(SemIR::Inst param_pattern) -> SemIR::InstKind { } } -auto MatchContext::GetSpecificPatternTypeId(State state, - SemIR::InstId pattern_id, - SemIR::TypeId param_pattern_type_id) - -> SemIR::TypeId { +// Returns the applicable specific for patterns handled in the given state. +static auto GetSpecific(State state) -> SemIR::SpecificId { CARBON_KIND_SWITCH(state) { - case CARBON_KIND(CallerState* caller): { - auto& sem_ir = context_.sem_ir(); - return ExtractScrutineeType( - sem_ir, SemIR::GetTypeOfInstInSpecific( - sem_ir, caller->callee_specific_id, pattern_id)); + case CARBON_KIND(CallerState* caller_state): { + return caller_state->callee_specific_id; + } + default: { + return SemIR::SpecificId::None; } - default: - return param_pattern_type_id; } } +// Returns the scrutinee type of `pattern_id` in the specific determined by +// `state`. +static auto GetSpecificScrutineeTypeId(const Context& context, State state, + SemIR::InstId pattern_id) + -> SemIR::TypeId { + const auto& sem_ir = context.sem_ir(); + return ExtractScrutineeType( + sem_ir, + SemIR::GetTypeOfInstInSpecific(sem_ir, GetSpecific(state), pattern_id)); +} + auto MatchContext::DoPreWork(State state, SemIR::AnyParamPattern param_pattern, SemIR::InstId scrutinee_id, WorkItem entry) -> void { AddAsPostWork(entry); - auto pattern_type_id = - GetSpecificPatternTypeId(state, entry.pattern_id, param_pattern.type_id); + auto scrutinee_type_id = + GetSpecificScrutineeTypeId(context_, state, entry.pattern_id); // If `param_pattern` is a `VarParamPattern`, match it as a `VarPattern` here, // and then as a `RefParamPattern` below. if (param_pattern.kind == SemIR::VarParamPattern::Kind) { scrutinee_id = - DoVarPreWorkImpl(state, pattern_type_id, scrutinee_id, entry); + DoVarPreWorkImpl(state, scrutinee_type_id, scrutinee_id, entry); entry.allow_unmarked_ref = true; } @@ -455,7 +456,7 @@ auto MatchContext::DoPreWork(State state, SemIR::AnyParamPattern param_pattern, caller_state->call_args.push_back( Convert(context_, SemIR::LocId(scrutinee_id), scrutinee_id, {.kind = ConversionKindFor(param_pattern, entry), - .type_id = pattern_type_id})); + .type_id = scrutinee_type_id})); } // Do not traverse farther or schedule PostWork, because the caller side // of the pattern ends here. @@ -574,10 +575,10 @@ auto MatchContext::DoPostWork(State state, auto MatchContext::DoPreWork(State state, SemIR::VarPattern var_pattern, SemIR::InstId scrutinee_id, WorkItem entry) -> void { - auto pattern_type_id = - GetSpecificPatternTypeId(state, entry.pattern_id, var_pattern.type_id); + auto scrutinee_type_id = + GetSpecificScrutineeTypeId(context_, state, entry.pattern_id); auto new_scrutinee_id = - DoVarPreWorkImpl(state, pattern_type_id, scrutinee_id, entry); + DoVarPreWorkImpl(state, scrutinee_type_id, scrutinee_id, entry); if (need_subpattern_results()) { AddAsPostWork(entry); } @@ -586,7 +587,8 @@ auto MatchContext::DoPreWork(State state, SemIR::VarPattern var_pattern, .allow_unmarked_ref = true}); } -auto MatchContext::DoVarPreWorkImpl(State state, SemIR::TypeId pattern_type_id, +auto MatchContext::DoVarPreWorkImpl(State state, + SemIR::TypeId scrutinee_type_id, SemIR::InstId scrutinee_id, WorkItem entry) const -> SemIR::InstId { CARBON_KIND_SWITCH(state) { @@ -635,7 +637,7 @@ auto MatchContext::DoVarPreWorkImpl(State state, SemIR::TypeId pattern_type_id, PendingBlock storage_block(&context_); auto storage_id = storage_block.AddInstWithCleanup( SemIR::LocId(entry.pattern_id), - {.type_id = pattern_type_id, .pattern_id = entry.pattern_id}); + {.type_id = scrutinee_type_id, .pattern_id = entry.pattern_id}); auto init_result = Initialize( context_, SemIR::LocId(entry.pattern_id), // Disable broken lint that suggests a "fix" that doesn't compile.