diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index dabf8fac1a02..f06a0d65c563 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -2642,32 +2642,37 @@ static auto AddRequirementImpls(Context& context, SemIR::LocId loc_id, // references are to the same top-level value for `.Self` and can all be // replaced together later. - SubstPeriodSelfCallbacks callbacks( - &context, loc_id, context.constant_values().Get(lhs_facet_or_type), - SubstPeriodSelfCallbacks::Behaviour::ImplicitOnly); + auto period_self_replacement_id = + context.constant_values().Get(lhs_facet_or_type); auto self_impls_interface = [&](SemIR::SpecificInterface si) { - return SubstPeriodSelf(context, callbacks, si); + return SubstPeriodSelf(context, loc_id, si, period_self_replacement_id, + SubstPeriodSelfBehaviour::ImplicitOnly); }; auto self_impls_constraint = [&](SemIR::SpecificNamedConstraint sc) { - return SubstPeriodSelf(context, callbacks, sc); + return SubstPeriodSelf(context, loc_id, sc, period_self_replacement_id, + SubstPeriodSelfBehaviour::ImplicitOnly); }; auto type_impls_interface = [&](SemIR::FacetTypeInfo::TypeImplsInterface impls) -> SemIR::FacetTypeInfo::TypeImplsInterface { auto self = SubstPeriodSelf( - context, callbacks, context.constant_values().Get(impls.self_type)); - auto interface = - SubstPeriodSelf(context, callbacks, impls.specific_interface); + context, loc_id, context.constant_values().Get(impls.self_type), + period_self_replacement_id, SubstPeriodSelfBehaviour::ImplicitOnly); + auto interface = SubstPeriodSelf( + context, loc_id, impls.specific_interface, period_self_replacement_id, + SubstPeriodSelfBehaviour::ImplicitOnly); return {context.constant_values().GetInstId(self), interface}; }; auto type_impls_constraint = [&](SemIR::FacetTypeInfo::TypeImplsNamedConstraint impls) -> SemIR::FacetTypeInfo::TypeImplsNamedConstraint { auto self = SubstPeriodSelf( - context, callbacks, context.constant_values().Get(impls.self_type)); - auto constraint = - SubstPeriodSelf(context, callbacks, impls.specific_named_constraint); + context, loc_id, context.constant_values().Get(impls.self_type), + period_self_replacement_id, SubstPeriodSelfBehaviour::ImplicitOnly); + auto constraint = SubstPeriodSelf( + context, loc_id, impls.specific_named_constraint, + period_self_replacement_id, SubstPeriodSelfBehaviour::ImplicitOnly); return {context.constant_values().GetInstId(self), constraint}; }; @@ -2688,9 +2693,11 @@ static auto AddRequirementImpls(Context& context, SemIR::LocId loc_id, [&](SemIR::FacetTypeInfo::RewriteConstraint rewrite) -> SemIR::FacetTypeInfo::RewriteConstraint { auto lhs_id = SubstPeriodSelf( - context, callbacks, context.constant_values().Get(rewrite.lhs_id)); + context, loc_id, context.constant_values().Get(rewrite.lhs_id), + period_self_replacement_id, SubstPeriodSelfBehaviour::ImplicitOnly); auto rhs_id = SubstPeriodSelf( - context, callbacks, context.constant_values().Get(rewrite.rhs_id)); + context, loc_id, context.constant_values().Get(rewrite.rhs_id), + period_self_replacement_id, SubstPeriodSelfBehaviour::ImplicitOnly); return {context.constant_values().GetInstId(lhs_id), context.constant_values().GetInstId(rhs_id)}; }; diff --git a/toolchain/check/eval_inst.cpp b/toolchain/check/eval_inst.cpp index bdd344a164f7..9a58f6d19e24 100644 --- a/toolchain/check/eval_inst.cpp +++ b/toolchain/check/eval_inst.cpp @@ -285,6 +285,94 @@ auto EvalConstantInst(Context& context, SemIR::InstId inst_id, return ConstantEvalResult::NewSamePhase(inst); } +// Given a SpecificInterface and an index of an associated constant in that +// interface, try find a value for that constant in the rewrite constraints of +// the type of `search_facet`. +static auto TryFindValueInRewriteConstraints( + Context& context, SemIR::LocId loc_id, + SemIR::SpecificInterfaceId specific_interface_id, + SemIR::ElementIndex interface_index, SemIR::InstId search_facet) + -> SemIR::ConstantId { + auto access_self_type_id = context.insts().Get(search_facet).type_id(); + if (context.types().Is(access_self_type_id)) { + // A self facet of type `type` has no rewrite constraints to look in. + return SemIR::ConstantId::None; + } + + // The `ImplWitnessAccess` is accessing a value, by index, for this `self + // impls interface` combination. + auto access_interface = + context.specific_interfaces().Get(specific_interface_id); + + auto access_self_facet_type_id = + context.types() + .GetAs(access_self_type_id) + .facet_type_id; + // TODO: We could consider something better than linear search here, such as a + // map. However that would probably require heap allocations which may be + // worse overall since the number of rewrite constraints is generally low. If + // the `rewrite_constraints` were sorted so that associated constants are + // grouped together, as in ResolveFacetTypeRewriteConstraints(), and limited + // to just the `ImplWitnessAccess` entries, then a binary search may work + // here. + for (const auto& rewrite : context.facet_types() + .Get(access_self_facet_type_id) + .rewrite_constraints) { + // Look at each rewrite constraint in the self facet's type. If the LHS is + // an `ImplWitnessAccess` into the same interface that `inst` is indexing + // into, then we can use its RHS as the value. + auto rewrite_lhs_access = + context.insts().TryGetAs(rewrite.lhs_id); + if (!rewrite_lhs_access) { + continue; + } + if (rewrite_lhs_access->index != interface_index) { + continue; + } + + // Witnesses come from impl lookup, and the operands are from + // IdentifiedFacetTypes, so `.Self` is replaced. However rewrite constraints + // are not part of an IdentifiedFacetType, so they are not replaced. We have + // to do the same replacement in the rewrite's LHS witness in order to + // compare it with the access witness. + // + // However we don't substitute the witness directly as that would + // re-evaluate it and cause us to do an impl lookup. Instead we substitute + // and compare its operands. + auto rewrite_lhs_witness = context.insts().GetAs( + rewrite_lhs_access->witness_id); + + auto self_const_id = context.constant_values().Get(search_facet); + + // The LHS of the rewrite might be `.Self` or it could be one or more nested + // ImplWitnessAccess instructions that eventually bottom out in `.Self`. + // Rewrite constraints must modify `.Self` so we know the target of the + // rewrite is ultimately always `.Self` which refers to the `search_facet`. + // So we don't have to substitute the `.Self` and do any comparison. + + auto rewrite_lhs_interface = + SubstPeriodSelf(context, loc_id, + context.specific_interfaces().Get( + rewrite_lhs_witness.query_specific_interface_id), + self_const_id); + + if (rewrite_lhs_interface != access_interface) { + // This rewrite is into a different interface than the access query. + continue; + } + + // The `ImplWitnessAccess` evaluates to the RHS from the witness self facet + // value's type. Any `.Self` references in the RHS are also replaced with + // the self type of the access. + auto rewrite_rhs = SubstPeriodSelf( + context, loc_id, context.constant_values().Get(rewrite.rhs_id), + self_const_id); + return rewrite_rhs; + } + + return SemIR::ConstantId::None; +} + auto EvalConstantInst(Context& context, SemIR::InstId inst_id, SemIR::ImplWitnessAccess inst) -> ConstantEvalResult { CARBON_DIAGNOSTIC(ImplAccessMemberBeforeSet, Error, @@ -332,94 +420,26 @@ auto EvalConstantInst(Context& context, SemIR::InstId inst_id, // If the witness is symbolic but has a self type that is a FacetType, it // can pull rewrite values from the self's facet type. If the access is // for one of those rewrites, evaluate to the RHS of the rewrite. - - // The type of the query self type (a FacetType or TypeType). - auto access_self_type_id = - context.insts().Get(witness.query_self_inst_id).type_id(); - if (context.types().Is(access_self_type_id)) { - // A self facet of type `type` has no rewrite constraints to look in. - return ConstantEvalResult::NewSamePhase(inst); - } - - // The `ImplWitnessAccess` is accessing a value, by index, for this - // `self impls interface` combination. - auto access_self = - context.constant_values().Get(witness.query_self_inst_id); - auto access_interface = context.specific_interfaces().Get( - witness.query_specific_interface_id); - - auto access_self_facet_type_id = - context.types() - .GetAs(access_self_type_id) - .facet_type_id; - // TODO: We could consider something better than linear search here, such - // as a map. However that would probably require heap allocations which - // may be worse overall since the number of rewrite constraints is - // generally low. If the `rewrite_constraints` were sorted so that - // associated constants are grouped together, as in - // ResolveFacetTypeRewriteConstraints(), and limited to just the - // `ImplWitnessAccess` entries, then a binary search may work here. - for (const auto& rewrite : context.facet_types() - .Get(access_self_facet_type_id) - .rewrite_constraints) { - // Look at each rewrite constraint in the self facet's type. If the LHS - // is an `ImplWitnessAccess` into the same interface that `inst` is - // indexing into, then we can use its RHS as the value. - auto rewrite_lhs_access = - context.insts().TryGetAs(rewrite.lhs_id); - if (!rewrite_lhs_access) { - continue; + // + // If we have a nested `.X1.Y1.Z1` we start with the facet type of .Y1 to + // look for a rewrite constraint that provides the value for .Z1. But if + // we don't find it, we try .X1 and .Self. + auto search_facet = witness.query_self_inst_id; + while (true) { + auto const_id = TryFindValueInRewriteConstraints( + context, SemIR::LocId(inst_id), witness.query_specific_interface_id, + inst.index, search_facet); + if (const_id.has_value()) { + return ConstantEvalResult::Existing(const_id); } - if (rewrite_lhs_access->index != inst.index) { - continue; + if (auto access = context.insts().TryGetAs( + search_facet)) { + auto witness = context.insts().GetAs( + access->witness_id); + search_facet = witness.query_self_inst_id; + } else { + break; } - - // Witnesses come from impl lookup, and the operands are from - // IdentifiedFacetTypes, so `.Self` is replaced. However rewrite - // constraints are not part of an IdentifiedFacetType, so they are not - // replaced. We have to do the same replacement in the rewrite's LHS - // witness in order to compare it with the access witness. - // - // However we don't substitute the witness directly as that would - // re-evaluate it and cause us to do an impl lookup. Instead we - // substitute and compare its operands. - auto rewrite_lhs_witness = - context.insts().GetAs( - rewrite_lhs_access->witness_id); - - SubstPeriodSelfCallbacks callbacks(&context, SemIR::LocId(inst_id), - access_self); - - auto rewrite_lhs_self = context.constant_values().Get( - rewrite_lhs_witness.query_self_inst_id); - rewrite_lhs_self = - SubstPeriodSelf(context, callbacks, rewrite_lhs_self); - // Witnesses have a canonicalized self value. Perform the same - // canonicalization here so that we can compare them. - rewrite_lhs_self = GetCanonicalQuerySelfForLookupImplWitness( - context, rewrite_lhs_self); - - if (rewrite_lhs_self != access_self) { - // This rewrite is into a different self type than the access query. - continue; - } - - auto rewrite_lhs_interface = SubstPeriodSelf( - context, callbacks, - context.specific_interfaces().Get( - rewrite_lhs_witness.query_specific_interface_id)); - - if (rewrite_lhs_interface != access_interface) { - // This rewrite is into a different interface than the access query. - continue; - } - - // The `ImplWitnessAccess` evaluates to the RHS from the witness self - // facet value's type. Any `.Self` references in the RHS are also - // replaced with the self type of the access. - auto rewrite_rhs = SubstPeriodSelf( - context, callbacks, context.constant_values().Get(rewrite.rhs_id)); - return ConstantEvalResult::Existing(rewrite_rhs); } break; } diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index 7cbea20964de..8bf7e8ae28f8 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -17,6 +17,7 @@ #include "toolchain/check/name_lookup.h" #include "toolchain/check/name_scope.h" #include "toolchain/check/pattern_match.h" +#include "toolchain/check/period_self.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" #include "toolchain/parse/node_ids.h" @@ -228,10 +229,31 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id) SemIR::ImplDecl{.impl_id = SemIR::ImplId::None, .decl_block_id = decl_block_id}); - // This requires that the facet type is identified. It returns None if an - // error was diagnosed. + if (!CheckConstraintIsFacetType(context, node_id, constraint_type_inst_id)) { + constraint_type_inst_id = SemIR::ErrorInst::TypeInstId; + } + + // The identified facet type will also replace `.Self` references in the + // specific interface, but we want to store the full facet type not just the + // identified one. So we have to replace `.Self` references explicitly here in + // the constraint. + // + // We do this after `CheckConstraintIsFacetType()` which has ensured the + // constraint is in fact a FacetType. We do this before identifying the facet + // type in `CheckConstraintIsInterface()` so that the identified facet type is + // for the substituted facet type instruction that will be stored in the Impl. + // This ensures the impl bucket finds the identified facet type. + constraint_type_inst_id = SubstPeriodSelfInFacetType( + context, constraint_node, self_type_inst_id, constraint_type_inst_id); + + // This requires that the facet type is identified, and returns the single + // interface from the identified facet type. It returns None if an error was + // diagnosed. auto specific_interface = CheckConstraintIsInterface( - context, impl_decl_id, self_type_inst_id, constraint_type_inst_id); + context, node_id, self_type_inst_id, constraint_type_inst_id); + if (!specific_interface.interface_id.has_value()) { + constraint_type_inst_id = SemIR::ErrorInst::TypeInstId; + } // The impl decl has a scope stack entry for the DeclNameStack, so we look at // the parent scope of that. @@ -256,8 +278,7 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id) context.types().GetTypeIdForTypeInstId(impl.self_id) == SemIR::ErrorInst::TypeId || context.types().GetTypeIdForTypeInstId(impl.constraint_id) == - SemIR::ErrorInst::TypeId || - !impl.interface.interface_id.has_value(); + SemIR::ErrorInst::TypeId; CARBON_KIND_SWITCH(FindImplId(context, impl)) { case CARBON_KIND(RedeclaredImpl redeclared_impl): { diff --git a/toolchain/check/handle_require.cpp b/toolchain/check/handle_require.cpp index fb39aff79a48..5fd9931cf6b0 100644 --- a/toolchain/check/handle_require.cpp +++ b/toolchain/check/handle_require.cpp @@ -268,85 +268,6 @@ static auto ValidateRequire(Context& context, SemIR::LocId full_require_loc_id, return ValidateRequireResult{.identified_facet_type = &identified}; } -// Replace all `.Self` references with the self-type. -static auto SubstPeriodSelfInConstraint(Context& context, SemIR::LocId loc_id, - SemIR::TypeInstId self_type_inst_id, - SemIR::TypeInstId constraint_inst_id) - -> SemIR::TypeInstId { - auto orig_facet_type = context.insts().GetAs( - context.constant_values().GetConstantInstId(constraint_inst_id)); - const auto& orig_info = - context.facet_types().Get(orig_facet_type.facet_type_id); - - SubstPeriodSelfCallbacks callbacks( - &context, loc_id, context.constant_values().Get(self_type_inst_id)); - - auto replace_interface = [&](SemIR::SpecificInterface si) { - return SubstPeriodSelf(context, callbacks, si); - }; - auto replace_constraint = [&](SemIR::SpecificNamedConstraint sc) { - return SubstPeriodSelf(context, callbacks, sc); - }; - auto replace_type_impls_interface = - [&](SemIR::FacetTypeInfo::TypeImplsInterface impls) - -> SemIR::FacetTypeInfo::TypeImplsInterface { - auto self = SubstPeriodSelf(context, callbacks, - context.constant_values().Get(impls.self_type)); - auto interface = - SubstPeriodSelf(context, callbacks, impls.specific_interface); - return {context.constant_values().GetInstId(self), interface}; - }; - auto replace_type_impls_constraint = - [&](SemIR::FacetTypeInfo::TypeImplsNamedConstraint impls) - -> SemIR::FacetTypeInfo::TypeImplsNamedConstraint { - auto self = SubstPeriodSelf(context, callbacks, - context.constant_values().Get(impls.self_type)); - auto constraint = - SubstPeriodSelf(context, callbacks, impls.specific_named_constraint); - return {context.constant_values().GetInstId(self), constraint}; - }; - - SemIR::FacetTypeInfo info; - llvm::append_range( - info.extend_constraints, - llvm::map_range(orig_info.extend_constraints, replace_interface)); - llvm::append_range( - info.extend_named_constraints, - llvm::map_range(orig_info.extend_named_constraints, replace_constraint)); - llvm::append_range( - info.self_impls_constraints, - llvm::map_range(orig_info.self_impls_constraints, replace_interface)); - llvm::append_range(info.self_impls_named_constraints, - llvm::map_range(orig_info.self_impls_named_constraints, - replace_constraint)); - llvm::append_range(info.type_impls_interfaces, - llvm::map_range(orig_info.type_impls_interfaces, - replace_type_impls_interface)); - llvm::append_range(info.type_impls_named_constraints, - llvm::map_range(orig_info.type_impls_named_constraints, - replace_type_impls_constraint)); - // TODO: Replace .Self in rewrites too. We need to actually validate rewrite - // constraints from named constraints in impl lookup (see - // todo_fail_require_with_mismatching_rewrite_constraint.carbon). - llvm::append_range(info.rewrite_constraints, orig_info.rewrite_constraints); - - info.Canonicalize(); - if (info == orig_info) { - // Nothing was substituted, keep the original instruction. - // - // It is noteworthy that we keep the non-canonical instruction here, since - // it may have a symbolic value (which is attached to a generic, and can be - // updated by specifics). Returning the canonical constraint instruction - // would lose the attachment to the generic which would be incorrect. - return constraint_inst_id; - } - - return AddTypeInst( - context, loc_id, - {.type_id = SemIR::TypeType::TypeId, - .facet_type_id = context.facet_types().Add(info)}); -} - auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool { auto [constraint_node_id, constraint_inst_id] = context.node_stack().PopExprWithNodeId(); @@ -391,7 +312,7 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool { // replace `.Self` references explicitly here in the canonical constraint. We // do this after `ValidateRequire()` which has ensured the constraint is in // fact a FacetType. - auto constraint_type_inst_id = SubstPeriodSelfInConstraint( + auto constraint_type_inst_id = SubstPeriodSelfInFacetType( context, constraint_node_id, self_inst_id, context.types().GetAsTypeInstId(constraint_inst_id)); // The replacement of `.Self` can create a new FacetType instruction which we diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index 22335bfaae69..afdad3ff74d2 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -405,10 +405,10 @@ static auto WitnessQueryMatchesInterface( // `.Self` replaced, so we need to do that here. // // TODO: Do this more eagerly as soon as we know the full decl before we - // construct the witness table from it? - SubstPeriodSelfCallbacks callbacks(&context, loc_id, + // construct the witness table from it? We do replace `.Self` in the facet + // type, but we don't replace the designators. + access_interface = SubstPeriodSelf(context, loc_id, access_interface, context.constant_values().Get(impl_self)); - access_interface = SubstPeriodSelf(context, callbacks, access_interface); return access_interface == impl_interface; } @@ -854,32 +854,39 @@ auto IsImplEffectivelyFinal(Context& context, const SemIR::Impl& impl) -> bool { context.constant_values().Get(impl.constraint_id).is_concrete()); } -auto CheckConstraintIsInterface(Context& context, SemIR::InstId impl_decl_id, +auto CheckConstraintIsFacetType(Context& context, SemIR::LocId loc_id, + SemIR::TypeInstId constraint_id) -> bool { + auto facet_type_const_inst_id = + context.constant_values().GetConstantInstId(constraint_id); + auto facet_type = + context.insts().TryGetAs(facet_type_const_inst_id); + if (!facet_type && facet_type_const_inst_id != SemIR::ErrorInst::InstId) { + CARBON_DIAGNOSTIC(ImplAsNonFacetType, Error, "impl as non-facet type {0}", + InstIdAsType); + context.emitter().Emit(loc_id, ImplAsNonFacetType, constraint_id); + return false; + } + return true; +} + +auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id, SemIR::InstId self_id, SemIR::TypeInstId constraint_id) -> SemIR::SpecificInterface { - auto facet_type_as_type_id = - context.types().GetTypeIdForTypeInstId(constraint_id); - if (facet_type_as_type_id == SemIR::ErrorInst::TypeId) { + auto canon_constraint_id = + context.constant_values().GetConstantInstId(constraint_id); + if (canon_constraint_id == SemIR::ErrorInst::TypeInstId) { return SemIR::SpecificInterface::None; } auto facet_type = - context.types().TryGetAs(facet_type_as_type_id); - if (!facet_type) { - CARBON_DIAGNOSTIC(ImplAsNonFacetType, Error, "impl as non-facet type {0}", - InstIdAsType); - context.emitter().Emit(impl_decl_id, ImplAsNonFacetType, constraint_id); - return SemIR::SpecificInterface::None; - } - + context.insts().GetAs(canon_constraint_id); auto identified_id = RequireIdentifiedFacetType( context, SemIR::LocId(constraint_id), - context.constant_values().Get(self_id), *facet_type, [&](auto& builder) { + context.constant_values().Get(self_id), facet_type, [&](auto& builder) { CARBON_DIAGNOSTIC(ImplOfUnidentifiedFacetType, Context, "facet type {0} cannot be identified in `impl as`", InstIdAsType); - builder.Context(impl_decl_id, ImplOfUnidentifiedFacetType, - constraint_id); + builder.Context(loc_id, ImplOfUnidentifiedFacetType, constraint_id); }); if (!identified_id.has_value()) { return SemIR::SpecificInterface::None; @@ -888,7 +895,7 @@ auto CheckConstraintIsInterface(Context& context, SemIR::InstId impl_decl_id, if (!identified.is_valid_impl_as_target()) { CARBON_DIAGNOSTIC(ImplOfNotOneInterface, Error, "impl as {0} interfaces, expected 1", int); - context.emitter().Emit(impl_decl_id, ImplOfNotOneInterface, + context.emitter().Emit(loc_id, ImplOfNotOneInterface, identified.num_interfaces_to_impl()); return SemIR::SpecificInterface::None; } diff --git a/toolchain/check/impl.h b/toolchain/check/impl.h index ba90737af804..b81b1433a891 100644 --- a/toolchain/check/impl.h +++ b/toolchain/check/impl.h @@ -84,10 +84,15 @@ auto CheckAssociatedFunctionImplementation( SemIR::SpecificId enclosing_specific_id, SemIR::InstId impl_decl_id, bool defer_thunk_definition) -> SemIR::InstId; -// Checks that the constraint specified for the impl is valid and identified. -// Returns the interface that the impl implements. On error, issues a diagnostic -// and returns `None`. -auto CheckConstraintIsInterface(Context& context, SemIR::InstId impl_decl_id, +// Checks that the constraint specified for the impl is a facet type. Returns +// false if an error was diagnosed. +auto CheckConstraintIsFacetType(Context& context, SemIR::LocId loc_id, + SemIR::TypeInstId constraint_id) -> bool; + +// Checks that the constraint specified for the impl is a valid, identified +// facet type that extends a single interface. Returns the interface that the +// impl implements. On error, issues a diagnostic and returns `None`. +auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id, SemIR::InstId self_id, SemIR::TypeInstId constraint_id) -> SemIR::SpecificInterface; diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index 2e1e8c424a17..8594461e8c6e 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -450,10 +450,10 @@ static auto TryFindMatchingWitnessFromImplLookup( // The `req_impls` come from an IdentifiedFacetType so they have `.Self` // replaced. We need to do the same for the self and interface in the // `orig_witness` for comparing with them. - SubstPeriodSelfCallbacks callbacks(&context, loc_id, - canonical_query_self_const_id); - orig_const_self = SubstPeriodSelf(context, callbacks, orig_const_self); - orig_interface = SubstPeriodSelf(context, callbacks, orig_interface); + orig_const_self = SubstPeriodSelf(context, loc_id, orig_const_self, + canonical_query_self_const_id); + orig_interface = SubstPeriodSelf(context, loc_id, orig_interface, + canonical_query_self_const_id); // Witnesses have a canonicalized self value. Perform the same // canonicalization here so that we can compare them. @@ -470,41 +470,6 @@ static auto TryFindMatchingWitnessFromImplLookup( return SemIR::InstId::None; } -class SubstPeriodSelfInRewriteCallbacks : public SubstPeriodSelfCallbacks { - public: - explicit SubstPeriodSelfInRewriteCallbacks( - Context* context, SemIR::LocId loc_id, - SemIR::ConstantId period_self_replacement_id, - llvm::ArrayRef req_impls, - llvm::ArrayRef witness_inst_ids) - : SubstPeriodSelfCallbacks(context, loc_id, period_self_replacement_id), - req_impls_(req_impls), - witness_inst_ids_(witness_inst_ids) {} - - auto Rebuild(SemIR::InstId orig_inst_id, SemIR::Inst new_inst) - -> SemIR::InstId override { - // When rebuilding a witness where `.Self` was replaced, use a witness we - // found in impl lookup instead of performing impl lookup again. - if (auto lookup = new_inst.TryAs()) { - auto witness = TryFindMatchingWitnessFromImplLookup( - context(), loc_id(), period_self_replacement_id(), req_impls_, - witness_inst_ids_, - context().constant_values().Get(lookup->query_self_inst_id), - context().specific_interfaces().Get( - lookup->query_specific_interface_id)); - if (witness.has_value()) { - return witness; - } - } - - return SubstPeriodSelfCallbacks::Rebuild(orig_inst_id, new_inst); - } - - private: - llvm::ArrayRef req_impls_; - llvm::ArrayRef witness_inst_ids_; -}; - static auto VerifyQueryFacetTypeConstraints( Context& context, SemIR::LocId loc_id, SemIR::ConstantId query_self_const_id, @@ -517,8 +482,22 @@ static auto VerifyQueryFacetTypeConstraints( .facet_type_id); if (!facet_type_info.rewrite_constraints.empty()) { - SubstPeriodSelfInRewriteCallbacks callbacks( - &context, loc_id, query_self_const_id, req_impls, witness_inst_ids); + auto rebuild = [&](SemIR::Inst new_inst) -> SemIR::InstId { + // When rebuilding a witness where `.Self` was replaced, use a witness we + // found in impl lookup instead of performing impl lookup again. + if (auto lookup = new_inst.TryAs()) { + auto witness = TryFindMatchingWitnessFromImplLookup( + context, loc_id, query_self_const_id, req_impls, witness_inst_ids, + context.constant_values().Get(lookup->query_self_inst_id), + context.specific_interfaces().Get( + lookup->query_specific_interface_id)); + if (witness.has_value()) { + return witness; + } + } + + return SemIR::InstId::None; + }; for (const auto& rewrite : facet_type_info.rewrite_constraints) { // Replace `.Self` in rewrite constraints with the query self in order to @@ -531,9 +510,11 @@ static auto VerifyQueryFacetTypeConstraints( // execute another impl lookup. auto lhs_id = context.constant_values().GetInstId(SubstPeriodSelf( - context, callbacks, context.constant_values().Get(rewrite.lhs_id))); + context, loc_id, context.constant_values().Get(rewrite.lhs_id), + query_self_const_id, SubstPeriodSelfBehaviour::All, rebuild)); auto rhs_id = context.constant_values().GetInstId(SubstPeriodSelf( - context, callbacks, context.constant_values().Get(rewrite.rhs_id))); + context, loc_id, context.constant_values().Get(rewrite.rhs_id), + query_self_const_id, SubstPeriodSelfBehaviour::All, rebuild)); if (lhs_id != rhs_id) { // TODO: Provide a diagnostic note and location for which rewrite diff --git a/toolchain/check/period_self.cpp b/toolchain/check/period_self.cpp index 25c6222ef508..aba77da09bf5 100644 --- a/toolchain/check/period_self.cpp +++ b/toolchain/check/period_self.cpp @@ -10,6 +10,7 @@ #include "toolchain/check/facet_type.h" #include "toolchain/check/generic.h" #include "toolchain/check/inst.h" +#include "toolchain/check/subst.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" #include "toolchain/sem_ir/typed_insts.h" @@ -40,199 +41,332 @@ auto MakePeriodSelfFacetValue(Context& context, SemIR::LocId loc_id, return inst_id; } -SubstPeriodSelfCallbacks::SubstPeriodSelfCallbacks( - Context* context, SemIR::LocId loc_id, - SemIR::ConstantId period_self_replacement_id, Behaviour behaviour) - : SubstInstCallbacks(context), - loc_id_(loc_id), - period_self_replacement_id_(period_self_replacement_id), - behaviour_(behaviour) {} +class SubstPeriodSelfCallbacks : public SubstInstCallbacks { + public: + explicit SubstPeriodSelfCallbacks( + Context* context, SemIR::LocId loc_id, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfRebuildInst rebuild) + : SubstInstCallbacks(context), + loc_id_(loc_id), + period_self_replacement_id_(period_self_replacement_id), + rebuild_callback_(rebuild) {} -auto SubstPeriodSelfCallbacks::Subst(SemIR::InstId& inst_id) -> SubstResult { - // FacetTypes are concrete even if they have `.Self` inside them, but we - // don't recurse into FacetTypes, so we can use this as a base case. This - // avoids infinite recursion on TypeType and ErrorInst. - if (context().constant_values().Get(inst_id).is_concrete()) { - return FullySubstituted; - } - // Don't recurse into nested facet types, even if they are symbolic. Leave - // their `.Self` as is. - if (context().insts().Is(inst_id)) { - return FullySubstituted; + virtual ~SubstPeriodSelfCallbacks() = default; + + auto Rebuild(SemIR::InstId orig_inst_id, SemIR::Inst new_inst) + -> SemIR::InstId override { + if (rebuild_callback_) { + if (auto inst_id = rebuild_callback_(new_inst); inst_id.has_value()) { + return inst_id; + } + } + return RebuildNewInst(SemIR::LocId(orig_inst_id), new_inst); } - // Look for implicit use of `.Self` in designators: `.X` is really `.Self.X`. - if (auto access = - context().insts().TryGetAs(inst_id)) { - if (auto witness = context().insts().TryGetAs( - access->witness_id)) { - // Canonicalization not necessary; We are working with the constant + protected: + auto GetReplacement(SemIR::InstId period_self) -> SemIR::InstId { + auto period_self_type_id = context().insts().Get(period_self).type_id(); + CARBON_CHECK(context().types().Is(period_self_type_id)); + + auto replacement_self_inst_id = + context().constant_values().GetInstId(period_self_replacement_id_); + auto replacement_type_id = + context().insts().Get(replacement_self_inst_id).type_id(); + CARBON_CHECK(context().types().IsFacetType(replacement_type_id)); + + // If the replacement has the same type as `.Self`, use it directly. + if (replacement_type_id == period_self_type_id) { + return replacement_self_inst_id; + } + + // If we have already converted the replacement to the type of `.Self`, use + // our previous conversion. + if (period_self_type_id == cached_replacement_type_id_) { + return cached_replacement_id_; + } + + // Convert the replacement facet to the type of `.Self`. + cached_replacement_id_ = ConvertReplacement( + replacement_self_inst_id, replacement_type_id, period_self_type_id); + cached_replacement_type_id_ = period_self_type_id; + return cached_replacement_id_; + } + + private: + auto ConvertReplacement(SemIR::InstId replacement_self_inst_id, + SemIR::TypeId replacement_type_id, + SemIR::TypeId period_self_type_id) -> SemIR::InstId { + // TODO: Replace all empty facet types with TypeType. + if (period_self_type_id == GetEmptyFacetType(context())) { + // Convert to an empty facet type (representing TypeType); we don't need + // any witnesses. + return ConvertToValueOfType(context(), loc_id_, replacement_self_inst_id, + period_self_type_id); + } + + // We have a facet or a type, but we need more interfaces in the facet type. + // We will have to synthesize a symbolic witness for each interface. + // + // Why is this okay? The type of `.Self` comes from interfaces that are + // before it (to the left of it) in the facet type. The replacement for + // `.Self` will have to impl those interfaces in order to match the facet + // type, so we know that it is valid to construct these witnesses. + + // Make the replacement into a type, which we will need for the FacetValue. + if (context().types().Is(replacement_type_id)) { + replacement_self_inst_id = context().constant_values().GetInstId( + EvalOrAddInst( + context(), loc_id_, + {.type_id = SemIR::TypeType::TypeId, + .facet_value_inst_id = replacement_self_inst_id})); + } + + auto period_self_facet_type = + context().types().GetAs(period_self_type_id); + auto identified_period_self_type_id = RequireIdentifiedFacetType( + context(), loc_id_, + context().constant_values().Get(replacement_self_inst_id), + period_self_facet_type, [&](auto& /*builder*/) { + // The facet type containing this `.Self` should have already been + // identified, which would ensure that the type of `.Self` can be + // identified since it can only depend on things to the left of it + // inside the same facet type. + CARBON_FATAL("could not identify type of `.Self`"); + }); + const auto& identified_period_self_type = + context().identified_facet_types().Get(identified_period_self_type_id); + auto required_impls = identified_period_self_type.required_impls(); + llvm::SmallVector witnesses; + witnesses.reserve(required_impls.size()); + for (const auto& req : required_impls) { + witnesses.push_back(context().constant_values().GetInstId( + EvalOrAddInst( + context(), loc_id_, + {.type_id = + GetSingletonType(context(), SemIR::WitnessType::TypeInstId), + .query_self_inst_id = + context().constant_values().GetInstId(req.self_facet_value), + .query_specific_interface_id = + context().specific_interfaces().Add( + req.specific_interface)}))); + } + return context().constant_values().GetInstId( + EvalOrAddInst( + context(), loc_id_, + { + .type_id = period_self_type_id, + .type_inst_id = + context().types().GetAsTypeInstId(replacement_self_inst_id), + .witnesses_block_id = context().inst_blocks().Add(witnesses), + })); + } + + SemIR::LocId loc_id_; + SemIR::ConstantId period_self_replacement_id_; + SubstPeriodSelfRebuildInst rebuild_callback_; + + // The last output of GetReplacement(). + SemIR::InstId cached_replacement_id_ = SemIR::InstId::None; + // The type of the last output of GetReplacement(). If the type of `.Self` + // matches, we can reuse the `cached_replacement_id_`. + SemIR::TypeId cached_replacement_type_id_ = SemIR::TypeId::None; +}; + +class SubstDesignatorPeriodSelfCallbacks : public SubstPeriodSelfCallbacks { + public: + explicit SubstDesignatorPeriodSelfCallbacks( + Context* context, SemIR::LocId loc_id, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfRebuildInst rebuild) + : SubstPeriodSelfCallbacks(context, loc_id, period_self_replacement_id, + rebuild) {} + + ~SubstDesignatorPeriodSelfCallbacks() override { + CARBON_CHECK(designator_states_.empty()); + } + + auto Subst(SemIR::InstId& inst_id) -> SubstResult override { + // FacetTypes are concrete even if they have `.Self` inside them, but we + // don't recurse into FacetTypes, so we can use this as a base case. This + // avoids infinite recursion on TypeType and ErrorInst. + if (context().constant_values().Get(inst_id).is_concrete()) { + return FullySubstituted; + } + // Don't recurse into nested facet types, even if they are symbolic. Leave + // their `.Self` as is. + if (context().insts().Is(inst_id)) { + return FullySubstituted; + } + + // Look for implicit use of `.Self` in designators: `.X` is really + // `.Self.X`. + if (auto access = + context().insts().TryGetAs(inst_id)) { + if (auto witness = context().insts().TryGetAs( + access->witness_id)) { + // Canonicalization not necessary; we are working with the constant + // value already, and the query self in a witness is already + // canonicalized. + if (IsPeriodSelf(context(), witness->query_self_inst_id, + /*canonicalize=*/false)) { + // We are entering a designator. We watch for the witness next. + designator_states_.push_back(WitnessNext); + return SubstOperands; + } + } + } + + if (GetDesignatorState() == WitnessNext) { + if (auto witness = + context().insts().TryGetAs(inst_id)) { + // The query self comes next, before the specific interface. This + // deepnds on the order of the operands in the LookupImplWitness, and + // that Subst visits them in top to bottom order. + designator_states_.back() = WitnessSelfNext; + return SubstOperands; + } + } + + if (GetDesignatorState() == WitnessSelfNext) { + // Canonicalization not necessary; we are working with the constant // value already, and the query self in a witness is already // canonicalized. - if (IsPeriodSelf(context(), witness->query_self_inst_id, + if (IsPeriodSelf(context(), inst_id, /*canonicalize=*/false)) { - auto replacement_id = GetReplacement(witness->query_self_inst_id); - auto new_witness = - Rebuild(access->witness_id, - SemIR::LookupImplWitness{ - .type_id = witness->type_id, - .query_self_inst_id = replacement_id, - // Don't replace `.Self` in the interface specific - // here. That is an explicit `.Self` use. We'll - // revisit the instruction for that. - .query_specific_interface_id = - witness->query_specific_interface_id, - }); - auto new_access = Rebuild(inst_id, SemIR::ImplWitnessAccess{ - .type_id = access->type_id, - .witness_id = new_witness, - .index = access->index, - }); - inst_id = new_access; - return SubstAgain; + // Found the implicit use of `.Self` in a designator. + inst_id = GetReplacement(inst_id); + designator_states_.back() = RebuildNext; + return FullySubstituted; + } + } + + return SubstOperands; + } + + auto Rebuild(SemIR::InstId orig_inst_id, SemIR::Inst new_inst) + -> SemIR::InstId override { + TryPopDesignatorState(orig_inst_id); + return SubstPeriodSelfCallbacks::Rebuild(orig_inst_id, new_inst); + } + + auto ReuseUnchanged(SemIR::InstId orig_inst_id) -> SemIR::InstId override { + TryPopDesignatorState(orig_inst_id); + return SubstPeriodSelfCallbacks::ReuseUnchanged(orig_inst_id); + } + + private: + enum DesignatorState { + // We are not inside a designator. + None, + // We are looking for the LookupImplWitness of a designator next. + WitnessNext, + // We are looking for `.Self`, the next one will be the query self of the + // LookupImplWitness of a designator. This is the implicit use of `.Self`. + WitnessSelfNext, + // We have seen the query self of the designator, and are now looking for + // the designator to be rebuilt with the replacement. Any other `.Self` that + // we find are explicit uses of `.Self`, such as in the designator's + // specific interface. + RebuildNext, + }; + + auto GetDesignatorState() const -> DesignatorState { + return designator_states_.empty() ? DesignatorState::None + : designator_states_.back(); + } + + auto TryPopDesignatorState(SemIR::InstId orig_inst_id) -> void { + if (GetDesignatorState() == RebuildNext) { + if (auto access = context().insts().TryGetAs( + orig_inst_id)) { + if (auto witness = context().insts().TryGetAs( + access->witness_id)) { + // Canonicalization not necessary; we are working with the constant + // value already, and the query self in a witness is already + // canonicalized. + if (IsPeriodSelf(context(), witness->query_self_inst_id, + /*canonicalize=*/false)) { + designator_states_.pop_back(); + } + } } } } - // Look for explicit use of `.Self`. - if (behaviour_ == Behaviour::All) { - // Canonicalization not necessary; Subst will recurse anyway, so avoid - // extra work for non-matches. - if (IsPeriodSelf(context(), inst_id, /*canonicalize=*/false)) { + llvm::SmallVector designator_states_; +}; + +class SubstAllPeriodSelfCallbacks : public SubstPeriodSelfCallbacks { + public: + explicit SubstAllPeriodSelfCallbacks( + Context* context, SemIR::LocId loc_id, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfRebuildInst rebuild) + : SubstPeriodSelfCallbacks(context, loc_id, period_self_replacement_id, + rebuild) {} + + auto Subst(SemIR::InstId& inst_id) -> SubstResult override { + // FacetTypes are concrete even if they have `.Self` inside them, but we + // don't recurse into FacetTypes, so we can use this as a base case. This + // avoids infinite recursion on TypeType and ErrorInst. + if (context().constant_values().Get(inst_id).is_concrete()) { + return FullySubstituted; + } + // Don't recurse into nested facet types, even if they are symbolic. Leave + // their `.Self` as is. + if (context().insts().Is(inst_id)) { + return FullySubstituted; + } + + if (IsPeriodSelf(context(), inst_id, + /*canonicalize=*/false)) { inst_id = GetReplacement(inst_id); return FullySubstituted; } + + return SubstOperands; } +}; - return SubstOperands; -} - -auto SubstPeriodSelfCallbacks::Rebuild(SemIR::InstId orig_inst_id, - SemIR::Inst new_inst) -> SemIR::InstId { - return RebuildNewInst(SemIR::LocId(orig_inst_id), new_inst); -} - -auto SubstPeriodSelfCallbacks::GetReplacement(SemIR::InstId period_self) - -> SemIR::InstId { - auto period_self_type_id = context().insts().Get(period_self).type_id(); - CARBON_CHECK(context().types().Is(period_self_type_id)); - - auto replacement_self_inst_id = - context().constant_values().GetInstId(period_self_replacement_id_); - auto replacement_type_id = - context().insts().Get(replacement_self_inst_id).type_id(); - CARBON_CHECK(context().types().IsFacetType(replacement_type_id)); - - // If the replacement has the same type as `.Self`, use it directly. - if (replacement_type_id == period_self_type_id) { - return replacement_self_inst_id; - } - - // If we have already converted the replacement to the type of `.Self`, use - // our previous conversion. - if (period_self_type_id == cached_replacement_type_id_) { - return cached_replacement_id_; - } - - // Convert the replacement facet to the type of `.Self`. - cached_replacement_id_ = ConvertReplacement( - replacement_self_inst_id, replacement_type_id, period_self_type_id); - cached_replacement_type_id_ = period_self_type_id; - return cached_replacement_id_; -} - -auto SubstPeriodSelfCallbacks::ConvertReplacement( - SemIR::InstId replacement_self_inst_id, SemIR::TypeId replacement_type_id, - SemIR::TypeId period_self_type_id) -> SemIR::InstId { - // TODO: Replace all empty facet types with TypeType. - if (period_self_type_id == GetEmptyFacetType(context())) { - // Convert to an empty facet type (representing TypeType); we don't need - // any witnesses. - return ConvertToValueOfType(context(), loc_id_, replacement_self_inst_id, - period_self_type_id); - } - - // We have a facet or a type, but we need more interfaces in the facet type. - // We will have to synthesize a symbolic witness for each interface. - // - // Why is this okay? The type of `.Self` comes from interfaces that are - // before it (to the left of it) in the facet type. The replacement for - // `.Self` will have to impl those interfaces in order to match the facet - // type, so we know that it is valid to construct these witnesses. - - // Make the replacement into a type, which we will need for the FacetValue. - if (context().types().Is(replacement_type_id)) { - replacement_self_inst_id = context().constant_values().GetInstId( - EvalOrAddInst( - context(), loc_id_, - {.type_id = SemIR::TypeType::TypeId, - .facet_value_inst_id = replacement_self_inst_id})); - } - - auto period_self_facet_type = - context().types().GetAs(period_self_type_id); - auto identified_period_self_type_id = RequireIdentifiedFacetType( - context(), loc_id_, - context().constant_values().Get(replacement_self_inst_id), - period_self_facet_type, [&](auto& /*builder*/) { - // The facet type containing this `.Self` should have already been - // identified, which would ensure that the type of `.Self` can be - // identified since it can only depend on things to the left of it - // inside the same facet type. - CARBON_FATAL("could not identify type of `.Self`"); - }); - const auto& identified_period_self_type = - context().identified_facet_types().Get(identified_period_self_type_id); - auto required_impls = identified_period_self_type.required_impls(); - llvm::SmallVector witnesses; - witnesses.reserve(required_impls.size()); - for (const auto& req : required_impls) { - witnesses.push_back(context().constant_values().GetInstId( - EvalOrAddInst( - context(), loc_id_, - {.type_id = - GetSingletonType(context(), SemIR::WitnessType::TypeInstId), - .query_self_inst_id = - context().constant_values().GetInstId(req.self_facet_value), - .query_specific_interface_id = context().specific_interfaces().Add( - req.specific_interface)}))); - } - return context().constant_values().GetInstId(EvalOrAddInst( - context(), loc_id_, - { - .type_id = period_self_type_id, - .type_inst_id = - context().types().GetAsTypeInstId(replacement_self_inst_id), - .witnesses_block_id = context().inst_blocks().Add(witnesses), - })); -} - -auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, - SemIR::ConstantId const_id) -> SemIR::ConstantId { +auto SubstPeriodSelf(Context& context, SemIR::LocId loc_id, + SemIR::ConstantId const_id, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfBehaviour behaviour, + SubstPeriodSelfRebuildInst rebuild) -> SemIR::ConstantId { // Don't replace `.Self` with itself; that is cyclical. // // If the types differ, we would try to convert the replacement to a `.Self` // of the desired type in `const_id`, which is what we already have, so // there's nothing we need to do. But trying to do that conversion recurses // when the type of the `.Self` contains a `.Self`. - if (auto bind_type = - context.constant_values().TryGetInstAs( - GetCanonicalFacetOrTypeValue( - context, callbacks.period_self_replacement_id()))) { - if (context.entity_names().Get(bind_type->entity_name_id).name_id == - SemIR::NameId::PeriodSelf) { - return const_id; - } + if (IsPeriodSelf(context, context.constant_values().GetInstId( + period_self_replacement_id))) { + return const_id; } - auto subst_id = SubstInst( - context, context.constant_values().GetInstId(const_id), callbacks); - return context.constant_values().Get(subst_id); + switch (behaviour) { + case SubstPeriodSelfBehaviour::All: { + SubstAllPeriodSelfCallbacks callbacks( + &context, loc_id, period_self_replacement_id, rebuild); + auto subst_id = SubstInst( + context, context.constant_values().GetInstId(const_id), callbacks); + return context.constant_values().Get(subst_id); + } + case SubstPeriodSelfBehaviour::ImplicitOnly: { + SubstDesignatorPeriodSelfCallbacks callbacks( + &context, loc_id, period_self_replacement_id, rebuild); + auto subst_id = SubstInst( + context, context.constant_values().GetInstId(const_id), callbacks); + return context.constant_values().Get(subst_id); + } + } } -static auto SubstPeriodSelfInSpecific(Context& context, - SubstPeriodSelfCallbacks& callbacks, - SemIR::SpecificId specific_id) +static auto SubstPeriodSelfInSpecific( + Context& context, SemIR::LocId loc_id, SemIR::SpecificId specific_id, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfBehaviour behaviour, SubstPeriodSelfRebuildInst rebuild) -> SemIR::SpecificId { if (!specific_id.has_value()) { return specific_id; @@ -246,27 +380,144 @@ static auto SubstPeriodSelfInSpecific(Context& context, context.inst_blocks().Get(specific.args_id)); for (auto& arg_id : args) { auto const_id = context.constant_values().Get(arg_id); - const_id = SubstPeriodSelf(context, callbacks, const_id); + const_id = SubstPeriodSelf(context, loc_id, const_id, + period_self_replacement_id, behaviour, rebuild); arg_id = context.constant_values().GetInstId(const_id); } - return MakeSpecific(context, callbacks.loc_id(), specific.generic_id, args); + return MakeSpecific(context, loc_id, specific.generic_id, args); } -auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, - SemIR::SpecificInterface interface) +auto SubstPeriodSelf(Context& context, SemIR::LocId loc_id, + SemIR::SpecificInterface interface, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfBehaviour behaviour, + SubstPeriodSelfRebuildInst rebuild) -> SemIR::SpecificInterface { interface.specific_id = - SubstPeriodSelfInSpecific(context, callbacks, interface.specific_id); + SubstPeriodSelfInSpecific(context, loc_id, interface.specific_id, + period_self_replacement_id, behaviour, rebuild); return interface; } -auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, - SemIR::SpecificNamedConstraint constraint) +auto SubstPeriodSelf(Context& context, SemIR::LocId loc_id, + SemIR::SpecificNamedConstraint constraint, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfBehaviour behaviour, + SubstPeriodSelfRebuildInst rebuild) -> SemIR::SpecificNamedConstraint { constraint.specific_id = - SubstPeriodSelfInSpecific(context, callbacks, constraint.specific_id); + SubstPeriodSelfInSpecific(context, loc_id, constraint.specific_id, + period_self_replacement_id, behaviour, rebuild); return constraint; } +auto SubstPeriodSelfInFacetType(Context& context, SemIR::LocId loc_id, + SemIR::TypeInstId self_type_inst_id, + SemIR::TypeInstId facet_type_inst_id) + -> SemIR::TypeInstId { + auto canon_facet_type_inst_id = + context.constant_values().GetConstantInstId(facet_type_inst_id); + if (canon_facet_type_inst_id == SemIR::ErrorInst::TypeInstId) { + return SemIR::ErrorInst::TypeInstId; + } + + auto period_self_replacement_id = + context.constant_values().Get(self_type_inst_id); + + auto orig_facet_type = + context.insts().GetAs(canon_facet_type_inst_id); + const auto& orig_info = + context.facet_types().Get(orig_facet_type.facet_type_id); + + auto replace_interface = [&](SemIR::SpecificInterface si) { + return SubstPeriodSelf(context, loc_id, si, period_self_replacement_id, + SubstPeriodSelfBehaviour::All); + }; + auto replace_constraint = [&](SemIR::SpecificNamedConstraint sc) { + return SubstPeriodSelf(context, loc_id, sc, period_self_replacement_id, + SubstPeriodSelfBehaviour::All); + }; + auto replace_type_impls_interface = + [&](SemIR::FacetTypeInfo::TypeImplsInterface impls) + -> SemIR::FacetTypeInfo::TypeImplsInterface { + auto self = SubstPeriodSelf( + context, loc_id, context.constant_values().Get(impls.self_type), + period_self_replacement_id, SubstPeriodSelfBehaviour::All); + auto interface = SubstPeriodSelf(context, loc_id, impls.specific_interface, + period_self_replacement_id, + SubstPeriodSelfBehaviour::All); + return {context.constant_values().GetInstId(self), interface}; + }; + auto replace_type_impls_constraint = + [&](SemIR::FacetTypeInfo::TypeImplsNamedConstraint impls) + -> SemIR::FacetTypeInfo::TypeImplsNamedConstraint { + auto self = SubstPeriodSelf( + context, loc_id, context.constant_values().Get(impls.self_type), + period_self_replacement_id, SubstPeriodSelfBehaviour::All); + auto constraint = SubstPeriodSelf( + context, loc_id, impls.specific_named_constraint, + period_self_replacement_id, SubstPeriodSelfBehaviour::All); + return {context.constant_values().GetInstId(self), constraint}; + }; + auto replace_rewrite = [&](SemIR::FacetTypeInfo::RewriteConstraint r) + -> SemIR::FacetTypeInfo::RewriteConstraint { + // Replace `.Self` only on the RHS, and only if's not a simple designator. + // The LHS is always a simple designator since only that is allowed. + if (auto access = + context.insts().TryGetAs(r.rhs_id)) { + if (auto lookup = context.insts().TryGetAs( + access->witness_id)) { + if (IsPeriodSelf(context, lookup->query_self_inst_id)) { + // Found a simple designator. Leave it alone. + return r; + } + } + } + auto rhs = SubstPeriodSelf( + context, loc_id, context.constant_values().Get(r.rhs_id), + period_self_replacement_id, SubstPeriodSelfBehaviour::All); + return {r.lhs_id, context.constant_values().GetInstId(rhs)}; + }; + + SemIR::FacetTypeInfo info; + llvm::append_range( + info.extend_constraints, + llvm::map_range(orig_info.extend_constraints, replace_interface)); + llvm::append_range( + info.extend_named_constraints, + llvm::map_range(orig_info.extend_named_constraints, replace_constraint)); + llvm::append_range( + info.self_impls_constraints, + llvm::map_range(orig_info.self_impls_constraints, replace_interface)); + llvm::append_range(info.self_impls_named_constraints, + llvm::map_range(orig_info.self_impls_named_constraints, + replace_constraint)); + llvm::append_range(info.type_impls_interfaces, + llvm::map_range(orig_info.type_impls_interfaces, + replace_type_impls_interface)); + llvm::append_range(info.type_impls_named_constraints, + llvm::map_range(orig_info.type_impls_named_constraints, + replace_type_impls_constraint)); + llvm::append_range( + info.rewrite_constraints, + llvm::map_range(orig_info.rewrite_constraints, replace_rewrite)); + + info.Canonicalize(); + if (info == orig_info) { + // Nothing was substituted, keep the original instruction. + // + // It is noteworthy that we keep the non-canonical instruction here, since + // it may have a symbolic value (which is attached to a generic, and can be + // updated by specifics). Returning the canonical facet type instruction + // would lose the attachment to the generic which would be incorrect. + return facet_type_inst_id; + } + + return AddTypeInst( + context, loc_id, + {.type_id = SemIR::TypeType::TypeId, + .facet_type_id = context.facet_types().Add(info)}); +} + auto IsPeriodSelf(Context& context, SemIR::InstId inst_id, bool canonicalize) -> bool { auto const_inst_id = context.constant_values().GetConstantInstId(inst_id); @@ -356,7 +607,7 @@ class SearchCanonicalForExplicitPeriodSelf : public SubstInstCallbacks { const_inst_id)) { if (auto lookup = context().insts().TryGetAs( access->witness_id)) { - // Canonicalization not necessary; We are working with the constant + // Canonicalization not necessary; we are working with the constant // value already, and the query self in a witness is already // canonicalized. if (IsPeriodSelf(context(), lookup->query_self_inst_id, diff --git a/toolchain/check/period_self.h b/toolchain/check/period_self.h index f72e6671d635..b2de3c03666d 100644 --- a/toolchain/check/period_self.h +++ b/toolchain/check/period_self.h @@ -21,57 +21,57 @@ namespace Carbon::Check { auto MakePeriodSelfFacetValue(Context& context, SemIR::LocId loc_id, SemIR::TypeId self_type_id) -> SemIR::InstId; -class SubstPeriodSelfCallbacks : public SubstInstCallbacks { - public: - enum Behaviour { - ImplicitOnly, - All, - }; - - explicit SubstPeriodSelfCallbacks( - Context* context, SemIR::LocId loc_id, - SemIR::ConstantId period_self_replacement_id, - Behaviour behaviour = Behaviour::All); - auto Subst(SemIR::InstId& inst_id) -> SubstResult override; - auto Rebuild(SemIR::InstId orig_inst_id, SemIR::Inst new_inst) - -> SemIR::InstId override; - - auto loc_id() const -> SemIR::LocId { return loc_id_; } - auto period_self_replacement_id() const -> SemIR::ConstantId { - return period_self_replacement_id_; - } - - private: - auto GetReplacement(SemIR::InstId period_self) -> SemIR::InstId; - auto ConvertReplacement(SemIR::InstId replacement_self_inst_id, - SemIR::TypeId replacement_type_id, - SemIR::TypeId period_self_type_id) -> SemIR::InstId; - - SemIR::LocId loc_id_; - SemIR::ConstantId period_self_replacement_id_; - Behaviour behaviour_; - - // The last output of GetReplacement(). - SemIR::InstId cached_replacement_id_ = SemIR::InstId::None; - // The type of the last output of GetReplacement(). If the type of `.Self` - // matches, we can reuse the `cached_replacement_id_`. - SemIR::TypeId cached_replacement_type_id_ = SemIR::TypeId::None; +enum class SubstPeriodSelfBehaviour { + ImplicitOnly, + All, }; -// Replace all `.Self` references in `const_id`. The `callbacks` specifies the -// facet to replace them with. -auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, - SemIR::ConstantId const_id) -> SemIR::ConstantId; +using SubstPeriodSelfRebuildInst = + llvm::function_refSemIR::InstId>; -// Replace all `.Self` references in the specific of the interface or named -// constraint. The `callbacks` specifies the facet to replace them with. -auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, - SemIR::SpecificInterface interface) - -> SemIR::SpecificInterface; -auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, - SemIR::SpecificNamedConstraint constraint) +// Replace `.Self` references in `const_id` with `period_self_replacement_id`. +// The `behaviour` specifies if all `.Self` are replaced or just implicit use in +// designators. The `rebuild` callback can optionally be specified to override +// how an instruction is re-constructed to form an InstId after replacement. It +// can return None to fall back to the default of evaluating the inst. +auto SubstPeriodSelf( + Context& context, SemIR::LocId loc_id, SemIR::ConstantId const_id, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfBehaviour behaviour = SubstPeriodSelfBehaviour::All, + SubstPeriodSelfRebuildInst rebuild = nullptr) -> SemIR::ConstantId; + +// Replace `.Self` references in the specific of the interface or named +// constraint. +// +// The `behaviour` specifies if all `.Self` are replaced or just implicit use in +// designators. The `rebuild` callback can optionally be specified to override +// how an instruction is re-constructed to form an InstId after replacement. It +// can return None to fall back to the default of evaluating the inst. +auto SubstPeriodSelf( + Context& context, SemIR::LocId loc_id, SemIR::SpecificInterface interface, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfBehaviour behaviour = SubstPeriodSelfBehaviour::All, + SubstPeriodSelfRebuildInst rebuild = nullptr) -> SemIR::SpecificInterface; +auto SubstPeriodSelf( + Context& context, SemIR::LocId loc_id, + SemIR::SpecificNamedConstraint constraint, + SemIR::ConstantId period_self_replacement_id, + SubstPeriodSelfBehaviour behaviour = SubstPeriodSelfBehaviour::All, + SubstPeriodSelfRebuildInst rebuild = nullptr) -> SemIR::SpecificNamedConstraint; +// Replace all `.Self` references with the self-type. The `facet_type_inst_id` +// must be a `FacetType` instruction (or error). +// +// Unlike SubstPeriodSelf, which works with constant values and thus canonical +// instructions, this operation can be done for non-canonical facet types. A new +// instruction is added for the output FacetType if anything does get replaced, +// and the original instruction id is preserved otherwise. +auto SubstPeriodSelfInFacetType(Context& context, SemIR::LocId loc_id, + SemIR::TypeInstId self_type_inst_id, + SemIR::TypeInstId facet_type_inst_id) + -> SemIR::TypeInstId; + // Returns whether the constant value of `inst_id` is a reference to `.Self`. // // If `canonicalize` is true, look at the constant value of `inst_id` and get diff --git a/toolchain/check/testdata/facet/access.carbon b/toolchain/check/testdata/facet/access.carbon index 1cd526a2ac99..b17bc935c88e 100644 --- a/toolchain/check/testdata/facet/access.carbon +++ b/toolchain/check/testdata/facet/access.carbon @@ -347,6 +347,75 @@ fn F2(U:! Z) { F1(U.Y1, U.G()); } +// --- find_access_value_in_first_nested_access.carbon +library "[[@TEST_NAME]]"; + +interface W {} +interface X { + let X1:! type; +} +interface Y(U:! type) { + let Y1:! X where .X1 = U; +} +interface Z(T:! type) { + let Z1:! type; +} + +fn F(U:! W, V:! Z(.Self) where .Z1 impls Y(U)) { + // This has to search for a value for `.Z1.Y1.X1` in V. To do so it needs to + // look for a rewrite of .X1. First it looks in `V.Z1.Y1`, where + // it finds the rewrite of `.X1 = U`. + // + // Only U impls W so we use `as W` to test that the LHS is U. + V.(Z(V).Z1).(Y(U).Y1).(X.X1) as W; +} + +// --- find_access_value_in_second_nested_access.carbon +library "[[@TEST_NAME]]"; + +interface W {} +interface X { + let X1:! type; +} +interface Y(T:! type) { + let Y1:! type; +} +interface Z(U:! type, PeriodSelf:! type) { + let Z1:! Y(PeriodSelf) where .Y1 impls (X where .X1 = U); +} + +fn F(U:! W, V:! Z(U, .Self)) { + // This has to search for a value for `.Z1.Y1.X1` in V. To do so it needs to + // look for a rewrite of .X1. First it looks in `V.Z1.Y1`, then `V.Z1`, where + // it finds the rewrite of `.X1 = U`. + // + // Only U impls W so we use `as W` to test that the LHS is U. + V.(Z(U, V).Z1).(Y(V).Y1).(X.X1) as W; +} + +// --- find_access_value_in_third_nested_access.carbon +library "[[@TEST_NAME]]"; + +interface W {} +interface X { + let X1:! type; +} +interface Y { + let Y1:! type; +} +interface Z(T:! type) { + let Z1:! type; +} + +fn F(U:! W, V:! Z(.Self) where .Z1 impls (Y where .Y1 impls (X where .X1 = U))) { + // This has to search for a value for `.Z1.Y1.X1` in V. To do so it needs to + // look for a rewrite of .X1. First it looks in `V.Z1.Y1`, then `V.Z1`, then + // `V` where it finds the rewrite of `.X1 = U`. + // + // Only U impls W so we use `as W` to test that the LHS is U. + V.(Z(V).Z1).(Y.Y1).(X.X1) as W; +} + // CHECK:STDOUT: --- access_assoc_fn.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -774,11 +843,11 @@ fn F2(U:! Z) { // CHECK:STDOUT: %AB: %facet_type.82c = symbolic_binding AB, 0 [symbolic] // CHECK:STDOUT: %AB.as_type: type = facet_access_type %AB [symbolic] // CHECK:STDOUT: %A.lookup_impl_witness.1b9: = lookup_impl_witness %AB, @A [symbolic] -// CHECK:STDOUT: %B.lookup_impl_witness.97b: = lookup_impl_witness %AB, @B [symbolic] // CHECK:STDOUT: %.262: Core.Form = init_form %empty_tuple.type [concrete] // CHECK:STDOUT: %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete] // CHECK:STDOUT: %F.type: type = fn_type @F [concrete] // CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %B.lookup_impl_witness.97b: = lookup_impl_witness %AB, @B [symbolic] // CHECK:STDOUT: %.469: Core.Form = init_form %empty_struct_type [concrete] // CHECK:STDOUT: %pattern_type.a96: type = pattern_type %empty_struct_type [concrete] // CHECK:STDOUT: %G.type: type = fn_type @G [concrete] diff --git a/toolchain/check/testdata/impl/assoc_const_self.carbon b/toolchain/check/testdata/impl/assoc_const_self.carbon index e47f75c760d0..269c6811fcc4 100644 --- a/toolchain/check/testdata/impl/assoc_const_self.carbon +++ b/toolchain/check/testdata/impl/assoc_const_self.carbon @@ -695,7 +695,7 @@ fn CallF() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @empty_struct_type.as..impl: %.loc15_7.2 as %.loc15_18 { +// CHECK:STDOUT: impl @empty_struct_type.as..impl: %.loc15_7.2 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/fail_extend_non_interface.carbon b/toolchain/check/testdata/impl/fail_extend_non_interface.carbon index 375dd22f8bca..24ff9d937653 100644 --- a/toolchain/check/testdata/impl/fail_extend_non_interface.carbon +++ b/toolchain/check/testdata/impl/fail_extend_non_interface.carbon @@ -50,7 +50,7 @@ class C { // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @C.as..impl: %Self.ref as %i32; +// CHECK:STDOUT: impl @C.as..impl: %Self.ref as ; // CHECK:STDOUT: // CHECK:STDOUT: class @C { // CHECK:STDOUT: impl_decl @C.as..impl [concrete] {} { diff --git a/toolchain/check/testdata/impl/fail_impl_bad_interface.carbon b/toolchain/check/testdata/impl/fail_impl_bad_interface.carbon index 79b5e8cfec5a..a53209907ffe 100644 --- a/toolchain/check/testdata/impl/fail_impl_bad_interface.carbon +++ b/toolchain/check/testdata/impl/fail_impl_bad_interface.carbon @@ -124,7 +124,7 @@ impl {.a: bool} as type where .Self impls I {} // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @bool.as..impl: %.loc8_6 as %.loc8_14 { +// CHECK:STDOUT: impl @bool.as..impl: %.loc8_6 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -170,7 +170,7 @@ impl {.a: bool} as type where .Self impls I {} // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @f64.as..impl: %f64 as %.loc8_18 { +// CHECK:STDOUT: impl @f64.as..impl: %f64 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -232,7 +232,7 @@ impl {.a: bool} as type where .Self impls I {} // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @struct_type.a.as..impl: %struct_type.a as %.loc10_25 { +// CHECK:STDOUT: impl @struct_type.a.as..impl: %struct_type.a as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/forward_decls.carbon b/toolchain/check/testdata/impl/forward_decls.carbon index 385f94118371..7ade658de026 100644 --- a/toolchain/check/testdata/impl/forward_decls.carbon +++ b/toolchain/check/testdata/impl/forward_decls.carbon @@ -1052,7 +1052,7 @@ impl C as Y {} // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @D.as..impl: %D.ref.loc13 as %.loc13_13 { +// CHECK:STDOUT: impl @D.as..impl: %D.ref.loc13 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -1502,7 +1502,7 @@ impl C as Y {} // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @empty_struct_type.as..impl: %.loc10_7.2 as file.%.loc10_14.2; +// CHECK:STDOUT: impl @empty_struct_type.as..impl: %.loc10_7.2 as ; // CHECK:STDOUT: // CHECK:STDOUT: specific @I.WithSelf(constants.%Self.ab9) {} // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/impl_assoc_const.carbon b/toolchain/check/testdata/impl/impl_assoc_const.carbon index c59cdfb62206..43e4eb6bca88 100644 --- a/toolchain/check/testdata/impl/impl_assoc_const.carbon +++ b/toolchain/check/testdata/impl/impl_assoc_const.carbon @@ -492,7 +492,7 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @empty_tuple.type.as..impl: %.loc13_7.2 as %.loc13_14 { +// CHECK:STDOUT: impl @empty_tuple.type.as..impl: %.loc13_7.2 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -558,7 +558,7 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @empty_tuple.type.as..impl: %.loc13_7.2 as %.loc13_14 { +// CHECK:STDOUT: impl @empty_tuple.type.as..impl: %.loc13_7.2 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/impl_assoc_const_with_prelude.carbon b/toolchain/check/testdata/impl/impl_assoc_const_with_prelude.carbon index 68f6af126647..d11f11f97392 100644 --- a/toolchain/check/testdata/impl/impl_assoc_const_with_prelude.carbon +++ b/toolchain/check/testdata/impl/impl_assoc_const_with_prelude.carbon @@ -435,7 +435,7 @@ impl () as I where .X = {.a = true, .b = (1, 2)} and .X = {.a = false, .b = (3, // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @empty_tuple.type.as..impl: %.loc10_7.2 as %.loc10_14 { +// CHECK:STDOUT: impl @empty_tuple.type.as..impl: %.loc10_7.2 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/import_interface_assoc_const.carbon b/toolchain/check/testdata/impl/import_interface_assoc_const.carbon index 0aa8dd0ff0fd..ef9c23d26ec1 100644 --- a/toolchain/check/testdata/impl/import_interface_assoc_const.carbon +++ b/toolchain/check/testdata/impl/import_interface_assoc_const.carbon @@ -856,9 +856,9 @@ impl CD as IF where .F = 0 { // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @C5.as..impl.bcbfb8.1: %C5.ref as %.loc17_15; +// CHECK:STDOUT: impl @C5.as..impl.bcbfb8.1: %C5.ref as ; // CHECK:STDOUT: -// CHECK:STDOUT: impl @C5.as..impl.bcbfb8.2: %C5.ref as %.loc27_15 { +// CHECK:STDOUT: impl @C5.as..impl.bcbfb8.2: %C5.ref as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -1055,7 +1055,7 @@ impl CD as IF where .F = 0 { // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @C7.as..impl: %C7.ref as %.loc10_14 { +// CHECK:STDOUT: impl @C7.as..impl: %C7.ref as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -1150,7 +1150,7 @@ impl CD as IF where .F = 0 { // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @C8.as..impl: %C8.ref as %.loc10_14 { +// CHECK:STDOUT: impl @C8.as..impl: %C8.ref as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -1244,7 +1244,7 @@ impl CD as IF where .F = 0 { // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @C9.as..impl: %C9.ref as %.loc10_14 { +// CHECK:STDOUT: impl @C9.as..impl: %C9.ref as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -1337,7 +1337,7 @@ impl CD as IF where .F = 0 { // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @CA.as..impl: %CA.ref as %.loc14_14 { +// CHECK:STDOUT: impl @CA.as..impl: %CA.ref as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/incomplete.carbon b/toolchain/check/testdata/impl/incomplete.carbon index 1b415de4bfc0..e177f838af2b 100644 --- a/toolchain/check/testdata/impl/incomplete.carbon +++ b/toolchain/check/testdata/impl/incomplete.carbon @@ -387,7 +387,7 @@ interface B { // CHECK:STDOUT: // CHECK:STDOUT: interface @J; // CHECK:STDOUT: -// CHECK:STDOUT: impl @C.as..impl: %C.ref.loc13 as %.loc13_13 { +// CHECK:STDOUT: impl @C.as..impl: %C.ref.loc13 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } @@ -756,7 +756,7 @@ interface B { // CHECK:STDOUT: // CHECK:STDOUT: constraint @X; // CHECK:STDOUT: -// CHECK:STDOUT: impl @C.as..impl: %C.ref as %X.ref; +// CHECK:STDOUT: impl @C.as..impl: %C.ref as ; // CHECK:STDOUT: // CHECK:STDOUT: class @C { // CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] diff --git a/toolchain/check/testdata/impl/lookup/access.carbon b/toolchain/check/testdata/impl/lookup/access.carbon index 97997b91601f..bcac443b1c32 100644 --- a/toolchain/check/testdata/impl/lookup/access.carbon +++ b/toolchain/check/testdata/impl/lookup/access.carbon @@ -22,33 +22,34 @@ interface Z { } // There's 2 ImplWitnessAccess instructions in the type, but they together -// resolve to a symbolic type value, so the type structure is: `?C(?)` -impl forall [U:! Z where .Z1 impls Y] U as X(U.Z1.(Y.Y1)) {} +// resolve to a symbolic type value, so the type structure is: `? as X(?)` +impl forall [T:! Z where .Z1 impls Y] T as X(T.Z1.(Y.Y1)) {} class C { impl as Y where .Y1 = {} {} } fn F(V:! Z where .Z1 = C) { - // The type stucture is `?C(C)` which will match the impl's less specific - // `?C(?)`, then the impl will deduce the parameter of `X` to be `{}` from the - // type of `V`. This would fail if ImplWitnessAccess instructions were treated - // as Concrete in the type structure, since the impl would have a different - // concrete value (an ImplWitnessAccess) than the query (a StructValue). + // The type stucture is `? as X({})` which will match the impl's less specific + // `? as X(?)`, then the impl will deduce the parameter of `X` to be `{}` from + // the type of `V`. This would fail if ImplWitnessAccess instructions were + // treated as Concrete in the type structure, since the impl would have a + // different concrete value (an ImplWitnessAccess) than the query (a + // StructValue). V as X({}); } fn G(V:! Z where .Z1 impls Y) { - // The type structure is `?C(?)`, also built from ImplWitnessAccess insts, - // which will match the impl's `?C(?)`. + // The type structure is `? as X(?)`, also built from ImplWitnessAccess insts, + // which will match the impl's `? as X(?)`. V as X(V.(Z.Z1).(Y.Y1)); } -// TODO: This creates an infinite loop in `.Self` substitution. -// fn H(U:! type, V:! Z where .Z1 impls (Y where .Y1 = U)) { -// // The type structure is `?C(?)`, without using an ImplWitnessAccess, which -// // will match the impl's `?C(?)`. This would fail if ImplWitnessAccess -// // instructions were treated as Concrete in the type structure, since the -// // impl's type structure would be more specific than the query's. -// V as X(U); -// } +fn H(U:! type, V:! Z where .Z1 impls (Y where .Y1 = U)) { + // The type structure is `? as X(?)`, without using an ImplWitnessAccess, + // which will match the impl's `? as X(?)`. This would fail if + // ImplWitnessAccess instructions were treated as Concrete in the type + // structure, since the impl's type structure would be more specific than the + // query's. + V as X(U); +} diff --git a/toolchain/check/testdata/interface/incomplete.carbon b/toolchain/check/testdata/interface/incomplete.carbon index 574e106a9200..02a311c90cba 100644 --- a/toolchain/check/testdata/interface/incomplete.carbon +++ b/toolchain/check/testdata/interface/incomplete.carbon @@ -200,7 +200,7 @@ interface A(T:! type) { // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @empty_struct_type.as..impl: %.loc16_7.2 as %.loc16_14 { +// CHECK:STDOUT: impl @empty_struct_type.as..impl: %.loc16_7.2 as { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon b/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon index 1d6acb6a8069..93f7ea582124 100644 --- a/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon +++ b/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon @@ -345,10 +345,10 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.97d: type = fn_type_with_self_type %AddWith.WithSelf.Op.type.82f, %AddWith.facet.570 [symbolic] // CHECK:STDOUT: %impl.elem1.07a: %.97d = impl_witness_access %AddWith.lookup_impl_witness.3c7, element1 [symbolic] // CHECK:STDOUT: %specific_impl_fn.dbc: = specific_impl_function %impl.elem1.07a, @AddWith.WithSelf.Op(%U.as_type.2b8, %AddWith.facet.570) [symbolic] -// CHECK:STDOUT: %Destroy.lookup_impl_witness.d86: = lookup_impl_witness %Result, @Destroy [symbolic] +// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result, @Destroy [symbolic] // CHECK:STDOUT: %Destroy.WithSelf.Op.type.cb2e47.2: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Result) [symbolic] // CHECK:STDOUT: %.d5f: type = fn_type_with_self_type %Destroy.WithSelf.Op.type.cb2e47.2, %Result [symbolic] -// CHECK:STDOUT: %impl.elem0.a6b: %.d5f = impl_witness_access %Destroy.lookup_impl_witness.d86, element0 [symbolic] +// CHECK:STDOUT: %impl.elem0.a6b: %.d5f = impl_witness_access %Destroy.lookup_impl_witness, element0 [symbolic] // CHECK:STDOUT: %specific_impl_fn.761: = specific_impl_function %impl.elem0.a6b, @Destroy.WithSelf.Op(%Result) [symbolic] // CHECK:STDOUT: %SubWith.type.99c: type = facet_type <@SubWith.1, @SubWith.1(%Other)> [symbolic] // CHECK:STDOUT: %Self.ddf: %SubWith.type.99c = symbolic_binding Self, 1 [symbolic] @@ -1383,7 +1383,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %specific_impl_fn.loc126_5.3: = specific_impl_function %impl.elem1.loc126_5.2, @AddWith.WithSelf.Op(%U.as_type.loc123_36.1, %AddWith.facet) [symbolic = %specific_impl_fn.loc126_5.3 (constants.%specific_impl_fn.dbc)] // CHECK:STDOUT: %Destroy.WithSelf.Op.type: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Result.loc121_9.1) [symbolic = %Destroy.WithSelf.Op.type (constants.%Destroy.WithSelf.Op.type.cb2e47.2)] // CHECK:STDOUT: %.loc126_5.5: type = fn_type_with_self_type %Destroy.WithSelf.Op.type, %Result.loc121_9.1 [symbolic = %.loc126_5.5 (constants.%.d5f)] -// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc121_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness.d86)] +// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc121_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness)] // CHECK:STDOUT: %impl.elem0.loc126_5.2: @AddWith.loc124.%.loc126_5.5 (%.d5f) = impl_witness_access %Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc126_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %specific_impl_fn.loc126_5.4: = specific_impl_function %impl.elem0.loc126_5.2, @Destroy.WithSelf.Op(%Result.loc121_9.1) [symbolic = %specific_impl_fn.loc126_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: @@ -1401,7 +1401,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.loc126_5.2: ref @AddWith.loc124.%Result.as_type.loc123_54.1 (%Result.as_type) = temporary_storage // CHECK:STDOUT: %AddWith.WithSelf.Op.call: init @AddWith.loc124.%Result.as_type.loc123_54.1 (%Result.as_type) to %.loc126_5.2 = call %bound_method.loc126_5.2(%x.ref, %y.ref) // CHECK:STDOUT: %.loc126_5.3: ref @AddWith.loc124.%Result.as_type.loc123_54.1 (%Result.as_type) = temporary %.loc126_5.2, %AddWith.WithSelf.Op.call -// CHECK:STDOUT: %impl.elem0.loc126_5.1: @AddWith.loc124.%.loc126_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness.d86, element0 [symbolic = %impl.elem0.loc126_5.2 (constants.%impl.elem0.a6b)] +// CHECK:STDOUT: %impl.elem0.loc126_5.1: @AddWith.loc124.%.loc126_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc126_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %bound_method.loc126_5.3: = bound_method %.loc126_5.3, %impl.elem0.loc126_5.1 // CHECK:STDOUT: %specific_impl_fn.loc126_5.2: = specific_impl_function %impl.elem0.loc126_5.1, @Destroy.WithSelf.Op(constants.%Result) [symbolic = %specific_impl_fn.loc126_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: %bound_method.loc126_5.4: = bound_method %.loc126_5.3, %specific_impl_fn.loc126_5.2 @@ -1425,7 +1425,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %specific_impl_fn.loc137_5.3: = specific_impl_function %impl.elem1.loc137_5.2, @SubWith.WithSelf.Op(%U.as_type.loc134_36.1, %SubWith.facet) [symbolic = %specific_impl_fn.loc137_5.3 (constants.%specific_impl_fn.0d3)] // CHECK:STDOUT: %Destroy.WithSelf.Op.type: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Result.loc132_9.1) [symbolic = %Destroy.WithSelf.Op.type (constants.%Destroy.WithSelf.Op.type.cb2e47.2)] // CHECK:STDOUT: %.loc137_5.5: type = fn_type_with_self_type %Destroy.WithSelf.Op.type, %Result.loc132_9.1 [symbolic = %.loc137_5.5 (constants.%.d5f)] -// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc132_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness.d86)] +// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc132_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness)] // CHECK:STDOUT: %impl.elem0.loc137_5.2: @SubWith.loc135.%.loc137_5.5 (%.d5f) = impl_witness_access %Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc137_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %specific_impl_fn.loc137_5.4: = specific_impl_function %impl.elem0.loc137_5.2, @Destroy.WithSelf.Op(%Result.loc132_9.1) [symbolic = %specific_impl_fn.loc137_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: @@ -1443,7 +1443,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.loc137_5.2: ref @SubWith.loc135.%Result.as_type.loc134_54.1 (%Result.as_type) = temporary_storage // CHECK:STDOUT: %SubWith.WithSelf.Op.call: init @SubWith.loc135.%Result.as_type.loc134_54.1 (%Result.as_type) to %.loc137_5.2 = call %bound_method.loc137_5.2(%x.ref, %y.ref) // CHECK:STDOUT: %.loc137_5.3: ref @SubWith.loc135.%Result.as_type.loc134_54.1 (%Result.as_type) = temporary %.loc137_5.2, %SubWith.WithSelf.Op.call -// CHECK:STDOUT: %impl.elem0.loc137_5.1: @SubWith.loc135.%.loc137_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness.d86, element0 [symbolic = %impl.elem0.loc137_5.2 (constants.%impl.elem0.a6b)] +// CHECK:STDOUT: %impl.elem0.loc137_5.1: @SubWith.loc135.%.loc137_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc137_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %bound_method.loc137_5.3: = bound_method %.loc137_5.3, %impl.elem0.loc137_5.1 // CHECK:STDOUT: %specific_impl_fn.loc137_5.2: = specific_impl_function %impl.elem0.loc137_5.1, @Destroy.WithSelf.Op(constants.%Result) [symbolic = %specific_impl_fn.loc137_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: %bound_method.loc137_5.4: = bound_method %.loc137_5.3, %specific_impl_fn.loc137_5.2 @@ -1467,7 +1467,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %specific_impl_fn.loc148_5.3: = specific_impl_function %impl.elem1.loc148_5.2, @MulWith.WithSelf.Op(%U.as_type.loc145_36.1, %MulWith.facet) [symbolic = %specific_impl_fn.loc148_5.3 (constants.%specific_impl_fn.889)] // CHECK:STDOUT: %Destroy.WithSelf.Op.type: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Result.loc143_9.1) [symbolic = %Destroy.WithSelf.Op.type (constants.%Destroy.WithSelf.Op.type.cb2e47.2)] // CHECK:STDOUT: %.loc148_5.5: type = fn_type_with_self_type %Destroy.WithSelf.Op.type, %Result.loc143_9.1 [symbolic = %.loc148_5.5 (constants.%.d5f)] -// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc143_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness.d86)] +// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc143_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness)] // CHECK:STDOUT: %impl.elem0.loc148_5.2: @MulWith.loc146.%.loc148_5.5 (%.d5f) = impl_witness_access %Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc148_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %specific_impl_fn.loc148_5.4: = specific_impl_function %impl.elem0.loc148_5.2, @Destroy.WithSelf.Op(%Result.loc143_9.1) [symbolic = %specific_impl_fn.loc148_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: @@ -1485,7 +1485,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.loc148_5.2: ref @MulWith.loc146.%Result.as_type.loc145_54.1 (%Result.as_type) = temporary_storage // CHECK:STDOUT: %MulWith.WithSelf.Op.call: init @MulWith.loc146.%Result.as_type.loc145_54.1 (%Result.as_type) to %.loc148_5.2 = call %bound_method.loc148_5.2(%x.ref, %y.ref) // CHECK:STDOUT: %.loc148_5.3: ref @MulWith.loc146.%Result.as_type.loc145_54.1 (%Result.as_type) = temporary %.loc148_5.2, %MulWith.WithSelf.Op.call -// CHECK:STDOUT: %impl.elem0.loc148_5.1: @MulWith.loc146.%.loc148_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness.d86, element0 [symbolic = %impl.elem0.loc148_5.2 (constants.%impl.elem0.a6b)] +// CHECK:STDOUT: %impl.elem0.loc148_5.1: @MulWith.loc146.%.loc148_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc148_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %bound_method.loc148_5.3: = bound_method %.loc148_5.3, %impl.elem0.loc148_5.1 // CHECK:STDOUT: %specific_impl_fn.loc148_5.2: = specific_impl_function %impl.elem0.loc148_5.1, @Destroy.WithSelf.Op(constants.%Result) [symbolic = %specific_impl_fn.loc148_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: %bound_method.loc148_5.4: = bound_method %.loc148_5.3, %specific_impl_fn.loc148_5.2 @@ -1509,7 +1509,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %specific_impl_fn.loc159_5.3: = specific_impl_function %impl.elem1.loc159_5.2, @DivWith.WithSelf.Op(%U.as_type.loc156_36.1, %DivWith.facet) [symbolic = %specific_impl_fn.loc159_5.3 (constants.%specific_impl_fn.dbd)] // CHECK:STDOUT: %Destroy.WithSelf.Op.type: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Result.loc154_9.1) [symbolic = %Destroy.WithSelf.Op.type (constants.%Destroy.WithSelf.Op.type.cb2e47.2)] // CHECK:STDOUT: %.loc159_5.5: type = fn_type_with_self_type %Destroy.WithSelf.Op.type, %Result.loc154_9.1 [symbolic = %.loc159_5.5 (constants.%.d5f)] -// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc154_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness.d86)] +// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc154_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness)] // CHECK:STDOUT: %impl.elem0.loc159_5.2: @DivWith.loc157.%.loc159_5.5 (%.d5f) = impl_witness_access %Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc159_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %specific_impl_fn.loc159_5.4: = specific_impl_function %impl.elem0.loc159_5.2, @Destroy.WithSelf.Op(%Result.loc154_9.1) [symbolic = %specific_impl_fn.loc159_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: @@ -1527,7 +1527,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.loc159_5.2: ref @DivWith.loc157.%Result.as_type.loc156_54.1 (%Result.as_type) = temporary_storage // CHECK:STDOUT: %DivWith.WithSelf.Op.call: init @DivWith.loc157.%Result.as_type.loc156_54.1 (%Result.as_type) to %.loc159_5.2 = call %bound_method.loc159_5.2(%x.ref, %y.ref) // CHECK:STDOUT: %.loc159_5.3: ref @DivWith.loc157.%Result.as_type.loc156_54.1 (%Result.as_type) = temporary %.loc159_5.2, %DivWith.WithSelf.Op.call -// CHECK:STDOUT: %impl.elem0.loc159_5.1: @DivWith.loc157.%.loc159_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness.d86, element0 [symbolic = %impl.elem0.loc159_5.2 (constants.%impl.elem0.a6b)] +// CHECK:STDOUT: %impl.elem0.loc159_5.1: @DivWith.loc157.%.loc159_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc159_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %bound_method.loc159_5.3: = bound_method %.loc159_5.3, %impl.elem0.loc159_5.1 // CHECK:STDOUT: %specific_impl_fn.loc159_5.2: = specific_impl_function %impl.elem0.loc159_5.1, @Destroy.WithSelf.Op(constants.%Result) [symbolic = %specific_impl_fn.loc159_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: %bound_method.loc159_5.4: = bound_method %.loc159_5.3, %specific_impl_fn.loc159_5.2 @@ -1551,7 +1551,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %specific_impl_fn.loc170_5.3: = specific_impl_function %impl.elem1.loc170_5.2, @ModWith.WithSelf.Op(%U.as_type.loc167_36.1, %ModWith.facet) [symbolic = %specific_impl_fn.loc170_5.3 (constants.%specific_impl_fn.772)] // CHECK:STDOUT: %Destroy.WithSelf.Op.type: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Result.loc165_9.1) [symbolic = %Destroy.WithSelf.Op.type (constants.%Destroy.WithSelf.Op.type.cb2e47.2)] // CHECK:STDOUT: %.loc170_5.5: type = fn_type_with_self_type %Destroy.WithSelf.Op.type, %Result.loc165_9.1 [symbolic = %.loc170_5.5 (constants.%.d5f)] -// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc165_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness.d86)] +// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc165_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness)] // CHECK:STDOUT: %impl.elem0.loc170_5.2: @ModWith.loc168.%.loc170_5.5 (%.d5f) = impl_witness_access %Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc170_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %specific_impl_fn.loc170_5.4: = specific_impl_function %impl.elem0.loc170_5.2, @Destroy.WithSelf.Op(%Result.loc165_9.1) [symbolic = %specific_impl_fn.loc170_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: @@ -1569,7 +1569,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.loc170_5.2: ref @ModWith.loc168.%Result.as_type.loc167_54.1 (%Result.as_type) = temporary_storage // CHECK:STDOUT: %ModWith.WithSelf.Op.call: init @ModWith.loc168.%Result.as_type.loc167_54.1 (%Result.as_type) to %.loc170_5.2 = call %bound_method.loc170_5.2(%x.ref, %y.ref) // CHECK:STDOUT: %.loc170_5.3: ref @ModWith.loc168.%Result.as_type.loc167_54.1 (%Result.as_type) = temporary %.loc170_5.2, %ModWith.WithSelf.Op.call -// CHECK:STDOUT: %impl.elem0.loc170_5.1: @ModWith.loc168.%.loc170_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness.d86, element0 [symbolic = %impl.elem0.loc170_5.2 (constants.%impl.elem0.a6b)] +// CHECK:STDOUT: %impl.elem0.loc170_5.1: @ModWith.loc168.%.loc170_5.5 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc170_5.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %bound_method.loc170_5.3: = bound_method %.loc170_5.3, %impl.elem0.loc170_5.1 // CHECK:STDOUT: %specific_impl_fn.loc170_5.2: = specific_impl_function %impl.elem0.loc170_5.1, @Destroy.WithSelf.Op(constants.%Result) [symbolic = %specific_impl_fn.loc170_5.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: %bound_method.loc170_5.4: = bound_method %.loc170_5.3, %specific_impl_fn.loc170_5.2 @@ -1787,7 +1787,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %specific_impl_fn.loc296_3.3: = specific_impl_function %impl.elem1.loc296_3.2, @Negate.WithSelf.Op(%Negate.facet) [symbolic = %specific_impl_fn.loc296_3.3 (constants.%specific_impl_fn.f22)] // CHECK:STDOUT: %Destroy.WithSelf.Op.type: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Result.loc292_9.1) [symbolic = %Destroy.WithSelf.Op.type (constants.%Destroy.WithSelf.Op.type.cb2e47.2)] // CHECK:STDOUT: %.loc296_3.4: type = fn_type_with_self_type %Destroy.WithSelf.Op.type, %Result.loc292_9.1 [symbolic = %.loc296_3.4 (constants.%.d5f)] -// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc292_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness.d86)] +// CHECK:STDOUT: %Destroy.lookup_impl_witness: = lookup_impl_witness %Result.loc292_9.1, @Destroy [symbolic = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness)] // CHECK:STDOUT: %impl.elem0.loc296_3.2: @TestNegate.%.loc296_3.4 (%.d5f) = impl_witness_access %Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc296_3.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %specific_impl_fn.loc296_3.4: = specific_impl_function %impl.elem0.loc296_3.2, @Destroy.WithSelf.Op(%Result.loc292_9.1) [symbolic = %specific_impl_fn.loc296_3.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: @@ -1801,7 +1801,7 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.loc296_3.1: ref @TestNegate.%Result.as_type.loc293_50.1 (%Result.as_type) = temporary_storage // CHECK:STDOUT: %Negate.WithSelf.Op.call: init @TestNegate.%Result.as_type.loc293_50.1 (%Result.as_type) to %.loc296_3.1 = call %bound_method.loc296_3.2(%x.ref) // CHECK:STDOUT: %.loc296_3.2: ref @TestNegate.%Result.as_type.loc293_50.1 (%Result.as_type) = temporary %.loc296_3.1, %Negate.WithSelf.Op.call -// CHECK:STDOUT: %impl.elem0.loc296_3.1: @TestNegate.%.loc296_3.4 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness.d86, element0 [symbolic = %impl.elem0.loc296_3.2 (constants.%impl.elem0.a6b)] +// CHECK:STDOUT: %impl.elem0.loc296_3.1: @TestNegate.%.loc296_3.4 (%.d5f) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc296_3.2 (constants.%impl.elem0.a6b)] // CHECK:STDOUT: %bound_method.loc296_3.3: = bound_method %.loc296_3.2, %impl.elem0.loc296_3.1 // CHECK:STDOUT: %specific_impl_fn.loc296_3.2: = specific_impl_function %impl.elem0.loc296_3.1, @Destroy.WithSelf.Op(constants.%Result) [symbolic = %specific_impl_fn.loc296_3.4 (constants.%specific_impl_fn.761)] // CHECK:STDOUT: %bound_method.loc296_3.4: = bound_method %.loc296_3.2, %specific_impl_fn.loc296_3.2 diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index 271d5609e675..18abb9a7e872 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -998,7 +998,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, llvm::SmallVector impls; // `.Self` is always replaced with the top-level self type. - SubstPeriodSelfCallbacks callbacks(&context, loc_id, initial_self_const_id); + auto period_self_replacement_id = initial_self_const_id; while (!work.empty()) { SelfImplsFacetType next_impls = work.pop_back_val(); @@ -1012,15 +1012,18 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, // Note that we subst `.Self` in the interface, but we do not in the // self type here, as that would be cyclical, replacing part of the self // type with itself. - return {self_const_id, SubstPeriodSelf(context, callbacks, interface)}; + return {self_const_id, SubstPeriodSelf(context, loc_id, interface, + period_self_replacement_id)}; }; auto type_and_interface = [&](SemIR::FacetTypeInfo::TypeImplsInterface impls) -> SemIR::IdentifiedFacetType::RequiredImpl { auto self = SubstPeriodSelf( - context, callbacks, context.constant_values().Get(impls.self_type)); + context, loc_id, context.constant_values().Get(impls.self_type), + period_self_replacement_id); auto interface = - SubstPeriodSelf(context, callbacks, impls.specific_interface); + SubstPeriodSelf(context, loc_id, impls.specific_interface, + period_self_replacement_id); return {self, interface}; }; diff --git a/toolchain/sem_ir/impl.cpp b/toolchain/sem_ir/impl.cpp index edae3eb5b802..79fbc6e68824 100644 --- a/toolchain/sem_ir/impl.cpp +++ b/toolchain/sem_ir/impl.cpp @@ -24,12 +24,12 @@ auto ImplStore::GetOrAddLookupBucket(const Impl& impl) -> LookupBucketRef { sem_ir_.types().TryGetAs(facet_type_type_id)) { auto identified_id = sem_ir_.identified_facet_types().Lookup( {facet_type->facet_type_id, self_const_id}); - if (identified_id.has_value()) { - const auto& identified = - sem_ir_.identified_facet_types().Get(identified_id); - if (identified.is_valid_impl_as_target()) { - impl_as_interface = identified.impl_as_target_interface(); - } + CARBON_CHECK(identified_id.has_value(), + "impl with unidentitied facet type"); + const auto& identified = + sem_ir_.identified_facet_types().Get(identified_id); + if (identified.is_valid_impl_as_target()) { + impl_as_interface = identified.impl_as_target_interface(); } } return LookupBucketRef(