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

Code before:
    result = HandleParseNode(context_, Parse::Name##Id(node_id)); \
    break;                                                        \
  }
#include "toolchain/parse/node_kind.def"
    }

    if (!result) {
      CARBON_CHECK(
          unit_and_imports_->err_tracker.seen_error(),
          "HandleParseNode for `{0}` returned false without diagnosing.",
          parse_kind);
      return false;
    }
    traversal.Handle(parse_kind);
  }
  return true;
}

auto CheckUnit::CheckRequiredDeclarations() -> void {
  for (const auto& function : context_.functions().array_ref()) {
    if (!function.first_owning_decl_id.has_value() &&
        function.extern_library_id == context_.sem_ir().library_id()) {
      // TODO: add condition function.package == context_.sem_ir().package_id()
      CARBON_DIAGNOSTIC(MissingDeclarationInApi, Error,
                        "no owning function declaration or definition found "
                        "for declaration in non-owning file");
      emitter_.Emit(function.non_owning_decl_id, MissingDeclarationInApi);
    }
  }
}

auto CheckUnit::CheckRequiredDefinitions() -> void {
  CARBON_DIAGNOSTIC(MissingDefinitionInImpl, Error,
                    "no definition found for declaration in impl file");
  // Note that more required definitions can be added during this loop.
  for (size_t i = 0; i != context_.definitions_required().size(); ++i) {
    SemIR::InstId decl_inst_id = context_.definitions_required()[i];
    SemIR::Inst decl_inst = context_.insts().Get(decl_inst_id);
    CARBON_KIND_SWITCH(context_.insts().Get(decl_inst_id)) {
      case CARBON_KIND(SemIR::ClassDecl class_decl): {
        if (!context_.classes().Get(class_decl.class_id).is_defined()) {
          emitter_.Emit(decl_inst_id, MissingDefinitionInImpl);
        }
        break;
      }
      case CARBON_KIND(SemIR::FunctionDecl function_decl): {
        if (context_.functions().Get(function_decl.function_id).definition_id ==
            SemIR::InstId::None) {
          emitter_.Emit(decl_inst_id, MissingDefinitionInImpl);
        }
        break;

Review comment (suggestion):
```suggestion
                        "owning declaration required for non-owning declaration");
```

Phrasing suggestion, trying to tinker to be more succinct. Note we talk about definitions as a subtype of declaration; either a forward declaration or definition would be the precise terms we'd use, but both are "owning declarations".

Also, suggesting to drop "function" because we'll want to use this same diagnostic for other entities. We only have non-owning functions right now, but we should end up with similar for classes and so on.

Code after:
    bool result;
    auto parse_kind = context_.parse_tree().node_kind(node_id);
    switch (parse_kind) {
#define CARBON_PARSE_NODE_KIND(Name)                              \
  case Parse::NodeKind::Name: {                                   \
    result = HandleParseNode(context_, Parse::Name##Id(node_id)); \
    break;                                                        \
  }
#include "toolchain/parse/node_kind.def"
    }

    if (!result) {
      CARBON_CHECK(
          unit_and_imports_->err_tracker.seen_error(),
          "HandleParseNode for `{0}` returned false without diagnosing.",
          parse_kind);
      return false;
    }
    traversal.Handle(parse_kind);
  }
  return true;
}

auto CheckUnit::CheckRequiredDeclarations() -> void {
  for (const auto& function : context_.functions().array_ref()) {
    if (!function.first_owning_decl_id.has_value() &&
        function.extern_library_id == context_.sem_ir().library_id()) {
      auto function_loc_id =
          context_.insts().GetLocId(function.non_owning_decl_id);
      CARBON_CHECK(function_loc_id.is_import_ir_inst_id());
      auto import_ir_id = context_.sem_ir()
                              .import_ir_insts()
                              .Get(function_loc_id.import_ir_inst_id())
                              .ir_id;
      auto& import_ir = context_.import_irs().Get(import_ir_id);
      if (import_ir.sem_ir->package_id().has_value() !=
          context_.sem_ir().package_id().has_value()) {
        continue;
      }

      CARBON_DIAGNOSTIC(
          MissingOwningDeclarationInApi, Error,
          "owning declaration required for non-owning declaration");
      if (!import_ir.sem_ir->package_id().has_value() &&
          !context_.sem_ir().package_id().has_value()) {
        emitter_.Emit(function.non_owning_decl_id,
                      MissingOwningDeclarationInApi);
        continue;
      }

      if (import_ir.sem_ir->identifiers().Get(