Skip to content

Commit c67920e

Browse files
authored
When diagnosing name used before declared, set the location of the usage (#4860)
Done by adding a poisoning location for each poisoned name. Part of #4622.
1 parent a8aca3c commit c67920e

File tree

14 files changed

+246
-120
lines changed

14 files changed

+246
-120
lines changed

toolchain/check/context.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -223,15 +223,15 @@ auto Context::DiagnoseDuplicateName(SemIRLoc dup_def, SemIRLoc prev_def)
223223
.Emit();
224224
}
225225

226-
auto Context::DiagnosePoisonedName(SemIR::InstId loc) -> void {
227-
// TODO: Improve the diagnostic to replace NodeId::None with the location
228-
// where the name was poisoned. See discussion in
229-
// https://github.com/carbon-language/carbon-lang/pull/4654#discussion_r1876607172
226+
auto Context::DiagnosePoisonedName(SemIR::LocId poisoning_loc_id,
227+
SemIR::InstId decl_inst_id) -> void {
228+
CARBON_CHECK(poisoning_loc_id.has_value(),
229+
"Trying to diagnose poisoned name with no poisoning location");
230230
CARBON_DIAGNOSTIC(NameUseBeforeDecl, Error,
231231
"name used before it was declared");
232232
CARBON_DIAGNOSTIC(NameUseBeforeDeclNote, Note, "declared here");
233-
emitter_->Build(SemIR::LocId::None, NameUseBeforeDecl)
234-
.Note(loc, NameUseBeforeDeclNote)
233+
emitter_->Build(poisoning_loc_id, NameUseBeforeDecl)
234+
.Note(decl_inst_id, NameUseBeforeDeclNote)
235235
.Emit();
236236
}
237237

@@ -421,13 +421,14 @@ auto Context::LookupUnqualifiedName(Parse::NodeId node_id,
421421
.scope_result = SemIR::ScopeLookupResult::MakeError()};
422422
}
423423

