class.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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/class.h"
  5. #include "toolchain/check/context.h"
  6. #include "toolchain/check/eval.h"
  7. #include "toolchain/check/function.h"
  8. #include "toolchain/check/import_ref.h"
  9. #include "toolchain/check/inst.h"
  10. #include "toolchain/check/type.h"
  11. #include "toolchain/parse/node_ids.h"
  12. namespace Carbon::Check {
  13. auto TryGetAsClass(Context& context, SemIR::TypeId type_id) -> SemIR::Class* {
  14. auto class_type = context.types().TryGetAs<SemIR::ClassType>(type_id);
  15. if (!class_type) {
  16. return nullptr;
  17. }
  18. return &context.classes().Get(class_type->class_id);
  19. }
  20. auto SetClassSelfType(Context& context, SemIR::ClassId class_id) -> void {
  21. auto& class_info = context.classes().Get(class_id);
  22. auto specific_id = context.generics().GetSelfSpecific(class_info.generic_id);
  23. class_info.self_type_id = GetClassType(context, class_id, specific_id);
  24. }
  25. auto StartClassDefinition(Context& context, SemIR::Class& class_info,
  26. SemIR::InstId definition_id) -> void {
  27. // Track that this declaration is the definition.
  28. CARBON_CHECK(!class_info.has_definition_started());
  29. class_info.definition_id = definition_id;
  30. class_info.scope_id = context.name_scopes().Add(
  31. definition_id, SemIR::NameId::None, class_info.parent_scope_id);
  32. // Introduce `Self`.
  33. context.name_scopes().AddRequiredName(
  34. class_info.scope_id, SemIR::NameId::SelfType,
  35. context.types().GetInstId(class_info.self_type_id));
  36. }
  37. // Checks that the specified finished adapter definition is valid and builds and
  38. // returns a corresponding complete type witness instruction.
  39. static auto CheckCompleteAdapterClassType(
  40. Context& context, Parse::NodeId node_id, SemIR::ClassId class_id,
  41. llvm::ArrayRef<SemIR::InstId> field_decls,
  42. llvm::ArrayRef<SemIR::InstId> body) -> SemIR::InstId {
  43. const auto& class_info = context.classes().Get(class_id);
  44. if (class_info.base_id.has_value()) {
  45. CARBON_DIAGNOSTIC(AdaptWithBase, Error, "adapter with base class");
  46. CARBON_DIAGNOSTIC(AdaptWithBaseHere, Note, "`base` declaration is here");
  47. context.emitter()
  48. .Build(class_info.adapt_id, AdaptWithBase)
  49. .Note(class_info.base_id, AdaptWithBaseHere)
  50. .Emit();
  51. return SemIR::ErrorInst::InstId;
  52. }
  53. if (!field_decls.empty()) {
  54. CARBON_DIAGNOSTIC(AdaptWithFields, Error, "adapter with fields");
  55. CARBON_DIAGNOSTIC(AdaptWithFieldHere, Note,
  56. "first field declaration is here");
  57. context.emitter()
  58. .Build(class_info.adapt_id, AdaptWithFields)
  59. .Note(field_decls.front(), AdaptWithFieldHere)
  60. .Emit();
  61. return SemIR::ErrorInst::InstId;
  62. }
  63. for (auto inst_id : body) {
  64. if (auto function_decl =
  65. context.insts().TryGetAs<SemIR::FunctionDecl>(inst_id)) {
  66. auto& function = context.functions().Get(function_decl->function_id);
  67. if (function.virtual_modifier ==
  68. SemIR::Function::VirtualModifier::Virtual) {
  69. CARBON_DIAGNOSTIC(AdaptWithVirtual, Error,
  70. "adapter with virtual function");
  71. CARBON_DIAGNOSTIC(AdaptWithVirtualHere, Note,
  72. "first virtual function declaration is here");
  73. context.emitter()
  74. .Build(class_info.adapt_id, AdaptWithVirtual)
  75. .Note(inst_id, AdaptWithVirtualHere)
  76. .Emit();
  77. return SemIR::ErrorInst::InstId;
  78. }
  79. }
  80. }
  81. // The object representation of the adapter is the object representation
  82. // of the adapted type.
  83. auto adapted_type_id =
  84. class_info.GetAdaptedType(context.sem_ir(), SemIR::SpecificId::None);
  85. auto object_repr_id = context.types().GetObjectRepr(adapted_type_id);
  86. return AddInst<SemIR::CompleteTypeWitness>(
  87. context, node_id,
  88. {.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
  89. // TODO: Use InstId from the adapt declaration.
  90. .object_repr_type_inst_id = context.types().GetInstId(object_repr_id)});
  91. }
  92. static auto AddStructTypeFields(
  93. Context& context,
  94. llvm::SmallVector<SemIR::StructTypeField>& struct_type_fields,
  95. llvm::ArrayRef<SemIR::InstId> field_decls) -> SemIR::StructTypeFieldsId {
  96. for (auto field_decl_id : field_decls) {
  97. auto field_decl = context.insts().GetAs<SemIR::FieldDecl>(field_decl_id);
  98. field_decl.index =
  99. SemIR::ElementIndex{static_cast<int>(struct_type_fields.size())};
  100. ReplaceInstPreservingConstantValue(context, field_decl_id, field_decl);
  101. if (field_decl.type_id == SemIR::ErrorInst::TypeId) {
  102. struct_type_fields.push_back(
  103. {.name_id = field_decl.name_id,
  104. .type_inst_id = SemIR::ErrorInst::TypeInstId});
  105. continue;
  106. }
  107. auto unbound_element_type =
  108. context.sem_ir().types().GetAs<SemIR::UnboundElementType>(
  109. field_decl.type_id);
  110. struct_type_fields.push_back(
  111. {.name_id = field_decl.name_id,
  112. .type_inst_id = unbound_element_type.element_type_inst_id});
  113. }
  114. auto fields_id =
  115. context.struct_type_fields().AddCanonical(struct_type_fields);
  116. return fields_id;
  117. }
  118. // Builds and returns a vtable for the current class. Assumes that the virtual
  119. // functions for the class are listed as the top element of the `vtable_stack`.
  120. static auto BuildVtable(Context& context, Parse::NodeId node_id,
  121. SemIR::InstId base_vtable_id,
  122. llvm::ArrayRef<SemIR::InstId> vtable_contents)
  123. -> SemIR::InstId {
  124. llvm::SmallVector<SemIR::InstId> vtable;
  125. if (base_vtable_id.has_value()) {
  126. LoadImportRef(context, base_vtable_id);
  127. auto canonical_base_vtable_id =
  128. context.constant_values().GetConstantInstId(base_vtable_id);
  129. if (canonical_base_vtable_id == SemIR::ErrorInst::InstId) {
  130. return SemIR::ErrorInst::InstId;
  131. }
  132. auto base_vtable_inst_block = context.inst_blocks().Get(
  133. context.insts()
  134. .GetAs<SemIR::Vtable>(canonical_base_vtable_id)
  135. .virtual_functions_id);
  136. // TODO: Avoid quadratic search. Perhaps build a map from `NameId` to the
  137. // elements of the top of `vtable_stack`.
  138. for (auto fn_decl_id : base_vtable_inst_block) {
  139. auto fn_decl = GetCalleeFunction(context.sem_ir(), fn_decl_id);
  140. auto& fn = context.functions().Get(fn_decl.function_id);
  141. for (auto override_fn_decl_id : vtable_contents) {
  142. auto override_fn_decl =
  143. context.insts().GetAs<SemIR::FunctionDecl>(override_fn_decl_id);
  144. const auto& override_fn =
  145. context.functions().Get(override_fn_decl.function_id);
  146. if (override_fn.virtual_modifier ==
  147. SemIR::FunctionFields::VirtualModifier::Impl &&
  148. override_fn.name_id == fn.name_id) {
  149. // TODO: Support generic base classes, rather than passing
  150. // `SpecificId::None`.
  151. CheckFunctionTypeMatches(context, override_fn, fn,
  152. SemIR::SpecificId::None,
  153. /*check_syntax=*/false,
  154. /*check_self=*/false);
  155. fn_decl_id = override_fn_decl_id;
  156. }
  157. }
  158. fn.virtual_index = vtable.size();
  159. vtable.push_back(fn_decl_id);
  160. }
  161. }
  162. for (auto inst_id : vtable_contents) {
  163. auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
  164. auto& fn = context.functions().Get(fn_decl.function_id);
  165. if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
  166. fn.virtual_index = vtable.size();
  167. vtable.push_back(inst_id);
  168. }
  169. }
  170. return AddInst<SemIR::Vtable>(
  171. context, node_id,
  172. {.type_id = GetSingletonType(context, SemIR::VtableType::TypeInstId),
  173. .virtual_functions_id = context.inst_blocks().Add(vtable)});
  174. }
  175. // Checks that the specified finished class definition is valid and builds and
  176. // returns a corresponding complete type witness instruction.
  177. static auto CheckCompleteClassType(
  178. Context& context, Parse::ClassDefinitionId node_id, SemIR::ClassId class_id,
  179. llvm::ArrayRef<SemIR::InstId> field_decls,
  180. llvm::ArrayRef<SemIR::InstId> vtable_contents,
  181. llvm::ArrayRef<SemIR::InstId> body) -> SemIR::InstId {
  182. auto& class_info = context.classes().Get(class_id);
  183. if (class_info.adapt_id.has_value()) {
  184. return CheckCompleteAdapterClassType(context, node_id, class_id,
  185. field_decls, body);
  186. }
  187. bool defining_vptr = class_info.is_dynamic;
  188. auto base_type_id =
  189. class_info.GetBaseType(context.sem_ir(), SemIR::SpecificId::None);
  190. // TODO: Use InstId from base declaration.
  191. auto base_type_inst_id = context.types().GetInstId(base_type_id);
  192. SemIR::Class* base_class_info = nullptr;
  193. if (base_type_id.has_value()) {
  194. // TODO: If the base class is template dependent, we will need to decide
  195. // whether to add a vptr as part of instantiation.
  196. base_class_info = TryGetAsClass(context, base_type_id);
  197. if (base_class_info && base_class_info->is_dynamic) {
  198. defining_vptr = false;
  199. }
  200. }
  201. llvm::SmallVector<SemIR::StructTypeField> struct_type_fields;
  202. struct_type_fields.reserve(defining_vptr + class_info.base_id.has_value() +
  203. field_decls.size());
  204. if (defining_vptr) {
  205. struct_type_fields.push_back(
  206. {.name_id = SemIR::NameId::Vptr,
  207. .type_inst_id = context.types().GetInstId(
  208. GetPointerType(context, SemIR::VtableType::TypeInstId))});
  209. }
  210. if (base_type_id.has_value()) {
  211. auto base_decl = context.insts().GetAs<SemIR::BaseDecl>(class_info.base_id);
  212. base_decl.index =
  213. SemIR::ElementIndex{static_cast<int>(struct_type_fields.size())};
  214. ReplaceInstPreservingConstantValue(context, class_info.base_id, base_decl);
  215. struct_type_fields.push_back(
  216. {.name_id = SemIR::NameId::Base, .type_inst_id = base_type_inst_id});
  217. }
  218. if (class_info.is_dynamic) {
  219. class_info.vtable_id = BuildVtable(
  220. context, node_id,
  221. defining_vptr ? SemIR::InstId::None : base_class_info->vtable_id,
  222. vtable_contents);
  223. }
  224. auto struct_type_inst_id = AddTypeInst<SemIR::StructType>(
  225. context, node_id,
  226. {.type_id = SemIR::TypeType::TypeId,
  227. .fields_id =
  228. AddStructTypeFields(context, struct_type_fields, field_decls)});
  229. return AddInst<SemIR::CompleteTypeWitness>(
  230. context, node_id,
  231. {.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
  232. .object_repr_type_inst_id = struct_type_inst_id});
  233. }
  234. auto ComputeClassObjectRepr(Context& context, Parse::ClassDefinitionId node_id,
  235. SemIR::ClassId class_id,
  236. llvm::ArrayRef<SemIR::InstId> field_decls,
  237. llvm::ArrayRef<SemIR::InstId> vtable_contents,
  238. llvm::ArrayRef<SemIR::InstId> body) -> void {
  239. auto complete_type_witness_id = CheckCompleteClassType(
  240. context, node_id, class_id, field_decls, vtable_contents, body);
  241. auto& class_info = context.classes().Get(class_id);
  242. class_info.complete_type_witness_id = complete_type_witness_id;
  243. }
  244. } // namespace Carbon::Check