custom_witness.cpp 30 KB

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