value_transform.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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_INTERPRETER_VALUE_TRANSFORM_H_
  5. #define CARBON_EXPLORER_INTERPRETER_VALUE_TRANSFORM_H_
  6. #include "explorer/interpreter/value.h"
  7. namespace Carbon {
  8. // A no-op visitor used to implement `IsRecursivelyTransformable`. The
  9. // `operator()` function returns `true_type` if it's called with arguments that
  10. // can be used to construct `T`, and `false_type` otherwise.
  11. template <typename T>
  12. struct IsRecursivelyTransformableVisitor {
  13. template <typename... Args>
  14. auto operator()(Args&&... args)
  15. -> std::integral_constant<bool, std::is_constructible_v<T, Args...>>;
  16. };
  17. // A type trait that indicates whether `T` is transformable. A transformable
  18. // type provides a function
  19. //
  20. // template<typename F> void Decompose(F f) const;
  21. //
  22. // that takes a callable `f` and passes it an argument list that can be passed
  23. // to the constructor of `T` to create an equivalent value.
  24. template <typename T, typename = std::true_type>
  25. constexpr bool IsRecursivelyTransformable = false;
  26. template <typename T>
  27. constexpr bool IsRecursivelyTransformable<
  28. T, decltype(std::declval<const T>().Decompose(
  29. IsRecursivelyTransformableVisitor<T>{}))> = true;
  30. // Base class for transforms of visitable data types.
  31. template <typename Derived>
  32. class TransformBase {
  33. public:
  34. TransformBase(Nonnull<Arena*> arena) : arena_(arena) {}
  35. template <typename T>
  36. auto Transform(T&& v) -> decltype(auto) {
  37. return static_cast<Derived&>(*this)(std::forward<T>(v));
  38. }
  39. // Transformable values are recursively transformed by default.
  40. template <typename T,
  41. std::enable_if_t<IsRecursivelyTransformable<T>, void*> = nullptr>
  42. auto operator()(const T& value) -> T {
  43. return value.Decompose([&](auto&&... elements) {
  44. return T{Transform(decltype(elements)(elements))...};
  45. });
  46. }
  47. // Transformable pointers are recursively transformed and reallocated by
  48. // default.
  49. template <typename T,
  50. std::enable_if_t<IsRecursivelyTransformable<T>, void*> = nullptr>
  51. auto operator()(Nonnull<const T*> value) -> auto{
  52. return value->Decompose([&](auto&&... elements) {
  53. return AllocateTrait<T>::New(arena_,
  54. Transform(decltype(elements)(elements))...);
  55. });
  56. }
  57. // Fundamental types like `int` are assumed to not need transformation.
  58. template <typename T>
  59. auto operator()(const T& v) -> std::enable_if_t<std::is_fundamental_v<T>, T> {
  60. return v;
  61. }
  62. auto operator()(const std::string& str) -> const std::string& { return str; }
  63. auto operator()(llvm::StringRef str) -> llvm::StringRef { return str; }
  64. // Transform `optional<T>` by transforming the `T` if it's present.
  65. template <typename T>
  66. auto operator()(const std::optional<T>& v) -> std::optional<T> {
  67. if (!v) {
  68. return std::nullopt;
  69. }
  70. return Transform(*v);
  71. }
  72. // Transform `pair<T, U>` by transforming T and U.
  73. template <typename T, typename U>
  74. auto operator()(const std::pair<T, U>& pair) -> std::pair<T, U> {
  75. return std::pair<T, U>{Transform(pair.first), Transform(pair.second)};
  76. }
  77. // Transform `vector<T>` by transforming its elements.
  78. template <typename T>
  79. auto operator()(const std::vector<T>& vec) -> std::vector<T> {
  80. std::vector<T> result;
  81. result.reserve(vec.size());
  82. for (auto& value : vec) {
  83. result.push_back(Transform(value));
  84. }
  85. return result;
  86. }
  87. // Transform `map<T, U>` by transforming its keys and values.
  88. template <typename T, typename U>
  89. auto operator()(const std::map<T, U>& map) -> std::map<T, U> {
  90. std::map<T, U> result;
  91. for (auto& [key, value] : map) {
  92. result.insert({Transform(key), Transform(value)});
  93. }
  94. return result;
  95. }
  96. // Transform `llvm::StringMap<T>` by transforming its keys and values.
  97. template <typename T>
  98. auto operator()(const llvm::StringMap<T>& map) -> llvm::StringMap<T> {
  99. llvm::StringMap<T> result;
  100. for (const auto& it : map) {
  101. result.insert({Transform(it.first()), Transform(it.second)});
  102. }
  103. return result;
  104. }
  105. private:
  106. Nonnull<Arena*> arena_;
  107. };
  108. // Base class for transforms of `Value`s.
  109. template <typename Derived>
  110. class ValueTransform : public TransformBase<Derived> {
  111. public:
  112. using TransformBase<Derived>::TransformBase;
  113. using TransformBase<Derived>::operator();
  114. // Leave references to AST nodes alone by default.
  115. // The 'int = 0' parameter avoids this function hiding the `operator()(const
  116. // T*)` in the base class. We can remove this once we start using a compiler
  117. // that implements P1787R6.
  118. template <typename NodeT>
  119. auto operator()(Nonnull<const NodeT*> node, int = 0)
  120. -> std::enable_if_t<std::is_base_of_v<AstNode, NodeT>,
  121. Nonnull<const NodeT*>> {
  122. return node;
  123. }
  124. auto operator()(Nonnull<ContinuationValue::StackFragment*> stack_fragment)
  125. -> Nonnull<ContinuationValue::StackFragment*> {
  126. return stack_fragment;
  127. }
  128. auto operator()(Address addr) -> Address { return addr; }
  129. auto operator()(ValueNodeView value_node) -> ValueNodeView {
  130. return value_node;
  131. }
  132. // For a type that provides a `Visit` function to visit the most-derived
  133. // object, visit and transform that most-derived object.
  134. template <typename R, typename T>
  135. auto TransformDerived(Nonnull<const T*> value) -> R {
  136. return value->template Visit<R>([&](const auto* derived_value) {
  137. using DerivedType = std::remove_pointer_t<decltype(derived_value)>;
  138. static_assert(IsRecursivelyTransformable<DerivedType>);
  139. return this->Transform(derived_value);
  140. });
  141. }
  142. // For values, dispatch on the value kind and recursively transform.
  143. auto operator()(Nonnull<const Value*> value) -> Nonnull<const Value*> {
  144. return TransformDerived<Nonnull<const Value*>>(value);
  145. }
  146. // Provide a more precise type from transforming a `Witness`.
  147. auto operator()(Nonnull<const Witness*> value) -> Nonnull<const Witness*> {
  148. return llvm::cast<Witness>(this->Transform(llvm::cast<Value>(value)));
  149. }
  150. // For elements, dispatch on the element kind and recursively transform.
  151. auto operator()(Nonnull<const Element*> elem) -> Nonnull<const Element*> {
  152. return TransformDerived<Nonnull<const Element*>>(elem);
  153. }
  154. // Preserve vtable during transformation.
  155. auto operator()(Nonnull<const VTable* const> vtable)
  156. -> Nonnull<const VTable* const> {
  157. return vtable;
  158. }
  159. // Preserve class value ptr during transformation.
  160. auto operator()(Nonnull<const NominalClassValue** const> value_ptr)
  161. -> Nonnull<const NominalClassValue** const> {
  162. return value_ptr;
  163. }
  164. };
  165. } // namespace Carbon
  166. #endif // CARBON_EXPLORER_INTERPRETER_VALUE_TRANSFORM_H_