| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #include "toolchain/check/pattern.h"
- #include "toolchain/check/control_flow.h"
- #include "toolchain/check/inst.h"
- #include "toolchain/check/return.h"
- #include "toolchain/check/type.h"
- namespace Carbon::Check {
- auto BeginSubpattern(Context& context) -> void {
- context.inst_block_stack().Push();
- context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
- }
- auto EndSubpatternAsExpr(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
- // will be determined later.
- AddInst(context,
- SemIR::LocIdAndInst::NoLoc<SemIR::Branch>(
- {.target_id = context.inst_blocks().AddPlaceholder()}));
- } else {
- // This single-block region will be inserted as a SpliceBlock, so we don't
- // need control flow out of it.
- }
- auto block_id = context.inst_block_stack().Pop();
- CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
- // TODO: Is it possible to validate that this region is genuinely
- // single-entry, single-exit?
- return context.sem_ir().expr_regions().Add(
- {.block_ids = context.region_stack().PopRegion(),
- .result_id = result_id});
- }
- auto EndSubpatternAsNonExpr(Context& context) -> void {
- auto block_id = context.inst_block_stack().Pop();
- CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
- CARBON_CHECK(context.region_stack().PeekRegion().size() == 1);
- CARBON_CHECK(context.inst_blocks().Get(block_id).empty());
- context.region_stack().PopAndDiscardRegion();
- }
- auto AddBindingPattern(Context& context, SemIR::LocId name_loc,
- SemIR::NameId name_id, SemIR::TypeId type_id,
- SemIR::ExprRegionId type_region_id,
- SemIR::InstKind pattern_kind, bool is_template,
- bool is_unused) -> BindingPatternInfo {
- SemIR::InstKind bind_name_kind;
- switch (pattern_kind) {
- case SemIR::InstKind::RefBindingPattern:
- bind_name_kind = SemIR::InstKind::RefBinding;
- break;
- case SemIR::InstKind::SymbolicBindingPattern:
- bind_name_kind = SemIR::InstKind::SymbolicBinding;
- break;
- case SemIR::InstKind::ValueBindingPattern:
- bind_name_kind = SemIR::InstKind::ValueBinding;
- break;
- default:
- CARBON_FATAL("pattern_kind is not a binding pattern kind");
- }
- bool is_generic = pattern_kind == SemIR::SymbolicBindingPattern::Kind;
- auto entity_name_id = context.entity_names().AddSymbolicBindingName(
- name_id, context.scope_stack().PeekNameScopeId(),
- is_generic ? context.scope_stack().AddCompileTimeBinding()
- : SemIR::CompileTimeBindIndex::None,
- is_template, is_unused || name_id == SemIR::NameId::Underscore);
- auto bind_id = AddInstInNoBlock(
- context,
- SemIR::LocIdAndInst::UncheckedLoc(
- name_loc, SemIR::AnyBinding{.kind = bind_name_kind,
- .type_id = type_id,
- .entity_name_id = entity_name_id,
- .value_id = SemIR::InstId::None}));
- auto pattern_type_id = GetPatternType(context, type_id);
- auto binding_pattern_id = AddPatternInst(
- context, SemIR::LocIdAndInst::UncheckedLoc(
- name_loc,
- SemIR::AnyBindingPattern{.kind = pattern_kind,
- .type_id = pattern_type_id,
- .entity_name_id = entity_name_id}));
- if (is_generic) {
- context.scope_stack().PushCompileTimeBinding(bind_id);
- }
- bool inserted =
- context.bind_name_map()
- .Insert(binding_pattern_id, {.bind_name_id = bind_id,
- .type_expr_region_id = type_region_id})
- .is_inserted();
- CARBON_CHECK(inserted);
- return {.pattern_id = binding_pattern_id, .bind_id = bind_id};
- }
- // Returns a VarStorage inst for the given `var` pattern. If the pattern
- // is the body of a returned var, this reuses the return parameter, and
- // otherwise it adds a new inst.
- static auto GetOrAddVarStorage(Context& context, SemIR::InstId var_pattern_id,
- bool is_returned_var) -> SemIR::InstId {
- if (is_returned_var) {
- if (auto return_param_id =
- GetReturnedVarParam(context, GetCurrentFunctionForReturn(context));
- return_param_id.has_value()) {
- return return_param_id;
- }
- }
- auto pattern = context.insts().GetWithLocId(var_pattern_id);
- return AddInstWithCleanup(
- context, pattern.loc_id,
- SemIR::VarStorage{.type_id = ExtractScrutineeType(context.sem_ir(),
- pattern.inst.type_id()),
- .pattern_id = var_pattern_id});
- }
- auto AddPatternVarStorage(Context& context, SemIR::InstBlockId pattern_block_id,
- bool is_returned_var) -> void {
- // We need to emit the VarStorage insts early, because they may be output
- // arguments for the initializer. However, we can't emit them when we emit
- // the corresponding `VarPattern`s because they're part of the pattern match,
- // not part of the pattern.
- // TODO: Find a way to do this without walking the whole pattern block.
- for (auto inst_id : context.inst_blocks().Get(pattern_block_id)) {
- if (context.insts().Is<SemIR::VarPattern>(inst_id)) {
- context.var_storage_map().Insert(
- inst_id, GetOrAddVarStorage(context, inst_id, is_returned_var));
- }
- }
- }
- auto AddParamPattern(Context& context, SemIR::LocId loc_id,
- SemIR::NameId name_id,
- SemIR::ExprRegionId type_expr_region_id,
- SemIR::TypeId type_id, bool is_ref) -> SemIR::InstId {
- const auto& binding_pattern_kind = is_ref ? SemIR::RefBindingPattern::Kind
- : SemIR::ValueBindingPattern::Kind;
- SemIR::InstId pattern_id =
- AddBindingPattern(context, loc_id, name_id, type_id, type_expr_region_id,
- binding_pattern_kind,
- /*is_template=*/false, /*is_unused=*/false)
- .pattern_id;
- const auto& param_pattern_kind =
- is_ref ? SemIR::RefParamPattern::Kind : SemIR::ValueParamPattern::Kind;
- pattern_id = AddPatternInst(
- context,
- SemIR::LocIdAndInst::UncheckedLoc(
- loc_id,
- SemIR::AnyParamPattern{
- .kind = param_pattern_kind,
- .type_id = context.insts().Get(pattern_id).type_id(),
- .subpattern_id = pattern_id,
- .index = context.full_pattern_stack().NextCallParamIndex()}));
- return pattern_id;
- }
- } // namespace Carbon::Check
|