clone_context.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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_EXPLORER_AST_CLONE_CONTEXT_H_
  5. #define CARBON_EXPLORER_AST_CLONE_CONTEXT_H_
  6. #include <optional>
  7. #include <type_traits>
  8. #include <vector>
  9. #include "common/check.h"
  10. #include "explorer/ast/ast_rtti.h"
  11. #include "explorer/base/arena.h"
  12. #include "llvm/ADT/DenseMap.h"
  13. #include "llvm/Support/Casting.h"
  14. namespace Carbon {
  15. class AstNode;
  16. class Element;
  17. class Value;
  18. // A context for performing a deep copy of some fragment of the AST.
  19. //
  20. // This class carries the state necessary to make the copy, including ensuring
  21. // that each node is cloned only once and mapping from old nodes to new ones.
  22. class CloneContext {
  23. public:
  24. explicit CloneContext(Nonnull<Arena*> arena) : arena_(arena) {}
  25. CloneContext(const CloneContext&) = delete;
  26. auto operator=(const CloneContext&) -> const CloneContext& = delete;
  27. // Clone an AST element.
  28. template <typename T>
  29. auto Clone(Nonnull<const T*> node) -> Nonnull<T*> {
  30. if constexpr (std::is_convertible_v<const T*, const AstNode*>) {
  31. const AstNode* base_node = node;
  32. // Note, we can't use `llvm::cast<T>` here because we might not have
  33. // finished cloning `base_node` yet and its kind might not be set. This
  34. // happens when there is a pointer cycle in the AST.
  35. return static_cast<T*>(CloneBase(base_node));
  36. } else if constexpr (std::is_convertible_v<const T*, const Value*>) {
  37. const Value* base_value = node;
  38. return static_cast<T*>(CloneBase(base_value));
  39. } else {
  40. static_assert(std::is_convertible_v<const T*, const Element*>,
  41. "unknown pointer type to clone");
  42. const Element* base_elem = node;
  43. return static_cast<T*>(CloneBase(base_elem));
  44. }
  45. }
  46. // Clone anything with a clone constructor, that is, a constructor of the
  47. // form:
  48. //
  49. // explicit MyType(CloneContext&, const MyType&)
  50. //
  51. // Clone constructors should call Clone on their owned elements to form a new
  52. // value. Pointers returned by Clone should not be inspected by the clone
  53. // constructor, as the pointee is not necessarily fully initialized until the
  54. // overall cloning process completes.
  55. //
  56. // Clone constructors should call Remap on values that they do not own, such
  57. // as for the declaration named by an IdentifierExpression.
  58. template <typename T>
  59. auto Clone(const T& other)
  60. -> std::enable_if_t<std::is_constructible_v<T, CloneContext&, const T&>,
  61. T> {
  62. return T(*this, other);
  63. }
  64. template <typename T>
  65. auto Clone(std::optional<T> node) -> std::optional<T> {
  66. if (node) {
  67. return Clone(*node);
  68. }
  69. return std::nullopt;
  70. }
  71. template <typename T>
  72. auto Clone(const std::vector<T>& nodes) -> std::vector<T> {
  73. std::vector<T> result;
  74. result.reserve(nodes.size());
  75. for (const auto& node : nodes) {
  76. result.push_back(Clone(node));
  77. }
  78. return result;
  79. }
  80. // Find the new or existing node corresponding to the given node. This should
  81. // be used when a cloned node has a non-owning reference to another node,
  82. // that might refer to something being cloned or might refer to the original
  83. // object. The returned node might not be fully constructed and should not be
  84. // inspected.
  85. template <typename T>
  86. auto Remap(Nonnull<T*> node) -> Nonnull<T*> {
  87. // Note, we can't use `llvm::cast<T>` here because we might not have
  88. // finished cloning `base_node` yet and its kind might not be set. This
  89. // happens when there is a pointer cycle in the AST.
  90. T* cloned = static_cast<T*>(nodes_[node]);
  91. return cloned ? cloned : node;
  92. }
  93. // It's safe to remap a `const` object by remapping the non-const version and
  94. // adding back the `const`.
  95. template <typename T>
  96. auto Remap(Nonnull<const T*> node) -> Nonnull<const T*> {
  97. return Remap(const_cast<T*>(node));
  98. }
  99. template <typename T>
  100. auto Remap(std::optional<T> node) -> std::optional<T> {
  101. if (node) {
  102. return Remap(*node);
  103. }
  104. return std::nullopt;
  105. }
  106. template <typename T>
  107. auto Remap(const std::vector<T>& nodes) -> std::vector<T> {
  108. std::vector<T> result;
  109. result.reserve(nodes.size());
  110. for (const auto& node : nodes) {
  111. result.push_back(Remap(node));
  112. }
  113. return result;
  114. }
  115. template <typename T>
  116. auto GetExistingClone(Nonnull<const T*> node) -> Nonnull<T*> {
  117. AstNode* cloned = nodes_.lookup(node);
  118. CARBON_CHECK(cloned, "expected node to be cloned");
  119. return llvm::cast<T>(cloned);
  120. }
  121. private:
  122. // A value transform that remaps or clones AST elements referred to by the
  123. // value being transformed.
  124. class CloneValueTransform;
  125. // Clone the given node, and remember the mapping from the original to the
  126. // new node for remapping.
  127. auto CloneBase(Nonnull<const AstNode*> node) -> Nonnull<AstNode*>;
  128. // Clone the given value, replacing references to cloned local declarations
  129. // with references to the copies.
  130. auto CloneBase(Nonnull<const Value*> value) -> Nonnull<Value*>;
  131. // Clone the given element reference.
  132. auto CloneBase(Nonnull<const Element*> elem) -> Nonnull<Element*>;
  133. // Clone the given node if it's not already been cloned. This should be used
  134. // very sparingly, in cases where ownership is unclear.
  135. void MaybeCloneBase(Nonnull<const AstNode*> node);
  136. // Arena to allocate new nodes within.
  137. Nonnull<Arena*> arena_;
  138. // Mapping from old nodes to new nodes.
  139. llvm::DenseMap<const AstNode*, AstNode*> nodes_;
  140. };
  141. } // namespace Carbon
  142. #endif // CARBON_EXPLORER_AST_CLONE_CONTEXT_H_