From 4b46e63b410b634e736932308d0aa62b5887f0a3 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Mon, 20 Jul 2026 17:45:17 -0400 Subject: [PATCH] Move IdentifiedFacetType to its own file (#7542) I wanted to move it to check but there'd still be an IdentifiedFacetTypeId and we keep all Ids in sem_ir. So leaving it in sem_ir, but moving it to its own file. This more clearly separates DeclaredFacetTypes and IdentifiedFacetTypes. --- toolchain/check/context.h | 1 + toolchain/check/impl.cpp | 1 + toolchain/check/impl_lookup.cpp | 1 + toolchain/check/import_ref.cpp | 1 + toolchain/check/type_completion.cpp | 1 + toolchain/sem_ir/BUILD | 2 + toolchain/sem_ir/declared_facet_type.cpp | 99 ---------------- toolchain/sem_ir/declared_facet_type.h | 106 ----------------- toolchain/sem_ir/file.h | 1 + toolchain/sem_ir/identified_facet_type.cpp | 131 +++++++++++++++++++++ toolchain/sem_ir/identified_facet_type.h | 129 ++++++++++++++++++++ 11 files changed, 268 insertions(+), 205 deletions(-) create mode 100644 toolchain/sem_ir/identified_facet_type.cpp create mode 100644 toolchain/sem_ir/identified_facet_type.h diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 01c5b5251059..4cc784f41e36 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -33,6 +33,7 @@ #include "toolchain/parse/tree_and_subtrees.h" #include "toolchain/sem_ir/declared_facet_type.h" #include "toolchain/sem_ir/file.h" +#include "toolchain/sem_ir/identified_facet_type.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/import_ir.h" #include "toolchain/sem_ir/inst.h" diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index c46c2e09b7b6..20f42de6eae6 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -26,6 +26,7 @@ #include "toolchain/check/type_structure.h" #include "toolchain/diagnostics/emitter.h" #include "toolchain/sem_ir/generic.h" +#include "toolchain/sem_ir/identified_facet_type.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/inst.h" diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index 11d9232e1f72..cbce56d92bf7 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -25,6 +25,7 @@ #include "toolchain/check/type_completion.h" #include "toolchain/check/type_structure.h" #include "toolchain/sem_ir/declared_facet_type.h" +#include "toolchain/sem_ir/identified_facet_type.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/inst.h" diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 4d22a657c367..397b51704bb5 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -27,6 +27,7 @@ #include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/constant.h" #include "toolchain/sem_ir/file.h" +#include "toolchain/sem_ir/identified_facet_type.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/import_ir.h" diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index 432166205c86..c0f02245a480 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -20,6 +20,7 @@ #include "toolchain/sem_ir/constant.h" #include "toolchain/sem_ir/declared_facet_type.h" #include "toolchain/sem_ir/generic.h" +#include "toolchain/sem_ir/identified_facet_type.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/named_constraint.h" #include "toolchain/sem_ir/specific_interface.h" diff --git a/toolchain/sem_ir/BUILD b/toolchain/sem_ir/BUILD index d7fe9893ba16..afdca88a4bf6 100644 --- a/toolchain/sem_ir/BUILD +++ b/toolchain/sem_ir/BUILD @@ -98,6 +98,7 @@ cc_library( "file.cpp", "function.cpp", "generic.cpp", + "identified_facet_type.cpp", "impl.cpp", "import_ir.cpp", "inst.cpp", @@ -132,6 +133,7 @@ cc_library( "file.h", "function.h", "generic.h", + "identified_facet_type.h", "impl.h", "import_cpp.h", "import_ir.h", diff --git a/toolchain/sem_ir/declared_facet_type.cpp b/toolchain/sem_ir/declared_facet_type.cpp index 916b319c3d08..d4c782e9456a 100644 --- a/toolchain/sem_ir/declared_facet_type.cpp +++ b/toolchain/sem_ir/declared_facet_type.cpp @@ -7,7 +7,6 @@ #include #include "toolchain/base/canonical_value_store_impl.h" -#include "toolchain/base/kind_switch.h" #include "toolchain/base/value_store_impl.h" #include "toolchain/sem_ir/file.h" #include "toolchain/sem_ir/ids.h" @@ -72,17 +71,6 @@ static auto TypeImplsNamedConstraintLess( rhs.specific_named_constraint.specific_id.index); } -// Canonically ordered by the numerical ids. -static auto RequiredLess(const IdentifiedFacetType::RequiredImpl& lhs, - const IdentifiedFacetType::RequiredImpl& rhs) -> bool { - return std::tie(lhs.self_facet_value.index, - lhs.specific_interface.interface_id.index, - lhs.specific_interface.specific_id.index) < - std::tie(rhs.self_facet_value.index, - rhs.specific_interface.interface_id.index, - rhs.specific_interface.specific_id.index); -} - // Assuming both `a` and `b` are sorted and deduplicated, replaces `a` with `a - // b` as sets. Assumes there are few elements between them. template @@ -307,93 +295,6 @@ auto DeclaredFacetType::Print(llvm::raw_ostream& out) const -> void { out << "}"; } -IdentifiedFacetType::IdentifiedFacetType( - IdentifiedFacetTypeKey key, bool partially_identified, - llvm::ArrayRef extends, - llvm::ArrayRef self_impls) - : key_(key) { - required_impls_.reserve(extends.size() + self_impls.size()); - llvm::append_range(required_impls_, extends); - SortAndDeduplicate(required_impls_, RequiredLess); - - // If there's a single extended interface then we present as that interface. - // Otherwise, we record the number extended interfaces. - if (required_impls_.size() == 1) { - interface_id_ = required_impls_.front().specific_interface.interface_id; - specific_id_ = required_impls_.front().specific_interface.specific_id; - } else { - interface_id_ = InterfaceId::None; - num_interface_to_impl_ = required_impls_.size(); - } - - llvm::append_range(required_impls_, self_impls); - SortAndDeduplicate(required_impls_, RequiredLess); - - if (partially_identified) { - // This marks the IdentifiedFacetType as being partially identified, and - // prevents the key from colliding with a fully identified facet type, or - // with other partially (but differently) identified facet types, with the - // same constituents but a more complete set of required interfaces. - key_.num_require_impls = required_impls_.size(); - } -} - -auto AddCanonicalWitnessesBlock(File& sem_ir, - llvm::SmallVector& witnesses) - -> InstBlockId { - // Small blocks don't need to be sorted. - if (witnesses.size() <= 1) { - return sem_ir.inst_blocks().AddCanonical(witnesses); - } - - llvm::SmallVector> sortable; - sortable.reserve(witnesses.size()); - - // Produce the sorted order based on the witness's SpecificInterface. - for (auto witness_id : witnesses) { - auto inst = sem_ir.insts().Get(witness_id); - CARBON_KIND_SWITCH(inst) { - case CARBON_KIND(CustomWitness witness): { - sortable.push_back({sem_ir.specific_interfaces().Get( - witness.query_specific_interface_id), - witness_id}); - break; - } - case CARBON_KIND(ImplWitness witness): { - auto table = - sem_ir.insts().GetAs(witness.witness_table_id); - sortable.push_back( - {sem_ir.impls().Get(table.impl_id).interface, witness_id}); - break; - } - case CARBON_KIND(LookupImplWitness witness): { - sortable.push_back({sem_ir.specific_interfaces().Get( - witness.query_specific_interface_id), - witness_id}); - break; - } - default: - CARBON_FATAL("Unhandled inst: {0}", inst); - } - } - // This matches the sort order of IdentifiedFacetType::required_interfaces, - // which is the order of the witnesses returned from impl lookup, and is - // canonical order in which the witnesses must appear for a given facet type - // so that ImplWitnessAccess can find the appropriate witness. - llvm::sort(sortable, [](auto& lhs, auto& rhs) { - return InterfaceLess(lhs.first, rhs.first); - }); - - // Update the original list with the new order (reusing to avoid an - // allocation). - for (auto [witness_id, sortable_entry] : - llvm::zip_equal(witnesses, sortable)) { - witness_id = sortable_entry.second; - } - - return sem_ir.inst_blocks().AddCanonical(witnesses); -} - } // namespace Carbon::SemIR namespace Carbon { diff --git a/toolchain/sem_ir/declared_facet_type.h b/toolchain/sem_ir/declared_facet_type.h index 96d1512d05f5..a87af1466e10 100644 --- a/toolchain/sem_ir/declared_facet_type.h +++ b/toolchain/sem_ir/declared_facet_type.h @@ -151,97 +151,6 @@ constexpr DeclaredFacetType::RewriteConstraint using DeclaredFacetTypeStore = CanonicalValueStore>; -struct IdentifiedFacetTypeKey { - DeclaredFacetTypeId declared_facet_type_id; - ConstantId self_const_id; - // Inside a named constraint, each identification of the `Self` facet type can - // be unique, as it can be modified by each require declaration seen so far. - // Uses -1 for identifying a facet type with a self-type from outside the - // definition of an named constraint. - int32_t num_require_impls = -1; - - friend auto operator==(const IdentifiedFacetTypeKey& lhs, - const IdentifiedFacetTypeKey& rhs) -> bool = default; -}; - -// The IdentifiedFacetType represents all of the interfaces required by a facet -// type against a given Self type, and any other types it constrains. The order -// of the interfaces is fixed for a given facet type, and can thus be used as a -// key for storing and finding witnesses or other data associated with a facet -// type. -struct IdentifiedFacetType { - // A requirement that `self_facet_value` implements the `specific_interface`. - struct RequiredImpl { - ConstantId self_facet_value; - SpecificInterface specific_interface; - - friend auto operator==(const RequiredImpl& lhs, const RequiredImpl& rhs) - -> bool = default; - }; - - IdentifiedFacetType(IdentifiedFacetTypeKey key, bool partially_identified, - llvm::ArrayRef extends, - llvm::ArrayRef self_impls); - - // The order here defines the order of impl witnesses for this facet type. - auto required_impls() const -> llvm::ArrayRef { - return required_impls_; - } - - // 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(); - } - - // The interface to implement when this facet type is used in an `impl` - // declaration. - auto impl_as_target_interface() const -> SpecificInterface { - if (is_valid_impl_as_target()) { - return {.interface_id = interface_id_, .specific_id = specific_id_}; - } else { - return SpecificInterface::None; - } - } - - auto num_interfaces_to_impl() const -> int { - if (is_valid_impl_as_target()) { - return 1; - } else { - return num_interface_to_impl_; - } - } - - auto partially_identified() const -> bool { - return key_.num_require_impls >= 0; - } - - auto GetAsKey() const -> IdentifiedFacetTypeKey { return key_; } - - private: - IdentifiedFacetTypeKey key_; - - // Requirements that a facet value implements an interface, mentioned - // explicitly in the facet type expression or transitively through a named - // constraint. Sorted and deduplicated. - llvm::SmallVector required_impls_; - - // 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. - InterfaceId interface_id_ = InterfaceId::None; - union { - // If `interface_id` is `None`, the number of interfaces to report in a - // diagnostic about why this facet type can't be implemented. - int num_interface_to_impl_ = 0; - // If `interface_id` is not `None`, the specific for that interface. - SpecificId specific_id_; - }; -}; - -using IdentifiedFacetTypeStore = - CanonicalValueStore, IdentifiedFacetType>; - // See common/hashing.h. inline auto CarbonHashValue(const DeclaredFacetType& value, uint64_t seed) -> HashCode { @@ -255,30 +164,15 @@ inline auto CarbonHashValue(const DeclaredFacetType& value, uint64_t seed) return static_cast(hasher); } -// Given an array of witnesses, sorts them to match the ordering of the specific -// interfaces in the IdentifiedFacetType that produced the witness set, which is -// the canonical witness order, and returns the resulting block ID. This assumes -// witnesses have already been deduplicated, and do not contain errors, because -// it's mainly for imports. -auto AddCanonicalWitnessesBlock(File& sem_ir, - llvm::SmallVector& witnesses) - -> InstBlockId; - } // namespace Carbon::SemIR namespace Carbon { extern template class CanonicalValueStore>; -extern template class CanonicalValueStore< - SemIR::IdentifiedFacetTypeId, SemIR::IdentifiedFacetTypeKey, - Tag, SemIR::IdentifiedFacetType>; extern template class ValueStore>; -extern template class ValueStore>; } // namespace Carbon #endif // CARBON_TOOLCHAIN_SEM_IR_DECLARED_FACET_TYPE_H_ diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index c87f95902b5d..e744519e9569 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -29,6 +29,7 @@ #include "toolchain/sem_ir/field.h" #include "toolchain/sem_ir/function.h" #include "toolchain/sem_ir/generic.h" +#include "toolchain/sem_ir/identified_facet_type.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/import_cpp.h" diff --git a/toolchain/sem_ir/identified_facet_type.cpp b/toolchain/sem_ir/identified_facet_type.cpp new file mode 100644 index 000000000000..c873a881fcd3 --- /dev/null +++ b/toolchain/sem_ir/identified_facet_type.cpp @@ -0,0 +1,131 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/sem_ir/identified_facet_type.h" + +#include "toolchain/base/canonical_value_store_impl.h" +#include "toolchain/base/kind_switch.h" +#include "toolchain/base/value_store_impl.h" +#include "toolchain/sem_ir/file.h" + +namespace Carbon::SemIR { + +template +using LessThanFn = llvm::function_refbool>; + +template +static auto SortAndDeduplicate(VecT& vec, + LessThanFn compare) + -> void { + llvm::sort(vec, compare); + vec.erase(llvm::unique(vec), vec.end()); +} + +// Canonically ordered by the numerical ids. Matches the order of RequiredLess +// when the `self_facet_value` is the same for all interfaces. +static auto InterfaceLess(const SpecificInterface& lhs, + const SpecificInterface& rhs) -> bool { + return std::tie(lhs.interface_id.index, lhs.specific_id.index) < + std::tie(rhs.interface_id.index, rhs.specific_id.index); +} + +// Canonically ordered by the numerical ids. +static auto RequiredLess(const IdentifiedFacetType::RequiredImpl& lhs, + const IdentifiedFacetType::RequiredImpl& rhs) -> bool { + return std::tie(lhs.self_facet_value.index, + lhs.specific_interface.interface_id.index, + lhs.specific_interface.specific_id.index) < + std::tie(rhs.self_facet_value.index, + rhs.specific_interface.interface_id.index, + rhs.specific_interface.specific_id.index); +} + +IdentifiedFacetType::IdentifiedFacetType( + IdentifiedFacetTypeKey key, bool partially_identified, + llvm::ArrayRef extends, + llvm::ArrayRef self_impls) + : key_(key) { + required_impls_.reserve(extends.size() + self_impls.size()); + llvm::append_range(required_impls_, extends); + SortAndDeduplicate(required_impls_, RequiredLess); + + // If there's a single extended interface then we present as that interface. + // Otherwise, we record the number extended interfaces. + if (required_impls_.size() == 1) { + interface_id_ = required_impls_.front().specific_interface.interface_id; + specific_id_ = required_impls_.front().specific_interface.specific_id; + } else { + interface_id_ = InterfaceId::None; + num_interface_to_impl_ = required_impls_.size(); + } + + llvm::append_range(required_impls_, self_impls); + SortAndDeduplicate(required_impls_, RequiredLess); + + if (partially_identified) { + // This marks the IdentifiedFacetType as being partially identified, and + // prevents the key from colliding with a fully identified facet type, or + // with other partially (but differently) identified facet types, with the + // same constituents but a more complete set of required interfaces. + key_.num_require_impls = required_impls_.size(); + } +} + +auto AddCanonicalWitnessesBlock(File& sem_ir, + llvm::SmallVector& witnesses) + -> InstBlockId { + // Small blocks don't need to be sorted. + if (witnesses.size() <= 1) { + return sem_ir.inst_blocks().AddCanonical(witnesses); + } + + llvm::SmallVector> sortable; + sortable.reserve(witnesses.size()); + + // Produce the sorted order based on the witness's SpecificInterface. + for (auto witness_id : witnesses) { + auto inst = sem_ir.insts().Get(witness_id); + CARBON_KIND_SWITCH(inst) { + case CARBON_KIND(CustomWitness witness): { + sortable.push_back({sem_ir.specific_interfaces().Get( + witness.query_specific_interface_id), + witness_id}); + break; + } + case CARBON_KIND(ImplWitness witness): { + auto table = + sem_ir.insts().GetAs(witness.witness_table_id); + sortable.push_back( + {sem_ir.impls().Get(table.impl_id).interface, witness_id}); + break; + } + case CARBON_KIND(LookupImplWitness witness): { + sortable.push_back({sem_ir.specific_interfaces().Get( + witness.query_specific_interface_id), + witness_id}); + break; + } + default: + CARBON_FATAL("Unhandled inst: {0}", inst); + } + } + // This matches the sort order of IdentifiedFacetType::required_interfaces, + // which is the order of the witnesses returned from impl lookup, and is + // canonical order in which the witnesses must appear for a given facet type + // so that ImplWitnessAccess can find the appropriate witness. + llvm::sort(sortable, [](auto& lhs, auto& rhs) { + return InterfaceLess(lhs.first, rhs.first); + }); + + // Update the original list with the new order (reusing to avoid an + // allocation). + for (auto [witness_id, sortable_entry] : + llvm::zip_equal(witnesses, sortable)) { + witness_id = sortable_entry.second; + } + + return sem_ir.inst_blocks().AddCanonical(witnesses); +} + +} // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/identified_facet_type.h b/toolchain/sem_ir/identified_facet_type.h new file mode 100644 index 000000000000..625d599b8ca8 --- /dev/null +++ b/toolchain/sem_ir/identified_facet_type.h @@ -0,0 +1,129 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_SEM_IR_IDENTIFIED_FACET_TYPE_H_ +#define CARBON_TOOLCHAIN_SEM_IR_IDENTIFIED_FACET_TYPE_H_ + +#include "llvm/ADT/SmallVector.h" +#include "toolchain/base/canonical_value_store.h" +#include "toolchain/sem_ir/declared_facet_type.h" +#include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/specific_interface.h" + +namespace Carbon::SemIR { + +class File; + +struct IdentifiedFacetTypeKey { + DeclaredFacetTypeId declared_facet_type_id; + ConstantId self_const_id; + // Inside a named constraint, each identification of the `Self` facet type can + // be unique, as it can be modified by each require declaration seen so far. + // Uses -1 for identifying a facet type with a self-type from outside the + // definition of an named constraint. + int32_t num_require_impls = -1; + + friend auto operator==(const IdentifiedFacetTypeKey& lhs, + const IdentifiedFacetTypeKey& rhs) -> bool = default; +}; + +// The IdentifiedFacetType represents all of the interfaces required by a facet +// type against a given Self type, and any other types it constrains. The order +// of the interfaces is fixed for a given facet type, and can thus be used as a +// key for storing and finding witnesses or other data associated with a facet +// type. +struct IdentifiedFacetType { + // A requirement that `self_facet_value` implements the `specific_interface`. + struct RequiredImpl { + ConstantId self_facet_value; + SpecificInterface specific_interface; + + friend auto operator==(const RequiredImpl& lhs, const RequiredImpl& rhs) + -> bool = default; + }; + + IdentifiedFacetType(IdentifiedFacetTypeKey key, bool partially_identified, + llvm::ArrayRef extends, + llvm::ArrayRef self_impls); + + // The order here defines the order of impl witnesses for this facet type. + auto required_impls() const -> llvm::ArrayRef { + return required_impls_; + } + + // 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(); + } + + // The interface to implement when this facet type is used in an `impl` + // declaration. + auto impl_as_target_interface() const -> SpecificInterface { + if (is_valid_impl_as_target()) { + return {.interface_id = interface_id_, .specific_id = specific_id_}; + } else { + return SpecificInterface::None; + } + } + + auto num_interfaces_to_impl() const -> int { + if (is_valid_impl_as_target()) { + return 1; + } else { + return num_interface_to_impl_; + } + } + + auto partially_identified() const -> bool { + return key_.num_require_impls >= 0; + } + + auto GetAsKey() const -> IdentifiedFacetTypeKey { return key_; } + + private: + IdentifiedFacetTypeKey key_; + + // Requirements that a facet value implements an interface, mentioned + // explicitly in the facet type expression or transitively through a named + // constraint. Sorted and deduplicated. + llvm::SmallVector required_impls_; + + // 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. + InterfaceId interface_id_ = InterfaceId::None; + union { + // If `interface_id` is `None`, the number of interfaces to report in a + // diagnostic about why this facet type can't be implemented. + int num_interface_to_impl_ = 0; + // If `interface_id` is not `None`, the specific for that interface. + SpecificId specific_id_; + }; +}; + +using IdentifiedFacetTypeStore = + CanonicalValueStore, IdentifiedFacetType>; + +// Given an array of witnesses, sorts them to match the ordering of the specific +// interfaces in the IdentifiedFacetType that produced the witness set, which is +// the canonical witness order, and returns the resulting block ID. This assumes +// witnesses have already been deduplicated, and do not contain errors, because +// it's mainly for imports. +auto AddCanonicalWitnessesBlock(File& sem_ir, + llvm::SmallVector& witnesses) + -> InstBlockId; + +} // namespace Carbon::SemIR + +namespace Carbon { +extern template class CanonicalValueStore< + SemIR::IdentifiedFacetTypeId, SemIR::IdentifiedFacetTypeKey, + Tag, SemIR ::IdentifiedFacetType>; +extern template class ValueStore>; +} // namespace Carbon + +#endif // CARBON_TOOLCHAIN_SEM_IR_IDENTIFIED_FACET_TYPE_H_