custom_witness.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  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/custom_witness.h"
  5. #include "toolchain/base/kind_switch.h"
  6. #include "toolchain/check/facet_type.h"
  7. #include "toolchain/check/function.h"
  8. #include "toolchain/check/generic.h"
  9. #include "toolchain/check/impl.h"
  10. #include "toolchain/check/impl_lookup.h"
  11. #include "toolchain/check/import_ref.h"
  12. #include "toolchain/check/inst.h"
  13. #include "toolchain/check/name_lookup.h"
  14. #include "toolchain/check/type.h"
  15. #include "toolchain/check/type_completion.h"
  16. #include "toolchain/sem_ir/associated_constant.h"
  17. #include "toolchain/sem_ir/builtin_function_kind.h"
  18. #include "toolchain/sem_ir/ids.h"
  19. #include "toolchain/sem_ir/type_info.h"
  20. #include "toolchain/sem_ir/typed_insts.h"
  21. namespace Carbon::Check {
  22. // Given a value whose type `IsFacetTypeOrError`, returns the corresponding
  23. // type.
  24. static auto GetFacetAsType(Context& context,
  25. SemIR::ConstantId facet_or_type_const_id)
  26. -> SemIR::TypeId {
  27. auto facet_or_type_id =
  28. context.constant_values().GetInstId(facet_or_type_const_id);
  29. auto type_type_id = context.insts().Get(facet_or_type_id).type_id();
  30. CARBON_CHECK(context.types().IsFacetTypeOrError(type_type_id));
  31. if (context.types().Is<SemIR::FacetType>(type_type_id)) {
  32. // It's a facet; access its type.
  33. facet_or_type_id = context.types().GetTypeInstId(
  34. GetFacetAccessType(context, facet_or_type_id));
  35. }
  36. return context.types().GetTypeIdForTypeInstId(facet_or_type_id);
  37. }
  38. // Returns a manufactured `Copy.Op` function with the `self` parameter typed
  39. // to `self_type_id`.
  40. static auto MakeCopyOpFunction(Context& context, SemIR::LocId loc_id,
  41. SemIR::TypeId self_type_id,
  42. SemIR::NameScopeId parent_scope_id)
  43. -> SemIR::InstId {
  44. auto name_id = context.core_identifiers().AddNameId(CoreIdentifier::Op);
  45. auto [decl_id, function_id] =
  46. MakeGeneratedFunctionDecl(context, loc_id,
  47. {.parent_scope_id = parent_scope_id,
  48. .name_id = name_id,
  49. .self_type_id = self_type_id,
  50. .self_is_ref = false,
  51. .return_type_id = self_type_id});
  52. auto& function = context.functions().Get(function_id);
  53. function.SetCoreWitness(SemIR::BuiltinFunctionKind::PrimitiveCopy);
  54. return decl_id;
  55. }
  56. // Returns the body for `Destroy.Op`. This will return `None` if using the
  57. // builtin `NoOp` is appropriate.
  58. // Returns a FacetType that contains only the query interface.
  59. static auto GetFacetTypeForQuerySpecificInterface(
  60. Context& context, SemIR::LocId loc_id,
  61. SemIR::SpecificInterfaceId query_specific_interface_id)
  62. -> SemIR::ConstantId {
  63. const auto query_specific_interface =
  64. context.specific_interfaces().Get(query_specific_interface_id);
  65. // The Self facet will have type FacetType, for the query interface.
  66. auto const_id = EvalOrAddInst<SemIR::FacetType>(
  67. context, loc_id,
  68. FacetTypeFromInterface(context, query_specific_interface.interface_id,
  69. query_specific_interface.specific_id));
  70. return const_id;
  71. }
  72. // Starts a block for lookup-related instructions, and returns the `FacetType`
  73. // for lookups in `HasWitnessForRepeatedField`.
  74. static auto PrepareForHasWitness(
  75. Context& context, SemIR::LocId loc_id,
  76. SemIR::SpecificInterfaceId query_specific_interface_id)
  77. -> SemIR::ConstantId {
  78. context.inst_block_stack().Push();
  79. StartGenericDecl(context);
  80. return GetFacetTypeForQuerySpecificInterface(context, loc_id,
  81. query_specific_interface_id);
  82. }
  83. // Cleans up state `PrepareForHasWitness`.
  84. static auto CleanupAfterHasWitness(Context& context) -> void {
  85. DiscardGenericDecl(context);
  86. context.inst_block_stack().PopAndDiscard();
  87. }
  88. // Returns true if `type_inst_id` has a witness for the query interface, which
  89. // comes from `PrepareForHasWitness`.
  90. static auto HasWitnessForRepeatedField(
  91. Context& context, SemIR::LocId loc_id, SemIR::InstId type_inst_id,
  92. SemIR::ConstantId query_facet_type_const_id) -> bool {
  93. auto type_const_id = context.constant_values().Get(type_inst_id);
  94. auto block_or_err = LookupImplWitness(context, loc_id, type_const_id,
  95. query_facet_type_const_id);
  96. return block_or_err.has_value();
  97. }
  98. // The format for `Destroy.Op`.
  99. enum class DestroyFormat {
  100. NoDestroy,
  101. Trivial,
  102. NonTrivial,
  103. };
  104. // Similar to `HasWitnessForRepeatedField`, but for cases where there's only one
  105. // field, this can handle the call to `PrepareForHasWitness`.
  106. static auto HasWitnessForOneField(
  107. Context& context, SemIR::LocId loc_id, SemIR::InstId field_inst_id,
  108. SemIR::SpecificInterfaceId query_specific_interface_id) -> DestroyFormat {
  109. auto query_facet_type_const_id =
  110. PrepareForHasWitness(context, loc_id, query_specific_interface_id);
  111. auto has_witness = HasWitnessForRepeatedField(context, loc_id, field_inst_id,
  112. query_facet_type_const_id);
  113. CleanupAfterHasWitness(context);
  114. return has_witness ? DestroyFormat::NonTrivial : DestroyFormat::NoDestroy;
  115. }
  116. // Returns true if `class_type` should impl `Destroy`.
  117. static auto CanDestroyClass(
  118. Context& context, SemIR::LocId loc_id, SemIR::ClassType class_type,
  119. const SemIR::CompleteTypeInfo& complete_info,
  120. SemIR::SpecificInterfaceId query_specific_interface_id, bool is_partial)
  121. -> DestroyFormat {
  122. // Abstract classes can't be destroyed.
  123. if (!is_partial && complete_info.IsAbstract()) {
  124. return DestroyFormat::NoDestroy;
  125. }
  126. auto class_info = context.classes().Get(class_type.class_id);
  127. // `LookupCppImpl` handles C++ types.
  128. if (context.name_scopes().Get(class_info.scope_id).is_cpp_scope()) {
  129. return DestroyFormat::NoDestroy;
  130. }
  131. auto object_repr_id =
  132. class_info.GetObjectRepr(context.sem_ir(), class_type.specific_id);
  133. return HasWitnessForOneField(context, loc_id,
  134. context.types().GetTypeInstId(object_repr_id),
  135. query_specific_interface_id);
  136. }
  137. // Returns true if the `Self` should impl `Destroy`. This will recurse into impl
  138. // lookup of `Destroy` for members, similar to `where .Self.members each impls
  139. // Destroy`.
  140. static auto CanDestroyType(
  141. Context& context, SemIR::LocId loc_id,
  142. SemIR::ConstantId query_self_const_id,
  143. SemIR::SpecificInterfaceId query_specific_interface_id) -> DestroyFormat {
  144. auto query_specific_interface =
  145. context.specific_interfaces().Get(query_specific_interface_id);
  146. auto destroy_interface_id = query_specific_interface.interface_id;
  147. auto inst_id = context.constant_values().GetInstId(
  148. GetCanonicalFacetOrTypeValue(context, query_self_const_id));
  149. auto inst = context.insts().Get(inst_id);
  150. // For facet values, look if the FacetType provides the same.
  151. if (auto facet_type =
  152. context.types().TryGetAs<SemIR::FacetType>(inst.type_id())) {
  153. const auto& info = context.facet_types().Get(facet_type->facet_type_id);
  154. for (auto interface : info.extend_constraints) {
  155. if (interface.interface_id == destroy_interface_id) {
  156. return DestroyFormat::Trivial;
  157. }
  158. }
  159. return DestroyFormat::NoDestroy;
  160. }
  161. // Incomplete types can not be destroyed.
  162. auto type_id = context.types().GetTypeIdForTypeInstId(inst_id);
  163. if (!TryToCompleteType(context, type_id, loc_id)) {
  164. return DestroyFormat::NoDestroy;
  165. }
  166. CARBON_KIND_SWITCH(inst) {
  167. case SemIR::ImplWitnessAccess::Kind:
  168. case SemIR::SymbolicBinding::Kind: {
  169. // A symbolic facet of type `type`. Such symbolic values can't be
  170. // destroyed.
  171. return DestroyFormat::NoDestroy;
  172. }
  173. case CARBON_KIND(SemIR::ArrayType array_type): {
  174. // A zero element array is always trivially destructible.
  175. if (auto int_bound =
  176. context.sem_ir().GetZExtIntValue(array_type.bound_id);
  177. !int_bound || *int_bound == 0) {
  178. return DestroyFormat::Trivial;
  179. }
  180. // Verify the element can be destroyed.
  181. return HasWitnessForOneField(context, loc_id,
  182. array_type.element_type_inst_id,
  183. query_specific_interface_id);
  184. }
  185. case SemIR::Call::Kind:
  186. // TODO: These seem like they shouldn't be getting directly queried for
  187. // destroy. The use is in a test that was TODO before this TODO.
  188. return DestroyFormat::NoDestroy;
  189. case CARBON_KIND(SemIR::ClassType class_type): {
  190. return CanDestroyClass(context, loc_id, class_type,
  191. context.types().GetCompleteTypeInfo(type_id),
  192. query_specific_interface_id,
  193. /*is_partial=*/false);
  194. }
  195. case CARBON_KIND(SemIR::ConstType const_type): {
  196. return HasWitnessForOneField(context, loc_id, const_type.inner_id,
  197. query_specific_interface_id);
  198. }
  199. case CARBON_KIND(SemIR::MaybeUnformedType maybe_unformed_type): {
  200. return HasWitnessForOneField(context, loc_id,
  201. maybe_unformed_type.inner_id,
  202. query_specific_interface_id);
  203. }
  204. case CARBON_KIND(SemIR::PartialType partial_type): {
  205. // In contrast with something like `const`, need to treat the inner
  206. // class differently based on the `partial` modifier.
  207. auto class_type =
  208. context.insts().GetAs<SemIR::ClassType>(partial_type.inner_id);
  209. return CanDestroyClass(context, loc_id, class_type,
  210. context.types().GetCompleteTypeInfo(type_id),
  211. query_specific_interface_id,
  212. /*is_partial=*/true);
  213. }
  214. case CARBON_KIND(SemIR::StructType struct_type): {
  215. auto fields = context.struct_type_fields().Get(struct_type.fields_id);
  216. if (fields.empty()) {
  217. return DestroyFormat::Trivial;
  218. }
  219. auto query_facet_type_const_id =
  220. PrepareForHasWitness(context, loc_id, query_specific_interface_id);
  221. bool has_witness = true;
  222. for (const auto& field : fields) {
  223. if (!HasWitnessForRepeatedField(context, loc_id, field.type_inst_id,
  224. query_facet_type_const_id)) {
  225. has_witness = false;
  226. break;
  227. }
  228. }
  229. CleanupAfterHasWitness(context);
  230. return has_witness ? DestroyFormat::NonTrivial : DestroyFormat::NoDestroy;
  231. }
  232. case CARBON_KIND(SemIR::TupleType tuple_type): {
  233. auto block = context.inst_blocks().Get(tuple_type.type_elements_id);
  234. if (block.empty()) {
  235. return DestroyFormat::Trivial;
  236. }
  237. auto query_facet_type_const_id =
  238. PrepareForHasWitness(context, loc_id, query_specific_interface_id);
  239. bool has_witness = true;
  240. for (const auto& element_id : block) {
  241. if (!HasWitnessForRepeatedField(context, loc_id, element_id,
  242. query_facet_type_const_id)) {
  243. has_witness = false;
  244. break;
  245. }
  246. }
  247. CleanupAfterHasWitness(context);
  248. return has_witness ? DestroyFormat::NonTrivial : DestroyFormat::NoDestroy;
  249. }
  250. case SemIR::BoolType::Kind:
  251. case SemIR::FacetType::Kind:
  252. case SemIR::FloatType::Kind:
  253. case SemIR::IntLiteralType::Kind:
  254. case SemIR::IntType::Kind:
  255. case SemIR::PointerType::Kind:
  256. case SemIR::TypeType::Kind:
  257. // Trivially destructible.
  258. return DestroyFormat::Trivial;
  259. default:
  260. CARBON_FATAL("Unexpected type for CanDestroyType: {0}", inst.kind());
  261. }
  262. }
  263. // Returns the body for `Destroy.Op`.
  264. //
  265. // TODO: This is a placeholder still not actually destroying things, intended to
  266. // maintain mostly-consistent behavior with current logic while working. That
  267. // also means using `self`.
  268. static auto MakeDestroyOpBody(Context& context, SemIR::LocId loc_id,
  269. SemIR::TypeId self_type_id,
  270. SemIR::InstId self_param_id)
  271. -> SemIR::InstBlockId {
  272. context.inst_block_stack().Push();
  273. auto inst = context.types().GetAsInst(self_type_id);
  274. CARBON_KIND_SWITCH(inst) {
  275. case SemIR::ArrayType::Kind:
  276. case SemIR::ClassType::Kind:
  277. case SemIR::ConstType::Kind:
  278. case SemIR::MaybeUnformedType::Kind:
  279. case SemIR::PartialType::Kind:
  280. case SemIR::StructType::Kind:
  281. case SemIR::TupleType::Kind:
  282. (void)self_param_id;
  283. // TODO: Implement destruction of the type.
  284. break;
  285. default:
  286. CARBON_FATAL("Unexpected type for MakeDestroyOpBody: {0}", inst);
  287. }
  288. AddInst(context, loc_id, SemIR::Return{});
  289. return context.inst_block_stack().Pop();
  290. }
  291. // Returns a manufactured `Destroy.Op` function with the `self` parameter typed
  292. // to `self_type_id`.
  293. static auto MakeDestroyOpFunction(Context& context, SemIR::LocId loc_id,
  294. SemIR::TypeId self_type_id,
  295. SemIR::NameScopeId parent_scope_id,
  296. DestroyFormat format) -> SemIR::InstId {
  297. auto name_id = context.core_identifiers().AddNameId(CoreIdentifier::Op);
  298. auto [decl_id, function_id] =
  299. MakeGeneratedFunctionDecl(context, loc_id,
  300. {.parent_scope_id = parent_scope_id,
  301. .name_id = name_id,
  302. .self_type_id = self_type_id});
  303. auto& function = context.functions().Get(function_id);
  304. if (format == DestroyFormat::Trivial) {
  305. function.SetCoreWitness(SemIR::BuiltinFunctionKind::NoOp);
  306. } else {
  307. CARBON_CHECK(format == DestroyFormat::NonTrivial);
  308. function.SetCoreWitness(SemIR::BuiltinFunctionKind::None);
  309. auto body_id = MakeDestroyOpBody(context, loc_id, self_type_id,
  310. function.self_param_id);
  311. function.body_block_ids.push_back(body_id);
  312. }
  313. return decl_id;
  314. }
  315. static auto MakeCustomWitnessConstantInst(
  316. Context& context, SemIR::LocId loc_id,
  317. SemIR::SpecificInterfaceId query_specific_interface_id,
  318. SemIR::InstBlockId associated_entities_block_id) -> SemIR::InstId {
  319. // The witness is a CustomWitness of the query interface with a table that
  320. // contains each associated entity.
  321. auto const_id = EvalOrAddInst<SemIR::CustomWitness>(
  322. context, loc_id,
  323. {.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
  324. .elements_id = associated_entities_block_id,
  325. .query_specific_interface_id = query_specific_interface_id});
  326. return context.constant_values().GetInstId(const_id);
  327. }
  328. struct TypesForSelfFacet {
  329. // A FacetType that contains only the query interface.
  330. SemIR::TypeId facet_type_for_query_specific_interface;
  331. // The query self as a type, which involves a conversion if it was a facet.
  332. SemIR::TypeId query_self_as_type_id;
  333. };
  334. static auto GetTypesForSelfFacet(
  335. Context& context, SemIR::LocId loc_id,
  336. SemIR::ConstantId query_self_const_id,
  337. SemIR::SpecificInterfaceId query_specific_interface_id)
  338. -> TypesForSelfFacet {
  339. // The Self facet will have type FacetType, for the query interface.
  340. auto facet_type_for_query_specific_interface =
  341. context.types().GetTypeIdForTypeConstantId(
  342. GetFacetTypeForQuerySpecificInterface(context, loc_id,
  343. query_specific_interface_id));
  344. // The Self facet needs to point to a type value. If it's not one already,
  345. // convert to type.
  346. auto query_self_as_type_id = GetFacetAsType(context, query_self_const_id);
  347. return {facet_type_for_query_specific_interface, query_self_as_type_id};
  348. }
  349. // Build a new facet from the query self, using a CustomWitness for the query
  350. // interface with an entry for each associated entity so far.
  351. static auto MakeSelfFacetWithCustomWitness(
  352. Context& context, SemIR::LocId loc_id, TypesForSelfFacet query_types,
  353. SemIR::SpecificInterfaceId query_specific_interface_id,
  354. SemIR::InstBlockId associated_entities_block_id) -> SemIR::ConstantId {
  355. // We are building a facet value for a single interface, so the witness block
  356. // is a single witness for that interface.
  357. auto witnesses_block_id =
  358. context.inst_blocks().Add({MakeCustomWitnessConstantInst(
  359. context, loc_id, query_specific_interface_id,
  360. associated_entities_block_id)});
  361. return EvalOrAddInst<SemIR::FacetValue>(
  362. context, loc_id,
  363. {.type_id = query_types.facet_type_for_query_specific_interface,
  364. .type_inst_id =
  365. context.types().GetTypeInstId(query_types.query_self_as_type_id),
  366. .witnesses_block_id = witnesses_block_id});
  367. }
  368. auto BuildCustomWitness(Context& context, SemIR::LocId loc_id,
  369. SemIR::ConstantId query_self_const_id,
  370. SemIR::SpecificInterfaceId query_specific_interface_id,
  371. llvm::ArrayRef<SemIR::InstId> values) -> SemIR::InstId {
  372. const auto query_specific_interface =
  373. context.specific_interfaces().Get(query_specific_interface_id);
  374. const auto& interface =
  375. context.interfaces().Get(query_specific_interface.interface_id);
  376. auto assoc_entities =
  377. context.inst_blocks().GetOrEmpty(interface.associated_entities_id);
  378. if (assoc_entities.size() != values.size()) {
  379. context.TODO(loc_id, ("Unsupported definition of interface " +
  380. context.names().GetFormatted(interface.name_id))
  381. .str());
  382. return SemIR::ErrorInst::InstId;
  383. }
  384. auto query_types_for_self_facet = GetTypesForSelfFacet(
  385. context, loc_id, query_self_const_id, query_specific_interface_id);
  386. // The values that will go in the witness table.
  387. llvm::SmallVector<SemIR::InstId> entries;
  388. // Fill in the witness table.
  389. for (const auto& [assoc_entity_id, value_id] :
  390. llvm::zip_equal(assoc_entities, values)) {
  391. LoadImportRef(context, assoc_entity_id);
  392. // Build a witness with the current contents of the witness table. This will
  393. // grow as we progress through the impl. In theory this will build O(n^2)
  394. // table entries, but in practice n <= 2, so that's OK.
  395. //
  396. // This is necessary because later associated entities may refer to earlier
  397. // associated entities in their signatures. In particular, an associated
  398. // result type may be used as the return type of an associated function.
  399. auto self_facet = MakeSelfFacetWithCustomWitness(
  400. context, loc_id, query_types_for_self_facet,
  401. query_specific_interface_id, context.inst_blocks().Add(entries));
  402. auto interface_with_self_specific_id = MakeSpecificWithInnerSelf(
  403. context, loc_id, interface.generic_id, interface.generic_with_self_id,
  404. query_specific_interface.specific_id, self_facet);
  405. CARBON_CHECK(
  406. !context.specifics().Get(interface_with_self_specific_id).HasError());
  407. auto decl_id =
  408. context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
  409. context.sem_ir(), interface_with_self_specific_id,
  410. assoc_entity_id));
  411. CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
  412. auto decl = context.insts().Get(decl_id);
  413. CARBON_KIND_SWITCH(decl) {
  414. case CARBON_KIND(SemIR::StructValue struct_value): {
  415. if (struct_value.type_id == SemIR::ErrorInst::TypeId) {
  416. return SemIR::ErrorInst::InstId;
  417. }
  418. // TODO: If a thunk is needed, this will build a different value each
  419. // time it's called, so we won't properly deduplicate repeated
  420. // witnesses.
  421. entries.push_back(CheckAssociatedFunctionImplementation(
  422. context,
  423. context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
  424. query_specific_interface.specific_id, value_id,
  425. /*defer_thunk_definition=*/false));
  426. break;
  427. }
  428. case CARBON_KIND(SemIR::AssociatedConstantDecl decl): {
  429. if (decl.type_id == SemIR::ErrorInst::TypeId) {
  430. return SemIR::ErrorInst::InstId;
  431. }
  432. // TODO: remove once we have a test-case for all associated constants.
  433. // Special-case the ones we want to support in this if-statement, until
  434. // we're able to account for everything.
  435. if (decl.type_id != SemIR::TypeType::TypeId) {
  436. context.TODO(loc_id,
  437. "Associated constant of type other than `TypeType` in "
  438. "synthesized impl");
  439. return SemIR::ErrorInst::InstId;
  440. }
  441. auto type_id = context.insts().Get(value_id).type_id();
  442. CARBON_CHECK(type_id == SemIR::TypeType::TypeId ||
  443. type_id == SemIR::ErrorInst::TypeId);
  444. auto impl_witness_associated_constant =
  445. AddInst<SemIR::ImplWitnessAssociatedConstant>(
  446. context, loc_id, {.type_id = type_id, .inst_id = value_id});
  447. entries.push_back(impl_witness_associated_constant);
  448. break;
  449. }
  450. default:
  451. CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
  452. "Unexpected kind of associated entity {0}", decl);
  453. return SemIR::ErrorInst::InstId;
  454. }
  455. }
  456. // TODO: Consider building one witness after all associated constants, and
  457. // then a second after all associated functions, rather than building one in
  458. // each `StructValue`. Right now the code is written assuming at most one
  459. // function, though this CHECK can be removed as a temporary workaround.
  460. auto associated_functions = llvm::count_if(entries, [&](SemIR::InstId id) {
  461. return context.insts().Get(id).kind() == SemIR::InstKind::FunctionDecl;
  462. });
  463. CARBON_CHECK(associated_functions <= 1,
  464. "TODO: Support multiple associated functions");
  465. return MakeCustomWitnessConstantInst(context, loc_id,
  466. query_specific_interface_id,
  467. context.inst_blocks().Add(entries));
  468. }
  469. auto AsCoreIdentifier(SemIR::CoreInterface core_interface) -> CoreIdentifier {
  470. using SemIR::CoreInterface;
  471. switch (core_interface) {
  472. case CoreInterface::AddAssignWith:
  473. return CoreIdentifier::AddAssignWith;
  474. case CoreInterface::AddWith:
  475. return CoreIdentifier::AddWith;
  476. case CoreInterface::Copy:
  477. return CoreIdentifier::Copy;
  478. case CoreInterface::CppUnsafeDeref:
  479. return CoreIdentifier::CppUnsafeDeref;
  480. case CoreInterface::Dec:
  481. return CoreIdentifier::Dec;
  482. case CoreInterface::Default:
  483. return CoreIdentifier::Default;
  484. case CoreInterface::Destroy:
  485. return CoreIdentifier::Destroy;
  486. case CoreInterface::DivAssignWith:
  487. return CoreIdentifier::DivAssignWith;
  488. case CoreInterface::DivWith:
  489. return CoreIdentifier::DivWith;
  490. case CoreInterface::Inc:
  491. return CoreIdentifier::Inc;
  492. case CoreInterface::IntFitsIn:
  493. return CoreIdentifier::IntFitsIn;
  494. case CoreInterface::ModAssignWith:
  495. return CoreIdentifier::ModAssignWith;
  496. case CoreInterface::ModWith:
  497. return CoreIdentifier::ModWith;
  498. case CoreInterface::MulAssignWith:
  499. return CoreIdentifier::MulAssignWith;
  500. case CoreInterface::MulWith:
  501. return CoreIdentifier::MulWith;
  502. case CoreInterface::Negate:
  503. return CoreIdentifier::Negate;
  504. case CoreInterface::SubAssignWith:
  505. return CoreIdentifier::SubAssignWith;
  506. case CoreInterface::SubWith:
  507. return CoreIdentifier::SubWith;
  508. case CoreInterface::Unknown:
  509. CARBON_FATAL("{0} doesn't have a `CoreIdentifier` mapping",
  510. core_interface);
  511. }
  512. }
  513. auto GetCoreInterface(Context& context, SemIR::InterfaceId interface_id)
  514. -> SemIR::CoreInterface {
  515. const auto& interface = context.interfaces().Get(interface_id);
  516. if (!context.name_scopes().IsCorePackage(interface.parent_scope_id) ||
  517. !interface.name_id.AsIdentifierId().has_value()) {
  518. return SemIR::CoreInterface::Unknown;
  519. }
  520. return interface.core_interface;
  521. }
  522. auto BuildPrimitiveCopyWitness(
  523. Context& context, SemIR::LocId loc_id, SemIR::NameScopeId parent_scope_id,
  524. SemIR::ConstantId query_self_const_id,
  525. SemIR::SpecificInterfaceId query_specific_interface_id) -> SemIR::InstId {
  526. auto self_type_id = GetFacetAsType(context, query_self_const_id);
  527. auto op_id =
  528. MakeCopyOpFunction(context, loc_id, self_type_id, parent_scope_id);
  529. return BuildCustomWitness(context, loc_id, query_self_const_id,
  530. query_specific_interface_id, {op_id});
  531. }
  532. static auto MakeDestroyWitness(
  533. Context& context, SemIR::LocId loc_id,
  534. SemIR::ConstantId query_self_const_id,
  535. SemIR::SpecificInterfaceId query_specific_interface_id, bool build_witness)
  536. -> std::optional<SemIR::InstId> {
  537. auto format = CanDestroyType(context, loc_id, query_self_const_id,
  538. query_specific_interface_id);
  539. if (format == DestroyFormat::NoDestroy) {
  540. return std::nullopt;
  541. }
  542. if (!build_witness || query_self_const_id.is_symbolic()) {
  543. // The type can be destroyed, but we shouldn't make a witness right now.
  544. return SemIR::InstId::None;
  545. }
  546. // Mark functions with the interface's scope as a hint to mangling. This
  547. // does not add them to the scope.
  548. auto query_specific_interface =
  549. context.specific_interfaces().Get(query_specific_interface_id);
  550. auto parent_scope_id = context.interfaces()
  551. .Get(query_specific_interface.interface_id)
  552. .scope_without_self_id;
  553. auto self_type_id = GetFacetAsType(context, query_self_const_id);
  554. auto op_id = MakeDestroyOpFunction(context, loc_id, self_type_id,
  555. parent_scope_id, format);
  556. return BuildCustomWitness(context, loc_id, query_self_const_id,
  557. query_specific_interface_id, {op_id});
  558. }
  559. static auto MakeIntFitsInWitness(
  560. Context& context, SemIR::LocId loc_id,
  561. SemIR::ConstantId query_self_const_id,
  562. SemIR::SpecificInterfaceId query_specific_interface_id, bool build_witness)
  563. -> std::optional<SemIR::InstId> {
  564. auto query_specific_interface =
  565. context.specific_interfaces().Get(query_specific_interface_id);
  566. auto args_id = query_specific_interface.specific_id;
  567. if (!args_id.has_value()) {
  568. return std::nullopt;
  569. }
  570. auto args_block_id = context.specifics().Get(args_id).args_id;
  571. auto args_block = context.inst_blocks().Get(args_block_id);
  572. if (args_block.size() != 1) {
  573. return std::nullopt;
  574. }
  575. auto dest_const_id = context.constant_values().Get(args_block[0]);
  576. if (!dest_const_id.is_constant()) {
  577. return std::nullopt;
  578. }
  579. auto src_type_id = GetFacetAsType(context, query_self_const_id);
  580. auto dest_type_id = GetFacetAsType(context, dest_const_id);
  581. auto context_fn = [](DiagnosticContextBuilder& /*builder*/) -> void {};
  582. if (!RequireCompleteType(context, src_type_id, loc_id, context_fn) ||
  583. !RequireCompleteType(context, dest_type_id, loc_id, context_fn)) {
  584. return std::nullopt;
  585. }
  586. auto src_info = context.types().TryGetIntTypeInfo(src_type_id);
  587. auto dest_info = context.types().TryGetIntTypeInfo(dest_type_id);
  588. if (!src_info || !dest_info) {
  589. return std::nullopt;
  590. }
  591. // If the bit width is unknown (e.g., due to symbolic evaluation), we cannot
  592. // determine whether it fits yet.
  593. if (src_info->bit_width == IntId::None ||
  594. dest_info->bit_width == IntId::None) {
  595. return std::nullopt;
  596. }
  597. const auto& src_width = context.ints().Get(src_info->bit_width);
  598. const auto& dest_width = context.ints().Get(dest_info->bit_width);
  599. bool fits = false;
  600. if (src_info->is_signed && !dest_info->is_signed) {
  601. // Signed -> unsigned: would truncate the sign bit.
  602. fits = false;
  603. } else if (src_info->is_signed == dest_info->is_signed) {
  604. // Signed -> signed or unsigned -> unsigned: allow widening or preserving
  605. // width.
  606. fits = src_width.sle(dest_width);
  607. } else {
  608. // Unsigned -> signed: strict widening required.
  609. fits = src_width.slt(dest_width);
  610. }
  611. if (!fits) {
  612. return std::nullopt;
  613. }
  614. if (!build_witness) {
  615. return SemIR::InstId::None;
  616. }
  617. return BuildCustomWitness(context, loc_id, query_self_const_id,
  618. query_specific_interface_id, {});
  619. }
  620. auto LookupCustomWitness(Context& context, SemIR::LocId loc_id,
  621. SemIR::CoreInterface core_interface,
  622. SemIR::ConstantId query_self_const_id,
  623. SemIR::SpecificInterfaceId query_specific_interface_id,
  624. bool build_witness) -> std::optional<SemIR::InstId> {
  625. switch (core_interface) {
  626. case SemIR::CoreInterface::Destroy:
  627. return MakeDestroyWitness(context, loc_id, query_self_const_id,
  628. query_specific_interface_id, build_witness);
  629. case SemIR::CoreInterface::IntFitsIn:
  630. return MakeIntFitsInWitness(context, loc_id, query_self_const_id,
  631. query_specific_interface_id, build_witness);
  632. case SemIR::CoreInterface::AddAssignWith:
  633. case SemIR::CoreInterface::AddWith:
  634. case SemIR::CoreInterface::Copy:
  635. case SemIR::CoreInterface::CppUnsafeDeref:
  636. case SemIR::CoreInterface::Dec:
  637. case SemIR::CoreInterface::Default:
  638. case SemIR::CoreInterface::DivAssignWith:
  639. case SemIR::CoreInterface::DivWith:
  640. case SemIR::CoreInterface::Inc:
  641. case SemIR::CoreInterface::ModAssignWith:
  642. case SemIR::CoreInterface::ModWith:
  643. case SemIR::CoreInterface::MulAssignWith:
  644. case SemIR::CoreInterface::MulWith:
  645. case SemIR::CoreInterface::Negate:
  646. case SemIR::CoreInterface::SubAssignWith:
  647. case SemIR::CoreInterface::SubWith:
  648. case SemIR::CoreInterface::Unknown:
  649. // TODO: Handle more interfaces, particularly copy, move, and conversion.
  650. return std::nullopt;
  651. }
  652. }
  653. } // namespace Carbon::Check