diff --git a/toolchain/check/pattern_match.cpp b/toolchain/check/pattern_match.cpp index 81bdb39eb95a..bce996edf1b9 100644 --- a/toolchain/check/pattern_match.cpp +++ b/toolchain/check/pattern_match.cpp @@ -42,19 +42,59 @@ enum class MatchKind : uint8_t { }; // The collected state of a pattern-matching operation. +// +// Conceptually, pattern matching is a recursive traversal of the pattern inst +// tree: we match a pattern inst to a scrutinee inst by converting the scrutinee +// as needed, matching any subpatterns against corresponding parts of the +// scrutinee, and assembling the results of those sub-matches to form the result +// of the whole match. +// +// This recursive traversal is implemented as a stack of work items, each +// associated with a particular pattern inst. There are two types of work items, +// PreWork and PostWork, which correspond to the work that is done before and +// after visiting an inst's subpatterns, and are handled by DoPreWork and +// DoPostWork overloads, respectively. Note that when there are no subpatterns, +// DoPreWork may push a PostWork onto the stack, or may do the post-work (if +// any) locally. +// +// DoPostWork is primarily responsible for computing the pattern's result and +// adding it to result_stack_. However, the result of matching a pattern is +// often not needed, so to avoid emitting unnecessary SemIR, it should only do +// that if need_subpattern_results() is true. +// +// The traversal behavior depends on the kind of matching being performed. In +// particular, many parts of a function signature pattern are irrelevant to the +// caller, or to the callee, in which case no work will be done in that part of +// the traversal. If an entire subpattern is known to be irrelevant in the +// current matching context, it will not be traversed at all. class MatchContext { public: - struct WorkItem : Printable { - SemIR::InstId pattern_id; + struct PreWork : Printable { // `None` when processing the callee side. SemIR::InstId scrutinee_id; + auto Print(llvm::raw_ostream& out) const -> void { + out << "{PreWork, scrutinee_id: " << scrutinee_id << "}"; + } + }; + + struct PostWork : Printable { + auto Print(llvm::raw_ostream& out) const -> void { out << "{PostWork}"; } + }; + + struct WorkItem : Printable { + SemIR::InstId pattern_id; + + std::variant work; + // If true, disables diagnostics that would otherwise require scrutinee_id // to be tagged with `ref`. Only affects caller pattern matching. bool allow_unmarked_ref = false; + auto Print(llvm::raw_ostream& out) const -> void { - out << "{pattern_id: " << pattern_id << ", scrutinee_id: " << scrutinee_id - << ", allow_unmarked_ref = " << allow_unmarked_ref << "}"; + out << "{pattern_id: " << pattern_id << ", work: "; + std::visit([&](const auto& work) { out << work; }, work); + out << ", allow_unmarked_ref: " << allow_unmarked_ref << "}"; } }; @@ -65,70 +105,85 @@ class MatchContext { SemIR::SpecificId::None) : kind_(kind), callee_specific_id_(callee_specific_id) {} - // Adds a work item to the stack. - auto AddWork(WorkItem work_item) -> void { stack_.push_back(work_item); } + // Whether the result of the work item at the top of the stack is needed. + auto need_subpattern_results() const -> bool { + return !results_stack_.empty(); + } + + // Adds `entry` to the front of the worklist. + auto AddWork(WorkItem entry) -> void { stack_.push_back(entry); } + + // Sets `entry.work` to `PostWork` and adds it to the front of the worklist. + auto AddAsPostWork(WorkItem entry) -> void { + entry.work = PostWork{}; + AddWork(entry); + } // Processes all work items on the stack. auto DoWork(Context& context) -> void; // Returns an inst block of references to all the emitted `Call` arguments. // Can only be called once, at the end of Caller pattern matching. - auto CallerResults(Context& context) && -> SemIR::InstBlockId; + auto GetCallArgs(Context& context) && -> SemIR::InstBlockId; // Returns an inst block of references to all the emitted `Call` params, // and an inst block of references to the `Call` param patterns they were // emitted to match. Can only be called once, at the end of Callee pattern // matching. - struct ParamsAndPatterns { + struct ParamBlocks { SemIR::InstBlockId call_param_patterns_id; SemIR::InstBlockId call_params_id; }; - auto CalleeResults(Context& context) && -> ParamsAndPatterns; + auto GetCallParams(Context& context) && -> ParamBlocks; // Returns the number of call parameters that have been emitted so far. auto param_count() -> int { return call_params_.size(); } ~MatchContext(); private: - // Emits the pattern-match insts necessary to match the pattern inst - // `entry.pattern_id` against the scrutinee value `entry.scrutinee_id`, and - // adds to `stack_` any work necessary to traverse into its subpatterns. This - // behavior is contingent on the kind of match being performed, as indicated - // by kind_`. For example, when performing a callee pattern match, this does - // not emit insts for patterns on the caller side. However, it still traverses - // into subpatterns if any of their descendants might emit insts. - // TODO: Require that `entry.scrutinee_id` is valid if and only if insts - // should be emitted, once we start emitting `Param` insts in the - // `ParamPattern` case. - auto EmitPatternMatch(Context& context, MatchContext::WorkItem entry) -> void; + // Dispatches `entry` to the appropriate DoWork method based on the kinds of + // `entry.pattern_id` and `entry.work`. + auto Dispatch(Context& context, WorkItem entry) -> void; - // Implementations of `EmitPatternMatch` for particular pattern inst kinds. - auto DoEmitPatternMatch(Context& context, - SemIR::AnyBindingPattern binding_pattern, - WorkItem entry) -> void; - auto DoEmitPatternMatch(Context& context, - SemIR::AnyParamPattern param_pattern, WorkItem entry) - -> void; - auto DoEmitPatternMatch(Context& context, - SemIR::ReturnSlotPattern return_slot_pattern, - WorkItem entry) -> void; - auto DoEmitPatternMatch(Context& context, SemIR::VarPattern var_pattern, - WorkItem entry) -> void; - auto DoEmitPatternMatch(Context& context, SemIR::TuplePattern tuple_pattern, - WorkItem entry) -> void; + // Do the pre-work for `entry`. `entry.work` must be a `PreWork` containing + // `scrutinee_id`, and the pattern argument must be the value of + // `entry.pattern_id` in `context`. + auto DoPreWork(Context& context, SemIR::AnyBindingPattern binding_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) -> void; + auto DoPreWork(Context& context, SemIR::AnyParamPattern param_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) -> void; + auto DoPreWork(Context& context, SemIR::ReturnSlotPattern return_slot_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) -> void; + auto DoPreWork(Context& context, SemIR::VarPattern var_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) -> void; + auto DoPreWork(Context& context, SemIR::TuplePattern tuple_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) -> void; + + // Do the post-work for `entry`. `entry.work` must be a `PostWork`, and + // the pattern argument must be the value of `entry.pattern_id` in `context`. + auto DoPostWork(Context& context, SemIR::VarPattern var_pattern, + WorkItem entry) -> void; + auto DoPostWork(Context& context, SemIR::AnyParamPattern param_pattern, + WorkItem entry) -> void; + auto DoPostWork(Context& context, SemIR::TuplePattern tuple_pattern, + WorkItem entry) -> void; // 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 when handling a `FormBindingPattern` or // `FormParamPattern` with an initializing form. - auto DoEmitVarPatternMatchImpl(Context& context, - SemIR::TypeId pattern_type_id, - WorkItem entry) const -> SemIR::InstId; + auto DoVarPreWorkImpl(Context& context, SemIR::TypeId pattern_type_id, + SemIR::InstId scrutinee_id, WorkItem entry) const + -> SemIR::InstId; // The stack of work to be processed. llvm::SmallVector stack_; + // The stack of in-progress match results. Each array in the stack represents + // a single result, which may have multiple sub-results. + ArrayStack results_stack_; + // The in-progress contents of the `Call` arguments block. This is populated // only when kind_ is Caller. llvm::SmallVector call_args_; @@ -152,18 +207,18 @@ class MatchContext { auto MatchContext::DoWork(Context& context) -> void { while (!stack_.empty()) { - EmitPatternMatch(context, stack_.pop_back_val()); + Dispatch(context, stack_.pop_back_val()); } } -auto MatchContext::CallerResults(Context& context) && -> SemIR::InstBlockId { +auto MatchContext::GetCallArgs(Context& context) && -> SemIR::InstBlockId { CARBON_CHECK(kind_ == MatchKind::Caller); auto block_id = context.inst_blocks().Add(call_args_); call_args_.clear(); return block_id; } -auto MatchContext::CalleeResults(Context& context) && -> ParamsAndPatterns { +auto MatchContext::GetCallParams(Context& context) && -> ParamBlocks { CARBON_CHECK(kind_ == MatchKind::Callee); CARBON_CHECK(call_params_.size() == call_param_patterns_.size()); auto call_param_patterns_id = context.inst_blocks().Add(call_param_patterns_); @@ -297,9 +352,10 @@ static auto ConversionKindFor(Context& context, SemIR::Inst pattern, } } -auto MatchContext::DoEmitPatternMatch(Context& context, - SemIR::AnyBindingPattern binding_pattern, - MatchContext::WorkItem entry) -> void { +auto MatchContext::DoPreWork(Context& context, + SemIR::AnyBindingPattern binding_pattern, + SemIR::InstId scrutinee_id, + MatchContext::WorkItem entry) -> void { if (kind_ == MatchKind::Caller) { CARBON_CHECK( binding_pattern.kind == SemIR::SymbolicBindingPattern::Kind, @@ -326,13 +382,13 @@ auto MatchContext::DoEmitPatternMatch(Context& context, conversion_kind = ConversionTarget::Discarded; } value_id = - Convert(context, SemIR::LocId(entry.scrutinee_id), entry.scrutinee_id, + Convert(context, SemIR::LocId(scrutinee_id), scrutinee_id, {.kind = conversion_kind, .type_id = context.insts().Get(bind_name_id).type_id()}); } else { // In a function call, conversion is handled while matching the enclosing // `*ParamPattern`. - value_id = entry.scrutinee_id; + value_id = scrutinee_id; } if (bind_name_id.has_value()) { auto bind_name = context.insts().GetAs(bind_name_id); @@ -341,6 +397,9 @@ auto MatchContext::DoEmitPatternMatch(Context& context, ReplaceInstBeforeConstantUse(context, bind_name_id, bind_name); context.inst_block_stack().AddInstId(bind_name_id); } + if (need_subpattern_results()) { + results_stack_.AppendToTop(value_id); + } } // Returns the inst kind to use for the parameter corresponding to the given @@ -378,9 +437,10 @@ static auto ParamKindFor(Context& context, SemIR::Inst param_pattern, } } -auto MatchContext::DoEmitPatternMatch(Context& context, - SemIR::AnyParamPattern param_pattern, - WorkItem entry) -> void { +auto MatchContext::DoPreWork(Context& context, + SemIR::AnyParamPattern param_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) + -> void { // If the form is initializing, match this as a `VarPattern` before matching // it as a parameter pattern. if (param_pattern.kind == SemIR::FormParamPattern::Kind) { @@ -388,31 +448,34 @@ auto MatchContext::DoEmitPatternMatch(Context& context, context.constant_values().GetInstId(param_pattern.form_id); if (context.insts().Get(form_inst_id).kind() == SemIR::InitForm::Kind) { auto new_scrutinee_id = - DoEmitVarPatternMatchImpl(context, param_pattern.type_id, entry); - entry.scrutinee_id = new_scrutinee_id; + DoVarPreWorkImpl(context, param_pattern.type_id, scrutinee_id, entry); + scrutinee_id = new_scrutinee_id; } } switch (kind_) { case MatchKind::Caller: { - CARBON_CHECK(entry.scrutinee_id.has_value()); - if (entry.scrutinee_id == SemIR::ErrorInst::InstId) { + CARBON_CHECK(scrutinee_id.has_value()); + if (scrutinee_id == SemIR::ErrorInst::InstId) { call_args_.push_back(SemIR::ErrorInst::InstId); } else { auto scrutinee_type_id = ExtractScrutineeType( context.sem_ir(), SemIR::GetTypeOfInstInSpecific( context.sem_ir(), callee_specific_id_, entry.pattern_id)); - call_args_.push_back(Convert( - context, SemIR::LocId(entry.scrutinee_id), entry.scrutinee_id, - {.kind = ConversionKindFor(context, param_pattern, entry), - .type_id = scrutinee_type_id})); + call_args_.push_back( + Convert(context, SemIR::LocId(scrutinee_id), scrutinee_id, + {.kind = ConversionKindFor(context, param_pattern, entry), + .type_id = scrutinee_type_id})); } // Do not traverse farther, because the caller side of the pattern // ends here. break; } case MatchKind::Callee: { + if (need_subpattern_results()) { + AddAsPostWork(entry); + } SemIR::AnyParam param = { .kind = ParamKindFor(context, param_pattern, entry), .type_id = @@ -424,7 +487,7 @@ auto MatchContext::DoEmitPatternMatch(Context& context, AddInst(context, SemIR::LocIdAndInst::UncheckedLoc( SemIR::LocId(entry.pattern_id), param)); AddWork({.pattern_id = param_pattern.subpattern_id, - .scrutinee_id = param_id}); + .work = PreWork{.scrutinee_id = param_id}}); call_params_.push_back(param_id); call_param_patterns_.push_back(entry.pattern_id); break; @@ -435,9 +498,16 @@ auto MatchContext::DoEmitPatternMatch(Context& context, } } -auto MatchContext::DoEmitPatternMatch( - Context& context, SemIR::ReturnSlotPattern return_slot_pattern, - WorkItem entry) -> void { +auto MatchContext::DoPostWork(Context& /*context*/, + SemIR::AnyParamPattern /*param_pattern*/, + WorkItem /*entry*/) -> void { + // No-op: the subpattern's result is this pattern's result. +} + +auto MatchContext::DoPreWork(Context& context, + SemIR::ReturnSlotPattern return_slot_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) + -> void { CARBON_CHECK(kind_ == MatchKind::Callee); auto type_id = ExtractScrutineeType(context.sem_ir(), return_slot_pattern.type_id); @@ -445,27 +515,33 @@ auto MatchContext::DoEmitPatternMatch( context, SemIR::LocId(entry.pattern_id), {.type_id = type_id, .type_inst_id = context.types().GetTypeInstId(type_id), - .storage_id = entry.scrutinee_id}); + .storage_id = scrutinee_id}); bool already_in_lookup = context.scope_stack() .LookupOrAddName(SemIR::NameId::ReturnSlot, return_slot_id) .has_value(); CARBON_CHECK(!already_in_lookup); + if (need_subpattern_results()) { + results_stack_.AppendToTop(return_slot_id); + } } -auto MatchContext::DoEmitPatternMatch(Context& context, - SemIR::VarPattern var_pattern, - WorkItem entry) -> void { +auto MatchContext::DoPreWork(Context& context, SemIR::VarPattern var_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) + -> void { auto new_scrutinee_id = - DoEmitVarPatternMatchImpl(context, var_pattern.type_id, entry); + DoVarPreWorkImpl(context, var_pattern.type_id, scrutinee_id, entry); + if (need_subpattern_results()) { + AddAsPostWork(entry); + } AddWork({.pattern_id = var_pattern.subpattern_id, - .scrutinee_id = new_scrutinee_id}); + .work = PreWork{.scrutinee_id = new_scrutinee_id}}); } -auto MatchContext::DoEmitVarPatternMatchImpl(Context& context, - SemIR::TypeId pattern_type_id, - WorkItem entry) const - -> SemIR::InstId { +auto MatchContext::DoVarPreWorkImpl(Context& context, + SemIR::TypeId pattern_type_id, + SemIR::InstId scrutinee_id, + WorkItem entry) const -> SemIR::InstId { auto storage_id = SemIR::InstId::None; switch (kind_) { case MatchKind::Callee: { @@ -486,7 +562,7 @@ auto MatchContext::DoEmitVarPatternMatchImpl(Context& context, storage_id = AddInst( context, SemIR::LocId(entry.pattern_id), {.type_id = ExtractScrutineeType(context.sem_ir(), pattern_type_id)}); - CARBON_CHECK(entry.scrutinee_id.has_value()); + CARBON_CHECK(scrutinee_id.has_value()); break; } } @@ -496,9 +572,9 @@ auto MatchContext::DoEmitVarPatternMatchImpl(Context& context, if (context.scope_stack().PeekIndex() == ScopeIndex::Package) { context.global_init().Resume(); } - if (entry.scrutinee_id.has_value()) { + if (scrutinee_id.has_value()) { auto init_id = Initialize(context, SemIR::LocId(entry.pattern_id), - storage_id, entry.scrutinee_id); + storage_id, scrutinee_id); // If we created a `TemporaryStorage` to hold the var, create a // corresponding `Temporary` to model that its initialization is complete. // TODO: If the subpattern is a binding, we may want to destroy the @@ -523,32 +599,43 @@ auto MatchContext::DoEmitVarPatternMatchImpl(Context& context, return storage_id; } -auto MatchContext::DoEmitPatternMatch(Context& context, - SemIR::TuplePattern tuple_pattern, - WorkItem entry) -> void { +auto MatchContext::DoPostWork(Context& /*context*/, + SemIR::VarPattern /*var_pattern*/, + WorkItem /*entry*/) -> void { + // No-op: the subpattern's result is this pattern's result. +} + +auto MatchContext::DoPreWork(Context& context, + SemIR::TuplePattern tuple_pattern, + SemIR::InstId scrutinee_id, WorkItem entry) + -> void { if (tuple_pattern.type_id == SemIR::ErrorInst::TypeId) { return; } auto subpattern_ids = context.inst_blocks().Get(tuple_pattern.elements_id); + if (need_subpattern_results()) { + results_stack_.PushArray(); + AddAsPostWork(entry); + } auto add_all_subscrutinees = [&](llvm::ArrayRef subscrutinee_ids) { for (auto [subpattern_id, subscrutinee_id] : llvm::reverse(llvm::zip_equal(subpattern_ids, subscrutinee_ids))) { - AddWork( - {.pattern_id = subpattern_id, .scrutinee_id = subscrutinee_id}); + AddWork({.pattern_id = subpattern_id, + .work = PreWork{.scrutinee_id = subscrutinee_id}}); } }; - if (!entry.scrutinee_id.has_value()) { + if (!scrutinee_id.has_value()) { CARBON_CHECK(kind_ == MatchKind::Callee); // If we don't have a scrutinee yet, we're still on the caller side of the // pattern, so the subpatterns don't have a scrutinee either. for (auto subpattern_id : llvm::reverse(subpattern_ids)) { - AddWork( - {.pattern_id = subpattern_id, .scrutinee_id = SemIR::InstId::None}); + AddWork({.pattern_id = subpattern_id, + .work = PreWork{.scrutinee_id = SemIR::InstId::None}}); } return; } - auto scrutinee = context.insts().GetWithLocId(entry.scrutinee_id); + auto scrutinee = context.insts().GetWithLocId(scrutinee_id); if (auto scrutinee_literal = scrutinee.inst.TryAs()) { auto subscrutinee_ids = context.inst_blocks().Get(scrutinee_literal->elements_id); @@ -568,9 +655,8 @@ auto MatchContext::DoEmitPatternMatch(Context& context, auto tuple_type_id = ExtractScrutineeType(context.sem_ir(), tuple_pattern.type_id); - auto converted_scrutinee_id = - ConvertToValueOrRefOfType(context, SemIR::LocId(entry.pattern_id), - entry.scrutinee_id, tuple_type_id); + auto converted_scrutinee_id = ConvertToValueOrRefOfType( + context, SemIR::LocId(entry.pattern_id), scrutinee_id, tuple_type_id); if (auto scrutinee_value = context.insts().TryGetAs(converted_scrutinee_id)) { add_all_subscrutinees( @@ -594,8 +680,20 @@ auto MatchContext::DoEmitPatternMatch(Context& context, add_all_subscrutinees(subscrutinee_ids); } -auto MatchContext::EmitPatternMatch(Context& context, - MatchContext::WorkItem entry) -> void { +auto MatchContext::DoPostWork(Context& context, + SemIR::TuplePattern tuple_pattern, WorkItem entry) + -> void { + auto elements_id = context.inst_blocks().Add(results_stack_.PeekArray()); + results_stack_.PopArray(); + auto tuple_value_id = + AddInst(context, SemIR::LocId(entry.pattern_id), + {.type_id = SemIR::ExtractScrutineeType( + context.sem_ir(), tuple_pattern.type_id), + .elements_id = elements_id}); + results_stack_.AppendToTop(tuple_value_id); +} + +auto MatchContext::Dispatch(Context& context, WorkItem entry) -> void { if (entry.pattern_id == SemIR::ErrorInst::InstId) { return; } @@ -608,30 +706,58 @@ auto MatchContext::EmitPatternMatch(Context& context, } }); auto pattern = context.insts().Get(entry.pattern_id); - CARBON_KIND_SWITCH(pattern) { - case CARBON_KIND_ANY(SemIR::AnyBindingPattern, any_binding_pattern): { - DoEmitPatternMatch(context, any_binding_pattern, entry); + CARBON_KIND_SWITCH(entry.work) { + case CARBON_KIND(PreWork work): { + // TODO: Require that `work.scrutinee_id` is valid if and only if insts + // should be emitted, once we start emitting `Param` insts in the + // `ParamPattern` case. + CARBON_KIND_SWITCH(pattern) { + case CARBON_KIND_ANY(SemIR::AnyBindingPattern, any_binding_pattern): { + DoPreWork(context, any_binding_pattern, work.scrutinee_id, entry); + break; + } + case CARBON_KIND_ANY(SemIR::AnyParamPattern, any_param_pattern): { + DoPreWork(context, any_param_pattern, work.scrutinee_id, entry); + break; + } + case CARBON_KIND(SemIR::ReturnSlotPattern return_slot_pattern): { + DoPreWork(context, return_slot_pattern, work.scrutinee_id, entry); + break; + } + case CARBON_KIND(SemIR::VarPattern var_pattern): { + DoPreWork(context, var_pattern, work.scrutinee_id, entry); + break; + } + case CARBON_KIND(SemIR::TuplePattern tuple_pattern): { + DoPreWork(context, tuple_pattern, work.scrutinee_id, entry); + break; + } + default: { + CARBON_FATAL("Inst kind not handled: {0}", pattern.kind()); + } + } break; } - case CARBON_KIND_ANY(SemIR::AnyParamPattern, any_param_pattern): { - DoEmitPatternMatch(context, any_param_pattern, entry); + case CARBON_KIND(PostWork _): { + CARBON_KIND_SWITCH(pattern) { + case CARBON_KIND_ANY(SemIR::AnyParamPattern, any_param_pattern): { + DoPostWork(context, any_param_pattern, entry); + break; + } + case CARBON_KIND(SemIR::VarPattern var_pattern): { + DoPostWork(context, var_pattern, entry); + break; + } + case CARBON_KIND(SemIR::TuplePattern tuple_pattern): { + DoPostWork(context, tuple_pattern, entry); + break; + } + default: { + CARBON_FATAL("Inst kind not handled: {0}", pattern.kind()); + } + } break; } - case CARBON_KIND(SemIR::ReturnSlotPattern return_slot_pattern): { - DoEmitPatternMatch(context, return_slot_pattern, entry); - break; - } - case CARBON_KIND(SemIR::VarPattern var_pattern): { - DoEmitPatternMatch(context, var_pattern, entry); - break; - } - case CARBON_KIND(SemIR::TuplePattern tuple_pattern): { - DoEmitPatternMatch(context, tuple_pattern, entry); - break; - } - default: { - CARBON_FATAL("Inst kind not handled: {0}", pattern.kind()); - } } } @@ -655,7 +781,8 @@ auto CalleePatternMatch(Context& context, for (SemIR::InstId inst_id : llvm::reverse(context.inst_blocks().Get(implicit_param_patterns_id))) { match.AddWork( - {.pattern_id = inst_id, .scrutinee_id = SemIR::InstId::None}); + {.pattern_id = inst_id, + .work = MatchContext::PreWork{.scrutinee_id = SemIR::InstId::None}}); } } match.DoWork(context); @@ -665,7 +792,8 @@ auto CalleePatternMatch(Context& context, for (SemIR::InstId inst_id : llvm::reverse(context.inst_blocks().Get(param_patterns_id))) { match.AddWork( - {.pattern_id = inst_id, .scrutinee_id = SemIR::InstId::None}); + {.pattern_id = inst_id, + .work = MatchContext::PreWork{.scrutinee_id = SemIR::InstId::None}}); } } match.DoWork(context); @@ -674,13 +802,14 @@ auto CalleePatternMatch(Context& context, for (auto return_pattern_id : context.inst_blocks().GetOrEmpty(return_patterns_id)) { match.AddWork( - {.pattern_id = return_pattern_id, .scrutinee_id = SemIR::InstId::None}); + {.pattern_id = return_pattern_id, + .work = MatchContext::PreWork{.scrutinee_id = SemIR::InstId::None}}); } match.DoWork(context); auto return_end = SemIR::CallParamIndex(match.param_count()); match.DoWork(context); - auto blocks = std::move(match).CalleeResults(context); + auto blocks = std::move(match).GetCallParams(context); return {.call_param_patterns_id = blocks.call_param_patterns_id, .call_params_id = blocks.call_params_id, .param_ranges = {implicit_end, explicit_end, return_end}}; @@ -702,7 +831,8 @@ auto CallerPatternMatch(Context& context, SemIR::SpecificId specific_id, llvm::zip_equal(return_patterns, return_arg_ids)) { if (return_arg_id.has_value()) { match.AddWork( - {.pattern_id = return_pattern_id, .scrutinee_id = return_arg_id}); + {.pattern_id = return_pattern_id, + .work = MatchContext::PreWork{.scrutinee_id = return_arg_id}}); } else { CARBON_CHECK(return_arg_ids.size() == 1, "TODO: do the match even if return_arg_id is None, so that " @@ -714,24 +844,25 @@ auto CallerPatternMatch(Context& context, SemIR::SpecificId specific_id, for (auto [arg_id, param_pattern_id] : llvm::reverse(llvm::zip_equal( arg_refs, context.inst_blocks().GetOrEmpty(param_patterns_id)))) { match.AddWork({.pattern_id = param_pattern_id, - .scrutinee_id = arg_id, + .work = MatchContext::PreWork{.scrutinee_id = arg_id}, .allow_unmarked_ref = is_operator_syntax}); } if (self_pattern_id.has_value()) { match.AddWork({.pattern_id = self_pattern_id, - .scrutinee_id = self_arg_id, + .work = MatchContext::PreWork{.scrutinee_id = self_arg_id}, .allow_unmarked_ref = true}); } match.DoWork(context); - return std::move(match).CallerResults(context); + return std::move(match).GetCallArgs(context); } auto LocalPatternMatch(Context& context, SemIR::InstId pattern_id, SemIR::InstId scrutinee_id) -> void { MatchContext match(MatchKind::Local); - match.AddWork({.pattern_id = pattern_id, .scrutinee_id = scrutinee_id}); + match.AddWork({.pattern_id = pattern_id, + .work = MatchContext::PreWork{.scrutinee_id = scrutinee_id}}); match.DoWork(context); }