Skip to content

Commit 7fd62ff

Browse files
authored
Stop using ImplWitness[Table] for a C++ synthesized witness. (#6451)
Add a `CppWitness` and use it instead of using `ImplWitness` with an `ImplId` and `SpecificId` of `None`. This witness can be substantially simpler because we never need a `SpecificId`.
1 parent d208e95 commit 7fd62ff

File tree

6 files changed

+103
-67
lines changed

6 files changed

+103
-67
lines changed

toolchain/check/cpp/impl_lookup.cpp

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -66,30 +66,30 @@ static auto BuildWitness(Context& context, SemIR::LocId loc_id,
6666
return SemIR::ErrorInst::InstId;
6767
}
6868

69-
// Prepare an empty witness table.
70-
auto witness_table_id =
71-
context.inst_blocks().AddUninitialized(assoc_entities.size());
72-
auto witness_table = context.inst_blocks().GetMutable(witness_table_id);
73-
for (auto& witness_value_id : witness_table) {
74-
witness_value_id = SemIR::InstId::ImplWitnessTablePlaceholder;
75-
}
76-
77-
// Build a witness. We use an `ImplWitness` with an `impl_id` of `None` to
78-
// represent a synthesized witness.
79-
// TODO: Stop using `ImplWitnessTable` here and add a distinct instruction
80-
// that doesn't contain an `InstId` and supports deduplication.
81-
auto witness_table_inst_id = AddInst<SemIR::ImplWitnessTable>(
82-
context, loc_id,
83-
{.elements_id = witness_table_id, .impl_id = SemIR::ImplId::None});
84-
auto witness_id = AddInst<SemIR::ImplWitness>(
85-
context, loc_id,
86-
{.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
87-
.witness_table_id = witness_table_inst_id,
88-
.specific_id = SemIR::SpecificId::None});
69+
llvm::SmallVector<SemIR::InstId> entries;
70+
71+
// Build a witness with the current contents of the witness table. This will
72+
// grow as we progress through the impl. In theory this will build O(n^2)
73+
// table entries, but in practice n <= 2, so that's OK.
74+
//
75+
// This is necessary because later associated entities may refer to earlier
76+
// associated entities in their signatures. In particular, an associated
77+
// result type may be used as the return type of an associated function.
78+
//
79+
// TODO: Consider building one witness after all associated constants, and
80+
// then a second after all associated functions, rather than building one at
81+
// each step. For now this doesn't really matter since we don't have more than
82+
// one of each anyway.
83+
auto make_witness = [&] {
84+
return context.constant_values().GetInstId(EvalOrAddInst<SemIR::CppWitness>(
85+
context, loc_id,
86+
{.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
87+
.elements_id = context.inst_blocks().Add(entries)}));
88+
};
8989

9090
// Fill in the witness table.
91-
for (const auto& [assoc_entity_id, value_id, witness_value_id] :
92-
llvm::zip_equal(assoc_entities, values, witness_table)) {
91+
for (const auto& [assoc_entity_id, value_id] :
92+
llvm::zip_equal(assoc_entities, values)) {
9393
LoadImportRef(context, assoc_entity_id);
9494
auto decl_id =
9595
context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
@@ -104,11 +104,13 @@ static auto BuildWitness(Context& context, SemIR::LocId loc_id,
104104
// TODO: If a thunk is needed, this will build a different value each
105105
// time it's called, so we won't properly deduplicate repeated
106106
// witnesses.
107-
witness_value_id = CheckAssociatedFunctionImplementation(
107+
// TODO: Skip calling make_witness if this function signature doesn't
108+
// involve `Self`.
109+
entries.push_back(CheckAssociatedFunctionImplementation(
108110
context,
109111
context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
110-
value_id, self_type_id, witness_id,
111-
/*defer_thunk_definition=*/false);
112+
value_id, self_type_id, make_witness(),
113+
/*defer_thunk_definition=*/false));
112114
break;
113115
}
114116
case SemIR::AssociatedConstantDecl::Kind: {
@@ -123,7 +125,7 @@ static auto BuildWitness(Context& context, SemIR::LocId loc_id,
123125
}
124126
}
125127

126-
return witness_id;
128+
return make_witness();
127129
}
128130

129131
static auto LookupCopyImpl(Context& context, SemIR::LocId loc_id,

toolchain/check/eval_inst.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
316316

317317
auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
318318
SemIR::ImplWitnessAccess inst) -> ConstantEvalResult {
319+
CARBON_DIAGNOSTIC(ImplAccessMemberBeforeSet, Error,
320+
"accessing member from impl before it has a defined value");
319321
if (auto witness =
320322
context.insts().TryGetAs<SemIR::ImplWitness>(inst.witness_id)) {
321323
// This is PerformAggregateAccess followed by GetConstantValueInSpecific.
@@ -334,12 +336,26 @@ auto EvalConstantInst(Context& context, SemIR::InstId inst_id,
334336
context.sem_ir(), witness->specific_id, element));
335337
}
336338
}
337-
CARBON_DIAGNOSTIC(
338-
ImplAccessMemberBeforeSet, Error,
339-
"accessing member from impl before it has a defined value");
339+
// If we get here, this impl witness table entry has not been populated yet,
340+
// because the impl was referenced within its own definition.
340341
// TODO: Add note pointing to the impl declaration.
341342
context.emitter().Emit(inst_id, ImplAccessMemberBeforeSet);
342343
return ConstantEvalResult::Error;
344+
} else if (auto cpp_witness =
345+
context.insts().TryGetAs<SemIR::CppWitness>(inst.witness_id)) {
346+
auto elements = context.inst_blocks().Get(cpp_witness->elements_id);
347+
auto index = static_cast<size_t>(inst.index.index);
348+
// `elements` can be shorter than the number of associated entities while
349+
// we're building the synthetic witness.
350+
if (index < elements.size()) {
351+
return ConstantEvalResult::Existing(
352+
context.constant_values().Get(elements[index]));
353+
}
354+
// If we get here, this synthesized witness table entry has not been
355+
// populated yet.
356+
// TODO: Is this reachable? We have no test coverage for this diagnostic.
357+
context.emitter().Emit(inst_id, ImplAccessMemberBeforeSet);
358+
return ConstantEvalResult::Error;
343359
} else if (auto witness = context.insts().TryGetAs<SemIR::LookupImplWitness>(
344360
inst.witness_id)) {
345361
// If the witness is symbolic but has a self type that is a FacetType, it

toolchain/check/testdata/interop/cpp/impls/copy.carbon

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ fn EqualWitnesses(p: Wrap(Cpp.Copyable)*) -> Wrap(Cpp.Copyable)* {
200200
// CHECK:STDOUT: %ptr.e47: type = ptr_type %Copyable [concrete]
201201
// CHECK:STDOUT: %Copyable__carbon_thunk.type: type = fn_type @Copyable__carbon_thunk [concrete]
202202
// CHECK:STDOUT: %Copyable__carbon_thunk: %Copyable__carbon_thunk.type = struct_value () [concrete]
203-
// CHECK:STDOUT: %impl_witness.65e: <witness> = impl_witness @CopyCopyable.%impl_witness_table [concrete]
204-
// CHECK:STDOUT: %Copy.facet.26f: %Copy.type = facet_value %Copyable, (%impl_witness.65e) [concrete]
205203
// CHECK:STDOUT: %Copyable.Op.type: type = fn_type @Copyable.Op [concrete]
206204
// CHECK:STDOUT: %Copyable.Op: %Copyable.Op.type = struct_value () [concrete]
207-
// CHECK:STDOUT: %.667: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet.26f [concrete]
205+
// CHECK:STDOUT: %cpp_witness.524: <witness> = cpp_witness (%Copyable.Op) [concrete]
206+
// CHECK:STDOUT: %Copy.facet.2cd: %Copy.type = facet_value %Copyable, (%cpp_witness.524) [concrete]
207+
// CHECK:STDOUT: %.dc1: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet.2cd [concrete]
208208
// CHECK:STDOUT: %ExplicitCopy: type = class_type @ExplicitCopy [concrete]
209209
// CHECK:STDOUT: %ExplicitCopy.ExplicitCopy.type: type = fn_type @ExplicitCopy.ExplicitCopy [concrete]
210210
// CHECK:STDOUT: %ExplicitCopy.ExplicitCopy: %ExplicitCopy.ExplicitCopy.type = struct_value () [concrete]
@@ -213,11 +213,11 @@ fn EqualWitnesses(p: Wrap(Cpp.Copyable)*) -> Wrap(Cpp.Copyable)* {
213213
// CHECK:STDOUT: %ptr.84c: type = ptr_type %ExplicitCopy [concrete]
214214
// CHECK:STDOUT: %ExplicitCopy__carbon_thunk.type: type = fn_type @ExplicitCopy__carbon_thunk [concrete]
215215
// CHECK:STDOUT: %ExplicitCopy__carbon_thunk: %ExplicitCopy__carbon_thunk.type = struct_value () [concrete]
216-
// CHECK:STDOUT: %impl_witness.215: <witness> = impl_witness @CopyExplicitCopy.%impl_witness_table [concrete]
217-
// CHECK:STDOUT: %Copy.facet.cfa: %Copy.type = facet_value %ExplicitCopy, (%impl_witness.215) [concrete]
218216
// CHECK:STDOUT: %ExplicitCopy.Op.type: type = fn_type @ExplicitCopy.Op [concrete]
219217
// CHECK:STDOUT: %ExplicitCopy.Op: %ExplicitCopy.Op.type = struct_value () [concrete]
220-
// CHECK:STDOUT: %.a87: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet.cfa [concrete]
218+
// CHECK:STDOUT: %cpp_witness.b38: <witness> = cpp_witness (%ExplicitCopy.Op) [concrete]
219+
// CHECK:STDOUT: %Copy.facet.27f: %Copy.type = facet_value %ExplicitCopy, (%cpp_witness.b38) [concrete]
220+
// CHECK:STDOUT: %.82a: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet.27f [concrete]
221221
// CHECK:STDOUT: }
222222
// CHECK:STDOUT:
223223
// CHECK:STDOUT: imports {
@@ -246,10 +246,8 @@ fn EqualWitnesses(p: Wrap(Cpp.Copyable)*) -> Wrap(Cpp.Copyable)* {
246246
// CHECK:STDOUT: fn @CopyCopyable(%c.param: %Copyable) -> %return.param: %Copyable {
247247
// CHECK:STDOUT: !entry:
248248
// CHECK:STDOUT: %c.ref: %Copyable = name_ref c, %c
249-
// CHECK:STDOUT: %impl_witness_table = impl_witness_table (%Copyable.Op.decl), invalid [concrete]
250-
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness %impl_witness_table [concrete = constants.%impl_witness.65e]
251249
// CHECK:STDOUT: <elided>
252-
// CHECK:STDOUT: %impl.elem0: %.667 = impl_witness_access constants.%impl_witness.65e, element0 [concrete = constants.%Copyable.Op]
250+
// CHECK:STDOUT: %impl.elem0: %.dc1 = impl_witness_access constants.%cpp_witness.524, element0 [concrete = constants.%Copyable.Op]
253251
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %c.ref, %impl.elem0
254252
// CHECK:STDOUT: %.loc8_10.1: ref %Copyable = temporary_storage
255253
// CHECK:STDOUT: %Op.ref: %Copyable.Copyable.type = name_ref Op, imports.%Copyable.Copyable.decl [concrete = constants.%Copyable.Copyable]
@@ -267,10 +265,8 @@ fn EqualWitnesses(p: Wrap(Cpp.Copyable)*) -> Wrap(Cpp.Copyable)* {
267265
// CHECK:STDOUT: fn @CopyExplicitCopy(%c.param: %ExplicitCopy) -> %return.param: %ExplicitCopy {
268266
// CHECK:STDOUT: !entry:
269267
// CHECK:STDOUT: %c.ref: %ExplicitCopy = name_ref c, %c
270-
// CHECK:STDOUT: %impl_witness_table = impl_witness_table (%ExplicitCopy.Op.decl), invalid [concrete]
271-
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness %impl_witness_table [concrete = constants.%impl_witness.215]
272268
// CHECK:STDOUT: <elided>
273-
// CHECK:STDOUT: %impl.elem0: %.a87 = impl_witness_access constants.%impl_witness.215, element0 [concrete = constants.%ExplicitCopy.Op]
269+
// CHECK:STDOUT: %impl.elem0: %.82a = impl_witness_access constants.%cpp_witness.b38, element0 [concrete = constants.%ExplicitCopy.Op]
274270
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %c.ref, %impl.elem0
275271
// CHECK:STDOUT: %.loc14_10.1: ref %ExplicitCopy = temporary_storage
276272
// CHECK:STDOUT: %Op.ref: %ExplicitCopy.ExplicitCopy.type = name_ref Op, imports.%ExplicitCopy.ExplicitCopy.decl [concrete = constants.%ExplicitCopy.ExplicitCopy]
@@ -296,17 +292,19 @@ fn EqualWitnesses(p: Wrap(Cpp.Copyable)*) -> Wrap(Cpp.Copyable)* {
296292
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.type.75b: type = fn_type @ptr.as.Copy.impl.Op, @ptr.as.Copy.impl(%T.d9f) [symbolic]
297293
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.692: %ptr.as.Copy.impl.Op.type.75b = struct_value () [symbolic]
298294
// CHECK:STDOUT: %Copyable: type = class_type @Copyable [concrete]
299-
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness @DoCopy.%impl_witness_table [concrete]
300-
// CHECK:STDOUT: %Copy.facet.26f: %Copy.type.705 = facet_value %Copyable, (%impl_witness) [concrete]
301-
// CHECK:STDOUT: %Copy.specific_fn: <specific function> = specific_function %Copy, @Copy.loc6(%Copy.facet.26f) [concrete]
302-
// CHECK:STDOUT: %Wrap.248: type = class_type @Wrap, @Wrap(%Copy.facet.26f) [concrete]
303-
// CHECK:STDOUT: %ptr.510: type = ptr_type %Wrap.248 [concrete]
304-
// CHECK:STDOUT: %Copy.impl_witness.cab: <witness> = impl_witness imports.%Copy.impl_witness_table.67d, @ptr.as.Copy.impl(%Wrap.248) [concrete]
305-
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.type.b1b: type = fn_type @ptr.as.Copy.impl.Op, @ptr.as.Copy.impl(%Wrap.248) [concrete]
306-
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.ea7: %ptr.as.Copy.impl.Op.type.b1b = struct_value () [concrete]
307-
// CHECK:STDOUT: %Copy.facet.5be: %Copy.type.705 = facet_value %ptr.510, (%Copy.impl_witness.cab) [concrete]
308-
// CHECK:STDOUT: %.e13: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet.5be [concrete]
309-
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.specific_fn: <specific function> = specific_function %ptr.as.Copy.impl.Op.ea7, @ptr.as.Copy.impl.Op(%Wrap.248) [concrete]
295+
// CHECK:STDOUT: %Copyable.Op.type: type = fn_type @Copyable.Op [concrete]
296+
// CHECK:STDOUT: %Copyable.Op: %Copyable.Op.type = struct_value () [concrete]
297+
// CHECK:STDOUT: %cpp_witness.524: <witness> = cpp_witness (%Copyable.Op) [concrete]
298+
// CHECK:STDOUT: %Copy.facet.2cd: %Copy.type.705 = facet_value %Copyable, (%cpp_witness.524) [concrete]
299+
// CHECK:STDOUT: %Copy.specific_fn: <specific function> = specific_function %Copy, @Copy.loc6(%Copy.facet.2cd) [concrete]
300+
// CHECK:STDOUT: %Wrap.380: type = class_type @Wrap, @Wrap(%Copy.facet.2cd) [concrete]
301+
// CHECK:STDOUT: %ptr.ca9: type = ptr_type %Wrap.380 [concrete]
302+
// CHECK:STDOUT: %Copy.impl_witness.c72: <witness> = impl_witness imports.%Copy.impl_witness_table.67d, @ptr.as.Copy.impl(%Wrap.380) [concrete]
303+
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.type.4f5: type = fn_type @ptr.as.Copy.impl.Op, @ptr.as.Copy.impl(%Wrap.380) [concrete]
304+
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.c1c: %ptr.as.Copy.impl.Op.type.4f5 = struct_value () [concrete]
305+
// CHECK:STDOUT: %Copy.facet.fd9: %Copy.type.705 = facet_value %ptr.ca9, (%Copy.impl_witness.c72) [concrete]
306+
// CHECK:STDOUT: %.127: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet.fd9 [concrete]
307+
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.specific_fn: <specific function> = specific_function %ptr.as.Copy.impl.Op.c1c, @ptr.as.Copy.impl.Op(%Wrap.380) [concrete]
310308
// CHECK:STDOUT: }
311309
// CHECK:STDOUT:
312310
// CHECK:STDOUT: imports {
@@ -318,27 +316,25 @@ fn EqualWitnesses(p: Wrap(Cpp.Copyable)*) -> Wrap(Cpp.Copyable)* {
318316
// CHECK:STDOUT: !entry:
319317
// CHECK:STDOUT: %Copy.ref: %Copy.type.6f0 = name_ref Copy, file.%Copy.decl [concrete = constants.%Copy]
320318
// CHECK:STDOUT: %c.ref: %Copyable = name_ref c, %c
321-
// CHECK:STDOUT: %impl_witness_table = impl_witness_table (%Copyable.Op.decl), invalid [concrete]
322-
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness %impl_witness_table [concrete = constants.%impl_witness]
323319
// CHECK:STDOUT: <elided>
324-
// CHECK:STDOUT: %Copy.facet.loc12_16.1: %Copy.type.705 = facet_value constants.%Copyable, (constants.%impl_witness) [concrete = constants.%Copy.facet.26f]
325-
// CHECK:STDOUT: %.loc12_16.1: %Copy.type.705 = converted constants.%Copyable, %Copy.facet.loc12_16.1 [concrete = constants.%Copy.facet.26f]
326-
// CHECK:STDOUT: %Copy.facet.loc12_16.2: %Copy.type.705 = facet_value constants.%Copyable, (constants.%impl_witness) [concrete = constants.%Copy.facet.26f]
327-
// CHECK:STDOUT: %.loc12_16.2: %Copy.type.705 = converted constants.%Copyable, %Copy.facet.loc12_16.2 [concrete = constants.%Copy.facet.26f]
328-
// CHECK:STDOUT: %Copy.specific_fn: <specific function> = specific_function %Copy.ref, @Copy.loc6(constants.%Copy.facet.26f) [concrete = constants.%Copy.specific_fn]
320+
// CHECK:STDOUT: %Copy.facet.loc12_16.1: %Copy.type.705 = facet_value constants.%Copyable, (constants.%cpp_witness.524) [concrete = constants.%Copy.facet.2cd]
321+
// CHECK:STDOUT: %.loc12_16.1: %Copy.type.705 = converted constants.%Copyable, %Copy.facet.loc12_16.1 [concrete = constants.%Copy.facet.2cd]
322+
// CHECK:STDOUT: %Copy.facet.loc12_16.2: %Copy.type.705 = facet_value constants.%Copyable, (constants.%cpp_witness.524) [concrete = constants.%Copy.facet.2cd]
323+
// CHECK:STDOUT: %.loc12_16.2: %Copy.type.705 = converted constants.%Copyable, %Copy.facet.loc12_16.2 [concrete = constants.%Copy.facet.2cd]
324+
// CHECK:STDOUT: %Copy.specific_fn: <specific function> = specific_function %Copy.ref, @Copy.loc6(constants.%Copy.facet.2cd) [concrete = constants.%Copy.specific_fn]
329325
// CHECK:STDOUT: <elided>
330326
// CHECK:STDOUT: %Copy.call: init %Copyable = call %Copy.specific_fn(%c.ref) to %.loc10_28
331327
// CHECK:STDOUT: return %Copy.call to %return
332328
// CHECK:STDOUT: }
333329
// CHECK:STDOUT:
334-
// CHECK:STDOUT: fn @EqualWitnesses(%p.param: %ptr.510) -> %ptr.510 {
330+
// CHECK:STDOUT: fn @EqualWitnesses(%p.param: %ptr.ca9) -> %ptr.ca9 {
335331
// CHECK:STDOUT: !entry:
336-
// CHECK:STDOUT: %p.ref: %ptr.510 = name_ref p, %p
337-
// CHECK:STDOUT: %impl.elem0: %.e13 = impl_witness_access constants.%Copy.impl_witness.cab, element0 [concrete = constants.%ptr.as.Copy.impl.Op.ea7]
332+
// CHECK:STDOUT: %p.ref: %ptr.ca9 = name_ref p, %p
333+
// CHECK:STDOUT: %impl.elem0: %.127 = impl_witness_access constants.%Copy.impl_witness.c72, element0 [concrete = constants.%ptr.as.Copy.impl.Op.c1c]
338334
// CHECK:STDOUT: %bound_method.loc20_10.1: <bound method> = bound_method %p.ref, %impl.elem0
339-
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @ptr.as.Copy.impl.Op(constants.%Wrap.248) [concrete = constants.%ptr.as.Copy.impl.Op.specific_fn]
335+
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @ptr.as.Copy.impl.Op(constants.%Wrap.380) [concrete = constants.%ptr.as.Copy.impl.Op.specific_fn]
340336
// CHECK:STDOUT: %bound_method.loc20_10.2: <bound method> = bound_method %p.ref, %specific_fn
341-
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.call: init %ptr.510 = call %bound_method.loc20_10.2(%p.ref)
337+
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.call: init %ptr.ca9 = call %bound_method.loc20_10.2(%p.ref)
342338
// CHECK:STDOUT: return %ptr.as.Copy.impl.Op.call to %return
343339
// CHECK:STDOUT: }
344340
// CHECK:STDOUT:

toolchain/sem_ir/inst_kind.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ CARBON_SEM_IR_INST_KIND(ConvertToValueAction)
5555
CARBON_SEM_IR_INST_KIND(Converted)
5656
CARBON_SEM_IR_INST_KIND(CppOverloadSetType)
5757
CARBON_SEM_IR_INST_KIND(CppOverloadSetValue)
58+
CARBON_SEM_IR_INST_KIND(CppWitness)
5859
CARBON_SEM_IR_INST_KIND(CustomLayoutType)
5960
CARBON_SEM_IR_INST_KIND(Deref)
6061
CARBON_SEM_IR_INST_KIND(ErrorInst)

toolchain/sem_ir/inst_namer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,10 @@ auto InstNamer::NamingContext::NameInst() -> void {
907907
AddInstName("const");
908908
return;
909909
}
910+
case CppWitness::Kind: {
911+
AddInstName("cpp_witness");
912+
return;
913+
}
910914
case CARBON_KIND(FacetAccessType inst): {
911915
auto name_id = SemIR::NameId::None;
912916
if (auto name =

toolchain/sem_ir/typed_insts.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,22 @@ struct CppOverloadSetValue {
754754
CppOverloadSetId overload_set_id;
755755
};
756756

757+
// A witness synthesized for a C++ construct such as a constructor, conversion
758+
// function, or overloaded operator.
759+
struct CppWitness {
760+
static constexpr auto Kind = InstKind::CppWitness.Define<Parse::NodeId>(
761+
{.ir_name = "cpp_witness",
762+
.constant_kind = InstConstantKind::Always,
763+
// TODO: For dynamic dispatch, we might want to lower witness tables as
764+
// constants.
765+
.is_lowered = false});
766+
767+
// Always the type of the builtin `WitnessType` singleton instruction.
768+
TypeId type_id;
769+
// The witness table of instructions.
770+
InstBlockId elements_id;
771+
};
772+
757773
// The type of the name of a generic class. The corresponding value is an empty
758774
// `StructValue`.
759775
struct GenericClassType {
@@ -2066,9 +2082,10 @@ struct WhereExpr {
20662082
InstBlockId requirements_id;
20672083
};
20682084

2069-
// The type of `ImplWitness` and `LookupImplWitness` instructions. The latter
2070-
// will evaluate at some point during specific computation into the former, and
2071-
// their types should not change in the process.
2085+
// The type of `ImplWitness`, `CppWitness`, and `LookupImplWitness`
2086+
// instructions. The latter will evaluate at some point during specific
2087+
// computation into one of the former two, and their types should not change in
2088+
// the process.
20722089
//
20732090
// Also the type of `RequireCompleteType` instructions.
20742091
//

0 commit comments

Comments
 (0)