Repository: carbon-language/carbon-lang
File: toolchain/check/handle_let_and_var.cpp (C++)

Code before:
// is the body of a returned var, this reuses the return slot, and otherwise it
// adds a new inst.
static auto GetOrAddStorage(Context& context, SemIR::InstId pattern_id)
    -> SemIR::InstId {
  if (context.decl_introducer_state_stack().innermost().modifier_set.HasAnyOf(
          KeywordModifierSet::Returned)) {
    auto& function = GetCurrentFunctionForReturn(context);
    auto return_info =
        SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
    if (return_info.has_return_slot()) {
      return GetCurrentReturnSlot(context);
    }
  }
  auto pattern = context.insts().GetWithLocId(pattern_id);
  auto subpattern =
      context.insts().Get(pattern.inst.As<SemIR::VarPattern>().subpattern_id);

  // Try to populate name_id on a best-effort basis.
  auto name_id = SemIR::NameId::Invalid;
  if (auto binding_pattern = subpattern.TryAs<SemIR::BindingPattern>()) {
    name_id =
        context.entity_names().Get(binding_pattern->entity_name_id).name_id;
  }
  return context.AddInst(SemIR::LocIdAndInst::UncheckedLoc(
      pattern.loc_id, SemIR::VarStorage{.type_id = subpattern.type_id(),
                                        .pretty_name_id = name_id}));
}

auto HandleParseNode(Context& context, Parse::VariablePatternId node_id)
    -> bool {
  auto subpattern_id = SemIR::InstId::Invalid;
  if (context.node_stack().PeekIs(Parse::NodeKind::TuplePattern)) {
    context.node_stack().PopAndIgnore();
    CARBON_CHECK(
        context.node_stack().PeekIs(Parse::NodeKind::TuplePatternStart));
    context.node_stack().PopAndIgnore();
    context.inst_block_stack().PopAndDiscard();
    context.TODO(node_id, "tuple pattern in let/var");
    subpattern_id = SemIR::ErrorInst::SingletonInstId;
  } else {
    subpattern_id = context.node_stack().PopPattern();
  }
  auto type_id = context.insts().Get(subpattern_id).type_id();

  auto pattern_id = context.AddPatternInst<SemIR::VarPattern>(
      node_id, {.type_id = type_id, .subpattern_id = subpattern_id});
  context.node_stack().Push(node_id, pattern_id);
  return true;
}

// Handle the end of the full-pattern of a let/var declaration (before the

Review comment (bug):
What is the difference between the pattern and subpattern types? (Or, what fails/breaks without this?)

Code after:
// Returns a VarStorage inst for the given pattern. If the pattern
// is the body of a returned var, this reuses the return slot, and otherwise it
// adds a new inst.
static auto GetOrAddStorage(Context& context, SemIR::InstId pattern_id)
    -> SemIR::InstId {
  if (context.decl_introducer_state_stack().innermost().modifier_set.HasAnyOf(
          KeywordModifierSet::Returned)) {
    auto& function = GetCurrentFunctionForReturn(context);
    auto return_info =
        SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
    if (return_info.has_return_slot()) {
      return GetCurrentReturnSlot(context);
    }
  }
  auto pattern = context.insts().GetWithLocId(pattern_id);
  auto subpattern =
      context.insts().Get(pattern.inst.As<SemIR::VarPattern>().subpattern_id);

  // Try to populate name_id on a best-effort basis.
  auto name_id = SemIR::NameId::Invalid;
  if (auto binding_pattern = subpattern.TryAs<SemIR::BindingPattern>()) {
    name_id =
        context.entity_names().Get(binding_pattern->entity_name_id).name_id;
  }
  return context.AddInst(SemIR::LocIdAndInst::UncheckedLoc(
      pattern.loc_id, SemIR::VarStorage{.type_id = pattern.inst.type_id(),
                                        .pretty_name_id = name_id}));
}

auto HandleParseNode(Context& context, Parse::VariablePatternId node_id)
    -> bool {
  auto subpattern_id = SemIR::InstId::Invalid;
  if (context.node_stack().PeekIs(Parse::NodeKind::TuplePattern)) {
    context.node_stack().PopAndIgnore();
    CARBON_CHECK(
        context.node_stack().PeekIs(Parse::NodeKind::TuplePatternStart));
    context.node_stack().PopAndIgnore();
    context.inst_block_stack().PopAndDiscard();
    context.TODO(node_id, "tuple pattern in let/var");
    subpattern_id = SemIR::ErrorInst::SingletonInstId;
  } else {
    subpattern_id = context.node_stack().PopPattern();
  }
  auto type_id = context.insts().Get(subpattern_id).type_id();

  auto pattern_id = context.AddPatternInst<SemIR::VarPattern>(
      node_id, {.type_id = type_id, .subpattern_id = subpattern_id});
  context.node_stack().Push(node_id, pattern_id);
  return true;
}