period_self.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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/period_self.h"
  5. #include "toolchain/base/kind_switch.h"
  6. #include "toolchain/check/control_flow.h"
  7. #include "toolchain/check/convert.h"
  8. #include "toolchain/check/facet_type.h"
  9. #include "toolchain/check/generic.h"
  10. #include "toolchain/check/inst.h"
  11. #include "toolchain/check/type.h"
  12. #include "toolchain/check/type_completion.h"
  13. #include "toolchain/sem_ir/typed_insts.h"
  14. namespace Carbon::Check {
  15. auto MakePeriodSelfFacetValue(Context& context, SemIR::TypeId self_type_id)
  16. -> SemIR::InstId {
  17. CARBON_CHECK(self_type_id == SemIR::ErrorInst::TypeId ||
  18. context.types().Is<SemIR::FacetType>(self_type_id));
  19. auto entity_name_id = context.entity_names().AddCanonical({
  20. .name_id = SemIR::NameId::PeriodSelf,
  21. .parent_scope_id = context.scope_stack().PeekNameScopeId(),
  22. });
  23. auto inst_id = AddInst(
  24. context, SemIR::LocIdAndInst::NoLoc<SemIR::SymbolicBinding>({
  25. .type_id = self_type_id,
  26. .entity_name_id = entity_name_id,
  27. // `None` because there is no equivalent non-symbolic value.
  28. .value_id = SemIR::InstId::None,
  29. }));
  30. auto existing = context.scope_stack().LookupOrAddName(
  31. SemIR::NameId::PeriodSelf, inst_id, ScopeIndex::None,
  32. IsCurrentPositionReachable(context));
  33. // Shouldn't have any names in newly created scope.
  34. CARBON_CHECK(!existing.has_value());
  35. return inst_id;
  36. }
  37. SubstPeriodSelfCallbacks::SubstPeriodSelfCallbacks(
  38. Context* context, SemIR::LocId loc_id,
  39. SemIR::ConstantId period_self_replacement_id)
  40. : SubstInstCallbacks(context),
  41. loc_id_(loc_id),
  42. period_self_replacement_id_(period_self_replacement_id) {}
  43. auto SubstPeriodSelfCallbacks::Subst(SemIR::InstId& inst_id) -> SubstResult {
  44. // FacetTypes are concrete even if they have `.Self` inside them, but we
  45. // don't recurse into FacetTypes, so we can use this as a base case. This
  46. // avoids infinite recursion on TypeType and ErrorInst.
  47. if (context().constant_values().Get(inst_id).is_concrete()) {
  48. return FullySubstituted;
  49. }
  50. // Don't recurse into nested facet types, even if they are symbolic. Leave
  51. // their `.Self` as is.
  52. if (context().insts().Is<SemIR::FacetType>(inst_id)) {
  53. return FullySubstituted;
  54. }
  55. // For `.X` (which is `.Self.X`) replace the `.Self` in the query self
  56. // position, and report it as `implicit`. Any `.Self` references in the
  57. // specific interface would be replaced later and not treated as `implicit`.
  58. //
  59. // TODO: This all goes away when eval doesn't need to know about implicit
  60. // .Self for diagnostics, once we diagnose invalid `.Self` in name lookup.
  61. if (auto access =
  62. context().insts().TryGetAs<SemIR::ImplWitnessAccess>(inst_id)) {
  63. if (auto witness = context().insts().TryGetAs<SemIR::LookupImplWitness>(
  64. access->witness_id)) {
  65. if (auto bind = context().insts().TryGetAs<SemIR::SymbolicBinding>(
  66. witness->query_self_inst_id)) {
  67. const auto& entity_name =
  68. context().entity_names().Get(bind->entity_name_id);
  69. if (entity_name.name_id == SemIR::NameId::PeriodSelf) {
  70. auto replacement_id =
  71. GetReplacement(witness->query_self_inst_id, true);
  72. auto new_witness =
  73. Rebuild(access->witness_id,
  74. SemIR::LookupImplWitness{
  75. .type_id = witness->type_id,
  76. .query_self_inst_id = replacement_id,
  77. // Don't replace `.Self` in the interface specific
  78. // here. That is an explicit `.Self` use. We'll
  79. // revisit the instruction for that.
  80. .query_specific_interface_id =
  81. witness->query_specific_interface_id,
  82. });
  83. auto new_access = Rebuild(inst_id, SemIR::ImplWitnessAccess{
  84. .type_id = access->type_id,
  85. .witness_id = new_witness,
  86. .index = access->index,
  87. });
  88. inst_id = new_access;
  89. return SubstAgain;
  90. }
  91. }
  92. }
  93. }
  94. if (auto bind = context().insts().TryGetAs<SemIR::SymbolicBinding>(inst_id)) {
  95. const auto& entity_name =
  96. context().entity_names().Get(bind->entity_name_id);
  97. if (entity_name.name_id == SemIR::NameId::PeriodSelf) {
  98. inst_id = GetReplacement(inst_id, false);
  99. return FullySubstituted;
  100. }
  101. }
  102. return SubstOperands;
  103. }
  104. auto SubstPeriodSelfCallbacks::Rebuild(SemIR::InstId orig_inst_id,
  105. SemIR::Inst new_inst) -> SemIR::InstId {
  106. return RebuildNewInst(SemIR::LocId(orig_inst_id), new_inst);
  107. }
  108. auto SubstPeriodSelfCallbacks::GetReplacement(SemIR::InstId period_self,
  109. bool implicit) -> SemIR::InstId {
  110. if (!ShouldReplace(implicit)) {
  111. return period_self;
  112. }
  113. auto period_self_type_id = context().insts().Get(period_self).type_id();
  114. CARBON_CHECK(context().types().Is<SemIR::FacetType>(period_self_type_id));
  115. auto replacement_self_inst_id =
  116. context().constant_values().GetInstId(period_self_replacement_id_);
  117. auto replacement_type_id =
  118. context().insts().Get(replacement_self_inst_id).type_id();
  119. CARBON_CHECK(context().types().IsFacetType(replacement_type_id));
  120. // If the replacement has the same type as `.Self`, use it directly.
  121. if (replacement_type_id == period_self_type_id) {
  122. return replacement_self_inst_id;
  123. }
  124. // If we have already converted the replacement to the type of `.Self`, use
  125. // our previous conversion.
  126. if (period_self_type_id == cached_replacement_type_id_) {
  127. return cached_replacement_id_;
  128. }
  129. // Convert the replacement facet to the type of `.Self`.
  130. cached_replacement_id_ = ConvertReplacement(
  131. replacement_self_inst_id, replacement_type_id, period_self_type_id);
  132. cached_replacement_type_id_ = period_self_type_id;
  133. return cached_replacement_id_;
  134. }
  135. auto SubstPeriodSelfCallbacks::ConvertReplacement(
  136. SemIR::InstId replacement_self_inst_id, SemIR::TypeId replacement_type_id,
  137. SemIR::TypeId period_self_type_id) -> SemIR::InstId {
  138. // TODO: Replace all empty facet types with TypeType.
  139. if (period_self_type_id == GetEmptyFacetType(context())) {
  140. // Convert to an empty facet type (representing TypeType); we don't need
  141. // any witnesses.
  142. return ConvertToValueOfType(context(), loc_id_, replacement_self_inst_id,
  143. period_self_type_id);
  144. }
  145. // We have a facet or a type, but we need more interfaces in the facet type.
  146. // We will have to synthesize a symbolic witness for each interface.
  147. //
  148. // Why is this okay? The type of `.Self` comes from interfaces that are
  149. // before it (to the left of it) in the facet type. The replacement for
  150. // `.Self` will have to impl those interfaces in order to match the facet
  151. // type, so we know that it is valid to construct these witnesses.
  152. // Make the replacement into a type, which we will need for the FacetValue.
  153. if (context().types().Is<SemIR::FacetType>(replacement_type_id)) {
  154. replacement_self_inst_id = context().constant_values().GetInstId(
  155. EvalOrAddInst<SemIR::FacetAccessType>(
  156. context(), loc_id_,
  157. {.type_id = SemIR::TypeType::TypeId,
  158. .facet_value_inst_id = replacement_self_inst_id}));
  159. }
  160. auto period_self_facet_type =
  161. context().types().GetAs<SemIR::FacetType>(period_self_type_id);
  162. auto identified_period_self_type_id = RequireIdentifiedFacetType(
  163. context(), loc_id_,
  164. context().constant_values().Get(replacement_self_inst_id),
  165. period_self_facet_type, [&](auto& /*builder*/) {
  166. // The facet type containing this `.Self` should have already been
  167. // identified, which would ensure that the type of `.Self` can be
  168. // identified since it can only depend on things to the left of it
  169. // inside the same facet type.
  170. CARBON_FATAL("could not identify type of `.Self`");
  171. });
  172. const auto& identified_period_self_type =
  173. context().identified_facet_types().Get(identified_period_self_type_id);
  174. auto required_impls = identified_period_self_type.required_impls();
  175. llvm::SmallVector<SemIR::InstId> witnesses;
  176. witnesses.reserve(required_impls.size());
  177. for (const auto& req : required_impls) {
  178. witnesses.push_back(context().constant_values().GetInstId(
  179. EvalOrAddInst<SemIR::LookupImplWitness>(
  180. context(), loc_id_,
  181. {.type_id =
  182. GetSingletonType(context(), SemIR::WitnessType::TypeInstId),
  183. .query_self_inst_id =
  184. context().constant_values().GetInstId(req.self_facet_value),
  185. .query_specific_interface_id = context().specific_interfaces().Add(
  186. req.specific_interface)})));
  187. }
  188. return context().constant_values().GetInstId(EvalOrAddInst<SemIR::FacetValue>(
  189. context(), loc_id_,
  190. {
  191. .type_id = period_self_type_id,
  192. .type_inst_id =
  193. context().types().GetAsTypeInstId(replacement_self_inst_id),
  194. .witnesses_block_id = context().inst_blocks().Add(witnesses),
  195. }));
  196. }
  197. auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks,
  198. SemIR::ConstantId const_id) -> SemIR::ConstantId {
  199. // Don't replace `.Self` with itself; that is cyclical.
  200. //
  201. // If the types differ, we would try to convert the replacement to a `.Self`
  202. // of the desired type in `const_id`, which is what we already have, so
  203. // there's nothing we need to do. But trying to do that conversion recurses
  204. // when the type of the `.Self` contains a `.Self`.
  205. if (auto bind_type =
  206. context.constant_values().TryGetInstAs<SemIR::SymbolicBinding>(
  207. GetCanonicalFacetOrTypeValue(
  208. context, callbacks.period_self_replacement_id()))) {
  209. if (context.entity_names().Get(bind_type->entity_name_id).name_id ==
  210. SemIR::NameId::PeriodSelf) {
  211. return const_id;
  212. }
  213. }
  214. auto subst_id = SubstInst(
  215. context, context.constant_values().GetInstId(const_id), callbacks);
  216. return context.constant_values().Get(subst_id);
  217. }
  218. static auto SubstPeriodSelfInSpecific(Context& context,
  219. SubstPeriodSelfCallbacks& callbacks,
  220. SemIR::SpecificId specific_id)
  221. -> SemIR::SpecificId {
  222. if (!specific_id.has_value()) {
  223. return specific_id;
  224. }
  225. const auto& specific = context.specifics().Get(specific_id);
  226. // Substitute into the specific without having to construct a FacetType
  227. // instruction just to hold the specific interface inside a constant id.
  228. llvm::SmallVector<SemIR::InstId> args(
  229. context.inst_blocks().Get(specific.args_id));
  230. for (auto& arg_id : args) {
  231. auto const_id = context.constant_values().Get(arg_id);
  232. const_id = SubstPeriodSelf(context, callbacks, const_id);
  233. arg_id = context.constant_values().GetInstId(const_id);
  234. }
  235. return MakeSpecific(context, callbacks.loc_id(), specific.generic_id, args);
  236. }
  237. auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks,
  238. SemIR::SpecificInterface interface)
  239. -> SemIR::SpecificInterface {
  240. interface.specific_id =
  241. SubstPeriodSelfInSpecific(context, callbacks, interface.specific_id);
  242. return interface;
  243. }
  244. auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks,
  245. SemIR::SpecificNamedConstraint constraint)
  246. -> SemIR::SpecificNamedConstraint {
  247. constraint.specific_id =
  248. SubstPeriodSelfInSpecific(context, callbacks, constraint.specific_id);
  249. return constraint;
  250. }
  251. auto IsPeriodSelf(Context& context, SemIR::InstId inst_id, bool canonicalize)
  252. -> bool {
  253. auto query_inst_id =
  254. canonicalize
  255. ? GetCanonicalFacetOrTypeValue(
  256. context, context.constant_values().GetConstantInstId(inst_id))
  257. : inst_id;
  258. if (auto bind =
  259. context.insts().TryGetAs<SemIR::SymbolicBinding>(query_inst_id)) {
  260. const auto& entity_name = context.entity_names().Get(bind->entity_name_id);
  261. return entity_name.name_id == SemIR::NameId::PeriodSelf;
  262. }
  263. return false;
  264. }
  265. class SearchNonCanonicalForExplicitPeriodSelf : public SubstInstCallbacks {
  266. public:
  267. explicit SearchNonCanonicalForExplicitPeriodSelf(Context* context,
  268. SemIR::LocId* found)
  269. : SubstInstCallbacks(context), found_(found) {}
  270. auto Subst(SemIR::InstId& inst_id) -> SubstResult override {
  271. if (found_->has_value()) {
  272. return FullySubstituted;
  273. }
  274. auto const_inst_id = context().constant_values().GetConstantInstId(inst_id);
  275. if (const_inst_id == SemIR::TypeType::TypeInstId) {
  276. // Recursion base case. TypeType has type TypeType.
  277. return FullySubstituted;
  278. }
  279. if (context().insts().Is<SemIR::FacetType>(const_inst_id)) {
  280. // Don't look for `.Self` in nested facet types, they aren't replaced
  281. // with a facet value and just remain as abstract. WhereExprs evaluate
  282. // to a FacetType but are handled outside of Subst.
  283. return FullySubstituted;
  284. }
  285. if (auto name_ref = context().insts().TryGetAs<SemIR::NameRef>(inst_id)) {
  286. // Canonicalization not necessary; NameRef contains the SymbolicBinding
  287. // directly, not an `as type` conversion.
  288. if (IsPeriodSelf(context(), name_ref->value_id,
  289. /*canonicalize=*/false)) {
  290. // `.Self` does not have a location, the NameRef pointing to it does.
  291. *found_ = SemIR::LocId(inst_id);
  292. return FullySubstituted;
  293. }
  294. }
  295. return SubstOperands;
  296. }
  297. auto Rebuild(SemIR::InstId /*orig_inst_id*/, SemIR::Inst /*new_inst*/)
  298. -> SemIR::InstId override {
  299. CARBON_FATAL();
  300. }
  301. private:
  302. SemIR::LocId* found_;
  303. };
  304. class SearchCanonicalForExplicitPeriodSelf : public SubstInstCallbacks {
  305. public:
  306. explicit SearchCanonicalForExplicitPeriodSelf(Context* context, bool* found)
  307. : SubstInstCallbacks(context), found_(found) {}
  308. auto Subst(SemIR::InstId& inst_id) -> SubstResult override {
  309. if (*found_) {
  310. return FullySubstituted;
  311. }
  312. auto const_inst_id = context().constant_values().GetConstantInstId(inst_id);
  313. if (const_inst_id == SemIR::TypeType::TypeInstId) {
  314. // Recursion base case. TypeType has type TypeType.
  315. return FullySubstituted;
  316. }
  317. if (context().insts().Is<SemIR::FacetType>(const_inst_id)) {
  318. // Don't look for `.Self` in nested facet types, they aren't replaced
  319. // with a facet value and just remain as abstract. WhereExprs evaluate
  320. // to a FacetType but are handled outside of Subst.
  321. return FullySubstituted;
  322. }
  323. if (auto access = context().insts().TryGetAs<SemIR::ImplWitnessAccess>(
  324. const_inst_id)) {
  325. if (auto lookup = context().insts().TryGetAs<SemIR::LookupImplWitness>(
  326. access->witness_id)) {
  327. // Canonicalization not necessary; We are working with the constant
  328. // value already, and the query self in a witness is already
  329. // canonicalized.
  330. if (IsPeriodSelf(context(), lookup->query_self_inst_id,
  331. /*canonicalize=*/false)) {
  332. // An implicit `.Self` in a member designator is always allowed.
  333. return FullySubstituted;
  334. }
  335. }
  336. }
  337. // Canonicalization not necessary; Subst will recurse anyway, so avoid
  338. // extra work for non-matches.
  339. if (IsPeriodSelf(context(), const_inst_id, /*canonicalize=*/false)) {
  340. *found_ = true;
  341. return FullySubstituted;
  342. }
  343. return SubstOperands;
  344. }
  345. auto Rebuild(SemIR::InstId /*orig_inst_id*/, SemIR::Inst /*new_inst*/)
  346. -> SemIR::InstId override {
  347. CARBON_FATAL();
  348. }
  349. private:
  350. bool* found_;
  351. };
  352. static auto ReportAmbiguousPeriodSelf(Context& context, SemIR::LocId loc_id)
  353. -> void {
  354. CARBON_DIAGNOSTIC(AmbiguousPeriodSelf, Error,
  355. "`.Self` is ambiguous after nested `where` in `<type> "
  356. "impls ...` clause.");
  357. context.emitter().Emit(loc_id, AmbiguousPeriodSelf);
  358. }
  359. // Searches a type for a reference to `.Self`. Types are canonical, so they
  360. // only contain canonical values/inststructions, which have no location of
  361. // their own.
  362. //
  363. // The search excludes ImplWitnessAccess into `.Self`, which represents a
  364. // designator like `.X`.
  365. //
  366. // The search does not recurse into FacetTypes, as some can include valid
  367. // references to the top level `.Self`, or abstract `.Self` references that
  368. // are not replaced. FacetTypes are handled by the higher level search.
  369. //
  370. // Returns true if found, and diagnosed.
  371. static auto SearchTypeForPeriodSelf(Context& context, SemIR::LocId loc_id,
  372. SemIR::TypeId type_id) -> bool {
  373. bool found_canonical = false;
  374. SearchCanonicalForExplicitPeriodSelf callbacks(&context, &found_canonical);
  375. auto canonical_inst_id = context.types().GetTypeInstId(type_id);
  376. SubstInst(context, canonical_inst_id, callbacks);
  377. // The type has no locations internally, as it stores canonical
  378. // instructions. If we find any `.Self` reference, we report the entire
  379. // type.
  380. if (found_canonical) {
  381. ReportAmbiguousPeriodSelf(context, loc_id);
  382. return true;
  383. }
  384. return false;
  385. }
  386. // Searches a facet type for a reference to `.Self`. FacetTypes are canonical,
  387. // so they only contain canonical values/inststructions, which have no
  388. // location of their own.
  389. //
  390. // The search excludes ImplWitnessAccess into `.Self`, which represents a
  391. // designator like `.X`.
  392. //
  393. // Returns true if found, and diagnosed.
  394. static auto SearchFacetTypeForPeriodSelf(Context& context, SemIR::LocId loc_id,
  395. SemIR::FacetTypeId facet_type_id)
  396. -> bool {
  397. bool found_canonical = false;
  398. SearchCanonicalForExplicitPeriodSelf callbacks(&context, &found_canonical);
  399. const auto& info = context.facet_types().Get(facet_type_id);
  400. // The LHS of a `WhereExpr` only has extend constraints.
  401. for (auto extend : info.extend_constraints) {
  402. auto block_id = context.specifics().GetArgsOrEmpty(extend.specific_id);
  403. for (auto inst_id : context.inst_blocks().GetOrEmpty(block_id)) {
  404. SubstInst(context, inst_id, callbacks);
  405. }
  406. }
  407. for (auto extend : info.extend_named_constraints) {
  408. auto block_id = context.specifics().GetArgsOrEmpty(extend.specific_id);
  409. for (auto inst_id : context.inst_blocks().GetOrEmpty(block_id)) {
  410. SubstInst(context, inst_id, callbacks);
  411. }
  412. }
  413. // The facet type has no locations internally, as it stores canonical
  414. // instructions. If we find any `.Self` reference, we report the entire
  415. // facet type.
  416. if (found_canonical) {
  417. ReportAmbiguousPeriodSelf(context, loc_id);
  418. return true;
  419. }
  420. return false;
  421. }
  422. // Searches a non-canonical instruction for an explicitly written use of
  423. // `.Self`, which is represented as a NameRef instruction.
  424. //
  425. // Returns true if found, and diagnosed.
  426. static auto SearchNonCanonicalInstForPeriodSelf(Context& context,
  427. SemIR::InstId inst_id) -> bool {
  428. auto found = SemIR::LocId::None;
  429. SearchNonCanonicalForExplicitPeriodSelf callbacks(&context, &found);
  430. SubstInst(context, inst_id, callbacks);
  431. if (found.has_value()) {
  432. ReportAmbiguousPeriodSelf(context, found);
  433. return true;
  434. }
  435. return false;
  436. }
  437. auto FindAndDiagnoseAmbiguousPeriodSelf(Context& context,
  438. SemIR::InstId impls_lhs_id,
  439. SemIR::InstId impls_rhs_id) -> bool {
  440. // Look for errors up front. We don't need to look for them in the rest of
  441. // the function.
  442. if (context.constant_values().Get(impls_lhs_id) ==
  443. SemIR::ErrorInst::ConstantId ||
  444. context.constant_values().Get(impls_rhs_id) ==
  445. SemIR::ErrorInst::ConstantId) {
  446. return false;
  447. }
  448. if (IsPeriodSelf(context, impls_lhs_id)) {
  449. // `.Self impls X where ...` does not restrict any use of `.Self` on the
  450. // RHS of the `where` since the `.Self` on the LHS of `where` did not
  451. // introduce any ambiguity. A `.Self` on the RHS of the `where` applies to
  452. // the same thing as on the LHS of the `impls`.
  453. return false;
  454. }
  455. struct WorkItem {
  456. SemIR::WhereExpr where_expr;
  457. bool search_lhs;
  458. };
  459. llvm::SmallVector<WorkItem> work;
  460. if (auto where_expr =
  461. context.insts().TryGetAs<SemIR::WhereExpr>(impls_rhs_id)) {
  462. work.push_back({.where_expr = *where_expr, .search_lhs = false});
  463. }
  464. while (!work.empty()) {
  465. auto work_item = work.pop_back_val();
  466. // Look in the non-canonical WhereExpr for explicit references to `.Self`,
  467. // which will be considered as ambiguous.
  468. for (auto inst_id : context.inst_blocks().GetOrEmpty(
  469. work_item.where_expr.requirements_id)) {
  470. auto inst = context.insts().Get(inst_id);
  471. CARBON_KIND_SWITCH(inst) {
  472. case CARBON_KIND(SemIR::RequirementBaseFacetType base): {
  473. if (work_item.search_lhs) {
  474. // If the base type is more than a reference to an interface or
  475. // constraint, such as having specific arguments, it will be a
  476. // FacetType instruction.
  477. if (auto facet_type = context.insts().TryGetAs<SemIR::FacetType>(
  478. base.base_type_inst_id)) {
  479. if (SearchFacetTypeForPeriodSelf(
  480. context, SemIR::LocId(base.base_type_inst_id),
  481. facet_type->facet_type_id)) {
  482. return true;
  483. }
  484. }
  485. }
  486. break;
  487. }
  488. case CARBON_KIND(SemIR::RequirementRewrite rewrite): {
  489. if (SearchNonCanonicalInstForPeriodSelf(context, rewrite.lhs_id)) {
  490. return true;
  491. }
  492. if (SearchNonCanonicalInstForPeriodSelf(context, rewrite.rhs_id)) {
  493. return true;
  494. }
  495. break;
  496. }
  497. case CARBON_KIND(SemIR::RequirementEquivalent equiv): {
  498. if (SearchNonCanonicalInstForPeriodSelf(context, equiv.lhs_id)) {
  499. return true;
  500. }
  501. if (SearchNonCanonicalInstForPeriodSelf(context, equiv.rhs_id)) {
  502. return true;
  503. }
  504. break;
  505. }
  506. case CARBON_KIND(SemIR::RequirementImpls impls): {
  507. if (!IsPeriodSelf(context, impls.lhs_id)) {
  508. if (SearchTypeForPeriodSelf(
  509. context, SemIR::LocId(impls.lhs_id),
  510. context.types().GetTypeIdForTypeInstId(impls.lhs_id))) {
  511. return true;
  512. }
  513. }
  514. CARBON_KIND_SWITCH(context.insts().Get(impls.rhs_id)) {
  515. case CARBON_KIND(SemIR::FacetType facet_type): {
  516. // If the RHS of the `impls` is a complex facet type (such as
  517. // when it has specific arguments) but has no `where`, then it
  518. // will be a FacetType instruction.
  519. if (SearchFacetTypeForPeriodSelf(context,
  520. SemIR::LocId(impls.rhs_id),
  521. facet_type.facet_type_id)) {
  522. return true;
  523. }
  524. break;
  525. }
  526. case CARBON_KIND(SemIR::WhereExpr rhs_where_expr): {
  527. // If the RHS of the `impls` contains a `where`, then it will be
  528. // a WhereExpr instruction.
  529. work.push_back(
  530. {.where_expr = rhs_where_expr, .search_lhs = true});
  531. break;
  532. }
  533. default:
  534. // Otherwise, it's a simple facet type, which is just a
  535. // reference to an interface or constraint. There's nowhere to
  536. // look for a
  537. // `.Self`.
  538. break;
  539. }
  540. break;
  541. }
  542. default:
  543. CARBON_FATAL("unexpected inst {0} in WhereExpr requirements block",
  544. inst);
  545. }
  546. }
  547. }
  548. return false;
  549. }
  550. } // namespace Carbon::Check