impl_lookup.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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/cpp/impl_lookup.h"
  5. #include "clang/Sema/Sema.h"
  6. #include "toolchain/base/kind_switch.h"
  7. #include "toolchain/check/cpp/import.h"
  8. #include "toolchain/check/cpp/location.h"
  9. #include "toolchain/check/cpp/overload_resolution.h"
  10. #include "toolchain/check/impl.h"
  11. #include "toolchain/check/impl_lookup.h"
  12. #include "toolchain/check/import_ref.h"
  13. #include "toolchain/check/inst.h"
  14. #include "toolchain/check/type.h"
  15. #include "toolchain/sem_ir/ids.h"
  16. #include "toolchain/sem_ir/typed_insts.h"
  17. namespace Carbon::Check {
  18. // If the given type is a C++ class type, returns the corresponding class
  19. // declaration. Otherwise returns nullptr.
  20. // TODO: Handle qualified types.
  21. static auto TypeAsClassDecl(Context& context, SemIR::TypeId type_id)
  22. -> clang::CXXRecordDecl* {
  23. auto class_type = context.types().TryGetAs<SemIR::ClassType>(type_id);
  24. if (!class_type) {
  25. // Not a class.
  26. return nullptr;
  27. }
  28. SemIR::NameScopeId class_scope_id =
  29. context.classes().Get(class_type->class_id).scope_id;
  30. if (!class_scope_id.has_value()) {
  31. return nullptr;
  32. }
  33. const auto& scope = context.name_scopes().Get(class_scope_id);
  34. auto decl_id = scope.clang_decl_context_id();
  35. if (!decl_id.has_value()) {
  36. return nullptr;
  37. }
  38. return dyn_cast<clang::CXXRecordDecl>(
  39. context.clang_decls().Get(decl_id).key.decl);
  40. }
  41. // Builds a witness that the given type implements the given interface,
  42. // populating it with the specified set of values. Returns a corresponding
  43. // lookup result. Produces a diagnostic and returns `None` if the specified
  44. // values aren't suitable for the interface.
  45. static auto BuildWitness(Context& context, SemIR::LocId loc_id,
  46. SemIR::TypeId self_type_id,
  47. SemIR::SpecificInterface specific_interface,
  48. llvm::ArrayRef<SemIR::InstId> values)
  49. -> SemIR::InstId {
  50. const auto& interface =
  51. context.interfaces().Get(specific_interface.interface_id);
  52. auto assoc_entities =
  53. context.inst_blocks().GetOrEmpty(interface.associated_entities_id);
  54. if (assoc_entities.size() != values.size()) {
  55. context.TODO(loc_id, ("Unsupported definition of interface " +
  56. context.names().GetFormatted(interface.name_id))
  57. .str());
  58. return SemIR::ErrorInst::InstId;
  59. }
  60. // Prepare an empty witness table.
  61. auto witness_table_id =
  62. context.inst_blocks().AddUninitialized(assoc_entities.size());
  63. auto witness_table = context.inst_blocks().GetMutable(witness_table_id);
  64. for (auto& witness_value_id : witness_table) {
  65. witness_value_id = SemIR::InstId::ImplWitnessTablePlaceholder;
  66. }
  67. // Build a witness. We use an `ImplWitness` with an `impl_id` of `None` to
  68. // represent a synthesized witness.
  69. // TODO: Stop using `ImplWitnessTable` here and add a distinct instruction
  70. // that doesn't contain an `InstId` and supports deduplication.
  71. auto witness_table_inst_id = AddInst<SemIR::ImplWitnessTable>(
  72. context, loc_id,
  73. {.elements_id = witness_table_id, .impl_id = SemIR::ImplId::None});
  74. auto witness_id = AddInst<SemIR::ImplWitness>(
  75. context, loc_id,
  76. {.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
  77. .witness_table_id = witness_table_inst_id,
  78. .specific_id = SemIR::SpecificId::None});
  79. // Fill in the witness table.
  80. for (const auto& [assoc_entity_id, value_id, witness_value_id] :
  81. llvm::zip_equal(assoc_entities, values, witness_table)) {
  82. LoadImportRef(context, assoc_entity_id);
  83. auto decl_id =
  84. context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
  85. context.sem_ir(), specific_interface.specific_id, assoc_entity_id));
  86. CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
  87. auto decl = context.insts().Get(decl_id);
  88. CARBON_KIND_SWITCH(decl) {
  89. case CARBON_KIND(SemIR::StructValue struct_value): {
  90. if (struct_value.type_id == SemIR::ErrorInst::TypeId) {
  91. return SemIR::ErrorInst::InstId;
  92. }
  93. // TODO: If a thunk is needed, this will build a different value each
  94. // time it's called, so we won't properly deduplicate repeated
  95. // witnesses.
  96. witness_value_id = CheckAssociatedFunctionImplementation(
  97. context,
  98. context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
  99. value_id, self_type_id, witness_id,
  100. /*defer_thunk_definition=*/false);
  101. break;
  102. }
  103. case SemIR::AssociatedConstantDecl::Kind: {
  104. context.TODO(loc_id,
  105. "Associated constant in interface with synthesized impl");
  106. return SemIR::ErrorInst::InstId;
  107. }
  108. default:
  109. CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
  110. "Unexpected kind of associated entity {0}", decl);
  111. return SemIR::ErrorInst::InstId;
  112. }
  113. }
  114. return witness_id;
  115. }
  116. static auto LookupCopyImpl(Context& context, SemIR::LocId loc_id,
  117. SemIR::TypeId self_type_id,
  118. SemIR::SpecificInterface specific_interface)
  119. -> SemIR::InstId {
  120. auto* class_decl = TypeAsClassDecl(context, self_type_id);
  121. if (!class_decl) {
  122. // TODO: Should we also provide a `Copy` implementation for enumerations?
  123. return SemIR::InstId::None;
  124. }
  125. auto* ctor = context.clang_sema().LookupCopyingConstructor(
  126. class_decl, clang::Qualifiers::Const);
  127. if (!ctor) {
  128. // TODO: If the impl lookup failure is an error, we should produce a
  129. // diagnostic explaining why the class is not copyable.
  130. return SemIR::InstId::None;
  131. }
  132. auto ctor_id =
  133. context.clang_sema().DiagnoseUseOfOverloadedDecl(
  134. ctor, GetCppLocation(context, loc_id))
  135. ? SemIR::ErrorInst::InstId
  136. : ImportCppFunctionDecl(context, loc_id, ctor, /*num_params=*/1);
  137. if (auto ctor_decl =
  138. context.insts().TryGetAsWithId<SemIR::FunctionDecl>(ctor_id)) {
  139. CheckCppOverloadAccess(context, loc_id,
  140. clang::DeclAccessPair::make(ctor, ctor->getAccess()),
  141. ctor_decl->inst_id);
  142. } else {
  143. CARBON_CHECK(ctor_id == SemIR::ErrorInst::InstId);
  144. return SemIR::ErrorInst::InstId;
  145. }
  146. return BuildWitness(context, loc_id, self_type_id, specific_interface,
  147. {ctor_id});
  148. }
  149. auto LookupCppImpl(Context& context, SemIR::LocId loc_id,
  150. SemIR::TypeId self_type_id,
  151. SemIR::SpecificInterface specific_interface,
  152. const TypeStructure* best_impl_type_structure,
  153. SemIR::LocId best_impl_loc_id) -> SemIR::InstId {
  154. // Determine whether this is an interface that we have special knowledge of.
  155. auto& interface = context.interfaces().Get(specific_interface.interface_id);
  156. if (!context.name_scopes().IsCorePackage(interface.parent_scope_id)) {
  157. return SemIR::InstId::None;
  158. }
  159. if (!interface.name_id.AsIdentifierId().has_value()) {
  160. return SemIR::InstId::None;
  161. }
  162. if (context.identifiers().Get(interface.name_id.AsIdentifierId()) == "Copy") {
  163. return LookupCopyImpl(context, loc_id, self_type_id, specific_interface);
  164. }
  165. // TODO: Handle other interfaces.
  166. // TODO: Infer a C++ type structure and check whether it's less strict than
  167. // the best Carbon type structure.
  168. static_cast<void>(best_impl_type_structure);
  169. static_cast<void>(best_impl_loc_id);
  170. return SemIR::InstId::None;
  171. }
  172. } // namespace Carbon::Check