mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 18:41:03 +01:00
Move diagnostic helpers from Context to other files (#4949)
Trying to find more specific homes for shared diagnostic function calls.
This commit is contained in:
@@ -214,76 +214,6 @@ auto Context::ReplaceInstPreservingConstantValue(SemIR::InstId inst_id,
|
||||
CARBON_CHECK(old_const_id == new_const_id);
|
||||
}
|
||||
|
||||
auto Context::DiagnoseDuplicateName(SemIRLoc dup_def, SemIRLoc prev_def)
|
||||
-> void {
|
||||
CARBON_DIAGNOSTIC(NameDeclDuplicate, Error,
|
||||
"duplicate name being declared in the same scope");
|
||||
CARBON_DIAGNOSTIC(NameDeclPrevious, Note, "name is previously declared here");
|
||||
emitter_->Build(dup_def, NameDeclDuplicate)
|
||||
.Note(prev_def, NameDeclPrevious)
|
||||
.Emit();
|
||||
}
|
||||
|
||||
auto Context::DiagnosePoisonedName(SemIR::LocId poisoning_loc_id,
|
||||
SemIR::LocId decl_name_loc_id) -> void {
|
||||
CARBON_CHECK(poisoning_loc_id.has_value(),
|
||||
"Trying to diagnose poisoned name with no poisoning location");
|
||||
CARBON_DIAGNOSTIC(NameUseBeforeDecl, Error,
|
||||
"name used before it was declared");
|
||||
CARBON_DIAGNOSTIC(NameUseBeforeDeclNote, Note, "declared here");
|
||||
emitter_->Build(poisoning_loc_id, NameUseBeforeDecl)
|
||||
.Note(decl_name_loc_id, NameUseBeforeDeclNote)
|
||||
.Emit();
|
||||
}
|
||||
|
||||
auto Context::DiagnoseNameNotFound(SemIRLoc loc, SemIR::NameId name_id)
|
||||
-> void {
|
||||
CARBON_DIAGNOSTIC(NameNotFound, Error, "name `{0}` not found", SemIR::NameId);
|
||||
emitter_->Emit(loc, NameNotFound, name_id);
|
||||
}
|
||||
|
||||
auto Context::NoteAbstractClass(SemIR::ClassId class_id,
|
||||
DiagnosticBuilder& builder) -> void {
|
||||
const auto& class_info = classes().Get(class_id);
|
||||
CARBON_CHECK(
|
||||
class_info.inheritance_kind == SemIR::Class::InheritanceKind::Abstract,
|
||||
"Class is not abstract");
|
||||
CARBON_DIAGNOSTIC(ClassAbstractHere, Note,
|
||||
"class was declared abstract here");
|
||||
builder.Note(class_info.definition_id, ClassAbstractHere);
|
||||
}
|
||||
|
||||
auto Context::NoteIncompleteClass(SemIR::ClassId class_id,
|
||||
DiagnosticBuilder& builder) -> void {
|
||||
const auto& class_info = classes().Get(class_id);
|
||||
CARBON_CHECK(!class_info.is_defined(), "Class is not incomplete");
|
||||
if (class_info.has_definition_started()) {
|
||||
CARBON_DIAGNOSTIC(ClassIncompleteWithinDefinition, Note,
|
||||
"class is incomplete within its definition");
|
||||
builder.Note(class_info.definition_id, ClassIncompleteWithinDefinition);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(ClassForwardDeclaredHere, Note,
|
||||
"class was forward declared here");
|
||||
builder.Note(class_info.latest_decl_id(), ClassForwardDeclaredHere);
|
||||
}
|
||||
}
|
||||
|
||||
auto Context::NoteUndefinedInterface(SemIR::InterfaceId interface_id,
|
||||
DiagnosticBuilder& builder) -> void {
|
||||
const auto& interface_info = interfaces().Get(interface_id);
|
||||
CARBON_CHECK(!interface_info.is_defined(), "Interface is not incomplete");
|
||||
if (interface_info.is_being_defined()) {
|
||||
CARBON_DIAGNOSTIC(InterfaceUndefinedWithinDefinition, Note,
|
||||
"interface is currently being defined");
|
||||
builder.Note(interface_info.definition_id,
|
||||
InterfaceUndefinedWithinDefinition);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(InterfaceForwardDeclaredHere, Note,
|
||||
"interface was forward declared here");
|
||||
builder.Note(interface_info.latest_decl_id(), InterfaceForwardDeclaredHere);
|
||||
}
|
||||
}
|
||||
|
||||
auto Context::Finalize() -> void {
|
||||
// Pop information for the file-level scope.
|
||||
sem_ir().set_top_inst_block_id(inst_block_stack().Pop());
|
||||
|
||||
@@ -178,28 +178,6 @@ class Context {
|
||||
sem_ir().insts().SetLocId(inst_id, SemIR::LocId(node_id));
|
||||
}
|
||||
|
||||
// Prints a diagnostic for a duplicate name.
|
||||
auto DiagnoseDuplicateName(SemIRLoc dup_def, SemIRLoc prev_def) -> void;
|
||||
|
||||
// Prints a diagnostic for a poisoned name when it's later declared.
|
||||
auto DiagnosePoisonedName(SemIR::LocId poisoning_loc_id,
|
||||
SemIR::LocId decl_name_loc_id) -> void;
|
||||
|
||||
// Prints a diagnostic for a missing name.
|
||||
auto DiagnoseNameNotFound(SemIRLoc loc, SemIR::NameId name_id) -> void;
|
||||
|
||||
// Adds a note to a diagnostic explaining that a class is incomplete.
|
||||
auto NoteIncompleteClass(SemIR::ClassId class_id, DiagnosticBuilder& builder)
|
||||
-> void;
|
||||
|
||||
// Adds a note to a diagnostic explaining that a class is abstract.
|
||||
auto NoteAbstractClass(SemIR::ClassId class_id, DiagnosticBuilder& builder)
|
||||
-> void;
|
||||
|
||||
// Adds a note to a diagnostic explaining that an interface is not defined.
|
||||
auto NoteUndefinedInterface(SemIR::InterfaceId interface_id,
|
||||
DiagnosticBuilder& builder) -> void;
|
||||
|
||||
// Returns the type ID for a constant that is a type value, i.e. it is a value
|
||||
// of type `TypeType`.
|
||||
//
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/check/type_completion.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/name_scope.h"
|
||||
@@ -176,10 +177,10 @@ auto DeclNameStack::AddNameOrDiagnose(NameContext name_context,
|
||||
SemIR::InstId target_id,
|
||||
SemIR::AccessKind access_kind) -> void {
|
||||
if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
|
||||
context_->DiagnosePoisonedName(name_context.poisoning_loc_id,
|
||||
name_context.loc_id);
|
||||
DiagnosePoisonedName(*context_, name_context.poisoning_loc_id,
|
||||
name_context.loc_id);
|
||||
} else if (auto id = name_context.prev_inst_id(); id.has_value()) {
|
||||
context_->DiagnoseDuplicateName(target_id, id);
|
||||
DiagnoseDuplicateName(*context_, target_id, id);
|
||||
} else {
|
||||
AddName(name_context, target_id, access_kind);
|
||||
}
|
||||
@@ -299,8 +300,8 @@ static auto CheckQualifierIsResolved(
|
||||
case DeclNameStack::NameContext::State::Unresolved:
|
||||
// Because more qualifiers were found, we diagnose that the earlier
|
||||
// qualifier failed to resolve.
|
||||
context.DiagnoseNameNotFound(name_context.loc_id,
|
||||
name_context.unresolved_name_id);
|
||||
DiagnoseNameNotFound(context, name_context.loc_id,
|
||||
name_context.unresolved_name_id);
|
||||
return false;
|
||||
|
||||
case DeclNameStack::NameContext::State::Finished:
|
||||
@@ -324,7 +325,7 @@ static auto DiagnoseQualifiedDeclInIncompleteClassScope(Context& context,
|
||||
auto builder =
|
||||
context.emitter().Build(loc, QualifiedDeclInIncompleteClassScope,
|
||||
context.classes().Get(class_id).self_type_id);
|
||||
context.NoteIncompleteClass(class_id, builder);
|
||||
NoteIncompleteClass(context, class_id, builder);
|
||||
builder.Emit();
|
||||
}
|
||||
|
||||
@@ -338,7 +339,7 @@ static auto DiagnoseQualifiedDeclInUndefinedInterfaceScope(
|
||||
InstIdAsType);
|
||||
auto builder = context.emitter().Build(
|
||||
loc, QualifiedDeclInUndefinedInterfaceScope, interface_inst_id);
|
||||
context.NoteUndefinedInterface(interface_id, builder);
|
||||
NoteUndefinedInterface(context, interface_id, builder);
|
||||
builder.Emit();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/check/type_completion.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
@@ -111,8 +112,8 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id,
|
||||
access_kind);
|
||||
if (lookup_result.is_poisoned()) {
|
||||
// This is a declaration of a poisoned name.
|
||||
context.DiagnosePoisonedName(lookup_result.poisoning_loc_id(),
|
||||
name_context.loc_id);
|
||||
DiagnosePoisonedName(context, lookup_result.poisoning_loc_id(),
|
||||
name_context.loc_id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -161,7 +162,7 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id,
|
||||
|
||||
if (!prev_class_id.has_value()) {
|
||||
// This is a redeclaration of something other than a class.
|
||||
context.DiagnoseDuplicateName(class_decl_id, prev_id);
|
||||
DiagnoseDuplicateName(context, class_decl_id, prev_id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/parse/typed_nodes.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
@@ -37,7 +38,7 @@ auto HandleParseNode(Context& context, Parse::ExportDeclId node_id) -> bool {
|
||||
|
||||
auto inst_id = name_context.prev_inst_id();
|
||||
if (!inst_id.has_value()) {
|
||||
context.DiagnoseNameNotFound(node_id, name_context.name_id_for_new_inst());
|
||||
DiagnoseNameNotFound(context, node_id, name_context.name_id_for_new_inst());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/check/type_completion.h"
|
||||
#include "toolchain/sem_ir/builtin_function_kind.h"
|
||||
#include "toolchain/sem_ir/entry_point.h"
|
||||
@@ -176,7 +177,7 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
|
||||
}
|
||||
|
||||
if (!prev_function_id.has_value()) {
|
||||
context.DiagnoseDuplicateName(function_info.latest_decl_id(), prev_id);
|
||||
DiagnoseDuplicateName(context, function_info.latest_decl_id(), prev_id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -272,8 +273,8 @@ static auto BuildFunctionDecl(Context& context,
|
||||
}
|
||||
|
||||
if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
|
||||
context.DiagnosePoisonedName(name_context.poisoning_loc_id,
|
||||
name_context.loc_id);
|
||||
DiagnosePoisonedName(context, name_context.poisoning_loc_id,
|
||||
name_context.loc_id);
|
||||
} else {
|
||||
TryMergeRedecl(context, node_id, name_context.prev_inst_id(), function_decl,
|
||||
function_info, is_definition);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
@@ -65,8 +66,8 @@ static auto BuildInterfaceDecl(Context& context,
|
||||
introducer.modifier_set.GetAccessKind());
|
||||
if (lookup_result.is_poisoned()) {
|
||||
// This is a declaration of a poisoned name.
|
||||
context.DiagnosePoisonedName(lookup_result.poisoning_loc_id(),
|
||||
name_context.loc_id);
|
||||
DiagnosePoisonedName(context, lookup_result.poisoning_loc_id(),
|
||||
name_context.loc_id);
|
||||
} else if (lookup_result.is_found()) {
|
||||
SemIR::InstId existing_id = lookup_result.target_inst_id();
|
||||
if (auto existing_interface_decl =
|
||||
@@ -102,7 +103,7 @@ static auto BuildInterfaceDecl(Context& context,
|
||||
}
|
||||
} else {
|
||||
// This is a redeclaration of something other than a interface.
|
||||
context.DiagnoseDuplicateName(interface_decl_id, existing_id);
|
||||
DiagnoseDuplicateName(context, interface_decl_id, existing_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
#include "toolchain/sem_ir/name_scope.h"
|
||||
@@ -46,8 +47,8 @@ auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool {
|
||||
context.decl_name_stack().LookupOrAddName(name_context, namespace_id,
|
||||
SemIR::AccessKind::Public);
|
||||
if (lookup_result.is_poisoned()) {
|
||||
context.DiagnosePoisonedName(lookup_result.poisoning_loc_id(),
|
||||
name_context.loc_id);
|
||||
DiagnosePoisonedName(context, lookup_result.poisoning_loc_id(),
|
||||
name_context.loc_id);
|
||||
} else if (lookup_result.is_found()) {
|
||||
SemIR::InstId existing_inst_id = lookup_result.target_inst_id();
|
||||
if (auto existing =
|
||||
@@ -62,7 +63,7 @@ auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool {
|
||||
.Get(existing->name_scope_id)
|
||||
.is_closed_import()) {
|
||||
// The existing name is a package name, so this is a name conflict.
|
||||
context.DiagnoseDuplicateName(namespace_id, existing_inst_id);
|
||||
DiagnoseDuplicateName(context, namespace_id, existing_inst_id);
|
||||
|
||||
// Treat this as a local namespace name from now on to avoid further
|
||||
// diagnostics.
|
||||
@@ -76,7 +77,7 @@ auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool {
|
||||
context.SetNamespaceNodeId(existing_inst_id, node_id);
|
||||
}
|
||||
} else {
|
||||
context.DiagnoseDuplicateName(namespace_id, existing_inst_id);
|
||||
DiagnoseDuplicateName(context, namespace_id, existing_inst_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
@@ -105,7 +106,7 @@ auto AddImportNamespace(Context& context, SemIR::TypeId namespace_type_id,
|
||||
if (diagnose_duplicate_namespace) {
|
||||
auto import_id = make_import_id();
|
||||
CARBON_CHECK(import_id.has_value());
|
||||
context.DiagnoseDuplicateName(import_id, prev_inst_id);
|
||||
DiagnoseDuplicateName(context, import_id, prev_inst_id);
|
||||
}
|
||||
return {.name_scope_id = namespace_inst->name_scope_id,
|
||||
.inst_id = prev_inst_id,
|
||||
@@ -146,7 +147,7 @@ auto AddImportNamespace(Context& context, SemIR::TypeId namespace_type_id,
|
||||
// may be overwriting a poisoned entry here.
|
||||
auto& result = parent_scope->GetEntry(entry_id).result;
|
||||
if (!result.is_poisoned() && !inserted) {
|
||||
context.DiagnoseDuplicateName(namespace_id, result.target_inst_id());
|
||||
DiagnoseDuplicateName(context, namespace_id, result.target_inst_id());
|
||||
}
|
||||
result = SemIR::ScopeLookupResult::MakeFound(namespace_id,
|
||||
SemIR::AccessKind::Public);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/eval.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/constant.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
@@ -147,7 +148,7 @@ auto VerifySameCanonicalImportIRInst(Context& context, SemIR::InstId prev_id,
|
||||
}
|
||||
auto conflict_id =
|
||||
AddImportRef(context, {.ir_id = new_ir_id, .inst_id = new_inst_id});
|
||||
context.DiagnoseDuplicateName(conflict_id, prev_id);
|
||||
DiagnoseDuplicateName(context, conflict_id, prev_id);
|
||||
}
|
||||
|
||||
// Returns an instruction that has the specified constant value.
|
||||
|
||||
@@ -17,7 +17,7 @@ auto AddNameToLookup(Context& context, SemIR::NameId name_id,
|
||||
if (auto existing = context.scope_stack().LookupOrAddName(name_id, target_id,
|
||||
scope_index);
|
||||
existing.has_value()) {
|
||||
context.DiagnoseDuplicateName(target_id, existing);
|
||||
DiagnoseDuplicateName(context, target_id, existing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ auto LookupUnqualifiedName(Context& context, Parse::NodeId node_id,
|
||||
|
||||
// We didn't find anything at all.
|
||||
if (required) {
|
||||
context.DiagnoseNameNotFound(node_id, name_id);
|
||||
DiagnoseNameNotFound(context, node_id, name_id);
|
||||
}
|
||||
|
||||
return {.specific_id = SemIR::SpecificId::None,
|
||||
@@ -480,4 +480,34 @@ auto LookupNameInCore(Context& context, SemIR::LocId loc_id,
|
||||
scope_result.target_inst_id());
|
||||
}
|
||||
|
||||
auto DiagnoseDuplicateName(Context& context, SemIRLoc dup_def,
|
||||
SemIRLoc prev_def) -> void {
|
||||
CARBON_DIAGNOSTIC(NameDeclDuplicate, Error,
|
||||
"duplicate name being declared in the same scope");
|
||||
CARBON_DIAGNOSTIC(NameDeclPrevious, Note, "name is previously declared here");
|
||||
context.emitter()
|
||||
.Build(dup_def, NameDeclDuplicate)
|
||||
.Note(prev_def, NameDeclPrevious)
|
||||
.Emit();
|
||||
}
|
||||
|
||||
auto DiagnosePoisonedName(Context& context, SemIR::LocId poisoning_loc_id,
|
||||
SemIR::LocId decl_name_loc_id) -> void {
|
||||
CARBON_CHECK(poisoning_loc_id.has_value(),
|
||||
"Trying to diagnose poisoned name with no poisoning location");
|
||||
CARBON_DIAGNOSTIC(NameUseBeforeDecl, Error,
|
||||
"name used before it was declared");
|
||||
CARBON_DIAGNOSTIC(NameUseBeforeDeclNote, Note, "declared here");
|
||||
context.emitter()
|
||||
.Build(poisoning_loc_id, NameUseBeforeDecl)
|
||||
.Note(decl_name_loc_id, NameUseBeforeDeclNote)
|
||||
.Emit();
|
||||
}
|
||||
|
||||
auto DiagnoseNameNotFound(Context& context, SemIRLoc loc, SemIR::NameId name_id)
|
||||
-> void {
|
||||
CARBON_DIAGNOSTIC(NameNotFound, Error, "name `{0}` not found", SemIR::NameId);
|
||||
context.emitter().Emit(loc, NameNotFound, name_id);
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
@@ -97,6 +97,18 @@ auto LookupQualifiedName(Context& context, SemIR::LocId loc_id,
|
||||
auto LookupNameInCore(Context& context, SemIR::LocId loc_id,
|
||||
llvm::StringRef name) -> SemIR::InstId;
|
||||
|
||||
// Prints a diagnostic for a duplicate name.
|
||||
auto DiagnoseDuplicateName(Context& context, SemIRLoc dup_def,
|
||||
SemIRLoc prev_def) -> void;
|
||||
|
||||
// Prints a diagnostic for a poisoned name when it's later declared.
|
||||
auto DiagnosePoisonedName(Context& context, SemIR::LocId poisoning_loc_id,
|
||||
SemIR::LocId decl_name_loc_id) -> void;
|
||||
|
||||
// Prints a diagnostic for a missing name.
|
||||
auto DiagnoseNameNotFound(Context& context, SemIRLoc loc, SemIR::NameId name_id)
|
||||
-> void;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_NAME_LOOKUP_H_
|
||||
|
||||
@@ -261,7 +261,7 @@ auto TypeCompleter::AddNestedIncompleteTypes(SemIR::Inst type_inst) -> bool {
|
||||
if (!class_info.is_defined()) {
|
||||
if (diagnoser_) {
|
||||
auto builder = diagnoser_();
|
||||
context_.NoteIncompleteClass(inst.class_id, builder);
|
||||
NoteIncompleteClass(context_, inst.class_id, builder);
|
||||
builder.Emit();
|
||||
}
|
||||
return false;
|
||||
@@ -497,6 +497,18 @@ auto RequireCompleteType(Context& context, SemIR::TypeId type_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adds a note to a diagnostic explaining that a class is abstract.
|
||||
static auto NoteAbstractClass(Context& context, SemIR::ClassId class_id,
|
||||
Context::DiagnosticBuilder& builder) -> void {
|
||||
const auto& class_info = context.classes().Get(class_id);
|
||||
CARBON_CHECK(
|
||||
class_info.inheritance_kind == SemIR::Class::InheritanceKind::Abstract,
|
||||
"Class is not abstract");
|
||||
CARBON_DIAGNOSTIC(ClassAbstractHere, Note,
|
||||
"class was declared abstract here");
|
||||
builder.Note(class_info.definition_id, ClassAbstractHere);
|
||||
}
|
||||
|
||||
auto RequireConcreteType(Context& context, SemIR::TypeId type_id,
|
||||
SemIR::LocId loc_id,
|
||||
Context::BuildDiagnosticFn diagnoser,
|
||||
@@ -519,7 +531,7 @@ auto RequireConcreteType(Context& context, SemIR::TypeId type_id,
|
||||
if (!builder) {
|
||||
return false;
|
||||
}
|
||||
context.NoteAbstractClass(class_type->class_id, builder);
|
||||
NoteAbstractClass(context, class_type->class_id, builder);
|
||||
builder.Emit();
|
||||
return false;
|
||||
}
|
||||
@@ -541,7 +553,7 @@ auto RequireDefinedType(Context& context, SemIR::TypeId type_id,
|
||||
auto interface_id = interface.interface_id;
|
||||
if (!context.interfaces().Get(interface_id).is_defined()) {
|
||||
auto builder = diagnoser();
|
||||
context.NoteUndefinedInterface(interface_id, builder);
|
||||
NoteUndefinedInterface(context, interface_id, builder);
|
||||
builder.Emit();
|
||||
return false;
|
||||
}
|
||||
@@ -590,4 +602,35 @@ auto AsConcreteType(Context& context, SemIR::TypeId type_id,
|
||||
: SemIR::ErrorInst::SingletonTypeId;
|
||||
}
|
||||
|
||||
auto NoteIncompleteClass(Context& context, SemIR::ClassId class_id,
|
||||
Context::DiagnosticBuilder& builder) -> void {
|
||||
const auto& class_info = context.classes().Get(class_id);
|
||||
CARBON_CHECK(!class_info.is_defined(), "Class is not incomplete");
|
||||
if (class_info.has_definition_started()) {
|
||||
CARBON_DIAGNOSTIC(ClassIncompleteWithinDefinition, Note,
|
||||
"class is incomplete within its definition");
|
||||
builder.Note(class_info.definition_id, ClassIncompleteWithinDefinition);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(ClassForwardDeclaredHere, Note,
|
||||
"class was forward declared here");
|
||||
builder.Note(class_info.latest_decl_id(), ClassForwardDeclaredHere);
|
||||
}
|
||||
}
|
||||
|
||||
auto NoteUndefinedInterface(Context& context, SemIR::InterfaceId interface_id,
|
||||
Context::DiagnosticBuilder& builder) -> void {
|
||||
const auto& interface_info = context.interfaces().Get(interface_id);
|
||||
CARBON_CHECK(!interface_info.is_defined(), "Interface is not incomplete");
|
||||
if (interface_info.is_being_defined()) {
|
||||
CARBON_DIAGNOSTIC(InterfaceUndefinedWithinDefinition, Note,
|
||||
"interface is currently being defined");
|
||||
builder.Note(interface_info.definition_id,
|
||||
InterfaceUndefinedWithinDefinition);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(InterfaceForwardDeclaredHere, Note,
|
||||
"interface was forward declared here");
|
||||
builder.Note(interface_info.latest_decl_id(), InterfaceForwardDeclaredHere);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
@@ -73,6 +73,14 @@ auto AsConcreteType(Context& context, SemIR::TypeId type_id,
|
||||
Context::BuildDiagnosticFn abstract_diagnoser)
|
||||
-> SemIR::TypeId;
|
||||
|
||||
// Adds a note to a diagnostic explaining that a class is incomplete.
|
||||
auto NoteIncompleteClass(Context& context, SemIR::ClassId class_id,
|
||||
Context::DiagnosticBuilder& builder) -> void;
|
||||
|
||||
// Adds a note to a diagnostic explaining that an interface is not defined.
|
||||
auto NoteUndefinedInterface(Context& context, SemIR::InterfaceId interface_id,
|
||||
Context::DiagnosticBuilder& builder) -> void;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_TYPE_COMPLETION_H_
|
||||
|
||||
Reference in New Issue
Block a user