Skip to content

Commit 077cf56

Browse files
authored
Emit function definitions in check, for all specifics seen. (carbon-language#5090)
Emitting definitions in check. This resolves the crash in lowering which necessitated definitions be emitted. Some of the test changes need further review.
1 parent 6ee1006 commit 077cf56

17 files changed

+100
-66
lines changed

toolchain/check/call.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,6 @@ auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
189189
context, SemIR::SpecificFunctionType::SingletonInstId),
190190
.callee_id = generic_callee_id,
191191
.specific_id = *callee_specific_id});
192-
// TODO: Add to `definitions_required` when evaluating the
193-
// `SpecificImplFunction`.
194192
} else {
195193
// This is a regular generic function. The callee is the specific function
196194
// we deduced.
@@ -201,9 +199,6 @@ auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
201199
context, SemIR::SpecificFunctionType::SingletonInstId),
202200
.callee_id = generic_callee_id,
203201
.specific_id = *callee_specific_id});
204-
// TODO: The specific function could be a symbolic constant. Delay doing
205-
// this until we form a concrete `SpecificFunction` constant.
206-
context.definitions_required().push_back(callee_id);
207202
}
208203

209204
// Add the `self` argument back if there was one.

toolchain/check/check_unit.cpp

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "toolchain/check/inst.h"
2121
#include "toolchain/check/node_id_traversal.h"
2222
#include "toolchain/check/type.h"
23+
#include "toolchain/sem_ir/function.h"
24+
#include "toolchain/sem_ir/ids.h"
2325
#include "toolchain/sem_ir/import_ir.h"
2426

