impl_lookup.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. witness_value_id = CheckAssociatedFunctionImplementation(
  94. context,
  95. context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
  96. value_id, self_type_id, witness_id,
  97. /*defer_thunk_definition=*/false);
  98. break;
  99. }
  100. case SemIR::AssociatedConstantDecl::Kind: {
  101. context.TODO(loc_id,
  102. "Associated constant in interface with synthesized impl");
  103. return SemIR::ErrorInst::InstId;
  104. }
  105. default:
  106. CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
  107. "Unexpected kind of associated entity {0}", decl);
  108. return SemIR::ErrorInst::InstId;
  109. }
  110. }
  111. return witness_id;
  112. }
  113. static auto LookupCopyImpl(Context& context, SemIR::LocId loc_id,
  114. SemIR::TypeId self_type_id,
  115. SemIR::SpecificInterface specific_interface)
  116. -> SemIR::InstId {
  117. auto* class_decl = TypeAsClassDecl(context, self_type_id);
  118. if (!class_decl) {
  119. // TODO: Should we also provide a `Copy` implementation for enumerations?
  120. return SemIR::InstId::None;
  121. }
  122. auto* ctor = context.clang_sema().LookupCopyingConstructor(
  123. class_decl, clang::Qualifiers::Const);
  124. if (!ctor) {
  125. // TODO: If the impl lookup failure is an error, we should produce a
  126. // diagnostic explaining why the class is not copyable.
  127. return SemIR::InstId::None;
  128. }
  129. auto ctor_id =
  130. context.clang_sema().DiagnoseUseOfOverloadedDecl(
  131. ctor, GetCppLocation(context, loc_id))
  132. ? SemIR::ErrorInst::InstId
  133. : ImportCppFunctionDecl(context, loc_id, ctor, /*num_params=*/1);
  134. if (auto ctor_decl =
  135. context.insts().TryGetAsWithId<SemIR::FunctionDecl>(ctor_id)) {
  136. CheckCppOverloadAccess(context, loc_id,
  137. clang::DeclAccessPair::make(ctor, ctor->getAccess()),
  138. ctor_decl->inst_id);
  139. } else {
  140. CARBON_CHECK(ctor_id == SemIR::ErrorInst::InstId);
  141. return SemIR::ErrorInst::InstId;
  142. }
  143. return BuildWitness(context, loc_id, self_type_id, specific_interface,
  144. {ctor_id});
  145. }
  146. auto LookupCppImpl(Context& context, SemIR::LocId loc_id,
  147. SemIR::TypeId self_type_id,
  148. SemIR::SpecificInterface specific_interface,
  149. const TypeStructure* best_impl_type_structure,
  150. SemIR::LocId best_impl_loc_id) -> SemIR::InstId {
  151. // Determine whether this is an interface that we have special knowledge of.
  152. auto& interface = context.interfaces().Get(specific_interface.interface_id);
  153. if (!context.name_scopes().IsCorePackage(interface.parent_scope_id)) {
  154. return SemIR::InstId::None;
  155. }
  156. if (!interface.name_id.AsIdentifierId().has_value()) {
  157. return SemIR::InstId::None;
  158. }
  159. if (context.identifiers().Get(interface.name_id.AsIdentifierId()) == "Copy") {
  160. return LookupCopyImpl(context, loc_id, self_type_id, specific_interface);
  161. }
  162. // TODO: Handle other interfaces.
  163. // TODO: Infer a C++ type structure and check whether it's less strict than
  164. // the best Carbon type structure.
  165. static_cast<void>(best_impl_type_structure);
  166. static_cast<void>(best_impl_loc_id);
  167. return SemIR::InstId::None;
  168. }
  169. } // namespace Carbon::Check