Support unqualified lookup into extended interfaces from classes and impls (#7217)

When a class extends an interface, referring to a member name of the
interface as an unqualified name should refer to the class's
corresponding associated entity value, not to the associated entity
itself. Similarly, in an `impl`, unqualified names of associated
entities should refer to the `impl`'s corresponding value for that
entity.

To support this, we treat `impl`s as `extend`ing their implemented facet
type, and we make lookups into an extended facet type use the `Self`
type of the extending `impl` or `class` if lookup finds an associated
entity. We already did the latter if the extending entity was an
interface; this extends the existing support for these other cases.
This commit is contained in:
Richard Smith
2026-05-19 18:01:54 +00:00
committed by GitHub
parent 0d7c4a99eb
commit ce080b3549
112 changed files with 962 additions and 4125 deletions
+14 -10
View File
@@ -184,9 +184,15 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
SemIR::FunctionDecl& function_decl,
SemIR::Function& function_info, bool is_definition)
-> void {
// Diagnose if we are declaring a poisoned name. However, don't diagnose at
// impl scope: if the name was referenced before being declared, we will have
// produced an error already.
if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
DiagnosePoisonedName(context, name_context.name_id_for_new_inst(),
name_context.poisoning_loc_id, name_context.loc_id);
if (!context.name_scopes().InstIs<SemIR::ImplDecl>(
name_context.parent_scope_id)) {
DiagnosePoisonedName(context, name_context.name_id_for_new_inst(),
name_context.poisoning_loc_id, name_context.loc_id);
}
return;
}
@@ -200,8 +206,7 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
auto prev_import_ir_id = SemIR::ImportIRId::None;
CARBON_KIND_SWITCH(context.insts().Get(prev_id)) {
case CARBON_KIND(SemIR::AssociatedEntity assoc_entity): {
// This is a function in an interface definition scope (see
// NameScope::is_interface_definition()).
// This is a function in an interface definition scope.
auto function_decl =
context.insts().GetAs<SemIR::FunctionDecl>(assoc_entity.decl_id);
prev_function_id = function_decl.function_id;
@@ -260,7 +265,7 @@ static auto MaybeAddToNameLookup(Context& context,
const KeywordModifierSet& modifier_set,
SemIR::NameScopeId parent_scope_id,
SemIR::InstId decl_id) -> void {
if (name_context.state == DeclNameStack::NameContext::State::Poisoned ||
if (name_context.state != DeclNameStack::NameContext::State::Poisoned &&
name_context.prev_inst_id().has_value()) {
return;
}
@@ -269,12 +274,11 @@ static auto MaybeAddToNameLookup(Context& context,
// function.
auto lookup_result_id = decl_id;
if (parent_scope_id.has_value() && !name_context.has_qualifiers) {
const auto& parent_scope = context.name_scopes().Get(parent_scope_id);
if (parent_scope.is_interface_definition()) {
auto interface_decl = context.insts().GetAs<SemIR::InterfaceWithSelfDecl>(
parent_scope.inst_id());
if (auto interface_decl =
context.name_scopes().TryGetInstAs<SemIR::InterfaceWithSelfDecl>(
parent_scope_id)) {
lookup_result_id =
BuildAssociatedEntity(context, interface_decl.interface_id, decl_id);
BuildAssociatedEntity(context, interface_decl->interface_id, decl_id);
}
}