FLANG
traverse.h
1//===-- include/flang/Evaluate/traverse.h -----------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef FORTRAN_EVALUATE_TRAVERSE_H_
10#define FORTRAN_EVALUATE_TRAVERSE_H_
11
12// A utility for scanning all of the constituent objects in an Expr<>
13// expression representation using a collection of mutually recursive
14// functions to compose a function object.
15//
16// The class template Traverse<> below implements a function object that
17// can handle every type that can appear in or around an Expr<>.
18// Each of its overloads for operator() should be viewed as a *default*
19// handler; some of these must be overridden by the client to accomplish
20// its particular task.
21//
22// The client (Visitor) of Traverse<Visitor,Result> must define:
23// - a member function "Result Default();"
24// - a member function "Result Combine(Result &&, Result &&)"
25// - overrides for "Result operator()"
26//
27// Boilerplate classes also appear below to ease construction of visitors.
28// See CheckSpecificationExpr() in check-expression.cpp for an example client.
29//
30// How this works:
31// - The operator() overloads in Traverse<> invoke the visitor's Default() for
32// expression leaf nodes. They invoke the visitor's operator() for the
33// subtrees of interior nodes, and the visitor's Combine() to merge their
34// results together.
35// - Overloads of operator() in each visitor handle the cases of interest.
36//
37// The default handler for semantics::Symbol will descend into the associated
38// expression of an ASSOCIATE (or related) construct entity.
39
40#include "expression.h"
41#include "flang/Common/indirection.h"
42#include "flang/Semantics/symbol.h"
43#include "flang/Semantics/type.h"
44#include <set>
45#include <type_traits>
46
47namespace Fortran::evaluate {
48template <typename Visitor, typename Result,
49 bool TraverseAssocEntityDetails = true>
50class Traverse {
51public:
52 explicit Traverse(Visitor &v) : visitor_{v} {}
53
54 // Packaging
55 template <typename A, bool C>
56 Result operator()(const common::Indirection<A, C> &x) const {
57 return visitor_(x.value());
58 }
59 template <typename A>
60 Result operator()(const common::ForwardOwningPointer<A> &p) const {
61 return visitor_(p.get());
62 }
63 template <typename _> Result operator()(const SymbolRef x) const {
64 return visitor_(*x);
65 }
66 template <typename A> Result operator()(const std::unique_ptr<A> &x) const {
67 return visitor_(x.get());
68 }
69 template <typename A> Result operator()(const std::shared_ptr<A> &x) const {
70 return visitor_(x.get());
71 }
72 template <typename A> Result operator()(const A *x) const {
73 if (x) {
74 return visitor_(*x);
75 } else {
76 return visitor_.Default();
77 }
78 }
79 template <typename A> Result operator()(const std::optional<A> &x) const {
80 if (x) {
81 return visitor_(*x);
82 } else {
83 return visitor_.Default();
84 }
85 }
86 template <typename... As>
87 Result operator()(const std::variant<As...> &u) const {
88 return common::visit([=](const auto &y) { return visitor_(y); }, u);
89 }
90 template <typename A> Result operator()(const std::vector<A> &x) const {
91 return CombineContents(x);
92 }
93 template <typename A, typename B>
94 Result operator()(const std::pair<A, B> &x) const {
95 return Combine(x.first, x.second);
96 }
97
98 // Leaves
99 Result operator()(const BOZLiteralConstant &) const {
100 return visitor_.Default();
101 }
102 Result operator()(const NullPointer &) const { return visitor_.Default(); }
103 template <typename T> Result operator()(const Constant<T> &x) const {
104 if constexpr (T::category == TypeCategory::Derived) {
105 return visitor_.Combine(
106 visitor_(x.result().derivedTypeSpec()), CombineContents(x.values()));
107 } else {
108 return visitor_.Default();
109 }
110 }
111 Result operator()(const Symbol &symbol) const {
112 const Symbol &ultimate{symbol.GetUltimate()};
113 if constexpr (TraverseAssocEntityDetails) {
114 if (const auto *assoc{
115 ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
116 return visitor_(assoc->expr());
117 }
118 }
119 return visitor_.Default();
120 }
121 Result operator()(const StaticDataObject &) const {
122 return visitor_.Default();
123 }
124 Result operator()(const ImpliedDoIndex &) const { return visitor_.Default(); }
125
126 // Variables
127 Result operator()(const BaseObject &x) const { return visitor_(x.u); }
128 Result operator()(const Component &x) const {
129 return Combine(x.base(), x.symbol());
130 }
131 Result operator()(const NamedEntity &x) const {
132 if (const Component * component{x.UnwrapComponent()}) {
133 return visitor_(*component);
134 } else {
135 return visitor_(DEREF(x.UnwrapSymbolRef()));
136 }
137 }
138 Result operator()(const TypeParamInquiry &x) const {
139 return visitor_(x.base());
140 }
141 Result operator()(const Triplet &x) const {
142 return Combine(x.GetLower(), x.GetUpper(), x.GetStride());
143 }
144 Result operator()(const Subscript &x) const { return visitor_(x.u); }
145 Result operator()(const ArrayRef &x) const {
146 return Combine(x.base(), x.subscript());
147 }
148 Result operator()(const CoarrayRef &x) const {
149 return Combine(x.base(), x.cosubscript(), x.notify(), x.stat(), x.team());
150 }
151 Result operator()(const DataRef &x) const { return visitor_(x.u); }
152 Result operator()(const Substring &x) const {
153 return Combine(x.parent(), x.GetLower(), x.GetUpper());
154 }
155 Result operator()(const ComplexPart &x) const {
156 return visitor_(x.complex());
157 }
158 template <typename T> Result operator()(const Designator<T> &x) const {
159 return visitor_(x.u);
160 }
161 Result operator()(const DescriptorInquiry &x) const {
162 return visitor_(x.base());
163 }
164
165 // Calls
166 Result operator()(const SpecificIntrinsic &) const {
167 return visitor_.Default();
168 }
169 Result operator()(const ProcedureDesignator &x) const {
170 if (const Component * component{x.GetComponent()}) {
171 return visitor_(*component);
172 } else if (const Symbol * symbol{x.GetSymbol()}) {
173 return visitor_(*symbol);
174 } else {
175 return visitor_(DEREF(x.GetSpecificIntrinsic()));
176 }
177 }
178 Result operator()(const ActualArgument &x) const {
179 if (const auto *symbol{x.GetAssumedTypeDummy()}) {
180 return visitor_(*symbol);
181 } else {
182 return visitor_(x.UnwrapExpr());
183 }
184 }
185 Result operator()(const ProcedureRef &x) const {
186 return Combine(x.proc(), x.arguments());
187 }
188 template <typename T> Result operator()(const FunctionRef<T> &x) const {
189 return visitor_(static_cast<const ProcedureRef &>(x));
190 }
191
192 // Other primaries
193 template <typename T>
194 Result operator()(const ArrayConstructorValue<T> &x) const {
195 return visitor_(x.u);
196 }
197 template <typename T>
198 Result operator()(const ArrayConstructorValues<T> &x) const {
199 return CombineContents(x);
200 }
201 template <typename T> Result operator()(const ImpliedDo<T> &x) const {
202 return Combine(x.lower(), x.upper(), x.stride(), x.values());
203 }
204 Result operator()(const semantics::ParamValue &x) const {
205 return visitor_(x.GetExplicit());
206 }
207 Result operator()(
208 const semantics::DerivedTypeSpec::ParameterMapType::value_type &x) const {
209 return visitor_(x.second);
210 }
211 Result operator()(
212 const semantics::DerivedTypeSpec::ParameterMapType &x) const {
213 return CombineContents(x);
214 }
215 Result operator()(const semantics::DerivedTypeSpec &x) const {
216 return Combine(x.originalTypeSymbol(), x.parameters());
217 }
218 Result operator()(const StructureConstructorValues::value_type &x) const {
219 return visitor_(x.second);
220 }
221 Result operator()(const StructureConstructorValues &x) const {
222 return CombineContents(x);
223 }
224 Result operator()(const StructureConstructor &x) const {
225 return visitor_.Combine(visitor_(x.derivedTypeSpec()), CombineContents(x));
226 }
227 // Conditional expressions (Fortran 2023)
228 template <typename T> Result operator()(const ConditionalExpr<T> &x) const {
229 return Combine(x.condition(), x.thenValue(), x.elseValue());
230 }
231
232 // Operations and wrappers
233 // Have a single operator() for all Operations.
234 template <typename D, typename R, typename... Os>
235 Result operator()(const Operation<D, R, Os...> &op) const {
236 if constexpr (sizeof...(Os) == 1) {
237 return visitor_(op.left());
238 } else {
239 return CombineOperands(op, std::index_sequence_for<Os...>{});
240 }
241 }
242 Result operator()(const Relational<SomeType> &x) const {
243 return visitor_(x.u);
244 }
245 template <typename T> Result operator()(const Expr<T> &x) const {
246 return visitor_(x.u);
247 }
248 Result operator()(const Assignment &x) const {
249 return Combine(x.lhs, x.rhs, x.u);
250 }
251 Result operator()(const Assignment::Intrinsic &) const {
252 return visitor_.Default();
253 }
254 Result operator()(const GenericExprWrapper &x) const { return visitor_(x.v); }
255 Result operator()(const GenericAssignmentWrapper &x) const {
256 return visitor_(x.v);
257 }
258
259private:
260 template <typename ITER> Result CombineRange(ITER iter, ITER end) const {
261 if (iter == end) {
262 return visitor_.Default();
263 } else {
264 Result result{visitor_(*iter)};
265 for (++iter; iter != end; ++iter) {
266 result = visitor_.Combine(std::move(result), visitor_(*iter));
267 }
268 return result;
269 }
270 }
271
272 template <typename A> Result CombineContents(const A &x) const {
273 return CombineRange(x.begin(), x.end());
274 }
275
276 template <typename D, typename R, typename... Os, size_t... Is>
277 Result CombineOperands(
278 const Operation<D, R, Os...> &op, std::index_sequence<Is...>) const {
279 static_assert(sizeof...(Os) > 1 && "Expecting multiple operands");
280 return Combine(op.template operand<Is>()...);
281 }
282
283 template <typename A, typename... Bs>
284 Result Combine(const A &x, const Bs &...ys) const {
285 if constexpr (sizeof...(Bs) == 0) {
286 return visitor_(x);
287 } else {
288 return visitor_.Combine(visitor_(x), Combine(ys...));
289 }
290 }
291
292 Visitor &visitor_;
293};
294
295// For validity checks across an expression: if any operator() result is
296// false, so is the overall result.
297template <typename Visitor, bool DefaultValue,
298 bool TraverseAssocEntityDetails = true,
300struct AllTraverse : public Base {
301 explicit AllTraverse(Visitor &v) : Base{v} {}
302 using Base::operator();
303 static bool Default() { return DefaultValue; }
304 static bool Combine(bool x, bool y) { return x && y; }
305};
306
307// For searches over an expression: the first operator() result that
308// is truthful is the final result. Works for Booleans, pointers,
309// and std::optional<>.
310template <typename Visitor, typename Result = bool,
311 bool TraverseAssocEntityDetails = true,
313class AnyTraverse : public Base {
314public:
315 explicit AnyTraverse(Visitor &v) : Base{v} {}
316 using Base::operator();
317 Result Default() const { return default_; }
318 static Result Combine(Result &&x, Result &&y) {
319 if (x) {
320 return std::move(x);
321 } else {
322 return std::move(y);
323 }
324 }
325
326private:
327 Result default_{};
328};
329
330template <typename Visitor, typename Set,
331 bool TraverseAssocEntityDetails = true,
333struct SetTraverse : public Base {
334 explicit SetTraverse(Visitor &v) : Base{v} {}
335 using Base::operator();
336 static Set Default() { return {}; }
337 static Set Combine(Set &&x, Set &&y) {
338#if defined __GNUC__ && !defined __APPLE__ && !(CLANG_LIBRARIES)
339 x.merge(y);
340#else
341 // std::set::merge() not available (yet)
342 for (auto &value : y) {
343 x.insert(std::move(value));
344 }
345#endif
346 return std::move(x);
347 }
348};
349
350} // namespace Fortran::evaluate
351#endif
Definition indirection.h:127
Definition indirection.h:31
Definition variable.h:205
Definition expression.h:908
Definition variable.h:243
Definition variable.h:357
Definition variable.h:73
Definition expression.h:395
Definition constant.h:147
Definition variable.h:413
Definition variable.h:381
Definition common.h:215
Definition call.h:293
Definition expression.h:432
Definition variable.h:101
Definition expression.h:114
Definition call.h:233
Definition expression.h:685
Definition static-data.h:29
Definition expression.h:769
Definition variable.h:304
Definition traverse.h:50
Definition variable.h:160
Definition variable.h:136
Definition type.h:96
Definition symbol.h:832
Definition call.h:34
Definition expression.h:460
Definition expression.h:913
Definition variable.h:50
Definition variable.h:288
Definition expression.h:926
Definition expression.h:424
Definition expression.h:857
Definition variable.h:191