diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index c83aed6c3b2d..b44543b2d41f 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -52,7 +52,7 @@ Context::Context(DiagnosticEmitter* emitter, param_and_arg_refs_stack_(*sem_ir, vlog_stream, node_stack_), args_type_info_stack_("args_type_info_stack_", *sem_ir, vlog_stream), decl_name_stack_(this), - scope_stack_(sem_ir_->identifiers()), + scope_stack_(sem_ir_), vtable_stack_("vtable_stack_", *sem_ir, vlog_stream), global_init_(this), region_stack_( diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 39c5741ff439..385807cf60ea 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -287,13 +287,6 @@ class Context { auto NoteUndefinedInterface(SemIR::InterfaceId interface_id, DiagnosticBuilder& builder) -> void; - // Returns the current scope, if it is of the specified kind. Otherwise, - // returns nullopt. - template - auto GetCurrentScopeAs() -> std::optional { - return scope_stack().GetCurrentScopeAs(sem_ir()); - } - // Returns the type ID for a constant that is a type value, i.e. it is a value // of type `TypeType`. // @@ -390,12 +383,6 @@ class Context { auto Finalize() -> void; - // True if the current file is an impl file. - auto IsImplFile() -> bool { - return sem_ir_->import_irs().Get(SemIR::ImportIRId::ApiForImpl).sem_ir != - nullptr; - } - // Prints information for a stack dump. auto PrintForStackDump(llvm::raw_ostream& output) const -> void; diff --git a/toolchain/check/handle_binding_pattern.cpp b/toolchain/check/handle_binding_pattern.cpp index 04ce50c0d7a5..e4ac7851e90d 100644 --- a/toolchain/check/handle_binding_pattern.cpp +++ b/toolchain/check/handle_binding_pattern.cpp @@ -111,7 +111,8 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, // A `var` binding in a class scope declares a field, not a true binding, // so we handle it separately. - if (auto parent_class_decl = context.GetCurrentScopeAs(); + if (auto parent_class_decl = + context.scope_stack().GetCurrentScopeAs(); parent_class_decl.has_value() && node_kind == Parse::NodeKind::VarBindingPattern) { cast_type_id = AsConcreteType( @@ -152,7 +153,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, // A binding in an interface scope declares an associated constant, not a // true binding, so we handle it separately. if (auto parent_interface_decl = - context.GetCurrentScopeAs(); + context.scope_stack().GetCurrentScopeAs(); parent_interface_decl.has_value() && is_generic) { cast_type_id = AsCompleteType(context, cast_type_id, type_node, [&] { CARBON_DIAGNOSTIC(IncompleteTypeInAssociatedDecl, Error, diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index 24e1e1b75c6c..16480b593318 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -10,6 +10,7 @@ #include "toolchain/check/eval.h" #include "toolchain/check/generic.h" #include "toolchain/check/handle.h" +#include "toolchain/check/import.h" #include "toolchain/check/import_ref.h" #include "toolchain/check/merge.h" #include "toolchain/check/modifiers.h" @@ -265,7 +266,7 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id, .specific_id = specific_id})); } - if (!is_definition && context.IsImplFile() && !is_extern) { + if (!is_definition && context.sem_ir().is_impl() && !is_extern) { context.definitions_required().push_back(class_decl_id); } @@ -333,7 +334,8 @@ static auto DiagnoseClassSpecificDeclOutsideClass(Context& context, static auto GetCurrentScopeAsClassOrDiagnose(Context& context, SemIRLoc loc, Lex::TokenKind tok) -> std::optional { - auto class_scope = context.GetCurrentScopeAs(); + auto class_scope = + context.scope_stack().GetCurrentScopeAs(); if (!class_scope) { DiagnoseClassSpecificDeclOutsideClass(context, loc, tok); } diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 83b937106e85..47360d946e92 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -11,6 +11,7 @@ #include "toolchain/check/function.h" #include "toolchain/check/generic.h" #include "toolchain/check/handle.h" +#include "toolchain/check/import.h" #include "toolchain/check/import_ref.h" #include "toolchain/check/interface.h" #include "toolchain/check/literal.h" @@ -280,7 +281,7 @@ static auto BuildFunctionDecl(Context& context, // Create a new function if this isn't a valid redeclaration. if (!function_decl.function_id.has_value()) { - if (function_info.is_extern && context.IsImplFile()) { + if (function_info.is_extern && context.sem_ir().is_impl()) { DiagnoseExternRequiresDeclInApiFile(context, node_id); } function_info.generic_id = BuildGenericDecl(context, decl_id); @@ -343,7 +344,7 @@ static auto BuildFunctionDecl(Context& context, } } - if (!is_definition && context.IsImplFile() && !is_extern) { + if (!is_definition && context.sem_ir().is_impl() && !is_extern) { context.definitions_required().push_back(decl_id); } diff --git a/toolchain/check/handle_let_and_var.cpp b/toolchain/check/handle_let_and_var.cpp index 742d0dd53b01..052e7991cd6a 100644 --- a/toolchain/check/handle_let_and_var.cpp +++ b/toolchain/check/handle_let_and_var.cpp @@ -88,7 +88,7 @@ static auto HandleIntroducer(Context& context, Parse::NodeId node_id) -> bool { } auto HandleParseNode(Context& context, Parse::LetIntroducerId node_id) -> bool { - if (context.GetCurrentScopeAs()) { + if (context.scope_stack().GetCurrentScopeAs()) { StartAssociatedConstant(context); } @@ -154,7 +154,7 @@ auto HandleParseNode(Context& context, Parse::VariablePatternId node_id) // Handle the end of the full-pattern of a let/var declaration (before the // start of the initializer, if any). static auto EndFullPattern(Context& context) -> void { - if (context.GetCurrentScopeAs()) { + if (context.scope_stack().GetCurrentScopeAs()) { // Don't emit NameBindingDecl for an associated constant, because it will // always be empty. context.pattern_block_stack().PopAndDiscard(); @@ -190,7 +190,8 @@ static auto HandleInitializer(Context& context, Parse::NodeId node_id) -> bool { auto HandleParseNode(Context& context, Parse::LetInitializerId node_id) -> bool { - if (auto interface_decl = context.GetCurrentScopeAs()) { + if (auto interface_decl = + context.scope_stack().GetCurrentScopeAs()) { EndAssociatedConstantDeclRegion(context, interface_decl->interface_id); // Start building the definition region of the constant. @@ -239,7 +240,7 @@ static auto HandleDecl(Context& context) -> DeclInfo { // now. We will have done this at the `=` if there was an initializer. if (IntroducerTokenKind == Lex::TokenKind::Let) { if (auto interface_decl = - context.GetCurrentScopeAs()) { + context.scope_stack().GetCurrentScopeAs()) { EndAssociatedConstantDeclRegion(context, interface_decl->interface_id); } } @@ -347,7 +348,7 @@ auto HandleParseNode(Context& context, Parse::LetDeclId node_id) -> bool { // At interface scope, we are forming an associated constant, which has // different rules. if (auto interface_scope = - context.GetCurrentScopeAs()) { + context.scope_stack().GetCurrentScopeAs()) { FinishAssociatedConstant(context, node_id, interface_scope->interface_id, decl_info); return true; @@ -379,7 +380,7 @@ auto HandleParseNode(Context& context, Parse::VariableDeclId node_id) -> bool { context, decl_info.introducer, KeywordModifierSet::Access | KeywordModifierSet::Returned); - if (context.GetCurrentScopeAs()) { + if (context.scope_stack().GetCurrentScopeAs()) { if (decl_info.init_id.has_value()) { // TODO: In a class scope, we should instead save the initializer // somewhere so that we can use it as a default. @@ -387,7 +388,7 @@ auto HandleParseNode(Context& context, Parse::VariableDeclId node_id) -> bool { } return true; } - if (context.GetCurrentScopeAs()) { + if (context.scope_stack().GetCurrentScopeAs()) { CARBON_DIAGNOSTIC(VarInInterfaceDecl, Error, "`var` declaration in interface"); context.emitter().Emit(node_id, VarInInterfaceDecl); diff --git a/toolchain/check/merge.cpp b/toolchain/check/merge.cpp index 0810296319b0..82481ad3464a 100644 --- a/toolchain/check/merge.cpp +++ b/toolchain/check/merge.cpp @@ -5,6 +5,7 @@ #include "toolchain/check/merge.h" #include "toolchain/base/kind_switch.h" +#include "toolchain/check/import.h" #include "toolchain/check/import_ref.h" #include "toolchain/diagnostics/format_providers.h" #include "toolchain/sem_ir/ids.h" @@ -135,7 +136,7 @@ auto DiagnoseIfInvalidRedecl(Context& context, Lex::TokenKind decl_kind, } // Check for disallowed redeclarations cross-library. - if (new_decl.is_extern && context.IsImplFile()) { + if (new_decl.is_extern && context.sem_ir().is_impl()) { // We continue after issuing the "missing API declaration" diagnostic, // because it may still be helpful to note other issues with the // declarations. diff --git a/toolchain/check/scope_stack.h b/toolchain/check/scope_stack.h index fd4a2cf88435..2169578e6063 100644 --- a/toolchain/check/scope_stack.h +++ b/toolchain/check/scope_stack.h @@ -20,8 +20,10 @@ namespace Carbon::Check { // checking within. class ScopeStack { public: - explicit ScopeStack(const CanonicalValueStore& identifiers) - : lexical_lookup_(identifiers), full_pattern_stack_(&lexical_lookup_) {} + explicit ScopeStack(const SemIR::File* sem_ir) + : sem_ir_(sem_ir), + lexical_lookup_(sem_ir->identifiers()), + full_pattern_stack_(&lexical_lookup_) {} // A scope in which `break` and `continue` can be used. struct BreakContinueScope { @@ -99,12 +101,12 @@ class ScopeStack { // Returns the current scope, if it is of the specified kind. Otherwise, // returns nullopt. template - auto GetCurrentScopeAs(const SemIR::File& sem_ir) -> std::optional { + auto GetCurrentScopeAs() -> std::optional { auto inst_id = PeekInstId(); if (!inst_id.has_value()) { return std::nullopt; } - return sem_ir.insts().TryGetAs(inst_id); + return sem_ir_->insts().TryGetAs(inst_id); } // If there is no `returned var` in scope, sets the given instruction to be @@ -225,6 +227,9 @@ class ScopeStack { auto VerifyNextCompileTimeBindIndex(llvm::StringLiteral label, const ScopeStackEntry& scope) -> void; + // The current file. + const SemIR::File* sem_ir_; + // A stack of scopes from which we can `return`. llvm::SmallVector return_scope_stack_; diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index dc11be538b66..dee93e92eae5 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -94,6 +94,11 @@ class File : public Printable { return types().GetAs(pointer_id).pointee_id; } + // Returns true if this file is an `impl`. + auto is_impl() -> bool { + return import_irs().Get(SemIR::ImportIRId::ApiForImpl).sem_ir != nullptr; + } + auto check_ir_id() const -> CheckIRId { return check_ir_id_; } auto package_id() const -> PackageNameId { return package_id_; } auto library_id() const -> SemIR::LibraryNameId { return library_id_; }