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

Code before:
          base_class_info->vtable_id);
      auto base_vtable_inst_block =
          context.inst_blocks().Get(context.insts()
                                        .GetAs<SemIR::Vtable>(base_vtable_id)
                                        .virtual_functions_id);
      // TODO: Avoid quadratic search. Perhaps build a map from `NameId` to the
      // elements of the top of `vtable_stack`.
      for (auto fn_decl_id : base_vtable_inst_block) {
        auto fn_decl = GetCalleeFunction(context.sem_ir(), fn_decl_id);
        const auto& fn = context.functions().Get(fn_decl.function_id);
        for (auto override_fn_decl_id :
             context.vtable_stack().PeekCurrentBlockContents()) {
          auto override_fn_decl =
              context.insts().GetAs<SemIR::FunctionDecl>(override_fn_decl_id);
          const auto& override_fn =
              context.functions().Get(override_fn_decl.function_id);
          // TODO: Validate that the overriding function's signature matches
          // that of the overridden function.
          if (override_fn.virtual_modifier ==
                  SemIR::FunctionFields::VirtualModifier::Impl &&
              override_fn.name_id == fn.name_id) {
            // TODO: This should be a semantic check rather than a syntactic
            // one. The functions should be allowed to have different signatures
            // as long as we can synthesize a suitable thunk.
            CheckFunctionTypeMatches(context, override_fn, fn,
                                     SemIR::SpecificId::Invalid, false);
            fn_decl_id = override_fn_decl_id;
          }
        }
        vtable.push_back(fn_decl_id);
      }
    }

    for (auto inst_id : context.vtable_stack().PeekCurrentBlockContents()) {
      auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
      const auto& fn = context.functions().Get(fn_decl.function_id);
      if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
        vtable.push_back(inst_id);
      }
    }
    class_info.vtable_id = context.AddInst<SemIR::Vtable>(
        node_id, {.type_id = context.GetSingletonType(
                      SemIR::VtableType::SingletonInstId),
                  .virtual_functions_id = context.inst_blocks().Add(vtable)});
  }

  return context.AddInst<SemIR::CompleteTypeWitness>(
      node_id,
      {.type_id = context.GetSingletonType(SemIR::WitnessType::SingletonInstId),
       .object_repr_id = context.GetStructType(
           AddStructTypeFields(context, struct_type_fields))});

Review comment (suggestion):
```suggestion
                                     SemIR::SpecificId::Invalid, /*check_syntax=*/false);
```

Code after:
      LoadImportRef(context, base_class_info->vtable_id);
      auto base_vtable_id = context.constant_values().GetConstantInstId(
          base_class_info->vtable_id);
      auto base_vtable_inst_block =
          context.inst_blocks().Get(context.insts()
                                        .GetAs<SemIR::Vtable>(base_vtable_id)
                                        .virtual_functions_id);
      // TODO: Avoid quadratic search. Perhaps build a map from `NameId` to the
      // elements of the top of `vtable_stack`.
      for (auto fn_decl_id : base_vtable_inst_block) {
        auto fn_decl = GetCalleeFunction(context.sem_ir(), fn_decl_id);
        const auto& fn = context.functions().Get(fn_decl.function_id);
        for (auto override_fn_decl_id :
             context.vtable_stack().PeekCurrentBlockContents()) {
          auto override_fn_decl =
              context.insts().GetAs<SemIR::FunctionDecl>(override_fn_decl_id);
          const auto& override_fn =
              context.functions().Get(override_fn_decl.function_id);
          if (override_fn.virtual_modifier ==
                  SemIR::FunctionFields::VirtualModifier::Impl &&
              override_fn.name_id == fn.name_id) {
            // TODO: Support generic base classes, rather than passing
            // `SpecificId::None`.
            CheckFunctionTypeMatches(context, override_fn, fn,
                                     SemIR::SpecificId::None,
                                     /*check_syntax=*/false);
            fn_decl_id = override_fn_decl_id;
          }
        }
        vtable.push_back(fn_decl_id);
      }
    }

    for (auto inst_id : context.vtable_stack().PeekCurrentBlockContents()) {
      auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
      const auto& fn = context.functions().Get(fn_decl.function_id);
      if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
        vtable.push_back(inst_id);
      }
    }
    class_info.vtable_id = context.AddInst<SemIR::Vtable>(
        node_id, {.type_id = context.GetSingletonType(
                      SemIR::VtableType::SingletonInstId),
                  .virtual_functions_id = context.inst_blocks().Add(vtable)});
  }

  return context.AddInst<SemIR::CompleteTypeWitness>(
      node_id,
      {.type_id = context.GetSingletonType(SemIR::WitnessType::SingletonInstId),
       .object_repr_id = context.GetStructType(
           AddStructTypeFields(context, struct_type_fields))});