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

Code before:
      // empty field.
      return GetTupleType(context, {});
    } else {
      return MakeIntType(context, node_id, SemIR::IntKind::Unsigned,
                         context.ints().Add(num_alternative_bits));
    }
  }();

  llvm::SmallVector<SemIR::StructTypeField, 1> struct_type_fields;
  struct_type_fields.push_back({
      .name_id = SemIR::NameId::ChoiceDiscriminant,
      .type_inst_id = context.types().GetInstId(discriminant_type_id),
  });
  auto fields_id =
      context.struct_type_fields().AddCanonical(struct_type_fields);
  auto choice_witness_id = AddInst(
      context, node_id,
      SemIR::CompleteTypeWitness{
          .type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
          .object_repr_type_inst_id =
              context.types().GetInstId(GetStructType(context, fields_id))});
  auto& class_info = context.classes().Get(class_id);
  class_info.complete_type_witness_id = choice_witness_id;

  auto self_type_id = class_info.self_type_id;
  auto name_scope_id = class_info.scope_id;

  auto self_struct_type_id = GetStructType(
      context, context.struct_type_fields().AddCanonical(struct_type_fields));

  for (auto [i, deferred_binding] :
       llvm::enumerate(context.choice_deferred_bindings())) {
    MakeLetBinding(context,
                   ChoiceInfo{.self_type_id = self_type_id,
                              .name_scope_id = name_scope_id,
                              .self_struct_type_id = self_struct_type_id,
                              .discriminant_type_id = discriminant_type_id,
                              .num_alternative_bits = num_alternative_bits},
                   i, deferred_binding);
  }

  // The scopes and blocks for the choice itself.
  context.inst_block_stack().Pop();
  context.decl_introducer_state_stack().Pop<Lex::TokenKind::Choice>();
  context.scope_stack().Pop();
  context.decl_name_stack().PopScope();

  FinishGenericDefinition(context, class_info.generic_id);

  context.choice_deferred_bindings().clear();
  return true;

Review comment (suggestion):
Should these be removed in favor of using `class_info` directly? They were probably being added due to invalidation, too.

Code after:
      // empty field.
      return GetTupleType(context, {});
    } else {
      return MakeIntType(context, node_id, SemIR::IntKind::Unsigned,
                         context.ints().Add(num_alternative_bits));
    }
  }();

  llvm::SmallVector<SemIR::StructTypeField, 1> struct_type_fields;
  struct_type_fields.push_back({
      .name_id = SemIR::NameId::ChoiceDiscriminant,
      .type_inst_id = context.types().GetInstId(discriminant_type_id),
  });
  auto fields_id =
      context.struct_type_fields().AddCanonical(struct_type_fields);
  auto choice_witness_id = AddInst(
      context, node_id,
      SemIR::CompleteTypeWitness{
          .type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
          .object_repr_type_inst_id =
              context.types().GetInstId(GetStructType(context, fields_id))});
  auto& class_info = context.classes().Get(class_id);
  class_info.complete_type_witness_id = choice_witness_id;

  auto self_struct_type_id = GetStructType(
      context, context.struct_type_fields().AddCanonical(struct_type_fields));

  for (auto [i, deferred_binding] :
       llvm::enumerate(context.choice_deferred_bindings())) {
    MakeLetBinding(context,
                   ChoiceInfo{.self_type_id = class_info.self_type_id,
                              .name_scope_id = class_info.scope_id,
                              .self_struct_type_id = self_struct_type_id,
                              .discriminant_type_id = discriminant_type_id,
                              .num_alternative_bits = num_alternative_bits},
                   i, deferred_binding);
  }

  // The scopes and blocks for the choice itself.
  context.inst_block_stack().Pop();
  context.decl_introducer_state_stack().Pop<Lex::TokenKind::Choice>();
  context.scope_stack().Pop();
  context.decl_name_stack().PopScope();

  FinishGenericDefinition(context, class_info.generic_id);

  context.choice_deferred_bindings().clear();
  return true;
}

auto HandleParseNode(Context& context,