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.
This commit is contained in:
Geoff Romer
2026-05-15 21:10:40 +00:00
committed by GitHub
parent ed1a949b47
commit 6d5a883d6d
+34 -32
View File
@@ -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<WorkItem> 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::VarStorage>(
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.