From bb199f62267aff836ba290b9fc9f09dd230327f3 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 30 Sep 2026 18:07:18 +0000 Subject: [PATCH] Track rewrites in IdentifiedFacetType (#7866) This allows us to collect rewrites from named constraints and use them to initialize the witness table for an `impl as` statement. Only rewrites from extend constraints are tracked, as other constraints should turn into equality constraints, as they don't modify the witness table. --- toolchain/check/handle_impl.cpp | 16 ++++-- toolchain/check/impl.cpp | 53 ++++++------------- toolchain/check/impl.h | 10 ++-- toolchain/check/impl_lookup.cpp | 3 ++ .../impl/impl_as_named_constraint.carbon | 32 +---------- toolchain/check/testdata/impl/rewrites.carbon | 28 +--------- toolchain/check/type_completion.cpp | 18 ++++++- toolchain/sem_ir/identified_facet_type.cpp | 4 +- toolchain/sem_ir/identified_facet_type.h | 20 ++++++- 9 files changed, 80 insertions(+), 104 deletions(-) diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index 1f98b5398cb3..40346097b79d 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -250,12 +250,19 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_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( + auto identified_id = CheckConstraintIsInterface( context, node_id, self_type_inst_id, full_constraint_type_inst_id); - if (!specific_interface.interface_id.has_value()) { + if (!identified_id.has_value()) { full_constraint_type_inst_id = SemIR::ErrorInst::TypeInstId; } + auto specific_interface = + full_constraint_type_inst_id != SemIR::ErrorInst::InstId + ? context.identified_facet_types() + .Get(identified_id) + .impl_as_target_interface() + : SemIR::SpecificInterface::None; + // Store an instruction in the decl's eval block that contains the target // interface's specific, whose constant value will be updated when specifics // are applied to the impl. @@ -268,7 +275,7 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id, // we introduced a new instruction with a SpecificId operand instead of // reusing ImplSelfWitness for this. auto interface_inst_id = - specific_interface.interface_id.has_value() + full_constraint_type_inst_id != SemIR::ErrorInst::InstId ? AddInst( context, node_id, {.type_id = @@ -407,7 +414,8 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id, // also must be part of the generic eval block by coming before // FinishGenericDecl(). impl.witness_id = AddImplWitnessForDeclaration( - context, node_id, impl, full_constraint_type_inst_id, + context, node_id, SemIR::LocId(full_constraint_type_inst_id), + impl, identified_id, context.generics().GetSelfSpecific(impl.generic_id)); impl.witness_block_id = context.inst_block_stack().Pop(); diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index acc907fc819b..cc66921a058e 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -395,32 +395,14 @@ auto AddImpl(Context& context, const SemIR::Impl& impl, } auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id, + SemIR::LocId constraint_loc_id, const SemIR::Impl& impl, - SemIR::TypeInstId full_constraint_id, + SemIR::IdentifiedFacetTypeId identified_id, SemIR::SpecificId self_specific_id) -> SemIR::InstId { - auto facet_type_id = - context.types().GetTypeIdForTypeInstId(full_constraint_id); - CARBON_CHECK(facet_type_id != SemIR::ErrorInst::TypeId); - auto facet_type = context.types().GetAs(facet_type_id); - // TODO: We need to collect rewrites from named constraints too, so we will - // want to get them from the IdentifiedFacetType, or something similar. That - // process should also replace `.Self` in the constraints as appropriate. - const auto& declared_facet_type = - context.declared_facet_types().Get(facet_type.declared_facet_type_id); + const auto& identified = context.identified_facet_types().Get(identified_id); - // An iterator over the rewrite_constraints where the LHS of the rewrite names - // a member of the `impl.interface`. This filters out rewrites of names - // from other interfaces, as they do not set values in the witness table. - auto rewrites_into_interface_to_witness = llvm::make_filter_range( - declared_facet_type.rewrite_constraints, - [&](const SemIR::DeclaredFacetType::RewriteConstraint& rewrite) { - auto access = context.insts().GetAs( - GetImplWitnessAccessWithoutSubstitution(context, rewrite.lhs_id)); - return context.insts().Is(access.witness_id); - }); - - if (rewrites_into_interface_to_witness.empty()) { + if (identified.rewrites().empty()) { // The witness table is not needed until the definition. Make a placeholder // for the declaration. auto witness_table_inst_id = AddInst( @@ -472,9 +454,9 @@ auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id, .specific_id = self_specific_id}); } - for (auto rewrite : rewrites_into_interface_to_witness) { - auto access = context.insts().GetAs( - GetImplWitnessAccessWithoutSubstitution(context, rewrite.lhs_id)); + for (auto rewrite : identified.rewrites()) { + auto access = context.constant_values().GetInstAs( + rewrite.lhs); auto& table_entry = table[access.index.index]; if (table_entry == SemIR::ErrorInst::InstId) { // Don't overwrite an error value. This prioritizes not generating @@ -482,7 +464,7 @@ auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id, // for it to use to attempt recovery. continue; } - auto rewrite_inst_id = rewrite.rhs_id; + auto rewrite_inst_id = context.constant_values().GetInstId(rewrite.rhs); if (rewrite_inst_id == SemIR::ErrorInst::InstId) { table_entry = SemIR::ErrorInst::InstId; continue; @@ -513,7 +495,7 @@ auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id, CARBON_DIAGNOSTIC(RewriteForAssociatedFunction, Error, "rewrite specified for associated function {0}", SemIR::NameId); - context.emitter().Emit(full_constraint_id, RewriteForAssociatedFunction, + context.emitter().Emit(constraint_loc_id, RewriteForAssociatedFunction, fn.name_id); table_entry = SemIR::ErrorInst::InstId; continue; @@ -540,9 +522,8 @@ auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id, // Perform the conversion of the value to the type. We skipped this when // forming the facet type because the type of the associated constant // was symbolic. - auto converted_inst_id = - ConvertToValueOfType(context, SemIR::LocId(full_constraint_id), - rewrite_inst_id, assoc_const_type_id); + auto converted_inst_id = ConvertToValueOfType( + context, constraint_loc_id, rewrite_inst_id, assoc_const_type_id); // Canonicalize the converted constant value. converted_inst_id = context.constant_values().GetConstantInstId(converted_inst_id); @@ -559,7 +540,7 @@ auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id, "after conversion to {2}", SemIR::NameId, InstIdAsConstant, SemIR::TypeId); context.emitter().Emit( - full_constraint_id, AssociatedConstantNotConstantAfterConversion, + constraint_loc_id, AssociatedConstantNotConstantAfterConversion, assoc_const.name_id, rewrite_inst_id, assoc_const_type_id); rewrite_inst_id = SemIR::ErrorInst::InstId; } @@ -1022,11 +1003,11 @@ auto CheckConstraintIsFacetType(Context& context, SemIR::LocId loc_id, auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id, SemIR::InstId self_id, SemIR::TypeInstId constraint_id) - -> SemIR::SpecificInterface { + -> SemIR::IdentifiedFacetTypeId { auto canon_constraint_id = context.constant_values().GetConstantTypeInstId(constraint_id); if (canon_constraint_id == SemIR::ErrorInst::TypeInstId) { - return SemIR::SpecificInterface::None; + return SemIR::IdentifiedFacetTypeId::None; } auto identified_id = RequireIdentifiedFacetType( context, SemIR::LocId(constraint_id), @@ -1038,7 +1019,7 @@ auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id, builder.Context(loc_id, ImplOfUnidentifiedFacetType, constraint_id); }); if (!identified_id.has_value()) { - return SemIR::SpecificInterface::None; + return SemIR::IdentifiedFacetTypeId::None; } const auto& identified = context.identified_facet_types().Get(identified_id); if (!identified.is_valid_impl_as_target()) { @@ -1046,9 +1027,9 @@ auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id, "impl as {0} interfaces, expected 1", int); context.emitter().Emit(loc_id, ImplOfNotOneInterface, identified.num_interfaces_to_impl()); - return SemIR::SpecificInterface::None; + return SemIR::IdentifiedFacetTypeId::None; } - return identified.impl_as_target_interface(); + return identified_id; } auto GetImplInterfaceInSpecific(Context& context, const SemIR::Impl& impl, diff --git a/toolchain/check/impl.h b/toolchain/check/impl.h index e052958f028f..b7ea14219879 100644 --- a/toolchain/check/impl.h +++ b/toolchain/check/impl.h @@ -52,8 +52,9 @@ auto AddImpl(Context& context, const SemIR::Impl& impl, // constraint facet type. `self_specific_id` will be the `specific_id` of the // resulting witness. auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id, + SemIR::LocId constraint_loc_id, const SemIR::Impl& impl, - SemIR::TypeInstId full_constraint_id, + SemIR::IdentifiedFacetTypeId identified_id, SemIR::SpecificId self_specific_id) -> SemIR::InstId; @@ -93,12 +94,13 @@ 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`. +// facet type that extends a single interface. Returns the IdentifiedFacetType +// which contains 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; + -> SemIR::IdentifiedFacetTypeId; // Given a specific for the impl, returns the specific interface that the impl // declaration is implementing. Returns None in the case of an error being diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index 46dafed3c1a2..837ab98d8057 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -471,6 +471,9 @@ static auto VerifyQueryFacetTypeConstraints( SemIR::ConstantId query_facet_type_const_id, llvm::ArrayRef req_impls, llvm::ArrayRef witness_inst_ids) -> bool { + // TODO: Get the rewrites and equality constraints from the + // IdentifiedFacetType so that we also find and verify requirements from named + // constraints. const auto& declared_facet_type = context.declared_facet_types().Get( context.constant_values() .GetInstAs(query_facet_type_const_id) diff --git a/toolchain/check/testdata/impl/impl_as_named_constraint.carbon b/toolchain/check/testdata/impl/impl_as_named_constraint.carbon index d90a00299ce5..287d29c9611e 100644 --- a/toolchain/check/testdata/impl/impl_as_named_constraint.carbon +++ b/toolchain/check/testdata/impl/impl_as_named_constraint.carbon @@ -227,7 +227,7 @@ fn G() { F(C); } -// --- fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon +// --- impl_as_constraint_containing_rewrite_for_concrete_interface.carbon library "[[@TEST_NAME]]"; interface I { @@ -239,28 +239,14 @@ constraint N { } class C; -// CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon:[[@LINE+7]]:1: error: associated constant I1 not given a value in impl of interface I [ImplAssociatedConstantNeedsValue] -// CHECK:STDERR: impl C as N {} -// CHECK:STDERR: ^~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon:[[@LINE-11]]:7: note: associated constant declared here [AssociatedConstantHere] -// CHECK:STDERR: let I1: type; -// CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: impl C as N {} fn F(generic _: I where .I1 = .Self) {} fn G() { - // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `I where .(I.I1) = .Self` [ConversionFailureTypeToFacet] - // CHECK:STDERR: F(C); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon:[[@LINE-5]]:14: note: initializing generic parameter `_` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(generic _: I where .I1 = .Self) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: F(C); } -// --- fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon +// --- impl_as_constraint_containing_rewrite_for_generic_interface.carbon library "[[@TEST_NAME]]"; interface I(T: type) { @@ -272,24 +258,10 @@ constraint N { } class C; -// CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon:[[@LINE+7]]:1: error: associated constant I1 not given a value in impl of interface I [ImplAssociatedConstantNeedsValue] -// CHECK:STDERR: impl C as N {} -// CHECK:STDERR: ^~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon:[[@LINE-11]]:7: note: associated constant declared here [AssociatedConstantHere] -// CHECK:STDERR: let I1: type; -// CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: impl C as N {} fn F(generic _: I(.Self) where .I1 = .Self) {} fn G() { - // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `I(.Self) where .(I(.Self).I1) = .Self` [ConversionFailureTypeToFacet] - // CHECK:STDERR: F(C); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon:[[@LINE-5]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] - // CHECK:STDERR: fn F(generic _: I(.Self) where .I1 = .Self) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: F(C); } diff --git a/toolchain/check/testdata/impl/rewrites.carbon b/toolchain/check/testdata/impl/rewrites.carbon index 58ec1820ee9d..139a96563829 100644 --- a/toolchain/check/testdata/impl/rewrites.carbon +++ b/toolchain/check/testdata/impl/rewrites.carbon @@ -59,7 +59,7 @@ interface J {} // CHECK:STDERR: impl forall [T: type] T as I where .X impls J and .X = () {} -// --- fail_todo_rewrite_in_named_constraint.carbon +// --- rewrite_in_named_constraint.carbon library "[[@TEST_NAME]]"; interface I { let X: type; } @@ -72,13 +72,6 @@ constraint GivesI { impl () as J {} // The rewrite from `extend` is inherited and should satisfy that `.X impls J`. -// CHECK:STDERR: fail_todo_rewrite_in_named_constraint.carbon:[[@LINE+7]]:1: error: associated constant X not given a value in impl of interface I [ImplAssociatedConstantNeedsValue] -// CHECK:STDERR: impl forall [T: type] T as GivesI where .X impls J {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_rewrite_in_named_constraint.carbon:[[@LINE-13]]:19: note: associated constant declared here [AssociatedConstantHere] -// CHECK:STDERR: interface I { let X: type; } -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: impl forall [T: type] T as GivesI where .X impls J {} // --- fail_rewrite_in_named_constraint_missing_impl.carbon @@ -92,12 +85,9 @@ constraint GivesI { } // .X does not impl J. -// CHECK:STDERR: fail_rewrite_in_named_constraint_missing_impl.carbon:[[@LINE+7]]:1: error: associated constant X not given a value in impl of interface I [ImplAssociatedConstantNeedsValue] +// CHECK:STDERR: fail_rewrite_in_named_constraint_missing_impl.carbon:[[@LINE+4]]:1: error: constraint `GivesI where .(I.X) impls J` being implemented requires that `()` implements `J` [IdentifiedRequireImplsNotImplemented] // CHECK:STDERR: impl forall [T: type] T as GivesI where .X impls J {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_rewrite_in_named_constraint_missing_impl.carbon:[[@LINE-11]]:19: note: associated constant declared here [AssociatedConstantHere] -// CHECK:STDERR: interface I { let X: type; } -// CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: impl forall [T: type] T as GivesI where .X impls J {} @@ -115,13 +105,6 @@ constraint GivesI { impl () as J {} // The rewrite from `extend` is inherited and should satisfy that `.X impls J`. -// CHECK:STDERR: fail_todo_rewrite_and_impls_in_named_constraint.carbon:[[@LINE+11]]:1: error: associated constant X not given a value in impl of interface I [ImplAssociatedConstantNeedsValue] -// CHECK:STDERR: impl forall [T: type] T as GivesI {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_rewrite_and_impls_in_named_constraint.carbon:[[@LINE-14]]:19: note: associated constant declared here [AssociatedConstantHere] -// CHECK:STDERR: interface I { let X: type; } -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: // CHECK:STDERR: fail_todo_rewrite_and_impls_in_named_constraint.carbon:[[@LINE+4]]:1: error: constraint `GivesI` being implemented requires that `T.(I.X)` implements `J` [IdentifiedRequireImplsNotImplemented] // CHECK:STDERR: impl forall [T: type] T as GivesI {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -140,13 +123,6 @@ constraint GivesI { } // .X does not impl J. -// CHECK:STDERR: fail_rewrite_and_impls_in_named_constraint_missing_impl.carbon:[[@LINE+11]]:1: error: associated constant X not given a value in impl of interface I [ImplAssociatedConstantNeedsValue] -// CHECK:STDERR: impl forall [T: type] T as GivesI {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_rewrite_and_impls_in_named_constraint_missing_impl.carbon:[[@LINE-12]]:19: note: associated constant declared here [AssociatedConstantHere] -// CHECK:STDERR: interface I { let X: type; } -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: // CHECK:STDERR: fail_rewrite_and_impls_in_named_constraint_missing_impl.carbon:[[@LINE+4]]:1: error: constraint `GivesI` being implemented requires that `T.(I.X)` implements `J` [IdentifiedRequireImplsNotImplemented] // CHECK:STDERR: impl forall [T: type] T as GivesI {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index e2b2b95f9ab6..ae4a9cc38aa4 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -8,6 +8,7 @@ #include "llvm/ADT/SmallVector.h" #include "toolchain/base/kind_switch.h" #include "toolchain/check/cpp/import.h" +#include "toolchain/check/facet_type.h" #include "toolchain/check/generic.h" #include "toolchain/check/inst.h" #include "toolchain/check/literal.h" @@ -1012,6 +1013,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, bool partially_identified = false; llvm::SmallVector extends; llvm::SmallVector impls; + llvm::SmallVector rewrites; while (!work.empty()) { SelfImplsFacetType next_impls = work.pop_back_val(); @@ -1046,6 +1048,20 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, llvm::append_range( impls, llvm::map_range(declared_facet_type.type_impls_interfaces, type_and_interface)); + if (facet_type_extends) { + auto rewrite_as_constants = + [&](auto rewrite) -> SemIR::IdentifiedFacetType::Rewrite { + return {context.constant_values().Get( + GetImplWitnessAccessWithoutSubstitution(context, + rewrite.lhs_id)), + context.constant_values().Get(rewrite.rhs_id)}; + }; + llvm::append_range( + rewrites, llvm::map_range(declared_facet_type.rewrite_constraints, + rewrite_as_constants)); + } else { + // TODO: Store the rewrites as equality constraints. + } if (declared_facet_type.extend_named_constraints.empty() && declared_facet_type.self_impls_named_constraints.empty() && @@ -1229,7 +1245,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, // TODO: Process other kinds of requirements. return context.identified_facet_types().Add( - {key, partially_identified, extends, impls}); + {key, partially_identified, extends, impls, rewrites}); } auto TryToIdentifyFacetType(Context& context, SemIR::LocId loc_id, diff --git a/toolchain/sem_ir/identified_facet_type.cpp b/toolchain/sem_ir/identified_facet_type.cpp index c873a881fcd3..3a3ccdf6a94a 100644 --- a/toolchain/sem_ir/identified_facet_type.cpp +++ b/toolchain/sem_ir/identified_facet_type.cpp @@ -44,7 +44,7 @@ static auto RequiredLess(const IdentifiedFacetType::RequiredImpl& lhs, IdentifiedFacetType::IdentifiedFacetType( IdentifiedFacetTypeKey key, bool partially_identified, llvm::ArrayRef extends, - llvm::ArrayRef self_impls) + llvm::ArrayRef self_impls, llvm::ArrayRef rewrites) : key_(key) { required_impls_.reserve(extends.size() + self_impls.size()); llvm::append_range(required_impls_, extends); @@ -70,6 +70,8 @@ IdentifiedFacetType::IdentifiedFacetType( // same constituents but a more complete set of required interfaces. key_.num_require_impls = required_impls_.size(); } + + rewrites_.assign(rewrites); } auto AddCanonicalWitnessesBlock(File& sem_ir, diff --git a/toolchain/sem_ir/identified_facet_type.h b/toolchain/sem_ir/identified_facet_type.h index 625d599b8ca8..12d71cae7b27 100644 --- a/toolchain/sem_ir/identified_facet_type.h +++ b/toolchain/sem_ir/identified_facet_type.h @@ -42,16 +42,26 @@ struct IdentifiedFacetType { friend auto operator==(const RequiredImpl& lhs, const RequiredImpl& rhs) -> bool = default; }; + struct Rewrite { + ConstantId lhs; + ConstantId rhs; + + friend auto operator==(const Rewrite& lhs, const Rewrite& rhs) + -> bool = default; + }; IdentifiedFacetType(IdentifiedFacetTypeKey key, bool partially_identified, llvm::ArrayRef extends, - llvm::ArrayRef self_impls); + llvm::ArrayRef self_impls, + llvm::ArrayRef rewrites); // The order here defines the order of impl witnesses for this facet type. auto required_impls() const -> llvm::ArrayRef { return required_impls_; } + auto rewrites() const -> llvm::ArrayRef { return rewrites_; } + // Can this be used to the right of an `as` in an `impl` declaration? auto is_valid_impl_as_target() const -> bool { return interface_id_.has_value(); @@ -89,6 +99,12 @@ struct IdentifiedFacetType { // constraint. Sorted and deduplicated. llvm::SmallVector required_impls_; + // Rewrite constraints from a facet type and any named constraints that it + // references, flattened to a single list with `.Self` replaced on the RHS. + // The witness on the LHS should be ignored other than to specify in which + // interface the associated constant is being rewritten. + llvm::SmallVector rewrites_; + // The single interface from `required_impls` to implement if this is // the facet type to the right of an `impl`...`as`, or `None` if no such // single interface. @@ -120,7 +136,7 @@ auto AddCanonicalWitnessesBlock(File& sem_ir, namespace Carbon { extern template class CanonicalValueStore< SemIR::IdentifiedFacetTypeId, SemIR::IdentifiedFacetTypeKey, - Tag, SemIR ::IdentifiedFacetType>; + Tag, SemIR::IdentifiedFacetType>; extern template class ValueStore>;