14
14
15
15
namespace Carbon ::Check {
16
16
17
- auto TryGetAsClass (Context& context, SemIR::TypeId type_id) -> SemIR::Class* {
18
- auto class_type = context.types ().TryGetAs <SemIR::ClassType>(type_id);
19
- if (!class_type) {
20
- return nullptr ;
21
- }
22
- return &context.classes ().Get (class_type->class_id );
23
- }
24
-
25
17
auto SetClassSelfType (Context& context, SemIR::ClassId class_id) -> void {
26
18
auto & class_info = context.classes ().Get (class_id);
27
19
auto specific_id = context.generics ().GetSelfSpecific (class_info.generic_id );
@@ -131,10 +123,51 @@ static auto AddStructTypeFields(
131
123
132
124
// Builds and returns a vtable for the current class. Assumes that the virtual
133
125
// functions for the class are listed as the top element of the `vtable_stack`.
134
- static auto BuildVtable (Context& context, SemIR::ClassId class_id,
135
- SemIR::VtableId base_vtable_id,
126
+ static auto BuildVtable (Context& context, Parse::ClassDefinitionId node_id,
127
+ SemIR::ClassId class_id,
128
+ std::optional<SemIR::ClassType> base_class_type,
136
129
llvm::ArrayRef<SemIR::InstId> vtable_contents)
137
130
-> SemIR::VtableId {
131
+ auto base_vtable_id = SemIR::VtableId::None;
132
+ auto base_class_specific_id = SemIR::SpecificId::None;
133
+
134
+ // Get some base class/type/specific info.
135
+ if (base_class_type) {
136
+ auto & base_class_info = context.classes ().Get (base_class_type->class_id );
137
+ auto base_vtable_ptr_inst_id = base_class_info.vtable_ptr_id ;
138
+ if (base_vtable_ptr_inst_id.has_value ()) {
139
+ LoadImportRef (context, base_vtable_ptr_inst_id);
140
+ auto canonical_base_vtable_inst_id =
141
+ context.constant_values ().GetConstantInstId (base_vtable_ptr_inst_id);
142
+ const auto & base_vtable_ptr_inst =
143
+ context.insts ().GetAs <SemIR::VtablePtr>(
144
+ canonical_base_vtable_inst_id);
145
+ base_vtable_id = base_vtable_ptr_inst.vtable_id ;
146
+ base_class_specific_id = base_class_type->specific_id ;
147
+ }
148
+ }
149
+
150
+ const auto & class_info = context.classes ().Get (class_id);
151
+ auto class_generic_id = class_info.generic_id ;
152
+
153
+ // Wrap vtable entries in SpecificFunctions as needed/in generic classes.
154
+ auto build_specific_function =
155
+ [&](SemIR::InstId fn_decl_id) -> SemIR::InstId {
156
+ if (!class_generic_id.has_value ()) {
157
+ return fn_decl_id;
158
+ }
159
+ const auto & fn_decl =
160
+ context.insts ().GetAs <SemIR::FunctionDecl>(fn_decl_id);
161
+ const auto & function = context.functions ().Get (fn_decl.function_id );
162
+ return GetOrAddInst<SemIR::SpecificFunction>(
163
+ context, node_id,
164
+ {.type_id =
165
+ GetSingletonType (context, SemIR::SpecificFunctionType::TypeInstId),
166
+ .callee_id = fn_decl_id,
167
+ .specific_id =
168
+ context.generics ().GetSelfSpecific (function.generic_id )});
169
+ };
170
+
138
171
llvm::SmallVector<SemIR::InstId> vtable;
139
172
if (base_vtable_id.has_value ()) {
140
173
auto base_vtable_inst_block = context.inst_blocks ().Get (
@@ -144,25 +177,36 @@ static auto BuildVtable(Context& context, SemIR::ClassId class_id,
144
177
for (auto fn_decl_id : base_vtable_inst_block) {
145
178
auto fn_decl = GetCalleeFunction (context.sem_ir (), fn_decl_id);
146
179
const auto & fn = context.functions ().Get (fn_decl.function_id );
147
- for (auto override_fn_decl_id : vtable_contents) {
148
- auto override_fn_decl =
149
- context.insts ().GetAs <SemIR::FunctionDecl>(override_fn_decl_id);
150
- auto & override_fn =
151
- context.functions ().Get (override_fn_decl.function_id );
152
- if (override_fn.virtual_modifier ==
153
- SemIR::FunctionFields::VirtualModifier::Impl &&
154
- override_fn.name_id == fn.name_id ) {
155
- // TODO: Support generic base classes, rather than passing
156
- // `SpecificId::None`.
157
- CheckFunctionTypeMatches (context, override_fn, fn,
158
- SemIR::SpecificId::None,
159
- /* check_syntax=*/ false ,
160
- /* check_self=*/ false );
161
- fn_decl_id = override_fn_decl_id;
162
- override_fn.virtual_index = vtable.size ();
163
- CARBON_CHECK (override_fn.virtual_index == fn.virtual_index );
164
- break ;
165
- }
180
+ const auto * i = llvm::find_if (
181
+ vtable_contents, [&](SemIR::InstId override_fn_decl_id) -> bool {
182
+ const auto & override_fn = context.functions ().Get (
183
+ context.insts ()
184
+ .GetAs <SemIR::FunctionDecl>(override_fn_decl_id)
185
+ .function_id );
186
+ return override_fn.virtual_modifier ==
187
+ SemIR::FunctionFields::VirtualModifier::Impl &&
188
+ override_fn.name_id == fn.name_id ;
189
+ });
190
+ if (i != vtable_contents.end ()) {
191
+ auto & override_fn = context.functions ().Get (
192
+ context.insts ().GetAs <SemIR::FunctionDecl>(*i).function_id );
193
+ // TODO: Support generic base classes, rather than passing
194
+ // `SpecificId::None`. This'll need to `GetConstantValueInSpecific` for
195
+ // the base function, then extract the specific from that for use here.
196
+ CheckFunctionTypeMatches (context, override_fn, fn,
197
+ SemIR::SpecificId::None,
198
+ /* check_syntax=*/ false ,
199
+ /* check_self=*/ false );
200
+ fn_decl_id = build_specific_function (*i);
201
+ override_fn.virtual_index = vtable.size ();
202
+ CARBON_CHECK (override_fn.virtual_index == fn.virtual_index );
203
+ } else {
204
+ // Remap the base's vtable entry to the appropriate constant usable in
205
+ // the context of the derived class (for the specific for the base
206
+ // class, for instance)..
207
+ fn_decl_id = context.sem_ir ().constant_values ().GetInstId (
208
+ GetConstantValueInSpecific (context.sem_ir (), base_class_specific_id,
209
+ fn_decl_id));
166
210
}
167
211
vtable.push_back (fn_decl_id);
168
212
}
@@ -173,7 +217,7 @@ static auto BuildVtable(Context& context, SemIR::ClassId class_id,
173
217
auto & fn = context.functions ().Get (fn_decl.function_id );
174
218
if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
175
219
fn.virtual_index = vtable.size ();
176
- vtable.push_back (inst_id);
220
+ vtable.push_back (build_specific_function ( inst_id) );
177
221
}
178
222
}
179
223
@@ -200,12 +244,13 @@ static auto CheckCompleteClassType(
200
244
class_info.GetBaseType (context.sem_ir (), SemIR::SpecificId::None);
201
245
// TODO: Use InstId from base declaration.
202
246
auto base_type_inst_id = context.types ().GetInstId (base_type_id);
203
- SemIR::Class* base_class_info = nullptr ;
247
+ std::optional< SemIR::ClassType> base_class_type ;
204
248
if (base_type_id.has_value ()) {
205
249
// TODO: If the base class is template dependent, we will need to decide
206
250
// whether to add a vptr as part of instantiation.
207
- base_class_info = TryGetAsClass (context, base_type_id);
208
- if (base_class_info && base_class_info->is_dynamic ) {
251
+ base_class_type = context.types ().TryGetAs <SemIR::ClassType>(base_type_id);
252
+ if (base_class_type &&
253
+ context.classes ().Get (base_class_type->class_id ).is_dynamic ) {
209
254
defining_vptr = false ;
210
255
}
211
256
}
@@ -229,35 +274,21 @@ static auto CheckCompleteClassType(
229
274
}
230
275
231
276
if (class_info.is_dynamic ) {
232
- SemIR::VtableId base_vtable_id = SemIR::VtableId::None;
233
- if (base_class_info) {
234
- auto base_vtable_ptr_inst_id = base_class_info->vtable_ptr_id ;
235
- if (base_vtable_ptr_inst_id.has_value ()) {
236
- LoadImportRef (context, base_vtable_ptr_inst_id);
237
- auto canonical_base_vtable_inst_id =
238
- context.constant_values ().GetConstantInstId (
239
- base_vtable_ptr_inst_id);
240
- const auto & base_vtable_ptr_inst =
241
- context.insts ().GetAs <SemIR::VtablePtr>(
242
- canonical_base_vtable_inst_id);
243
- base_vtable_id = base_vtable_ptr_inst.vtable_id ;
244
- // TODO: Retrieve the specific_id from the base_vtable_ptr_inst here,
245
- // for use in BuildVtable.
246
- }
247
- }
248
- auto vtable_id =
249
- BuildVtable (context, class_id, base_vtable_id, vtable_contents);
277
+ auto vtable_id = BuildVtable (context, node_id, class_id, base_class_type,
278
+ vtable_contents);
250
279
251
280
auto vptr_type_id = GetPointerType (context, SemIR::VtableType::TypeInstId);
252
281
// TODO: Handle specifics here, probably passing
253
282
// `context.generics().GetSelfSpecific(class_info.generic_id)` as the
254
283
// specific_id here (but more work involved to get this all plumbed in and
255
284
// tested).
285
+ auto generic_id = class_info.generic_id ;
286
+ auto self_specific_id = context.generics ().GetSelfSpecific (generic_id);
256
287
class_info.vtable_ptr_id =
257
288
AddInst<SemIR::VtablePtr>(context, node_id,
258
289
{.type_id = vptr_type_id,
259
290
.vtable_id = vtable_id,
260
- .specific_id = SemIR::SpecificId::None });
291
+ .specific_id = self_specific_id });
261
292
}
262
293
263
294
auto struct_type_inst_id = AddTypeInst<SemIR::StructType>(
0 commit comments