merge.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/check/merge.h"
  5. #include "toolchain/check/function.h"
  6. #include "toolchain/check/import_ref.h"
  7. #include "toolchain/sem_ir/typed_insts.h"
  8. namespace Carbon::Check {
  9. auto ResolvePrevInstForMerge(Context& context, Parse::NodeId node_id,
  10. SemIR::InstId prev_inst_id) -> PrevInstForMerge {
  11. PrevInstForMerge prev_inst{.inst = context.insts().Get(prev_inst_id),
  12. .is_import = false};
  13. if (auto import_ref = prev_inst.inst.TryAs<SemIR::ImportRefUsed>()) {
  14. CARBON_DIAGNOSTIC(
  15. RedeclOfUsedImport, Error,
  16. "Redeclaration of imported entity that was previously used.");
  17. CARBON_DIAGNOSTIC(UsedImportLoc, Note, "Import used here.");
  18. context.emitter()
  19. .Build(node_id, RedeclOfUsedImport)
  20. .Note(import_ref->used_id, UsedImportLoc)
  21. .Emit();
  22. } else if (!prev_inst.inst.Is<SemIR::ImportRefLoaded>()) {
  23. return prev_inst;
  24. }
  25. prev_inst.is_import = true;
  26. prev_inst.inst = context.insts().Get(
  27. context.constant_values().Get(prev_inst_id).inst_id());
  28. return prev_inst;
  29. }
  30. // Returns the instruction to consider when merging the given inst_id. Returns
  31. // nullopt if merging is infeasible and no diagnostic should be printed.
  32. static auto ResolveMergeableInst(Context& context, SemIR::InstId inst_id)
  33. -> std::optional<SemIR::Inst> {
  34. auto inst = context.insts().Get(inst_id);
  35. switch (inst.kind()) {
  36. case SemIR::ImportRefUnloaded::Kind:
  37. // Load before merging.
  38. LoadImportRef(context, inst_id, SemIR::LocId::Invalid);
  39. break;
  40. case SemIR::ImportRefUsed::Kind:
  41. // Already loaded.
  42. break;
  43. case SemIR::Namespace::Kind:
  44. // Return back the namespace directly.
  45. return inst;
  46. default:
  47. CARBON_FATAL() << "Unexpected inst kind passed to ResolveMergeableInst: "
  48. << inst;
  49. }
  50. auto const_id = context.constant_values().Get(inst_id);
  51. // TODO: Function and type declarations are constant, but `var` declarations
  52. // are non-constant and should still merge.
  53. if (!const_id.is_constant()) {
  54. return std::nullopt;
  55. }
  56. return context.insts().Get(const_id.inst_id());
  57. }
  58. auto MergeImportRef(Context& context, SemIR::InstId new_inst_id,
  59. SemIR::InstId prev_inst_id) -> void {
  60. auto new_inst = ResolveMergeableInst(context, new_inst_id);
  61. auto prev_inst = ResolveMergeableInst(context, prev_inst_id);
  62. if (!new_inst || !prev_inst) {
  63. // TODO: Once `var` declarations get an associated instruction for handling,
  64. // it might be more appropriate to return without diagnosing here, to handle
  65. // invalid declarations.
  66. context.DiagnoseDuplicateName(new_inst_id, prev_inst_id);
  67. return;
  68. }
  69. if (new_inst->kind() != prev_inst->kind()) {
  70. context.DiagnoseDuplicateName(new_inst_id, prev_inst_id);
  71. return;
  72. }
  73. switch (new_inst->kind()) {
  74. case SemIR::FunctionDecl::Kind: {
  75. auto new_fn = context.functions().Get(
  76. new_inst->As<SemIR::FunctionDecl>().function_id);
  77. auto prev_fn_id = prev_inst->As<SemIR::FunctionDecl>().function_id;
  78. // TODO: May need to "spoil" the new function to prevent it from being
  79. // emitted, since it will already be added.
  80. MergeFunctionRedecl(context, context.insts().GetLocId(new_inst_id),
  81. new_fn,
  82. /*new_is_definition=*/false, prev_fn_id,
  83. /*prev_is_imported=*/true);
  84. return;
  85. }
  86. default:
  87. context.TODO(new_inst_id, "Merging not yet supported.");
  88. return;
  89. }
  90. }
  91. } // namespace Carbon::Check