diff --git a/explorer/ast/static_scope.cpp b/explorer/ast/static_scope.cpp index 38626c9dd99e..2e0a5b043047 100644 --- a/explorer/ast/static_scope.cpp +++ b/explorer/ast/static_scope.cpp @@ -52,14 +52,21 @@ auto StaticScope::Resolve(std::string_view name, return *result; } -auto StaticScope::ResolveHere(std::string_view name, SourceLocation source_loc, +auto StaticScope::ResolveHere(std::optional this_scope, + std::string_view name, SourceLocation source_loc, bool allow_undeclared) const -> ErrorOr { CARBON_ASSIGN_OR_RETURN(std::optional result, TryResolveHere(name, source_loc, allow_undeclared)); if (!result) { - return ProgramError(source_loc) - << "could not resolve '" << name << "' in this scope"; + if (this_scope) { + return ProgramError(source_loc) + << "name '" << name << "' has not been declared in " + << PrintAsID(this_scope->base()); + } else { + return ProgramError(source_loc) + << "name '" << name << "' has not been declared in this scope"; + } } return *result; } diff --git a/explorer/ast/static_scope.h b/explorer/ast/static_scope.h index a5065db5574a..79da6b2e86a3 100644 --- a/explorer/ast/static_scope.h +++ b/explorer/ast/static_scope.h @@ -65,7 +65,8 @@ class StaticScope { // error at `source_loc` if the name is not declared in this scope. If // `allow_undeclared` is `true`, names that have been added but not yet marked // declared or usable do not result in an error. - auto ResolveHere(std::string_view name, SourceLocation source_loc, + auto ResolveHere(std::optional this_scope, + std::string_view name, SourceLocation source_loc, bool allow_undeclared) const -> ErrorOr; // Returns the value node of the BindingPattern of the returned var definition diff --git a/explorer/interpreter/resolve_names.cpp b/explorer/interpreter/resolve_names.cpp index 025c05fc350b..e5a3ed07b67b 100644 --- a/explorer/interpreter/resolve_names.cpp +++ b/explorer/interpreter/resolve_names.cpp @@ -113,14 +113,16 @@ auto NameResolver::ResolveQualifier(DeclaredName name, bool allow_undeclared) -> ErrorOr> { Nonnull scope = &enclosing_scope; + std::optional scope_node; for (const auto& [loc, qualifier] : name.qualifiers()) { // TODO: If we permit qualified names anywhere other than the top level, we // will need to decide whether the first name in the qualifier is looked up // only in the innermost enclosing scope or in all enclosing scopes. CARBON_ASSIGN_OR_RETURN( ValueNodeView node, - scope->ResolveHere(qualifier, loc, allow_undeclared)); + scope->ResolveHere(scope_node, qualifier, loc, allow_undeclared)); + scope_node = node; if (const auto* namespace_decl = dyn_cast(&node.base())) { scope = &namespace_scopes_[namespace_decl]; @@ -282,7 +284,8 @@ auto NameResolver::ResolveNames(Expression& expression, << "name resolved to undeclared namespace"; CARBON_ASSIGN_OR_RETURN( const auto value_node, - ns_it->second.ResolveHere(access.member_name(), access.source_loc(), + ns_it->second.ResolveHere(scope, access.member_name(), + access.source_loc(), /*allow_undeclared=*/false)); access.set_value_node(value_node); return {value_node}; diff --git a/explorer/testdata/namespace/fail_unknown_member.carbon b/explorer/testdata/namespace/fail_unknown_member.carbon index 2f52cb98bd72..21a3ed2df814 100644 --- a/explorer/testdata/namespace/fail_unknown_member.carbon +++ b/explorer/testdata/namespace/fail_unknown_member.carbon @@ -11,6 +11,6 @@ package ExplorerTest api; namespace N; fn Main() -> i32 { - // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/namespace/fail_unknown_member.carbon:[[@LINE+1]]: could not resolve 'value' in this scope + // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/namespace/fail_unknown_member.carbon:[[@LINE+1]]: name 'value' has not been declared in namespace N return N.value; } diff --git a/explorer/testdata/namespace/fail_unknown_namespace.carbon b/explorer/testdata/namespace/fail_unknown_namespace.carbon index 8df20bbe31d1..8c0c2cd55dcd 100644 --- a/explorer/testdata/namespace/fail_unknown_namespace.carbon +++ b/explorer/testdata/namespace/fail_unknown_namespace.carbon @@ -8,7 +8,7 @@ package ExplorerTest api; -// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/namespace/fail_unknown_namespace.carbon:[[@LINE+1]]: could not resolve 'N' in this scope +// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/namespace/fail_unknown_namespace.carbon:[[@LINE+1]]: name 'N' has not been declared in this scope fn N.F() {} fn Main() -> i32 {