424-
auto Context::LookupNameInExactScope(SemIRLoc loc, SemIR::NameId name_id,
424+
auto Context::LookupNameInExactScope(SemIR::LocId loc_id, SemIR::NameId name_id,
425425
SemIR::NameScopeId scope_id,
426426
SemIR::NameScope& scope,
427427
bool is_being_declared)
428428
-> SemIR::ScopeLookupResult {
429-
if (auto entry_id = is_being_declared ? scope.Lookup(name_id)
430-
: scope.LookupOrPoison(name_id)) {
429+
if (auto entry_id = is_being_declared
430+
? scope.Lookup(name_id)
431+
: scope.LookupOrPoison(loc_id, name_id)) {
431432
auto lookup_result = scope.GetEntry(*entry_id).result;
432433
if (!lookup_result.is_poisoned()) {
433434
LoadImportRef(*this, lookup_result.target_inst_id());
@@ -438,7 +439,7 @@ auto Context::LookupNameInExactScope(SemIRLoc loc, SemIR::NameId name_id,
438439
if (!scope.import_ir_scopes().empty()) {
439440
// TODO: Enforce other access modifiers for imports.
440441
return SemIR::ScopeLookupResult::MakeWrappedLookupResult(
441-
ImportNameFromOtherPackage(*this, loc, scope_id,
442+
ImportNameFromOtherPackage(*this, loc_id, scope_id,
442443
scope.import_ir_scopes(), name_id),
443444
SemIR::AccessKind::Public);
444445
}

toolchain/check/context.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,7 @@ class Context {
215215

216216
// Performs name lookup in a specified scope for a name appearing in a
217217
// declaration. If scope_id is `None`, performs lookup into the lexical scope
218-
// specified by scope_index instead. If found, returns the referenced
219-
// `InstId` and false. If poisoned, returns `InstId::None` and true.
220-
// TODO: For poisoned names, return the poisoning `InstId`.
218+
// specified by scope_index instead.
221219
auto LookupNameInDecl(SemIR::LocId loc_id, SemIR::NameId name_id,
222220
SemIR::NameScopeId scope_id, ScopeIndex scope_index)
223221
-> SemIR::ScopeLookupResult;
@@ -235,7 +233,7 @@ class Context {
235233
// poisoned name will be treated as if it is not declared. Otherwise, this is
236234
// a lookup for a name being declared, so the name will not be poisoned, but
237235
// poison will be returned if it's already been looked up.
238-
auto LookupNameInExactScope(SemIRLoc loc, SemIR::NameId name_id,
236+
auto LookupNameInExactScope(SemIR::LocId loc_id, SemIR::NameId name_id,
239237
SemIR::NameScopeId scope_id,
240238
SemIR::NameScope& scope,
241239
bool is_being_declared = false)
@@ -265,8 +263,9 @@ class Context {
265263
// Prints a diagnostic for a duplicate name.
266264
auto DiagnoseDuplicateName(SemIRLoc dup_def, SemIRLoc prev_def) -> void;
267265

268-
// Prints a diagnostic for a poisoned name.
269-
auto DiagnosePoisonedName(SemIR::InstId loc) -> void;
266+
// Prints a diagnostic for a poisoned name when it's later declared.
267+
auto DiagnosePoisonedName(SemIR::LocId poisoning_loc_id,
268+
SemIR::InstId decl_inst_id) -> void;
270269

271270
// Prints a diagnostic for a missing name.
272271
auto DiagnoseNameNotFound(SemIRLoc loc, SemIR::NameId name_id) -> void;

toolchain/check/decl_name_stack.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ auto DeclNameStack::AddNameOrDiagnose(NameContext name_context,
175175
SemIR::InstId target_id,
176176
SemIR::AccessKind access_kind) -> void {
177177
if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
178-
context_->DiagnosePoisonedName(target_id);
178+
context_->DiagnosePoisonedName(name_context.poisoning_loc_id, target_id);
179179
} else if (auto id = name_context.prev_inst_id(); id.has_value()) {
180180
context_->DiagnoseDuplicateName(target_id, id);
181181
} else {
@@ -188,7 +188,8 @@ auto DeclNameStack::LookupOrAddName(NameContext name_context,
188188
SemIR::AccessKind access_kind)
189189
-> SemIR::ScopeLookupResult {
190190
if (name_context.state == NameContext::State::Poisoned) {
191-
return SemIR::ScopeLookupResult::MakePoisoned();
191+
return SemIR::ScopeLookupResult::MakePoisoned(
192+
name_context.poisoning_loc_id);
192193
}
193194
if (auto id = name_context.prev_inst_id(); id.has_value()) {
194195
return SemIR::ScopeLookupResult::MakeFound(id, access_kind);
@@ -267,6 +268,7 @@ auto DeclNameStack::ApplyAndLookupName(NameContext& name_context,
267268
name_context.initial_scope_index);
268269
if (lookup_result.is_poisoned()) {
269270
name_context.unresolved_name_id = name_id;
271+
name_context.poisoning_loc_id = lookup_result.poisoning_loc_id();
270272
name_context.state = NameContext::State::Poisoned;
271273
} else if (!lookup_result.is_found()) {
272274
// Invalid indicates an unresolved name. Store it and return.

toolchain/check/decl_name_stack.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ class DeclNameStack {
156156
// The ID of an unresolved identifier.
157157
SemIR::NameId unresolved_name_id = SemIR::NameId::None;
158158
};
159+
160+
// When `state` is `Poisoned` (name is unresolved due to name poisoning),
161+
// the poisoning location.
162+
SemIR::LocId poisoning_loc_id = SemIR::LocId::None;
159163
};
160164

161165
// Information about a declaration name that has been temporarily removed from

toolchain/check/handle_class.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id,
109109
access_kind);
110110
if (lookup_result.is_poisoned()) {
111111
// This is a declaration of a poisoned name.
112-
context.DiagnosePoisonedName(class_decl_id);
112+
context.DiagnosePoisonedName(lookup_result.poisoning_loc_id(),
113+
class_decl_id);
113114
return;
114115
}
115116

toolchain/check/handle_function.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ static auto BuildFunctionDecl(Context& context,
255255
}
256256

257257
if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
258-
context.DiagnosePoisonedName(function_info.latest_decl_id());
258+
context.DiagnosePoisonedName(name_context.poisoning_loc_id,
259+
function_info.latest_decl_id());
259260
} else {
260261
TryMergeRedecl(context, node_id, name_context.prev_inst_id(), function_decl,
261262
function_info, is_definition);

toolchain/check/handle_interface.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ static auto BuildInterfaceDecl(Context& context,
6565
introducer.modifier_set.GetAccessKind());
6666
if (lookup_result.is_poisoned()) {
6767
// This is a declaration of a poisoned name.
68-
context.DiagnosePoisonedName(interface_decl_id);
68+
context.DiagnosePoisonedName(lookup_result.poisoning_loc_id(),
69+
interface_decl_id);
6970
} else if (lookup_result.is_found()) {
7071
SemIR::InstId existing_id = lookup_result.target_inst_id();
7172
if (auto existing_interface_decl =

toolchain/check/handle_namespace.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ auto HandleParseNode(Context& context, Parse::NamespaceId node_id) -> bool {
4646
context.decl_name_stack().LookupOrAddName(name_context, namespace_id,
4747
SemIR::AccessKind::Public);
4848
if (lookup_result.is_poisoned()) {
49-
context.DiagnosePoisonedName(namespace_id);
49+
context.DiagnosePoisonedName(lookup_result.poisoning_loc_id(),
50+
namespace_id);
5051
} else if (lookup_result.is_found()) {
5152
SemIR::InstId existing_inst_id = lookup_result.target_inst_id();
5253
if (auto existing =

toolchain/check/impl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ auto FinishImplWitness(Context& context, SemIR::Impl& impl) -> void {
376376
}
377377
auto& fn = context.functions().Get(fn_type->function_id);
378378
auto lookup_result = context.LookupNameInExactScope(
379-
decl_id, fn.name_id, impl.scope_id, impl_scope);
379+
context.insts().GetLocId(decl_id), fn.name_id, impl.scope_id,
380+
impl_scope);
380381
if (lookup_result.is_found()) {
381382
used_decl_ids.push_back(lookup_result.target_inst_id());
382383
witness_block[index] = CheckAssociatedFunctionImplementation(

0 commit comments

Comments
 (0)