Only look in facet types for name scopes when they have constraints (#7819)

This falls back to diagnosing that values of type `type` can not be used
for name lookup more consistently.
This commit is contained in:
Dana Jansens
2026-09-23 17:50:34 +00:00
committed by GitHub
parent efbe1d2489
commit 15e3eeaca9
4 changed files with 21 additions and 15 deletions
+16 -6
View File
@@ -21,6 +21,7 @@
#include "toolchain/sem_ir/generic.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/name_scope.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::Check {
@@ -323,15 +324,16 @@ auto AppendLookupScopesForConstant(Context& context, SemIR::LocId loc_id,
llvm::SmallVector<LookupScope>* scopes)
-> bool {
auto lookup_inst_id = context.constant_values().GetInstId(lookup_const_id);
auto lookup = context.insts().Get(lookup_inst_id);
if (auto ns = lookup.TryAs<SemIR::Namespace>()) {
if (auto ns = context.insts().TryGetAs<SemIR::Namespace>(lookup_inst_id)) {
scopes->push_back(LookupScope{.name_scope_id = ns->name_scope_id,
.specific_id = SemIR::SpecificId::None,
.self_const_id = SemIR::ConstantId::None});
return true;
}
if (auto class_ty = lookup.TryAs<SemIR::ClassType>()) {
if (auto class_ty =
context.insts().TryGetAs<SemIR::ClassType>(lookup_inst_id)) {
if (!extended_scope) {
// TODO: Allow name lookup into classes that are being defined even if
// they are not complete.
@@ -351,8 +353,14 @@ auto AppendLookupScopesForConstant(Context& context, SemIR::LocId loc_id,
.self_const_id = self_type_const_id});
return true;
}
// Extended scopes may point to a FacetType.
if (auto facet_type = lookup.TryAs<SemIR::FacetType>()) {
// Extended scopes may point to a FacetType. If it has constraints, collect
// the extended ones as scopes.
auto lookup_type_id =
context.types().TryGetTypeIdForTypeInstId(lookup_inst_id);
if (lookup_type_id.has_value() &&
context.types().IsConstrainedFacetType(lookup_type_id)) {
auto facet_type = context.types().GetAs<SemIR::FacetType>(lookup_type_id);
if (!extended_scope) {
// TODO: Allow name lookup into facet types that are being defined even if
// they are not complete.
@@ -378,7 +386,7 @@ auto AppendLookupScopesForConstant(Context& context, SemIR::LocId loc_id,
}
auto declared_facet_type =
context.declared_facet_types().Get(facet_type->declared_facet_type_id);
context.declared_facet_types().Get(facet_type.declared_facet_type_id);
// Name lookup into "extend" constraints but not "self impls" constraints.
for (const auto& extend : declared_facet_type.extend_constraints) {
auto& interface = context.interfaces().Get(extend.interface_id);
@@ -413,6 +421,7 @@ auto AppendLookupScopesForConstant(Context& context, SemIR::LocId loc_id,
}
return true;
}
if (lookup_const_id == SemIR::ErrorInst::ConstantId) {
// Lookup into this scope should fail without producing an error.
scopes->push_back(LookupScope{.name_scope_id = SemIR::NameScopeId::None,
@@ -420,6 +429,7 @@ auto AppendLookupScopesForConstant(Context& context, SemIR::LocId loc_id,
.self_const_id = SemIR::ConstantId::None});
return true;
}
// TODO: Per the design, if `base_id` is any kind of type, then lookup should
// treat it as a name scope, even if it doesn't have members. For example,
// `(i32*).X` should fail because there's no name `X` in `i32*`, not because
@@ -32,7 +32,7 @@ interface Z {
let X: type;
}
// CHECK:STDERR: fail_todo_struct_access_through_witness.carbon:[[@LINE+4]]:43: error: member name `t` not found [MemberNameNotFound]
// CHECK:STDERR: fail_todo_struct_access_through_witness.carbon:[[@LINE+4]]:43: error: type `type` does not support qualified expressions [QualifiedExprUnsupported]
// CHECK:STDERR: fn F(generic T: Z where .X = {.t: ()}) -> T.X.t {
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
+1 -1
View File
@@ -148,7 +148,7 @@ fn F(T: Z) {
library "[[@TEST_NAME]]";
fn F(T: type) {
// CHECK:STDERR: fail_member_access_runtime_type.carbon:[[@LINE+4]]:3: error: member name `G` not found [MemberNameNotFound]
// CHECK:STDERR: fail_member_access_runtime_type.carbon:[[@LINE+4]]:3: error: type `type` does not support qualified expressions [QualifiedExprUnsupported]
// CHECK:STDERR: T.G();
// CHECK:STDERR: ^~~
// CHECK:STDERR:
@@ -16,7 +16,7 @@
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_lookup_in_type.carbon:[[@LINE+4]]:8: error: member name `not_found` not found [MemberNameNotFound]
// CHECK:STDERR: fail_lookup_in_type.carbon:[[@LINE+4]]:8: error: type `type` does not support qualified expressions [QualifiedExprUnsupported]
// CHECK:STDERR: let T: type.not_found = {};
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR:
@@ -26,7 +26,7 @@ let T: type.not_found = {};
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_lookup_type_where.carbon:[[@LINE+4]]:8: error: member name `missing` not found [MemberNameNotFound]
// CHECK:STDERR: fail_lookup_type_where.carbon:[[@LINE+4]]:8: error: type `type` does not support qualified expressions [QualifiedExprUnsupported]
// CHECK:STDERR: let U: (type where .Self impls type).missing = {};
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
@@ -44,10 +44,7 @@ let U: (type where .Self impls type).missing = {};
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .T = %T
// CHECK:STDOUT: }
// CHECK:STDOUT: %.1: <error> = splice_block <error> [concrete = <error>] {
// CHECK:STDOUT: %.loc8: type = type_literal type [concrete = type]
// CHECK:STDOUT: %not_found.ref: <error> = name_ref not_found, <error> [concrete = <error>]
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc8: type = type_literal type [concrete = type]
// CHECK:STDOUT: %T: <error> = wrapper_binding T, <error> [concrete = <error>]
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %T.patt: <error> = value_binding_pattern T [concrete = <error>]
@@ -88,7 +85,6 @@ let U: (type where .Self impls type).missing = {};
// CHECK:STDOUT: %base_facet_type = requirement_base_facet_type %.loc8_9 [concrete]
// CHECK:STDOUT: %impls.loc8_26.2 = requirement_impls %.Self.ref.loc8_20.2, %.loc8_32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %missing.ref: <error> = name_ref missing, <error> [concrete = <error>]
// CHECK:STDOUT: }
// CHECK:STDOUT: %U: <error> = wrapper_binding U, <error> [concrete = <error>]
// CHECK:STDOUT: name_binding_decl {