2527
namespace Carbon::Check {
@@ -440,9 +442,11 @@ auto CheckUnit::CheckRequiredDeclarations() -> void {
440442
auto CheckUnit::CheckRequiredDefinitions() -> void {
441443
CARBON_DIAGNOSTIC(MissingDefinitionInImpl, Error,
442444
"no definition found for declaration in impl file");
445+
443446
// Note that more required definitions can be added during this loop.
444-
for (size_t i = 0; i != context_.definitions_required().size(); ++i) {
445-
SemIR::InstId decl_inst_id = context_.definitions_required()[i];
447+
// NOLINTNEXTLINE(modernize-loop-convert)
448+
for (size_t i = 0; i != context_.definitions_required_by_decl().size(); ++i) {
449+
SemIR::InstId decl_inst_id = context_.definitions_required_by_decl()[i];
446450
SemIR::Inst decl_inst = context_.insts().Get(decl_inst_id);
447451
CARBON_KIND_SWITCH(context_.insts().Get(decl_inst_id)) {
448452
case CARBON_KIND(SemIR::ClassDecl class_decl): {
@@ -474,33 +478,32 @@ auto CheckUnit::CheckRequiredDefinitions() -> void {
474478
// https://github.com/carbon-language/carbon-lang/issues/4071.
475479
CARBON_FATAL("TODO: Support interfaces in DiagnoseMissingDefinitions");
476480
}
477-
case CARBON_KIND(SemIR::SpecificFunction specific_function): {
478-
// TODO: Track a location for the use. In general we may want to track a
479-
// list of enclosing locations if this was used from a generic.
480-
SemIRLoc use_loc = decl_inst_id;
481-
if (!ResolveSpecificDefinition(context_, use_loc,
482-
specific_function.specific_id)) {
483-
CARBON_DIAGNOSTIC(MissingGenericFunctionDefinition, Error,
484-
"use of undefined generic function");
485-
CARBON_DIAGNOSTIC(MissingGenericFunctionDefinitionHere, Note,
486-
"generic function declared here");
487-
auto generic_decl_id =
488-
context_.generics()
489-
.Get(context_.specifics()
490-
.Get(specific_function.specific_id)
491-
.generic_id)
492-
.decl_id;
493-
emitter_.Build(decl_inst_id, MissingGenericFunctionDefinition)
494-
.Note(generic_decl_id, MissingGenericFunctionDefinitionHere)
495-
.Emit();
496-
}
497-
break;
498-
}
499481
default: {
500482
CARBON_FATAL("Unexpected inst in definitions_required: {0}", decl_inst);
501483
}
502484
}
503485
}
486+
487+
// Note that more required definitions can be added during this loop.
488+
// NOLINTNEXTLINE(modernize-loop-convert)
489+
for (size_t i = 0; i != context_.definitions_required_by_use().size(); ++i) {
490+
// This is using the location for the use. We could track the
491+
// list of enclosing locations if this was used from a generic.
492+
auto [loc, specific_id] = context_.definitions_required_by_use()[i];
493+
if (!ResolveSpecificDefinition(context_, loc, specific_id)) {
494+
CARBON_DIAGNOSTIC(MissingGenericFunctionDefinition, Error,
495+
"use of undefined generic function");
496+
CARBON_DIAGNOSTIC(MissingGenericFunctionDefinitionHere, Note,
497+
"generic function declared here");
498+
auto generic_decl_id =
499+
context_.generics()
500+
.Get(context_.specifics().Get(specific_id).generic_id)
501+
.decl_id;
502+
emitter_.Build(loc, MissingGenericFunctionDefinition)
503+
.Note(generic_decl_id, MissingGenericFunctionDefinitionHere)
504+
.Emit();
505+
}
506+
}
504507
}
505508

506509
auto CheckUnit::FinishRun() -> void {

toolchain/check/check_unit.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ class CheckUnit {
162162

163163
// Checks that each required definition is available. If the definition can be
164164
// generated by resolving a specific, does so, otherwise emits a diagnostic
165-
// for each declaration in context.definitions_required() that doesn't have a
166-
// definition.
165+
// for each declaration in context.definitions_required_by_decl() and
166+
// context.definitions_required_by_use that doesn't have a definition.
167167
auto CheckRequiredDefinitions() -> void;
168168

169169
// Does work after processing the parse tree, such as finishing the IR and

toolchain/check/context.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,13 @@ class Context {
147147
return import_ir_constant_values_;
148148
}
149149

150-
auto definitions_required() -> llvm::SmallVector<SemIR::InstId>& {
151-
return definitions_required_;
150+
auto definitions_required_by_decl() -> llvm::SmallVector<SemIR::InstId>& {
151+
return definitions_required_by_decl_;
152+
}
153+
154+
auto definitions_required_by_use()
155+
-> llvm::SmallVector<std::pair<SemIRLoc, SemIR::SpecificId>>& {
156+
return definitions_required_by_use_;
152157
}
153158

154159
auto global_init() -> GlobalInit& { return global_init_; }
@@ -343,7 +348,13 @@ class Context {
343348

344349
// Declaration instructions of entities that should have definitions by the
345350
// end of the current source file.
346-
llvm::SmallVector<SemIR::InstId> definitions_required_;
351+
llvm::SmallVector<SemIR::InstId> definitions_required_by_decl_;
352+
353+
// Entities that should have definitions by the end of the current source
354+
// file, because of a generic was used a concrete specific. This is currently
355+
// only tracking specific functions that should have a definition emitted.
356+
llvm::SmallVector<std::pair<SemIRLoc, SemIR::SpecificId>>
357+
definitions_required_by_use_;
347358

348359
// State for global initialization.
349360
GlobalInit global_init_;

toolchain/check/eval_inst.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "toolchain/check/generic.h"
1212
#include "toolchain/check/impl_lookup.h"
1313
#include "toolchain/check/import_ref.h"
14+
#include "toolchain/check/inst.h"
1415
#include "toolchain/check/type.h"
1516
#include "toolchain/check/type_completion.h"
1617
#include "toolchain/sem_ir/ids.h"
@@ -393,14 +394,26 @@ auto EvalConstantInst(Context& context, SemIRLoc loc,
393394
args.append(interface_fn_args.end() - remaining_params,
394395
interface_fn_args.end());
395396
auto specific_id = MakeSpecific(context, loc, generic_id, args);
397+
context.definitions_required_by_use().push_back({loc, specific_id});
396398

397-
// TODO: Add the new `SpecificFunction` to definitions_required.
398399
return ConstantEvalResult::NewSamePhase(
399400
SemIR::SpecificFunction{.type_id = inst.type_id,
400401
.callee_id = inst.callee_id,
401402
.specific_id = specific_id});
402403
}
403404

405+
auto EvalConstantInst(Context& context, SemIRLoc loc,
406+
SemIR::SpecificFunction inst) -> ConstantEvalResult {
407+
if (!SemIR::GetCalleeFunction(context.sem_ir(), inst.callee_id)
408+
.self_type_id.has_value()) {
409+
// This is not an associated function. Those will be required to be defined
410+
// as part of checking that the impl is complete.
411+
context.definitions_required_by_use().push_back({loc, inst.specific_id});
412+
}
413+
// Create new constant for a specific function.
414+
return ConstantEvalResult::NewSamePhase(inst);
415+
}
416+
404417
auto EvalConstantInst(Context& context, SemIRLoc /*loc*/,
405418
SemIR::SpliceBlock inst) -> ConstantEvalResult {
406419
// SpliceBlock evaluates to the result value that is (typically) within the

toolchain/check/handle_class.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
275275
}
276276

277277
if (!is_definition && context.sem_ir().is_impl() && !is_extern) {
278-
context.definitions_required().push_back(class_decl_id);
278+
context.definitions_required_by_decl().push_back(class_decl_id);
279279
}
280280

281281
return {class_decl.class_id, class_decl_id};

toolchain/check/handle_function.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ static auto BuildFunctionDecl(Context& context,
531531
function_info);
532532

533533
if (!is_definition && context.sem_ir().is_impl() && !is_extern) {
534-
context.definitions_required().push_back(decl_id);
534+
context.definitions_required_by_decl().push_back(decl_id);
535535
}
536536

537537
return {function_decl.function_id, decl_id};

toolchain/check/handle_impl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
506506
if (!is_definition && !invalid_redeclaration &&
507507
context.impls().Get(impl_decl.impl_id).witness_id !=
508508
SemIR::ErrorInst::SingletonInstId) {
509-
context.definitions_required().push_back(impl_decl_id);
509+
context.definitions_required_by_decl().push_back(impl_decl_id);
510510
}
511511

512512
return {impl_decl.impl_id, impl_decl_id};

toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_itself.carbon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ fn F() {
172172
// CHECK:STDOUT: specific @FeedAnimal(constants.%Animal.facet) {
173173
// CHECK:STDOUT: %T.loc16_15.2 => constants.%Animal.facet
174174
// CHECK:STDOUT: %T.patt.loc16_15.2 => constants.%T.patt
175+
// CHECK:STDOUT:
176+
// CHECK:STDOUT: !definition:
175177
// CHECK:STDOUT: }
176178
// CHECK:STDOUT:
177179
// CHECK:STDOUT: --- include_files/convert.carbon

toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,10 @@ fn F() {
532532
// CHECK:STDOUT: %T.loc30_24.2 => constants.%Eats.facet.fa6
533533
// CHECK:STDOUT: %T.patt.loc30_24.2 => constants.%T.patt.1ac
534534
// CHECK:STDOUT: %T.as_type.loc30_43.2 => constants.%Goat
535+
// CHECK:STDOUT:
536+
// CHECK:STDOUT: !definition:
537+
// CHECK:STDOUT: %require_complete.loc30_41 => constants.%complete_type.357
538+
// CHECK:STDOUT: %require_complete.loc30_50 => constants.%complete_type.357
535539
// CHECK:STDOUT: }
536540
// CHECK:STDOUT:
537541
// CHECK:STDOUT: --- include_files/convert.carbon

0 commit comments

Comments
 (0)