| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // 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_EXPLORER_AST_CLONE_CONTEXT_H_
- #define CARBON_EXPLORER_AST_CLONE_CONTEXT_H_
- #include <optional>
- #include <type_traits>
- #include <vector>
- #include "common/check.h"
- #include "explorer/ast/ast_rtti.h"
- #include "explorer/base/arena.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/Support/Casting.h"
- namespace Carbon {
- class AstNode;
- class Element;
- class Value;
- // A context for performing a deep copy of some fragment of the AST.
- //
- // This class carries the state necessary to make the copy, including ensuring
- // that each node is cloned only once and mapping from old nodes to new ones.
- class CloneContext {
- public:
- explicit CloneContext(Nonnull<Arena*> arena) : arena_(arena) {}
- CloneContext(const CloneContext&) = delete;
- auto operator=(const CloneContext&) -> const CloneContext& = delete;
- // Clone an AST element.
- template <typename T>
- auto Clone(Nonnull<const T*> node) -> Nonnull<T*> {
- if constexpr (std::is_convertible_v<const T*, const AstNode*>) {
- const AstNode* base_node = node;
- // Note, we can't use `llvm::cast<T>` here because we might not have
- // finished cloning `base_node` yet and its kind might not be set. This
- // happens when there is a pointer cycle in the AST.
- return static_cast<T*>(CloneBase(base_node));
- } else if constexpr (std::is_convertible_v<const T*, const Value*>) {
- const Value* base_value = node;
- return static_cast<T*>(CloneBase(base_value));
- } else {
- static_assert(std::is_convertible_v<const T*, const Element*>,
- "unknown pointer type to clone");
- const Element* base_elem = node;
- return static_cast<T*>(CloneBase(base_elem));
- }
- }
- // Clone anything with a clone constructor, that is, a constructor of the
- // form:
- //
- // explicit MyType(CloneContext&, const MyType&)
- //
- // Clone constructors should call Clone on their owned elements to form a new
- // value. Pointers returned by Clone should not be inspected by the clone
- // constructor, as the pointee is not necessarily fully initialized until the
- // overall cloning process completes.
- //
- // Clone constructors should call Remap on values that they do not own, such
- // as for the declaration named by an IdentifierExpression.
- template <typename T>
- auto Clone(const T& other)
- -> std::enable_if_t<std::is_constructible_v<T, CloneContext&, const T&>,
- T> {
- return T(*this, other);
- }
- template <typename T>
- auto Clone(std::optional<T> node) -> std::optional<T> {
- if (node) {
- return Clone(*node);
- }
- return std::nullopt;
- }
- template <typename T>
- auto Clone(const std::vector<T>& nodes) -> std::vector<T> {
- std::vector<T> result;
- result.reserve(nodes.size());
- for (const auto& node : nodes) {
- result.push_back(Clone(node));
- }
- return result;
- }
- // Find the new or existing node corresponding to the given node. This should
- // be used when a cloned node has a non-owning reference to another node,
- // that might refer to something being cloned or might refer to the original
- // object. The returned node might not be fully constructed and should not be
- // inspected.
- template <typename T>
- auto Remap(Nonnull<T*> node) -> Nonnull<T*> {
- // Note, we can't use `llvm::cast<T>` here because we might not have
- // finished cloning `base_node` yet and its kind might not be set. This
- // happens when there is a pointer cycle in the AST.
- T* cloned = static_cast<T*>(nodes_[node]);
- return cloned ? cloned : node;
- }
- // It's safe to remap a `const` object by remapping the non-const version and
- // adding back the `const`.
- template <typename T>
- auto Remap(Nonnull<const T*> node) -> Nonnull<const T*> {
- return Remap(const_cast<T*>(node));
- }
- template <typename T>
- auto Remap(std::optional<T> node) -> std::optional<T> {
- if (node) {
- return Remap(*node);
- }
- return std::nullopt;
- }
- template <typename T>
- auto Remap(const std::vector<T>& nodes) -> std::vector<T> {
- std::vector<T> result;
- result.reserve(nodes.size());
- for (const auto& node : nodes) {
- result.push_back(Remap(node));
- }
- return result;
- }
- template <typename T>
- auto GetExistingClone(Nonnull<const T*> node) -> Nonnull<T*> {
- AstNode* cloned = nodes_.lookup(node);
- CARBON_CHECK(cloned, "expected node to be cloned");
- return llvm::cast<T>(cloned);
- }
- private:
- // A value transform that remaps or clones AST elements referred to by the
- // value being transformed.
- class CloneValueTransform;
- // Clone the given node, and remember the mapping from the original to the
- // new node for remapping.
- auto CloneBase(Nonnull<const AstNode*> node) -> Nonnull<AstNode*>;
- // Clone the given value, replacing references to cloned local declarations
- // with references to the copies.
- auto CloneBase(Nonnull<const Value*> value) -> Nonnull<Value*>;
- // Clone the given element reference.
- auto CloneBase(Nonnull<const Element*> elem) -> Nonnull<Element*>;
- // Clone the given node if it's not already been cloned. This should be used
- // very sparingly, in cases where ownership is unclear.
- void MaybeCloneBase(Nonnull<const AstNode*> node);
- // Arena to allocate new nodes within.
- Nonnull<Arena*> arena_;
- // Mapping from old nodes to new nodes.
- llvm::DenseMap<const AstNode*, AstNode*> nodes_;
- };
- } // namespace Carbon
- #endif // CARBON_EXPLORER_AST_CLONE_CONTEXT_H_
|