value_transform.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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_VALUE_TRANSFORM_H_
  5. #define CARBON_EXPLORER_AST_VALUE_TRANSFORM_H_
  6. #include "common/error.h"
  7. #include "explorer/ast/expression_category.h"
  8. #include "explorer/ast/value.h"
  9. namespace Carbon {
  10. // Constructs a T instance by direct-list-initialization from the given
  11. // components (which must have been produced by Decompose).
  12. template <typename T, typename... Args>
  13. auto ConstructFromComponents(Args&&... args)
  14. -> decltype(T{std::declval<Args>()...}) {
  15. return T{std::forward<Args>(args)...};
  16. }
  17. // Overload of the above to accommodate the case where T is an aggregate and
  18. // has a CRTP base class, in which case the initializer list must start with
  19. // an empty initializer for the base class.
  20. template <typename T, typename... Args>
  21. auto ConstructFromComponents(Args&&... args)
  22. -> decltype(T{{}, std::declval<Args>()...}) {
  23. return T{{}, std::forward<Args>(args)...};
  24. }
  25. template <typename T, typename, typename... Args>
  26. constexpr bool IsConstructibleFromComponentsImpl = false;
  27. template <typename T, typename... Args>
  28. constexpr bool IsConstructibleFromComponentsImpl<
  29. T, decltype(ConstructFromComponents<T>(std::declval<Args>()...)), Args...> =
  30. true;
  31. // A no-op visitor used to implement `IsRecursivelyTransformable`. The
  32. // `operator()` function returns `true_type` if it's called with arguments that
  33. // can be used to direct-list-initialize `T`, and `false_type` otherwise.
  34. template <typename T>
  35. struct IsRecursivelyTransformableVisitor {
  36. template <typename... Args>
  37. auto operator()(Args&&... args) -> std::integral_constant<
  38. bool, IsConstructibleFromComponentsImpl<T, T, Args...>>;
  39. };
  40. // A type trait that indicates whether `T` is transformable. A transformable
  41. // type provides a function
  42. //
  43. // template<typename F> void Decompose(F f) const;
  44. //
  45. // that takes a callable `f` and passes it an argument list that can be passed
  46. // to the constructor of `T` to create an equivalent value.
  47. template <typename T, typename = std::true_type>
  48. constexpr bool IsRecursivelyTransformable = false;
  49. template <typename T>
  50. // NOLINTNEXTLINE(misc-definitions-in-headers)
  51. constexpr bool IsRecursivelyTransformable<
  52. T, decltype(std::declval<const T>().Decompose(
  53. IsRecursivelyTransformableVisitor<T>{}))> = true;
  54. // Unwrapper for the case where there's nothing to unwrap.
  55. class NoOpUnwrapper {
  56. public:
  57. template <typename T, typename U>
  58. auto UnwrapOr(T&& value, const U&) -> T {
  59. return std::forward<T>(value);
  60. }
  61. template <typename T>
  62. auto Wrap(T&& value) -> T&& {
  63. return std::forward<T>(value);
  64. }
  65. constexpr bool failed() const { return false; }
  66. };
  67. // Helper to temporarily unwrap the ErrorOr around a value, and then put it
  68. // back when we're done with the overall computation.
  69. class ErrorUnwrapper {
  70. public:
  71. // Unwrap the `ErrorOr` from the given value, or collect the error and return
  72. // the given fallback value on failure.
  73. template <typename T, typename U>
  74. auto UnwrapOr(ErrorOr<T> value, const U& fallback) -> T {
  75. if (!value.ok()) {
  76. status_ = std::move(value).error();
  77. return fallback;
  78. }
  79. return std::move(*value);
  80. }
  81. template <typename T, typename U>
  82. auto UnwrapOr(T&& value, const U&) -> T {
  83. return std::forward<T>(value);
  84. }
  85. // Wrap the given value into `ErrorOr`, returning our collected error if any,
  86. // or the given value if we succeeded.
  87. template <typename T>
  88. auto Wrap(T&& value) -> ErrorOr<T> {
  89. if (!status_.ok()) {
  90. Error error = std::move(status_).error();
  91. status_ = Success();
  92. return error;
  93. }
  94. return std::forward<T>(value);
  95. }
  96. bool failed() const { return !status_.ok(); }
  97. private:
  98. ErrorOr<Success> status_ = Success();
  99. };
  100. // Base class for transforms of visitable data types.
  101. template <typename Derived, typename ResultUnwrapper>
  102. class TransformBase {
  103. public:
  104. explicit TransformBase(Nonnull<Arena*> arena) : arena_(arena) {}
  105. // Transform the given value, and produce either the transformed value or an
  106. // error.
  107. template <typename T>
  108. auto Transform(const T& v) -> decltype(auto) {
  109. return unwrapper_.Wrap(TransformOrOriginal(v));
  110. }
  111. protected:
  112. // Transform the given value, or return the original if transformation fails.
  113. template <typename T>
  114. auto TransformOrOriginal(const T& v)
  115. -> decltype(std::declval<ResultUnwrapper>().UnwrapOr(
  116. std::declval<Derived>()(v), v)) {
  117. // If we've already failed, don't do any more transformations.
  118. if (unwrapper_.failed()) {
  119. return v;
  120. }
  121. return unwrapper_.UnwrapOr(static_cast<Derived&>(*this)(v), v);
  122. }
  123. // Transformable values are recursively transformed by default.
  124. template <typename T,
  125. std::enable_if_t<IsRecursivelyTransformable<T>, void*> = nullptr>
  126. auto operator()(const T& value) -> T {
  127. return value.Decompose([&](const auto&... elements) {
  128. return [&](auto&&... transformed_elements) {
  129. if (unwrapper_.failed()) {
  130. return value;
  131. }
  132. return ConstructFromComponents<T>(
  133. decltype(transformed_elements)(transformed_elements)...);
  134. }(TransformOrOriginal(elements)...);
  135. });
  136. }
  137. // Transformable pointers are recursively transformed and reallocated by
  138. // default.
  139. template <typename T,
  140. std::enable_if_t<IsRecursivelyTransformable<T>, void*> = nullptr>
  141. auto operator()(Nonnull<const T*> value) -> auto {
  142. return value->Decompose([&](const auto&... elements) {
  143. return [&](auto&&... transformed_elements)
  144. -> decltype(AllocateTrait<T>::New(
  145. arena_,
  146. decltype(transformed_elements)(transformed_elements)...)) {
  147. if (unwrapper_.failed()) {
  148. return value;
  149. }
  150. return AllocateTrait<T>::New(
  151. arena_, decltype(transformed_elements)(transformed_elements)...);
  152. }(TransformOrOriginal(elements)...);
  153. });
  154. }
  155. // Fundamental types like `int` are assumed to not need transformation.
  156. template <typename T>
  157. auto operator()(const T& v) -> std::enable_if_t<std::is_fundamental_v<T>, T> {
  158. return v;
  159. }
  160. auto operator()(const std::string& str) -> const std::string& { return str; }
  161. auto operator()(llvm::StringRef str) -> llvm::StringRef { return str; }
  162. // Transform `optional<T>` by transforming the `T` if it's present.
  163. template <typename T>
  164. auto operator()(const std::optional<T>& v) -> std::optional<T> {
  165. if (!v) {
  166. return std::nullopt;
  167. }
  168. return TransformOrOriginal(*v);
  169. }
  170. // Transform `pair<T, U>` by transforming T and U.
  171. template <typename T, typename U>
  172. auto operator()(const std::pair<T, U>& pair) -> std::pair<T, U> {
  173. return std::pair<T, U>{TransformOrOriginal(pair.first),
  174. TransformOrOriginal(pair.second)};
  175. }
  176. // Transform `vector<T>` by transforming its elements.
  177. template <typename T>
  178. auto operator()(const std::vector<T>& vec) -> std::vector<T> {
  179. std::vector<T> result;
  180. result.reserve(vec.size());
  181. for (auto& value : vec) {
  182. result.push_back(TransformOrOriginal(value));
  183. }
  184. return result;
  185. }
  186. // Transform `map<T, U>` by transforming its keys and values.
  187. template <typename T, typename U>
  188. auto operator()(const std::map<T, U>& map) -> std::map<T, U> {
  189. std::map<T, U> result;
  190. for (auto& [key, value] : map) {
  191. result.insert({TransformOrOriginal(key), TransformOrOriginal(value)});
  192. }
  193. return result;
  194. }
  195. // Transform `llvm::StringMap<T>` by transforming its keys and values.
  196. template <typename T>
  197. auto operator()(const llvm::StringMap<T>& map) -> llvm::StringMap<T> {
  198. llvm::StringMap<T> result;
  199. for (const auto& it : map) {
  200. result.insert(
  201. {TransformOrOriginal(it.first()), TransformOrOriginal(it.second)});
  202. }
  203. return result;
  204. }
  205. private:
  206. Nonnull<Arena*> arena_;
  207. // Unwrapper for results. Used to remove an ErrorOr<...> wrapper temporarily
  208. // during recursive transformations and re-apply it when we're done.
  209. ResultUnwrapper unwrapper_;
  210. };
  211. // Base class for transforms of `Value`s.
  212. template <typename Derived, typename ResultUnwrapper>
  213. class ValueTransform : public TransformBase<Derived, ResultUnwrapper> {
  214. public:
  215. using TransformBase<Derived, ResultUnwrapper>::TransformBase;
  216. using TransformBase<Derived, ResultUnwrapper>::operator();
  217. // Leave references to AST nodes alone by default.
  218. // The 'int = 0' parameter avoids this function hiding the `operator()(const
  219. // T*)` in the base class. We can remove this once we start using a compiler
  220. // that implements P1787R6.
  221. template <typename NodeT>
  222. auto operator()(Nonnull<const NodeT*> node, int /*unused*/ = 0)
  223. -> std::enable_if_t<std::is_base_of_v<AstNode, NodeT>,
  224. Nonnull<const NodeT*>> {
  225. return node;
  226. }
  227. auto operator()(Address addr) -> Address { return addr; }
  228. auto operator()(ExpressionCategory cat) -> ExpressionCategory { return cat; }
  229. auto operator()(ValueNodeView value_node) -> ValueNodeView {
  230. return value_node;
  231. }
  232. // For a type that provides a `Visit` function to visit the most-derived
  233. // object, visit and transform that most-derived object.
  234. template <typename R, typename T>
  235. auto TransformDerived(Nonnull<const T*> value) -> R {
  236. return value->template Visit<R>([&](const auto* derived_value) {
  237. using DerivedType = std::remove_pointer_t<decltype(derived_value)>;
  238. static_assert(IsRecursivelyTransformable<DerivedType>);
  239. return this->TransformOrOriginal(derived_value);
  240. });
  241. }
  242. // For values, dispatch on the value kind and recursively transform.
  243. auto operator()(Nonnull<const Value*> value) -> Nonnull<const Value*> {
  244. return TransformDerived<Nonnull<const Value*>>(value);
  245. }
  246. // Provide a more precise type from transforming a `Witness`.
  247. auto operator()(Nonnull<const Witness*> value) -> Nonnull<const Witness*> {
  248. return llvm::cast<Witness>(
  249. this->TransformOrOriginal(llvm::cast<Value>(value)));
  250. }
  251. // For elements, dispatch on the element kind and recursively transform.
  252. auto operator()(Nonnull<const Element*> elem) -> Nonnull<const Element*> {
  253. return TransformDerived<Nonnull<const Element*>>(elem);
  254. }
  255. // Preserve vtable during transformation.
  256. auto operator()(Nonnull<const VTable*> vtable) -> Nonnull<const VTable*> {
  257. return vtable;
  258. }
  259. // Preserve class value ptr during transformation.
  260. auto operator()(Nonnull<const NominalClassValue**> value_ptr)
  261. -> Nonnull<const NominalClassValue**> {
  262. return value_ptr;
  263. }
  264. // Preserve constraint kind for intrinsic constraints.
  265. auto operator()(IntrinsicConstraint::Kind kind) -> IntrinsicConstraint::Kind {
  266. return kind;
  267. }
  268. };
  269. } // namespace Carbon
  270. #endif // CARBON_EXPLORER_AST_VALUE_TRANSFORM_H_