custom_witness.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  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_kind = ParamPatternKind::Value,
  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. .self_kind = ParamPatternKind::Ref});
  304. auto& function = context.functions().Get(function_id);
  305. if (format == DestroyFormat::Trivial) {
  306. function.SetCoreWitness(SemIR::BuiltinFunctionKind::NoOp);
  307. } else {
  308. CARBON_CHECK(format == DestroyFormat::NonTrivial);
  309. function.SetCoreWitness(SemIR::BuiltinFunctionKind::None);
  310. auto body_id = MakeDestroyOpBody(context, loc_id, self_type_id,
  311. function.self_param_id);
  312. function.body_block_ids.push_back(body_id);
  313. }
  314. return decl_id;
  315. }
  316. static auto MakeCustomWitnessConstantInst(
  317. Context& context, SemIR::LocId loc_id,
  318. SemIR::SpecificInterfaceId query_specific_interface_id,
  319. SemIR::InstBlockId associated_entities_block_id) -> SemIR::InstId {
  320. // The witness is a CustomWitness of the query interface with a table that
  321. // contains each associated entity.
  322. auto const_id = EvalOrAddInst<SemIR::CustomWitness>(
  323. context, loc_id,
  324. {.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
  325. .elements_id = associated_entities_block_id,
  326. .query_specific_interface_id = query_specific_interface_id});
  327. return context.constant_values().GetInstId(const_id);
  328. }
  329. struct TypesForSelfFacet {
  330. // A FacetType that contains only the query interface.
  331. SemIR::TypeId facet_type_for_query_specific_interface;
  332. // The query self as a type, which involves a conversion if it was a facet.
  333. SemIR::TypeId query_self_as_type_id;
  334. };
  335. static auto GetTypesForSelfFacet(
  336. Context& context, SemIR::LocId loc_id,
  337. SemIR::ConstantId query_self_const_id,
  338. SemIR::SpecificInterfaceId query_specific_interface_id)
  339. -> TypesForSelfFacet {
  340. // The Self facet will have type FacetType, for the query interface.
  341. auto facet_type_for_query_specific_interface =
  342. context.types().GetTypeIdForTypeConstantId(
  343. GetFacetTypeForQuerySpecificInterface(context, loc_id,
  344. query_specific_interface_id));
  345. // The Self facet needs to point to a type value. If it's not one already,
  346. // convert to type.
  347. auto query_self_as_type_id = GetFacetAsType(context, query_self_const_id);
  348. return {facet_type_for_query_specific_interface, query_self_as_type_id};
  349. }
  350. // Build a new facet from the query self, using a CustomWitness for the query
  351. // interface with an entry for each associated entity so far.
  352. static auto MakeSelfFacetWithCustomWitness(
  353. Context& context, SemIR::LocId loc_id, TypesForSelfFacet query_types,
  354. SemIR::SpecificInterfaceId query_specific_interface_id,
  355. SemIR::InstBlockId associated_entities_block_id) -> SemIR::ConstantId {
  356. // We are building a facet value for a single interface, so the witness block
  357. // is a single witness for that interface.
  358. auto witnesses_block_id =
  359. context.inst_blocks().Add({MakeCustomWitnessConstantInst(
  360. context, loc_id, query_specific_interface_id,
  361. associated_entities_block_id)});
  362. return EvalOrAddInst<SemIR::FacetValue>(
  363. context, loc_id,
  364. {.type_id = query_types.facet_type_for_query_specific_interface,
  365. .type_inst_id =
  366. context.types().GetTypeInstId(query_types.query_self_as_type_id),
  367. .witnesses_block_id = witnesses_block_id});
  368. }
  369. auto BuildCustomWitness(Context& context, SemIR::LocId loc_id,
  370. SemIR::ConstantId query_self_const_id,
  371. SemIR::SpecificInterfaceId query_specific_interface_id,
  372. llvm::ArrayRef<SemIR::InstId> values) -> SemIR::InstId {
  373. const auto query_specific_interface =
  374. context.specific_interfaces().Get(query_specific_interface_id);
  375. const auto& interface =
  376. context.interfaces().Get(query_specific_interface.interface_id);
  377. auto assoc_entities =
  378. context.inst_blocks().GetOrEmpty(interface.associated_entities_id);
  379. if (assoc_entities.size() != values.size()) {
  380. context.TODO(loc_id, ("Unsupported definition of interface " +
  381. context.names().GetFormatted(interface.name_id))
  382. .str());
  383. return SemIR::ErrorInst::InstId;
  384. }
  385. auto query_types_for_self_facet = GetTypesForSelfFacet(
  386. context, loc_id, query_self_const_id, query_specific_interface_id);
  387. // The values that will go in the witness table.
  388. llvm::SmallVector<SemIR::InstId> entries;
  389. // Fill in the witness table.
  390. for (const auto& [assoc_entity_id, value_id] :
  391. llvm::zip_equal(assoc_entities, values)) {
  392. LoadImportRef(context, assoc_entity_id);
  393. // Build a witness with the current contents of the witness table. This will
  394. // grow as we progress through the impl. In theory this will build O(n^2)
  395. // table entries, but in practice n <= 2, so that's OK.
  396. //
  397. // This is necessary because later associated entities may refer to earlier
  398. // associated entities in their signatures. In particular, an associated
  399. // result type may be used as the return type of an associated function.
  400. auto self_facet = MakeSelfFacetWithCustomWitness(
  401. context, loc_id, query_types_for_self_facet,
  402. query_specific_interface_id, context.inst_blocks().Add(entries));
  403. auto interface_with_self_specific_id = MakeSpecificWithInnerSelf(
  404. context, loc_id, interface.generic_id, interface.generic_with_self_id,
  405. query_specific_interface.specific_id, self_facet);
  406. CARBON_CHECK(
  407. !context.specifics().Get(interface_with_self_specific_id).HasError());
  408. auto decl_id =
  409. context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
  410. context.sem_ir(), interface_with_self_specific_id,
  411. assoc_entity_id));
  412. CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
  413. auto decl = context.insts().Get(decl_id);
  414. CARBON_KIND_SWITCH(decl) {
  415. case CARBON_KIND(SemIR::StructValue struct_value): {
  416. if (struct_value.type_id == SemIR::ErrorInst::TypeId) {
  417. return SemIR::ErrorInst::InstId;
  418. }
  419. // TODO: If a thunk is needed, this will build a different value each
  420. // time it's called, so we won't properly deduplicate repeated
  421. // witnesses.
  422. entries.push_back(CheckAssociatedFunctionImplementation(
  423. context,
  424. context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
  425. query_specific_interface.specific_id, value_id,
  426. /*defer_thunk_definition=*/false));
  427. break;
  428. }
  429. case CARBON_KIND(SemIR::AssociatedConstantDecl decl): {
  430. if (decl.type_id == SemIR::ErrorInst::TypeId) {
  431. return SemIR::ErrorInst::InstId;
  432. }
  433. // TODO: remove once we have a test-case for all associated constants.
  434. // Special-case the ones we want to support in this if-statement, until
  435. // we're able to account for everything.
  436. if (decl.type_id != SemIR::TypeType::TypeId) {
  437. context.TODO(loc_id,
  438. "Associated constant of type other than `TypeType` in "
  439. "synthesized impl");
  440. return SemIR::ErrorInst::InstId;
  441. }
  442. auto type_id = context.insts().Get(value_id).type_id();
  443. CARBON_CHECK(type_id == SemIR::TypeType::TypeId ||
  444. type_id == SemIR::ErrorInst::TypeId);
  445. auto impl_witness_associated_constant =
  446. AddInst<SemIR::ImplWitnessAssociatedConstant>(
  447. context, loc_id, {.type_id = type_id, .inst_id = value_id});
  448. entries.push_back(impl_witness_associated_constant);
  449. break;
  450. }
  451. default:
  452. CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
  453. "Unexpected kind of associated entity {0}", decl);
  454. return SemIR::ErrorInst::InstId;
  455. }
  456. }
  457. // TODO: Consider building one witness after all associated constants, and
  458. // then a second after all associated functions, rather than building one in
  459. // each `StructValue`. Right now the code is written assuming at most one
  460. // function, though this CHECK can be removed as a temporary workaround.
  461. auto associated_functions = llvm::count_if(entries, [&](SemIR::InstId id) {
  462. return context.insts().Get(id).kind() == SemIR::InstKind::FunctionDecl;
  463. });
  464. CARBON_CHECK(associated_functions <= 1,
  465. "TODO: Support multiple associated functions");
  466. return MakeCustomWitnessConstantInst(context, loc_id,
  467. query_specific_interface_id,
  468. context.inst_blocks().Add(entries));
  469. }
  470. auto AsCoreIdentifier(SemIR::CoreInterface core_interface) -> CoreIdentifier {
  471. using SemIR::CoreInterface;
  472. switch (core_interface) {
  473. case CoreInterface::AddAssignWith:
  474. return CoreIdentifier::AddAssignWith;
  475. case CoreInterface::AddWith:
  476. return CoreIdentifier::AddWith;
  477. case CoreInterface::Copy:
  478. return CoreIdentifier::Copy;
  479. case CoreInterface::CppUnsafeDeref:
  480. return CoreIdentifier::CppUnsafeDeref;
  481. case CoreInterface::Dec:
  482. return CoreIdentifier::Dec;
  483. case CoreInterface::Default:
  484. return CoreIdentifier::Default;
  485. case CoreInterface::Destroy:
  486. return CoreIdentifier::Destroy;
  487. case CoreInterface::DivAssignWith:
  488. return CoreIdentifier::DivAssignWith;
  489. case CoreInterface::DivWith:
  490. return CoreIdentifier::DivWith;
  491. case CoreInterface::Inc:
  492. return CoreIdentifier::Inc;
  493. case CoreInterface::IntFitsIn:
  494. return CoreIdentifier::IntFitsIn;
  495. case CoreInterface::ModAssignWith:
  496. return CoreIdentifier::ModAssignWith;
  497. case CoreInterface::ModWith:
  498. return CoreIdentifier::ModWith;
  499. case CoreInterface::MulAssignWith:
  500. return CoreIdentifier::MulAssignWith;
  501. case CoreInterface::MulWith:
  502. return CoreIdentifier::MulWith;
  503. case CoreInterface::Negate:
  504. return CoreIdentifier::Negate;
  505. case CoreInterface::SubAssignWith:
  506. return CoreIdentifier::SubAssignWith;
  507. case CoreInterface::SubWith:
  508. return CoreIdentifier::SubWith;
  509. case CoreInterface::Unknown:
  510. CARBON_FATAL("{0} doesn't have a `CoreIdentifier` mapping",
  511. core_interface);
  512. }
  513. }
  514. auto GetCoreInterface(Context& context, SemIR::InterfaceId interface_id)
  515. -> SemIR::CoreInterface {
  516. const auto& interface = context.interfaces().Get(interface_id);
  517. if (!context.name_scopes().IsCorePackage(interface.parent_scope_id) ||
  518. !interface.name_id.AsIdentifierId().has_value()) {
  519. return SemIR::CoreInterface::Unknown;
  520. }
  521. return interface.core_interface;
  522. }
  523. auto BuildPrimitiveCopyWitness(
  524. Context& context, SemIR::LocId loc_id, SemIR::NameScopeId parent_scope_id,
  525. SemIR::ConstantId query_self_const_id,
  526. SemIR::SpecificInterfaceId query_specific_interface_id) -> SemIR::InstId {
  527. auto self_type_id = GetFacetAsType(context, query_self_const_id);
  528. auto op_id =
  529. MakeCopyOpFunction(context, loc_id, self_type_id, parent_scope_id);
  530. return BuildCustomWitness(context, loc_id, query_self_const_id,
  531. query_specific_interface_id, {op_id});
  532. }
  533. static auto MakeDestroyWitness(
  534. Context& context, SemIR::LocId loc_id,
  535. SemIR::ConstantId query_self_const_id,
  536. SemIR::SpecificInterfaceId query_specific_interface_id, bool build_witness)
  537. -> std::optional<SemIR::InstId> {
  538. auto format = CanDestroyType(context, loc_id, query_self_const_id,
  539. query_specific_interface_id);
  540. if (format == DestroyFormat::NoDestroy) {
  541. return std::nullopt;
  542. }
  543. if (!build_witness || query_self_const_id.is_symbolic()) {
  544. // The type can be destroyed, but we shouldn't make a witness right now.
  545. return SemIR::InstId::None;
  546. }
  547. // Mark functions with the interface's scope as a hint to mangling. This
  548. // does not add them to the scope.
  549. auto query_specific_interface =
  550. context.specific_interfaces().Get(query_specific_interface_id);
  551. auto parent_scope_id = context.interfaces()
  552. .Get(query_specific_interface.interface_id)
  553. .scope_without_self_id;
  554. auto self_type_id = GetFacetAsType(context, query_self_const_id);
  555. auto op_id = MakeDestroyOpFunction(context, loc_id, self_type_id,
  556. parent_scope_id, format);
  557. return BuildCustomWitness(context, loc_id, query_self_const_id,
  558. query_specific_interface_id, {op_id});
  559. }
  560. static auto MakeIntFitsInWitness(
  561. Context& context, SemIR::LocId loc_id,
  562. SemIR::ConstantId query_self_const_id,
  563. SemIR::SpecificInterfaceId query_specific_interface_id, bool build_witness)
  564. -> std::optional<SemIR::InstId> {
  565. auto query_specific_interface =
  566. context.specific_interfaces().Get(query_specific_interface_id);
  567. auto args_id = query_specific_interface.specific_id;
  568. if (!args_id.has_value()) {
  569. return std::nullopt;
  570. }
  571. auto args_block_id = context.specifics().Get(args_id).args_id;
  572. auto args_block = context.inst_blocks().Get(args_block_id);
  573. if (args_block.size() != 1) {
  574. return std::nullopt;
  575. }
  576. auto dest_const_id = context.constant_values().Get(args_block[0]);
  577. if (!dest_const_id.is_constant()) {
  578. return std::nullopt;
  579. }
  580. auto src_type_id = GetFacetAsType(context, query_self_const_id);
  581. auto dest_type_id = GetFacetAsType(context, dest_const_id);
  582. auto context_fn = [](DiagnosticContextBuilder& /*builder*/) -> void {};
  583. if (!RequireCompleteType(context, src_type_id, loc_id, context_fn) ||
  584. !RequireCompleteType(context, dest_type_id, loc_id, context_fn)) {
  585. return std::nullopt;
  586. }
  587. auto src_info = context.types().TryGetIntTypeInfo(src_type_id);
  588. auto dest_info = context.types().TryGetIntTypeInfo(dest_type_id);
  589. if (!src_info || !dest_info) {
  590. return std::nullopt;
  591. }
  592. // If the bit width is unknown (e.g., due to symbolic evaluation), we cannot
  593. // determine whether it fits yet.
  594. if (src_info->bit_width == IntId::None ||
  595. dest_info->bit_width == IntId::None) {
  596. return std::nullopt;
  597. }
  598. const auto& src_width = context.ints().Get(src_info->bit_width);
  599. const auto& dest_width = context.ints().Get(dest_info->bit_width);
  600. bool fits = false;
  601. if (src_info->is_signed && !dest_info->is_signed) {
  602. // Signed -> unsigned: would truncate the sign bit.
  603. fits = false;
  604. } else if (src_info->is_signed == dest_info->is_signed) {
  605. // Signed -> signed or unsigned -> unsigned: allow widening or preserving
  606. // width.
  607. fits = src_width.sle(dest_width);
  608. } else {
  609. // Unsigned -> signed: strict widening required.
  610. fits = src_width.slt(dest_width);
  611. }
  612. if (!fits) {
  613. return std::nullopt;
  614. }
  615. if (!build_witness) {
  616. return SemIR::InstId::None;
  617. }
  618. return BuildCustomWitness(context, loc_id, query_self_const_id,
  619. query_specific_interface_id, {});
  620. }
  621. auto LookupCustomWitness(Context& context, SemIR::LocId loc_id,
  622. SemIR::CoreInterface core_interface,
  623. SemIR::ConstantId query_self_const_id,
  624. SemIR::SpecificInterfaceId query_specific_interface_id,
  625. bool build_witness) -> std::optional<SemIR::InstId> {
  626. switch (core_interface) {
  627. case SemIR::CoreInterface::Destroy:
  628. return MakeDestroyWitness(context, loc_id, query_self_const_id,
  629. query_specific_interface_id, build_witness);
  630. case SemIR::CoreInterface::IntFitsIn:
  631. return MakeIntFitsInWitness(context, loc_id, query_self_const_id,
  632. query_specific_interface_id, build_witness);
  633. case SemIR::CoreInterface::AddAssignWith:
  634. case SemIR::CoreInterface::AddWith:
  635. case SemIR::CoreInterface::Copy:
  636. case SemIR::CoreInterface::CppUnsafeDeref:
  637. case SemIR::CoreInterface::Dec:
  638. case SemIR::CoreInterface::Default:
  639. case SemIR::CoreInterface::DivAssignWith:
  640. case SemIR::CoreInterface::DivWith:
  641. case SemIR::CoreInterface::Inc:
  642. case SemIR::CoreInterface::ModAssignWith:
  643. case SemIR::CoreInterface::ModWith:
  644. case SemIR::CoreInterface::MulAssignWith:
  645. case SemIR::CoreInterface::MulWith:
  646. case SemIR::CoreInterface::Negate:
  647. case SemIR::CoreInterface::SubAssignWith:
  648. case SemIR::CoreInterface::SubWith:
  649. case SemIR::CoreInterface::Unknown:
  650. // TODO: Handle more interfaces, particularly copy, move, and conversion.
  651. return std::nullopt;
  652. }
  653. }
  654. } // namespace Carbon::Check