mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Split the witness table into a separate ImplWitnessTable instruction (#5272)
This allows us to import the table for a given impl only once, while we can import many ImplWitness instructions with different specifics for a generic impl. For example in convert_facet_value_to_narrowed_facet_type.carbon we see that a single witness table is imported for the BitAnd interface, with multiple witnesses (for different specifics) imported and sharing the same table. The ImplWitnessTable now contains a back-link to the Impl the witness is for, allowing inst namer to name that interface in the textual semir, and allowing the interface to be found when debugging from a witness. --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
c34a8d0a3a
commit
0e8d354567
@@ -11,6 +11,7 @@
|
||||
#include "toolchain/check/function.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/interface.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/check/type.h"
|
||||
@@ -108,14 +109,17 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
|
||||
return;
|
||||
}
|
||||
auto witness = context.insts().GetAs<SemIR::ImplWitness>(impl.witness_id);
|
||||
auto witness_block = context.inst_blocks().GetMutable(witness.elements_id);
|
||||
// `witness.elements_id` will be `SemIR::InstBlockId::Empty` when the
|
||||
auto witness_table =
|
||||
context.insts().GetAs<SemIR::ImplWitnessTable>(witness.witness_table_id);
|
||||
auto witness_block =
|
||||
context.inst_blocks().GetMutable(witness_table.elements_id);
|
||||
// `witness_table.elements_id` will be `SemIR::InstBlockId::Empty` when the
|
||||
// definition is the first declaration and the interface has no members. The
|
||||
// other case where `witness_block` will be empty is when we are using a
|
||||
// placeholder witness. This happens when there is a forward declaration of
|
||||
// the impl and the facet type has no rewrite constraints and so it wasn't
|
||||
// required to be complete.
|
||||
if (witness.elements_id != SemIR::InstBlockId::Empty &&
|
||||
if (witness_table.elements_id != SemIR::InstBlockId::Empty &&
|
||||
witness_block.empty()) {
|
||||
if (!RequireCompleteFacetTypeForImplDefinition(
|
||||
context, impl.latest_decl_id(), impl.constraint_id)) {
|
||||
@@ -123,8 +127,8 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
|
||||
}
|
||||
|
||||
AllocateFacetTypeImplWitness(context, impl.interface.interface_id,
|
||||
witness.elements_id);
|
||||
witness_block = context.inst_blocks().GetMutable(witness.elements_id);
|
||||
witness_table.elements_id);
|
||||
witness_block = context.inst_blocks().GetMutable(witness_table.elements_id);
|
||||
}
|
||||
const auto& interface = context.interfaces().Get(impl.interface.interface_id);
|
||||
auto assoc_entities =
|
||||
@@ -171,7 +175,10 @@ auto FinishImplWitness(Context& context, SemIR::Impl& impl) -> void {
|
||||
return;
|
||||
}
|
||||
auto witness = context.insts().GetAs<SemIR::ImplWitness>(impl.witness_id);
|
||||
auto witness_block = context.inst_blocks().GetMutable(witness.elements_id);
|
||||
auto witness_table =
|
||||
context.insts().GetAs<SemIR::ImplWitnessTable>(witness.witness_table_id);
|
||||
auto witness_block =
|
||||
context.inst_blocks().GetMutable(witness_table.elements_id);
|
||||
auto& impl_scope = context.name_scopes().Get(impl.scope_id);
|
||||
auto self_type_id = context.types().GetTypeIdForTypeInstId(impl.self_id);
|
||||
const auto& interface = context.interfaces().Get(impl.interface.interface_id);
|
||||
@@ -240,7 +247,10 @@ auto FillImplWitnessWithErrors(Context& context, SemIR::Impl& impl) -> void {
|
||||
if (impl.witness_id.has_value() &&
|
||||
impl.witness_id != SemIR::ErrorInst::SingletonInstId) {
|
||||
auto witness = context.insts().GetAs<SemIR::ImplWitness>(impl.witness_id);
|
||||
auto witness_block = context.inst_blocks().GetMutable(witness.elements_id);
|
||||
auto witness_table = context.insts().GetAs<SemIR::ImplWitnessTable>(
|
||||
witness.witness_table_id);
|
||||
auto witness_block =
|
||||
context.inst_blocks().GetMutable(witness_table.elements_id);
|
||||
for (auto& elem : witness_block) {
|
||||
if (elem == SemIR::ImplWitnessTablePlaceholder::SingletonInstId) {
|
||||
elem = SemIR::ErrorInst::SingletonInstId;
|
||||
@@ -249,6 +259,22 @@ auto FillImplWitnessWithErrors(Context& context, SemIR::Impl& impl) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto AssignImplIdInWitness(Context& context, SemIR::ImplId impl_id,
|
||||
SemIR::InstId witness_id) -> void {
|
||||
if (witness_id == SemIR::ErrorInst::SingletonInstId) {
|
||||
return;
|
||||
}
|
||||
auto witness = context.insts().GetAs<SemIR::ImplWitness>(witness_id);
|
||||
auto witness_table =
|
||||
context.insts().GetAs<SemIR::ImplWitnessTable>(witness.witness_table_id);
|
||||
witness_table.impl_id = impl_id;
|
||||
// Note: The `ImplWitnessTable` instruction is `Unique`, so while this marks
|
||||
// the instruction as being a dependent instruction of a generic impl, it will
|
||||
// not be substituted into the eval block.
|
||||
ReplaceInstBeforeConstantUse(context, witness.witness_table_id,
|
||||
witness_table);
|
||||
}
|
||||
|
||||
auto IsImplEffectivelyFinal(Context& context, const SemIR::Impl& impl) -> bool {
|
||||
return impl.is_final ||
|
||||
(context.constant_values().Get(impl.self_id).is_concrete() &&
|
||||
|
||||
Reference in New Issue
Block a user