impl.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  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/impl.h"
  5. #include "toolchain/base/kind_switch.h"
  6. #include "toolchain/check/context.h"
  7. #include "toolchain/check/deduce.h"
  8. #include "toolchain/check/eval.h"
  9. #include "toolchain/check/facet_type.h"
  10. #include "toolchain/check/function.h"
  11. #include "toolchain/check/generic.h"
  12. #include "toolchain/check/import_ref.h"
  13. #include "toolchain/check/inst.h"
  14. #include "toolchain/check/interface.h"
  15. #include "toolchain/check/merge.h"
  16. #include "toolchain/check/name_lookup.h"
  17. #include "toolchain/check/name_scope.h"
  18. #include "toolchain/check/thunk.h"
  19. #include "toolchain/check/type.h"
  20. #include "toolchain/check/type_completion.h"
  21. #include "toolchain/check/type_structure.h"
  22. #include "toolchain/diagnostics/diagnostic_emitter.h"
  23. #include "toolchain/sem_ir/generic.h"
  24. #include "toolchain/sem_ir/ids.h"
  25. #include "toolchain/sem_ir/impl.h"
  26. #include "toolchain/sem_ir/inst.h"
  27. #include "toolchain/sem_ir/typed_insts.h"
  28. namespace Carbon::Check {
  29. // Adds the location of the associated function to a diagnostic.
  30. static auto NoteAssociatedFunction(Context& context, DiagnosticBuilder& builder,
  31. SemIR::FunctionId function_id) -> void {
  32. CARBON_DIAGNOSTIC(AssociatedFunctionHere, Note,
  33. "associated function {0} declared here", SemIR::NameId);
  34. const auto& function = context.functions().Get(function_id);
  35. builder.Note(function.latest_decl_id(), AssociatedFunctionHere,
  36. function.name_id);
  37. }
  38. auto CheckAssociatedFunctionImplementation(
  39. Context& context, SemIR::FunctionType interface_function_type,
  40. SemIR::InstId impl_decl_id, SemIR::TypeId self_type_id,
  41. SemIR::InstId witness_inst_id, bool defer_thunk_definition)
  42. -> SemIR::InstId {
  43. auto impl_function_decl =
  44. context.insts().TryGetAs<SemIR::FunctionDecl>(impl_decl_id);
  45. if (!impl_function_decl) {
  46. if (impl_decl_id != SemIR::ErrorInst::InstId) {
  47. CARBON_DIAGNOSTIC(ImplFunctionWithNonFunction, Error,
  48. "associated function {0} implemented by non-function",
  49. SemIR::NameId);
  50. auto builder = context.emitter().Build(
  51. impl_decl_id, ImplFunctionWithNonFunction,
  52. context.functions().Get(interface_function_type.function_id).name_id);
  53. NoteAssociatedFunction(context, builder,
  54. interface_function_type.function_id);
  55. builder.Emit();
  56. }
  57. return SemIR::ErrorInst::InstId;
  58. }
  59. auto impl_enclosing_specific_id =
  60. context.types()
  61. .GetAs<SemIR::FunctionType>(impl_function_decl->type_id)
  62. .specific_id;
  63. // Map from the specific for the function type to the specific for the
  64. // function signature. The function signature may have additional generic
  65. // parameters.
  66. auto interface_function_specific_id =
  67. GetSelfSpecificForInterfaceMemberWithSelfType(
  68. context, SemIR::LocId(impl_decl_id),
  69. interface_function_type.specific_id,
  70. context.functions()
  71. .Get(interface_function_type.function_id)
  72. .generic_id,
  73. impl_enclosing_specific_id, self_type_id, witness_inst_id);
  74. return BuildThunk(context, interface_function_type.function_id,
  75. interface_function_specific_id, impl_decl_id,
  76. defer_thunk_definition);
  77. }
  78. // Builds an initial witness from the rewrites in the facet type, if any.
  79. auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl)
  80. -> SemIR::InstId {
  81. CARBON_CHECK(!impl.has_definition_started());
  82. auto self_type_id = context.types().GetTypeIdForTypeInstId(impl.self_id);
  83. if (self_type_id == SemIR::ErrorInst::TypeId) {
  84. // When 'impl as' is invalid, the self type is an error.
  85. return SemIR::ErrorInst::InstId;
  86. }
  87. return InitialFacetTypeImplWitness(
  88. context, SemIR::LocId(impl.latest_decl_id()), impl.constraint_id,
  89. impl.self_id, impl.interface,
  90. context.generics().GetSelfSpecific(impl.generic_id));
  91. }
  92. auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
  93. CARBON_CHECK(impl.is_being_defined());
  94. CARBON_CHECK(impl.witness_id.has_value());
  95. if (impl.witness_id == SemIR::ErrorInst::InstId) {
  96. return;
  97. }
  98. if (!RequireCompleteType(
  99. context, context.types().GetTypeIdForTypeInstId(impl.constraint_id),
  100. SemIR::LocId(impl.constraint_id), [&] {
  101. CARBON_DIAGNOSTIC(ImplAsIncompleteFacetTypeDefinition, Error,
  102. "definition of impl as incomplete facet type {0}",
  103. InstIdAsType);
  104. return context.emitter().Build(SemIR::LocId(impl.latest_decl_id()),
  105. ImplAsIncompleteFacetTypeDefinition,
  106. impl.constraint_id);
  107. })) {
  108. FillImplWitnessWithErrors(context, impl);
  109. return;
  110. }
  111. const auto& interface = context.interfaces().Get(impl.interface.interface_id);
  112. auto assoc_entities =
  113. context.inst_blocks().Get(interface.associated_entities_id);
  114. for (auto decl_id : assoc_entities) {
  115. LoadImportRef(context, decl_id);
  116. }
  117. auto witness = context.insts().GetAs<SemIR::ImplWitness>(impl.witness_id);
  118. auto witness_table =
  119. context.insts().GetAs<SemIR::ImplWitnessTable>(witness.witness_table_id);
  120. auto witness_block =
  121. context.inst_blocks().GetMutable(witness_table.elements_id);
  122. // The impl declaration may have created a placeholder witness table, or a
  123. // full witness table. We can detect that the witness table is a placeholder
  124. // table if it's not the `Empty` id, but it is empty still. If it was a
  125. // placeholder, we can replace the placeholder here with a table of the proper
  126. // size, since the interface must be complete for the impl definition.
  127. bool witness_table_is_placeholder =
  128. witness_table.elements_id != SemIR::InstBlockId::Empty &&
  129. witness_block.empty();
  130. if (witness_table_is_placeholder) {
  131. // TODO: Since our `empty_table` repeats the same value throughout, we could
  132. // skip an allocation here if there was a `ReplacePlaceholder` function that
  133. // took a size and value instead of an array of values.
  134. llvm::SmallVector<SemIR::InstId> empty_table(
  135. assoc_entities.size(), SemIR::InstId::ImplWitnessTablePlaceholder);
  136. context.inst_blocks().ReplacePlaceholder(witness_table.elements_id,
  137. empty_table);
  138. witness_block = context.inst_blocks().GetMutable(witness_table.elements_id);
  139. }
  140. // Check we have a value for all non-function associated constants in the
  141. // witness.
  142. for (auto [assoc_entity, witness_value] :
  143. llvm::zip_equal(assoc_entities, witness_block)) {
  144. auto decl_id = context.constant_values().GetConstantInstId(assoc_entity);
  145. CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
  146. if (auto decl =
  147. context.insts().TryGetAs<SemIR::AssociatedConstantDecl>(decl_id)) {
  148. if (witness_value == SemIR::InstId::ImplWitnessTablePlaceholder) {
  149. CARBON_DIAGNOSTIC(ImplAssociatedConstantNeedsValue, Error,
  150. "associated constant {0} not given a value in impl "
  151. "of interface {1}",
  152. SemIR::NameId, SemIR::NameId);
  153. CARBON_DIAGNOSTIC(AssociatedConstantHere, Note,
  154. "associated constant declared here");
  155. context.emitter()
  156. .Build(impl.definition_id, ImplAssociatedConstantNeedsValue,
  157. context.associated_constants()
  158. .Get(decl->assoc_const_id)
  159. .name_id,
  160. interface.name_id)
  161. .Note(assoc_entity, AssociatedConstantHere)
  162. .Emit();
  163. witness_value = SemIR::ErrorInst::InstId;
  164. }
  165. }
  166. }
  167. }
  168. // Adds functions to the witness that the specified impl implements the given
  169. // interface.
  170. auto FinishImplWitness(Context& context, SemIR::ImplId impl_id) -> void {
  171. const auto& impl = context.impls().Get(impl_id);
  172. CARBON_CHECK(impl.is_being_defined());
  173. CARBON_CHECK(impl.witness_id.has_value());
  174. if (impl.witness_id == SemIR::ErrorInst::InstId) {
  175. return;
  176. }
  177. auto witness = context.insts().GetAs<SemIR::ImplWitness>(impl.witness_id);
  178. auto witness_table =
  179. context.insts().GetAs<SemIR::ImplWitnessTable>(witness.witness_table_id);
  180. auto witness_block =
  181. context.inst_blocks().GetMutable(witness_table.elements_id);
  182. auto& impl_scope = context.name_scopes().Get(impl.scope_id);
  183. auto self_type_id = context.types().GetTypeIdForTypeInstId(impl.self_id);
  184. const auto& interface = context.interfaces().Get(impl.interface.interface_id);
  185. auto assoc_entities =
  186. context.inst_blocks().Get(interface.associated_entities_id);
  187. llvm::SmallVector<SemIR::InstId> used_decl_ids;
  188. for (auto [assoc_entity, witness_value] :
  189. llvm::zip_equal(assoc_entities, witness_block)) {
  190. auto decl_id =
  191. context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
  192. context.sem_ir(), impl.interface.specific_id, assoc_entity));
  193. CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
  194. auto decl = context.insts().Get(decl_id);
  195. CARBON_KIND_SWITCH(decl) {
  196. case CARBON_KIND(SemIR::StructValue struct_value): {
  197. if (struct_value.type_id == SemIR::ErrorInst::TypeId) {
  198. witness_value = SemIR::ErrorInst::InstId;
  199. break;
  200. }
  201. auto type_inst = context.types().GetAsInst(struct_value.type_id);
  202. auto fn_type = type_inst.TryAs<SemIR::FunctionType>();
  203. if (!fn_type) {
  204. CARBON_FATAL("Unexpected type: {0}", type_inst);
  205. }
  206. auto& fn = context.functions().Get(fn_type->function_id);
  207. auto lookup_result =
  208. LookupNameInExactScope(context, SemIR::LocId(decl_id), fn.name_id,
  209. impl.scope_id, impl_scope);
  210. if (lookup_result.is_found()) {
  211. used_decl_ids.push_back(lookup_result.target_inst_id());
  212. witness_value = CheckAssociatedFunctionImplementation(
  213. context, *fn_type, lookup_result.target_inst_id(), self_type_id,
  214. impl.witness_id, /*defer_thunk_definition=*/true);
  215. } else {
  216. CARBON_DIAGNOSTIC(
  217. ImplMissingFunction, Error,
  218. "missing implementation of {0} in impl of interface {1}",
  219. SemIR::NameId, SemIR::NameId);
  220. auto builder =
  221. context.emitter().Build(impl.definition_id, ImplMissingFunction,
  222. fn.name_id, interface.name_id);
  223. NoteAssociatedFunction(context, builder, fn_type->function_id);
  224. builder.Emit();
  225. witness_value = SemIR::ErrorInst::InstId;
  226. }
  227. break;
  228. }
  229. case SemIR::AssociatedConstantDecl::Kind: {
  230. // These are set to their final values already.
  231. break;
  232. }
  233. default:
  234. CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
  235. "Unexpected kind of associated entity {0}", decl);
  236. witness_value = SemIR::ErrorInst::InstId;
  237. break;
  238. }
  239. }
  240. // TODO: Diagnose if any declarations in the impl are not in used_decl_ids.
  241. }
  242. auto FillImplWitnessWithErrors(Context& context, SemIR::Impl& impl) -> void {
  243. if (impl.witness_id == SemIR::ErrorInst::InstId) {
  244. return;
  245. }
  246. auto witness = context.insts().GetAs<SemIR::ImplWitness>(impl.witness_id);
  247. auto witness_table =
  248. context.insts().GetAs<SemIR::ImplWitnessTable>(witness.witness_table_id);
  249. auto witness_block =
  250. context.inst_blocks().GetMutable(witness_table.elements_id);
  251. for (auto& elem : witness_block) {
  252. if (elem == SemIR::InstId::ImplWitnessTablePlaceholder) {
  253. elem = SemIR::ErrorInst::InstId;
  254. }
  255. }
  256. impl.witness_id = SemIR::ErrorInst::InstId;
  257. }
  258. auto IsImplEffectivelyFinal(Context& context, const SemIR::Impl& impl) -> bool {
  259. return impl.is_final ||
  260. (context.constant_values().Get(impl.self_id).is_concrete() &&
  261. context.constant_values().Get(impl.constraint_id).is_concrete());
  262. }
  263. auto CheckConstraintIsInterface(Context& context, SemIR::InstId impl_decl_id,
  264. SemIR::TypeInstId constraint_id)
  265. -> SemIR::SpecificInterface {
  266. auto facet_type_id = context.types().GetTypeIdForTypeInstId(constraint_id);
  267. if (facet_type_id == SemIR::ErrorInst::TypeId) {
  268. return SemIR::SpecificInterface::None;
  269. }
  270. auto facet_type = context.types().TryGetAs<SemIR::FacetType>(facet_type_id);
  271. if (!facet_type) {
  272. CARBON_DIAGNOSTIC(ImplAsNonFacetType, Error, "impl as non-facet type {0}",
  273. InstIdAsType);
  274. context.emitter().Emit(impl_decl_id, ImplAsNonFacetType, constraint_id);
  275. return SemIR::SpecificInterface::None;
  276. }
  277. auto identified_id = RequireIdentifiedFacetType(
  278. context, SemIR::LocId(constraint_id), *facet_type, [&] {
  279. CARBON_DIAGNOSTIC(ImplOfUnidentifiedFacetType, Error,
  280. "facet type {0} cannot be identified in `impl as`",
  281. InstIdAsType);
  282. return context.emitter().Build(
  283. impl_decl_id, ImplOfUnidentifiedFacetType, constraint_id);
  284. });
  285. if (!identified_id.has_value()) {
  286. return SemIR::SpecificInterface::None;
  287. }
  288. const auto& identified = context.identified_facet_types().Get(identified_id);
  289. if (!identified.is_valid_impl_as_target()) {
  290. CARBON_DIAGNOSTIC(ImplOfNotOneInterface, Error,
  291. "impl as {0} interfaces, expected 1", int);
  292. context.emitter().Emit(impl_decl_id, ImplOfNotOneInterface,
  293. identified.num_interfaces_to_impl());
  294. return SemIR::SpecificInterface::None;
  295. }
  296. return identified.impl_as_target_interface();
  297. }
  298. // Returns true if impl redeclaration parameters match.
  299. static auto CheckImplRedeclParamsMatch(Context& context,
  300. const SemIR::Impl& new_impl,
  301. SemIR::ImplId prev_impl_id) -> bool {
  302. auto& prev_impl = context.impls().Get(prev_impl_id);
  303. // If the parameters aren't the same, then this is not a redeclaration of this
  304. // `impl`. Keep looking for a prior declaration without issuing a diagnostic.
  305. if (!CheckRedeclParamsMatch(context, DeclParams(new_impl),
  306. DeclParams(prev_impl), SemIR::SpecificId::None,
  307. /*diagnose=*/false, /*check_syntax=*/true,
  308. /*check_self=*/true)) {
  309. // NOLINTNEXTLINE(readability-simplify-boolean-expr)
  310. return false;
  311. }
  312. return true;
  313. }
  314. // Returns whether an impl can be redeclared. For example, defined impls
  315. // cannot be redeclared.
  316. static auto IsValidImplRedecl(Context& context, const SemIR::Impl& new_impl,
  317. SemIR::ImplId prev_impl_id) -> bool {
  318. auto& prev_impl = context.impls().Get(prev_impl_id);
  319. // TODO: Following #3763, disallow redeclarations in different scopes.
  320. // Following #4672, disallowing defining non-extern declarations in another
  321. // file.
  322. if (auto import_ref =
  323. context.insts().TryGetAs<SemIR::AnyImportRef>(prev_impl.self_id)) {
  324. // TODO: Handle extern.
  325. CARBON_DIAGNOSTIC(RedeclImportedImpl, Error,
  326. "redeclaration of imported impl");
  327. // TODO: Note imported declaration
  328. context.emitter().Emit(new_impl.latest_decl_id(), RedeclImportedImpl);
  329. return false;
  330. }
  331. if (prev_impl.has_definition_started()) {
  332. // Impls aren't merged in order to avoid generic region lookup into a
  333. // mismatching table.
  334. CARBON_DIAGNOSTIC(ImplRedefinition, Error,
  335. "redefinition of `impl {0} as {1}`", InstIdAsRawType,
  336. InstIdAsRawType);
  337. CARBON_DIAGNOSTIC(ImplPreviousDefinition, Note,
  338. "previous definition was here");
  339. context.emitter()
  340. .Build(new_impl.latest_decl_id(), ImplRedefinition, new_impl.self_id,
  341. new_impl.constraint_id)
  342. .Note(prev_impl.definition_id, ImplPreviousDefinition)
  343. .Emit();
  344. return false;
  345. }
  346. // TODO: Only allow redeclaration in a match_first/impl_priority block.
  347. return true;
  348. }
  349. // Sets the `ImplId` in the `ImplWitnessTable`.
  350. static auto AssignImplIdInWitness(Context& context, SemIR::ImplId impl_id,
  351. SemIR::InstId witness_id) -> void {
  352. if (witness_id == SemIR::ErrorInst::InstId) {
  353. return;
  354. }
  355. auto witness = context.insts().GetAs<SemIR::ImplWitness>(witness_id);
  356. auto witness_table =
  357. context.insts().GetAs<SemIR::ImplWitnessTable>(witness.witness_table_id);
  358. witness_table.impl_id = impl_id;
  359. // Note: The `ImplWitnessTable` instruction is `Unique`, so while this marks
  360. // the instruction as being a dependent instruction of a generic impl, it will
  361. // not be substituted into the eval block.
  362. ReplaceInstBeforeConstantUse(context, witness.witness_table_id,
  363. witness_table);
  364. }
  365. // Looks for any unused generic bindings. If one is found, it is diagnosed and
  366. // false is returned.
  367. static auto VerifyAllGenericBindingsUsed(Context& context, SemIR::LocId loc_id,
  368. SemIR::LocId implicit_params_loc_id,
  369. SemIR::Impl& impl) -> bool {
  370. if (impl.witness_id == SemIR::ErrorInst::InstId) {
  371. return true;
  372. }
  373. if (!impl.generic_id.has_value()) {
  374. return true;
  375. }
  376. if (impl.implicit_param_patterns_id.has_value()) {
  377. for (auto inst_id :
  378. context.inst_blocks().Get(impl.implicit_param_patterns_id)) {
  379. if (inst_id == SemIR::ErrorInst::InstId) {
  380. // An error was already diagnosed for a generic binding.
  381. return true;
  382. }
  383. }
  384. }
  385. auto deduced_specific_id = DeduceImplArguments(
  386. context, loc_id, impl, context.constant_values().Get(impl.self_id),
  387. impl.interface.specific_id);
  388. if (deduced_specific_id.has_value()) {
  389. // Deduction succeeded, all bindings were used.
  390. return true;
  391. }
  392. CARBON_DIAGNOSTIC(ImplUnusedBinding, Error,
  393. "`impl` with unused generic binding");
  394. // TODO: This location may be incorrect, the binding may be inherited
  395. // from an outer declaration. It would be nice to get the particular
  396. // binding that was undeducible back from DeduceImplArguments here and
  397. // use that.
  398. auto diag_loc_id =
  399. implicit_params_loc_id.has_value() ? implicit_params_loc_id : loc_id;
  400. context.emitter().Emit(diag_loc_id, ImplUnusedBinding);
  401. return false;
  402. }
  403. // Apply an `extend impl` declaration by extending the parent scope with the
  404. // `impl`. If there's an error it is diagnosed and false is returned.
  405. static auto ApplyExtendImplAs(Context& context, SemIR::LocId loc_id,
  406. const SemIR::Impl& impl,
  407. Parse::NodeId extend_node,
  408. SemIR::LocId implicit_params_loc_id) -> bool {
  409. auto parent_scope_id = context.decl_name_stack().PeekParentScopeId();
  410. // TODO: Also handle the parent scope being a mixin or an interface.
  411. auto class_scope = TryAsClassScope(context, parent_scope_id);
  412. if (!class_scope) {
  413. if (impl.witness_id != SemIR::ErrorInst::InstId) {
  414. CARBON_DIAGNOSTIC(
  415. ExtendImplOutsideClass, Error,
  416. "`extend impl` can only be used in an interface or class");
  417. context.emitter().Emit(loc_id, ExtendImplOutsideClass);
  418. }
  419. return false;
  420. }
  421. auto& parent_scope = *class_scope->name_scope;
  422. // An error was already diagnosed, but this is `extend impl as` inside a
  423. // class, so propagate the error into the enclosing class scope.
  424. if (impl.witness_id == SemIR::ErrorInst::InstId) {
  425. parent_scope.set_has_error();
  426. return false;
  427. }
  428. if (implicit_params_loc_id.has_value()) {
  429. CARBON_DIAGNOSTIC(ExtendImplForall, Error,
  430. "cannot `extend` a parameterized `impl`");
  431. context.emitter().Emit(extend_node, ExtendImplForall);
  432. parent_scope.set_has_error();
  433. return false;
  434. }
  435. if (!RequireCompleteType(
  436. context, context.types().GetTypeIdForTypeInstId(impl.constraint_id),
  437. SemIR::LocId(impl.constraint_id), [&] {
  438. CARBON_DIAGNOSTIC(ExtendImplAsIncomplete, Error,
  439. "`extend impl as` incomplete facet type {0}",
  440. InstIdAsType);
  441. return context.emitter().Build(impl.latest_decl_id(),
  442. ExtendImplAsIncomplete,
  443. impl.constraint_id);
  444. })) {
  445. parent_scope.set_has_error();
  446. return false;
  447. }
  448. if (!impl.generic_id.has_value()) {
  449. parent_scope.AddExtendedScope(impl.constraint_id);
  450. } else {
  451. auto constraint_id_in_self_specific = AddTypeInst<SemIR::SpecificConstant>(
  452. context, SemIR::LocId(impl.constraint_id),
  453. {.type_id = SemIR::TypeType::TypeId,
  454. .inst_id = impl.constraint_id,
  455. .specific_id = context.generics().GetSelfSpecific(impl.generic_id)});
  456. parent_scope.AddExtendedScope(constraint_id_in_self_specific);
  457. }
  458. return true;
  459. }
  460. auto GetOrAddImpl(Context& context, SemIR::LocId loc_id,
  461. SemIR::LocId implicit_params_loc_id, SemIR::Impl impl,
  462. Parse::NodeId extend_node) -> SemIR::ImplId {
  463. auto impl_id = SemIR::ImplId::None;
  464. // Look for an existing matching declaration.
  465. auto lookup_bucket_ref = context.impls().GetOrAddLookupBucket(impl);
  466. // TODO: Detect two impl declarations with the same self type and interface,
  467. // and issue an error if they don't match.
  468. for (auto prev_impl_id : lookup_bucket_ref) {
  469. if (CheckImplRedeclParamsMatch(context, impl, prev_impl_id)) {
  470. if (IsValidImplRedecl(context, impl, prev_impl_id)) {
  471. impl_id = prev_impl_id;
  472. } else {
  473. // IsValidImplRedecl() has issued a diagnostic, take care to avoid
  474. // generating more diagnostics for this declaration.
  475. impl.witness_id = SemIR::ErrorInst::InstId;
  476. }
  477. break;
  478. }
  479. }
  480. if (impl_id.has_value()) {
  481. // This is a redeclaration of another impl, now held in `impl_id`.
  482. auto& prev_impl = context.impls().Get(impl_id);
  483. FinishGenericRedecl(context, prev_impl.generic_id);
  484. return impl_id;
  485. }
  486. // This is a new declaration (possibly with an attached definition). Create a
  487. // new `impl_id`, filling the missing generic and witness in the provided
  488. // `Impl`.
  489. impl.generic_id = BuildGeneric(context, impl.latest_decl_id());
  490. // Due to lack of an instruction to set to `ErrorInst`, an `InterfaceId::None`
  491. // indicates that the interface could not be identified and an error was
  492. // diagnosed. If there's any error in the construction of the impl, then the
  493. // witness can't be constructed. We set it to `ErrorInst` to make the impl
  494. // unusable for impl lookup.
  495. if (!impl.interface.interface_id.has_value() ||
  496. impl.self_id == SemIR::ErrorInst::TypeInstId ||
  497. impl.constraint_id == SemIR::ErrorInst::TypeInstId) {
  498. impl.witness_id = SemIR::ErrorInst::InstId;
  499. // TODO: We might also want to mark that the name scope for the impl has an
  500. // error -- at least once we start making name lookups within the impl also
  501. // look into the facet (eg, so you can name associated constants from within
  502. // the impl).
  503. }
  504. if (impl.witness_id != SemIR::ErrorInst::InstId) {
  505. // This makes either a placeholder witness or a full witness table. The full
  506. // witness table is deferred to the impl definition unless the declaration
  507. // uses rewrite constraints to set values of associated constants in the
  508. // interface.
  509. impl.witness_id = ImplWitnessForDeclaration(context, impl);
  510. }
  511. FinishGenericDecl(context, SemIR::LocId(impl.latest_decl_id()),
  512. impl.generic_id);
  513. // From here on, use the `Impl` from the `ImplStore` instead of `impl` in
  514. // order to make and see any changes to the `Impl`.
  515. impl_id = context.impls().Add(impl);
  516. lookup_bucket_ref.push_back(impl_id);
  517. AssignImplIdInWitness(context, impl_id, impl.witness_id);
  518. auto& stored_impl = context.impls().Get(impl_id);
  519. // Look to see if there are any generic bindings on the `impl` declaration
  520. // that are not deducible. If so, and the `impl` does not actually use all its
  521. // generic bindings, and will never be matched. This should be diagnosed to
  522. // the user.
  523. if (!VerifyAllGenericBindingsUsed(context, loc_id, implicit_params_loc_id,
  524. stored_impl)) {
  525. FillImplWitnessWithErrors(context, stored_impl);
  526. }
  527. if (extend_node.has_value()) {
  528. if (!ApplyExtendImplAs(context, loc_id, stored_impl, extend_node,
  529. implicit_params_loc_id)) {
  530. FillImplWitnessWithErrors(context, stored_impl);
  531. }
  532. }
  533. return impl_id;
  534. }
  535. } // namespace Carbon::Check