// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef CARBON_TOOLCHAIN_CHECK_NODE_ID_TRAVERSAL_H_ #define CARBON_TOOLCHAIN_CHECK_NODE_ID_TRAVERSAL_H_ #include "common/ostream.h" #include "llvm/ADT/SmallVector.h" #include "toolchain/check/context.h" #include "toolchain/check/deferred_definition_worklist.h" #include "toolchain/parse/tree.h" namespace Carbon::Check { // A traversal of the node IDs in the parse tree, in the order in which we need // to check them. class NodeIdTraversal { public: // `context` must not be null. explicit NodeIdTraversal(Context* context); // Finds the next `NodeId` to type-check. Returns nullopt if the traversal is // complete. auto Next() -> std::optional; // Performs any processing necessary after we type-check a node. auto Handle(Parse::NodeKind parse_kind) -> void; private: // State used to track the next deferred function definition that we will // encounter and need to reorder. class NextDeferredDefinitionCache { public: explicit NextDeferredDefinitionCache(const Parse::Tree* tree); // Set the specified deferred definition index as being the next one that // will be encountered. auto SkipTo(Parse::DeferredDefinitionIndex next_index) -> void; // Returns the index of the next deferred definition to be encountered. auto index() const -> Parse::DeferredDefinitionIndex { return index_; } // Returns the ID of the start node of the next deferred definition. auto start_id() const -> Parse::NodeId { return start_id_; } private: const Parse::Tree* tree_; Parse::DeferredDefinitionIndex index_ = Parse::DeferredDefinitionIndex::None; Parse::NodeId start_id_ = Parse::NodeId::None; }; // A chunk of the parse tree that we need to type-check. struct Chunk { Parse::Tree::PostorderIterator it; Parse::Tree::PostorderIterator end; // The next definition that will be encountered after this chunk completes. Parse::DeferredDefinitionIndex next_definition; // Whether we are currently checking deferred definitions, rather than the // tokens of this chunk. If so, we'll pull tasks off `worklist` and execute // them until we're done with this batch of deferred definitions. Otherwise, // we'll pull node IDs from `*it` until it reaches `end`. bool checking_deferred_definitions = false; // If we're checking deferred definitions, the index of the first task to // execute from `worklist`. size_t first_worklist_index; // If we're checking deferred definitions, the index of the next task to // execute from `worklist`. size_t next_worklist_index; }; auto worklist() -> DeferredDefinitionWorklist& { return *worklist_; } // Re-enter a nested deferred definition scope. auto PerformTask( DeferredDefinitionWorklist::EnterNestedDeferredDefinitionScope&& enter) -> void; // Leave a nested deferred definition scope. auto PerformTask( DeferredDefinitionWorklist::LeaveNestedDeferredDefinitionScope&& leave) -> void; // Resume checking a deferred definition. auto PerformTask( DeferredDefinitionWorklist::CheckSkippedDefinition&& parse_definition) -> void; // Define a thunk. auto PerformTask(DeferredDefinitionWorklist::DefineThunk&& define_thunk) -> void; Context* context_; NextDeferredDefinitionCache next_deferred_definition_; DeferredDefinitionWorklist* worklist_; llvm::SmallVector chunks_; }; } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_NODE_ID_TRAVERSAL_H_