deferred_definition_worklist.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_CHECK_DEFERRED_DEFINITION_WORKLIST_H_
  5. #define CARBON_TOOLCHAIN_CHECK_DEFERRED_DEFINITION_WORKLIST_H_
  6. #include <optional>
  7. #include <variant>
  8. #include "common/ostream.h"
  9. #include "llvm/ADT/SmallVector.h"
  10. #include "toolchain/check/decl_name_stack.h"
  11. #include "toolchain/check/function.h"
  12. #include "toolchain/parse/tree.h"
  13. namespace Carbon::Check {
  14. // A worklist of pending tasks to perform to check deferred function definitions
  15. // in the right order.
  16. class DeferredDefinitionWorklist {
  17. public:
  18. // A worklist task that indicates we should check a deferred function
  19. // definition that we previously skipped.
  20. struct CheckSkippedDefinition {
  21. // The definition that we skipped.
  22. Parse::DeferredDefinitionIndex definition_index;
  23. // The suspended function.
  24. SuspendedFunction suspended_fn;
  25. };
  26. // A worklist task that indicates we should enter a nested deferred definition
  27. // scope. We delay processing the contents of nested deferred definition
  28. // scopes until we reach the end of the parent scope. For example:
  29. //
  30. // ```
  31. // class A {
  32. // class B {
  33. // fn F() -> A { return {}; }
  34. // }
  35. // } // A.B.F is type-checked here, with A complete.
  36. //
  37. // fn F() {
  38. // class C {
  39. // fn G() {}
  40. // } // C.G is type-checked here.
  41. // }
  42. // ```
  43. struct EnterNestedDeferredDefinitionScope {
  44. // The suspended scope. This is only set once we reach the end of the scope.
  45. std::optional<DeclNameStack::SuspendedName> suspended_name;
  46. };
  47. // A worklist task that indicates we should leave a nested deferred definition
  48. // scope.
  49. struct LeaveNestedDeferredDefinitionScope {};
  50. // A pending type-checking task.
  51. using Task =
  52. std::variant<CheckSkippedDefinition, EnterNestedDeferredDefinitionScope,
  53. LeaveNestedDeferredDefinitionScope>;
  54. explicit DeferredDefinitionWorklist(llvm::raw_ostream* vlog_stream);
  55. // Suspends the current function definition and push a task onto the worklist
  56. // to finish it later.
  57. auto SuspendFunctionAndPush(Context& context,
  58. Parse::DeferredDefinitionIndex index,
  59. Parse::FunctionDefinitionStartId node_id) -> void;
  60. // Pushes a task to re-enter a function scope, so that functions defined
  61. // within it are type-checked in the right context. Returns whether a
  62. // non-nested scope was entered.
  63. auto PushEnterDeferredDefinitionScope(Context& context) -> bool;
  64. // The kind of scope that we just finished.
  65. enum class FinishedScopeKind {
  66. // We finished a nested scope. No further action is taken at this point.
  67. Nested,
  68. // We finished a non-nested scope that has no further actions to perform.
  69. NonNestedEmpty,
  70. // We finished a non-nested scope that has further actions to perform.
  71. NonNestedWithWork,
  72. };
  73. // Suspends the current deferred definition scope, which is finished but still
  74. // on the decl_name_stack, and pushes a task to leave the scope when we're
  75. // type-checking deferred definitions. Returns `true` if the current list of
  76. // deferred definitions should be type-checked immediately.
  77. auto SuspendFinishedScopeAndPush(Context& context) -> FinishedScopeKind;
  78. // Returns the current size of the worklist.
  79. auto size() const -> size_t { return worklist_.size(); }
  80. // Truncates the worklist to the given size.
  81. auto truncate(int new_size) -> void { worklist_.truncate(new_size); }
  82. // Gets the given item on the worklist.
  83. auto operator[](int index) -> Task& { return worklist_[index]; }
  84. // CHECK that the work list has no further work.
  85. auto VerifyEmpty() {
  86. CARBON_CHECK(worklist_.empty() && entered_scopes_.empty(),
  87. "Tasks left behind on worklist.");
  88. }
  89. private:
  90. // A deferred definition scope that is currently still open.
  91. struct EnteredScope {
  92. // Whether this scope is nested immediately within the enclosing scope. If
  93. // so, deferred definitions are not processed at the end of this scope.
  94. bool nested;
  95. // The index in worklist_ of the first task in this scope. For a nested
  96. // scope, this is a EnterNestedDeferredDefinitionScope task.
  97. size_t worklist_start_index;
  98. // The corresponding lexical scope index.
  99. ScopeIndex scope_index;
  100. };
  101. llvm::raw_ostream* vlog_stream_;
  102. // A worklist of type-checking tasks we'll need to do later.
  103. //
  104. // Don't allocate any inline storage here. A Task is fairly large, so we never
  105. // want this to live on the stack. Instead, we reserve space in the
  106. // constructor for a fairly large number of deferred definitions.
  107. llvm::SmallVector<Task, 0> worklist_;
  108. // The deferred definition scopes for the current checking actions.
  109. llvm::SmallVector<EnteredScope> entered_scopes_;
  110. };
  111. } // namespace Carbon::Check
  112. #endif // CARBON_TOOLCHAIN_CHECK_DEFERRED_DEFINITION_WORKLIST_H_