deferred_definition_worklist.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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.
  28. struct EnterDeferredDefinitionScope {
  29. // The suspended scope. This is only set once we reach the end of the scope.
  30. std::optional<DeclNameStack::SuspendedName> suspended_name;
  31. // Whether this scope is itself within an outer deferred definition scope.
  32. // If so, we'll delay processing its contents until we reach the end of the
  33. // parent scope. For example:
  34. //
  35. // ```
  36. // class A {
  37. // class B {
  38. // fn F() -> A { return {}; }
  39. // }
  40. // } // A.B.F is type-checked here, with A complete.
  41. //
  42. // fn F() {
  43. // class C {
  44. // fn G() {}
  45. // } // C.G is type-checked here.
  46. // }
  47. // ```
  48. bool in_deferred_definition_scope;
  49. };
  50. // A worklist task that indicates we should leave a deferred definition scope.
  51. struct LeaveDeferredDefinitionScope {
  52. // Whether this scope is within another deferred definition scope.
  53. bool in_deferred_definition_scope;
  54. };
  55. // A pending type-checking task.
  56. using Task =
  57. std::variant<CheckSkippedDefinition, EnterDeferredDefinitionScope,
  58. LeaveDeferredDefinitionScope>;
  59. explicit DeferredDefinitionWorklist(llvm::raw_ostream* vlog_stream);
  60. // Suspend the current function definition and push a task onto the worklist
  61. // to finish it later.
  62. auto SuspendFunctionAndPush(Context& context,
  63. Parse::DeferredDefinitionIndex index,
  64. Parse::FunctionDefinitionStartId node_id) -> void;
  65. // Push a task to re-enter a function scope, so that functions defined within
  66. // it are type-checked in the right context.
  67. auto PushEnterDeferredDefinitionScope(Context& context) -> void;
  68. // Suspend the current deferred definition scope, which is finished but still
  69. // on the decl_name_stack, and push a task to leave the scope when we're
  70. // type-checking deferred definitions. Returns `true` if the current list of
  71. // deferred definitions should be type-checked immediately.
  72. auto SuspendFinishedScopeAndPush(Context& context) -> bool;
  73. // Pop the next task off the worklist.
  74. auto Pop() -> Task;
  75. // CHECK that the work list has no further work.
  76. auto VerifyEmpty() {
  77. CARBON_CHECK(worklist_.empty() && entered_scopes_.empty(),
  78. "Tasks left behind on worklist.");
  79. }
  80. private:
  81. // A deferred definition scope that is currently still open.
  82. struct EnteredScope {
  83. // The index in worklist_ of the EnterDeferredDefinitionScope task.
  84. size_t worklist_start_index;
  85. // The corresponding lexical scope index.
  86. ScopeIndex scope_index;
  87. };
  88. llvm::raw_ostream* vlog_stream_;
  89. // A worklist of type-checking tasks we'll need to do later.
  90. //
  91. // Don't allocate any inline storage here. A Task is fairly large, so we never
  92. // want this to live on the stack. Instead, we reserve space in the
  93. // constructor for a fairly large number of deferred definitions.
  94. llvm::SmallVector<Task, 0> worklist_;
  95. // The deferred definition scopes for the current checking actions.
  96. llvm::SmallVector<EnteredScope> entered_scopes_;
  97. };
  98. } // namespace Carbon::Check
  99. #endif // CARBON_TOOLCHAIN_CHECK_DEFERRED_DEFINITION_WORKLIST_H_