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
45namespace Fortran::evaluate {
46template <typename Visitor, typename Result,
47 bool TraverseAssocEntityDetails = true>
48class Traverse {
49public:
50 explicit Traverse(Visitor &v) : visitor_{v} {}
51
52 // Packaging
53 template <typename A, bool C>
54 Result operator()(const common::Indirection<A, C> &x) const {
55 return visitor_(x.value());
56 }
57 template <typename A>
58 Result operator()(const common::ForwardOwningPointer<A> &p) const {
59 return visitor_(p.get());
60 }
61 template <typename _> Result operator()(const SymbolRef x) const {
62 return visitor_(*x);
63 }
64 template <typename A> Result operator()(const std::unique_ptr<A> &x) const {
65 return visitor_(x.get());
66 }
67 template <typename A> Result operator()(const std::shared_ptr<A> &x) const {
68 return visitor_(x.get());
69 }
70 template <typename A> Result operator()(const A *x) const {
71 if (x) {
72 return visitor_(*x);
73 } else {
74 return visitor_.Default();
75 }
76 }
77 template <typename A> Result operator()(const std::optional<A> &x) const {
78 if (x) {
79 return visitor_(*x);
80 } else {
81 return visitor_.Default();
82 }
83 }
84 template <typename... As>
85 Result operator()(const std::variant<As...> &u) const {
86 return common::visit([=](const auto &y) { return visitor_(y); }, u);
87 }
88 template <typename A> Result operator()(const std::vector<A> &x) const {
89 return CombineContents(x);
90 }
91 template <typename A, typename B>
92 Result operator()(const std::pair<A, B> &x) const {
93 return Combine(x.first, x.second);
94 }
95
96 // Leaves
97 Result operator()(const BOZLiteralConstant &) const {
98 return visitor_.Default();
99 }
100 Result operator()(const NullPointer &) const { return visitor_.Default(); }
101 template <typename T> Result operator()(const Constant<T> &x) const {
102 if constexpr (T::category == TypeCategory::Derived) {
103 return visitor_.Combine(
104 visitor_(x.result().derivedTypeSpec()), CombineContents(x.values()));
105 } else {
106 return visitor_.Default();
107 }
108 }
109 Result operator()(const Symbol &symbol) const {
110 const Symbol &ultimate{symbol.GetUltimate()};
111 if constexpr (TraverseAssocEntityDetails) {
112 if (const auto *assoc{
113 ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
114 return visitor_(assoc->expr());
115 }
116 }
117 return visitor_.Default();
118 }
119 Result operator()(const StaticDataObject &) const {
120 return visitor_.Default();
121 }
122 Result operator()(const ImpliedDoIndex &) const { return visitor_.Default(); }
123
124 // Variables
125 Result operator()(const BaseObject &x) const { return visitor_(x.u); }
126 Result operator()(const Component &x) const {
127 return Combine(x.base(), x.symbol());
128 }
129 Result operator()(const NamedEntity &x) const {
130 if (const Component * component{x.UnwrapComponent()}) {
131 return visitor_(*component);
132 } else {
133 return visitor_(DEREF(x.UnwrapSymbolRef()));
134 }
135 }
136 Result operator()(const TypeParamInquiry &x) const {
137 return visitor_(x.base());
138 }
139 Result operator()(const Triplet &x) const {
140 return Combine(x.GetLower(), x.GetUpper(), x.GetStride());
141 }
142 Result operator()(const Subscript &x) const { return visitor_(x.u); }
143 Result operator()(const ArrayRef &x) const {
144 return Combine(x.base(), x.subscript());
145 }
146 Result operator()(const CoarrayRef &x) const {
147 return Combine(x.base(), x.cosubscript(), x.notify(), x.stat(), x.team());
148 }
149 Result operator()(const DataRef &x) const { return visitor_(x.u); }
150 Result operator()(const Substring &x) const {
151 return Combine(x.parent(), x.GetLower(), x.GetUpper());
152 }
153 Result operator()(const ComplexPart &x) const {
154 return visitor_(x.complex());
155 }
156 template <typename T> Result operator()(const Designator<T> &x) const {
157 return visitor_(x.u);
158 }
159 Result operator()(const DescriptorInquiry &x) const {
160 return visitor_(x.base());
161 }
162
163 // Calls
164 Result operator()(const SpecificIntrinsic &) const {
165 return visitor_.Default();
166 }
167 Result operator()(const ProcedureDesignator &x) const {
168 if (const Component * component{x.GetComponent()}) {
169 return visitor_(*component);
170 } else if (const Symbol * symbol{x.GetSymbol()}) {
171 return visitor_(*symbol);
172 } else {
173 return visitor_(DEREF(x.GetSpecificIntrinsic()));
174 }
175 }
176 Result operator()(const ActualArgument &x) const {
177 if (const auto *symbol{x.GetAssumedTypeDummy()}) {
178 return visitor_(*symbol);
179 } else {
180 return visitor_(x.UnwrapExpr());
181 }
182 }
183 Result operator()(const ProcedureRef &x) const {
184 return Combine(x.proc(), x.arguments());
185 }
186 template <typename T> Result operator()(const FunctionRef<T> &x) const {
187 return visitor_(static_cast<const ProcedureRef &>(x));
188 }
189
190 // Other primaries
191 template <typename T>
192 Result operator()(const ArrayConstructorValue<T> &x) const {
193 return visitor_(x.u);
194 }
195 template <typename T>
196 Result operator()(const ArrayConstructorValues<T> &x) const {
197 return CombineContents(x);
198 }
199 template <typename T> Result operator()(const ImpliedDo<T> &x) const {
200 return Combine(x.lower(), x.upper(), x.stride(), x.values());
201 }
202 Result operator()(const semantics::ParamValue &x) const {
203 return visitor_(x.GetExplicit());
204 }
205 Result operator()(
206 const semantics::DerivedTypeSpec::ParameterMapType::value_type &x) const {
207 return visitor_(x.second);
208 }
209 Result operator()(
210 const semantics::DerivedTypeSpec::ParameterMapType &x) const {
211 return CombineContents(x);
212 }
213 Result operator()(const semantics::DerivedTypeSpec &x) const {
214 return Combine(x.originalTypeSymbol(), x.parameters());
215 }
216 Result operator()(const StructureConstructorValues::value_type &x) const {
217 return visitor_(x.second);
218 }
219 Result operator()(const StructureConstructorValues &x) const {
220 return CombineContents(x);
221 }
222 Result operator()(const StructureConstructor &x) const {
223 return visitor_.Combine(visitor_(x.derivedTypeSpec()), CombineContents(x));
224 }
225 // Conditional expressions (Fortran 2023)
226 template <typename T> Result operator()(const ConditionalExpr<T> &x) const {
227 return Combine(x.condition(), x.thenValue(), x.elseValue());
228 }
229
230 // Operations and wrappers
231 // Have a single operator() for all Operations.
232 template <typename D, typename R, typename... Os>
233 Result operator()(const Operation<D, R, Os...> &op) const {
234 if constexpr (sizeof...(Os) == 1) {
235 return visitor_(op.left());
236 } else {
237 return CombineOperands(op, std::index_sequence_for<Os...>{});
238 }
239 }
240 Result operator()(const Relational<SomeType> &x) const {
241 return visitor_(x.u);
242 }
243 template <typename T> Result operator()(const Expr<T> &x) const {
244 return visitor_(x.u);
245 }
246 Result operator()(const Assignment &x) const {
247 return Combine(x.lhs, x.rhs, x.u);
248 }
249 Result operator()(const Assignment::Intrinsic &) const {
250 return visitor_.Default();
251 }
252 Result operator()(const GenericExprWrapper &x) const { return visitor_(x.v); }
253 Result operator()(const GenericAssignmentWrapper &x) const {
254 return visitor_(x.v);
255 }
256
257private:
258 template <typename ITER> Result CombineRange(ITER iter, ITER end) const {
259 if (iter == end) {
260 return visitor_.Default();
261 } else {
262 Result result{visitor_(*iter)};
263 for (++iter; iter != end; ++iter) {
264 result = visitor_.Combine(std::move(result), visitor_(*iter));
265 }
266 return result;
267 }
268 }
269
270 template <typename A> Result CombineContents(const A &x) const {
271 return CombineRange(x.begin(), x.end());
272 }
273
274 template <typename D, typename R, typename... Os, size_t... Is>
275 Result CombineOperands(
276 const Operation<D, R, Os...> &op, std::index_sequence<Is...>) const {
277 static_assert(sizeof...(Os) > 1 && "Expecting multiple operands");
278 return Combine(op.template operand<Is>()...);
279 }
280
281 template <typename A, typename... Bs>
282 Result Combine(const A &x, const Bs &...ys) const {
283 if constexpr (sizeof...(Bs) == 0) {
284 return visitor_(x);
285 } else {
286 return visitor_.Combine(visitor_(x), Combine(ys...));
287 }
288 }
289
290 Visitor &visitor_;
291};
292
293// For validity checks across an expression: if any operator() result is
294// false, so is the overall result.
295template <typename Visitor, bool DefaultValue,
296 bool TraverseAssocEntityDetails = true,
298struct AllTraverse : public Base {
299 explicit AllTraverse(Visitor &v) : Base{v} {}
300 using Base::operator();
301 static bool Default() { return DefaultValue; }
302 static bool Combine(bool x, bool y) { return x && y; }
303};
304
305// For searches over an expression: the first operator() result that
306// is truthful is the final result. Works for Booleans, pointers,
307// and std::optional<>.
308template <typename Visitor, typename Result = bool,
309 bool TraverseAssocEntityDetails = true,
311class AnyTraverse : public Base {
312public:
313 explicit AnyTraverse(Visitor &v) : Base{v} {}
314 using Base::operator();
315 Result Default() const { return default_; }
316 static Result Combine(Result &&x, Result &&y) {
317 if (x) {
318 return std::move(x);
319 } else {
320 return std::move(y);
321 }
322 }
323
324private:
325 Result default_{};
326};
327
328template <typename Visitor, typename Set,
329 bool TraverseAssocEntityDetails = true,
331struct SetTraverse : public Base {
332 explicit SetTraverse(Visitor &v) : Base{v} {}
333 using Base::operator();
334 static Set Default() { return {}; }
335 static Set Combine(Set &&x, Set &&y) {
336#if defined __GNUC__ && !defined __APPLE__ && !(CLANG_LIBRARIES)
337 x.merge(y);
338#else
339 // std::set::merge() not available (yet)
340 for (auto &value : y) {
341 x.insert(std::move(value));
342 }
343#endif
344 return std::move(x);
345 }
346};
347
348} // namespace Fortran::evaluate
349#endif
Definition indirection.h:127
Definition indirection.h:31
Definition variable.h:205
Definition expression.h:920
Definition variable.h:243
Definition variable.h:357
Definition variable.h:73
Definition expression.h:394
Definition constant.h:147
Definition variable.h:413
Definition variable.h:381
Definition common.h:215
Definition call.h:294
Definition expression.h:444
Definition variable.h:101
Definition expression.h:113
Definition call.h:234
Definition expression.h:697
Definition static-data.h:29
Definition expression.h:781
Definition variable.h:304
Definition traverse.h:48
Definition variable.h:160
Definition variable.h:136
Definition type.h:95
Definition symbol.h:893
Definition call.h:34
Definition expression.h:472
Definition expression.h:925
Definition variable.h:50
Definition variable.h:288
Definition expression.h:938
Definition expression.h:436
Definition expression.h:869
Definition variable.h:191