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.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
228 // Operations and wrappers
229 // Have a single operator() for all Operations.
230 template <typename D, typename R, typename... Os>
231 Result operator()(const Operation<D, R, Os...> &op) const {
232 if constexpr (sizeof...(Os) == 1) {
233 return visitor_(op.left());
234 } else {
235 return CombineOperands(op, std::index_sequence_for<Os...>{});
236 }
237 }
238 Result operator()(const Relational<SomeType> &x) const {
239 return visitor_(x.u);
240 }
241 template <typename T> Result operator()(const Expr<T> &x) const {
242 return visitor_(x.u);
243 }
244 Result operator()(const Assignment &x) const {
245 return Combine(x.lhs, x.rhs, x.u);
246 }
247 Result operator()(const Assignment::Intrinsic &) const {
248 return visitor_.Default();
249 }
250 Result operator()(const GenericExprWrapper &x) const { return visitor_(x.v); }
251 Result operator()(const GenericAssignmentWrapper &x) const {
252 return visitor_(x.v);
253 }
254
255private:
256 template <typename ITER> Result CombineRange(ITER iter, ITER end) const {
257 if (iter == end) {
258 return visitor_.Default();
259 } else {
260 Result result{visitor_(*iter)};
261 for (++iter; iter != end; ++iter) {
262 result = visitor_.Combine(std::move(result), visitor_(*iter));
263 }
264 return result;
265 }
266 }
267
268 template <typename A> Result CombineContents(const A &x) const {
269 return CombineRange(x.begin(), x.end());
270 }
271
272 template <typename D, typename R, typename... Os, size_t... Is>
273 Result CombineOperands(
274 const Operation<D, R, Os...> &op, std::index_sequence<Is...>) const {
275 static_assert(sizeof...(Os) > 1 && "Expecting multiple operands");
276 return Combine(op.template operand<Is>()...);
277 }
278
279 template <typename A, typename... Bs>
280 Result Combine(const A &x, const Bs &...ys) const {
281 if constexpr (sizeof...(Bs) == 0) {
282 return visitor_(x);
283 } else {
284 return visitor_.Combine(visitor_(x), Combine(ys...));
285 }
286 }
287
288 Visitor &visitor_;
289};
290
291// For validity checks across an expression: if any operator() result is
292// false, so is the overall result.
293template <typename Visitor, bool DefaultValue,
294 bool TraverseAssocEntityDetails = true,
296struct AllTraverse : public Base {
297 explicit AllTraverse(Visitor &v) : Base{v} {}
298 using Base::operator();
299 static bool Default() { return DefaultValue; }
300 static bool Combine(bool x, bool y) { return x && y; }
301};
302
303// For searches over an expression: the first operator() result that
304// is truthful is the final result. Works for Booleans, pointers,
305// and std::optional<>.
306template <typename Visitor, typename Result = bool,
307 bool TraverseAssocEntityDetails = true,
309class AnyTraverse : public Base {
310public:
311 explicit AnyTraverse(Visitor &v) : Base{v} {}
312 using Base::operator();
313 Result Default() const { return default_; }
314 static Result Combine(Result &&x, Result &&y) {
315 if (x) {
316 return std::move(x);
317 } else {
318 return std::move(y);
319 }
320 }
321
322private:
323 Result default_{};
324};
325
326template <typename Visitor, typename Set,
327 bool TraverseAssocEntityDetails = true,
329struct SetTraverse : public Base {
330 explicit SetTraverse(Visitor &v) : Base{v} {}
331 using Base::operator();
332 static Set Default() { return {}; }
333 static Set Combine(Set &&x, Set &&y) {
334#if defined __GNUC__ && !defined __APPLE__ && !(CLANG_LIBRARIES)
335 x.merge(y);
336#else
337 // std::set::merge() not available (yet)
338 for (auto &value : y) {
339 x.insert(std::move(value));
340 }
341#endif
342 return std::move(x);
343 }
344};
345
346} // namespace Fortran::evaluate
347#endif
Definition indirection.h:127
Definition indirection.h:31
Definition variable.h:205
Definition expression.h:878
Definition variable.h:243
Definition variable.h:353
Definition variable.h:73
Definition constant.h:147
Definition variable.h:409
Definition variable.h:377
Definition common.h:214
Definition call.h:282
Definition expression.h:404
Definition variable.h:101
Definition expression.h:114
Definition call.h:232
Definition expression.h:656
Definition static-data.h:29
Definition expression.h:740
Definition variable.h:300
Definition traverse.h:50
Definition variable.h:160
Definition variable.h:136
Definition type.h:96
Definition symbol.h:778
Definition call.h:34
Definition expression.h:432
Definition expression.h:883
Definition variable.h:50
Definition variable.h:284
Definition expression.h:896
Definition expression.h:396
Definition expression.h:827
Definition variable.h:191