xref: /llvm-project/flang/include/flang/Evaluate/variable.h (revision ebec4d6369cbf9bbd64236b02d90e8f3597ad103)
1 //===-- include/flang/Evaluate/variable.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_VARIABLE_H_
10 #define FORTRAN_EVALUATE_VARIABLE_H_
11 
12 // Defines data structures to represent data access and function calls
13 // for use in expressions and assignment statements.  Both copy and move
14 // semantics are supported.  The representation adheres closely to the
15 // Fortran 2018 language standard (q.v.) and uses strong typing to ensure
16 // that only admissable combinations can be constructed.
17 
18 #include "call.h"
19 #include "common.h"
20 #include "formatting.h"
21 #include "static-data.h"
22 #include "type.h"
23 #include "flang/Common/idioms.h"
24 #include "flang/Common/reference.h"
25 #include "flang/Common/template.h"
26 #include "flang/Parser/char-block.h"
27 #include <optional>
28 #include <variant>
29 #include <vector>
30 
31 namespace llvm {
32 class raw_ostream;
33 }
34 
35 namespace Fortran::semantics {
36 class Symbol;
37 }
38 
39 namespace Fortran::evaluate {
40 
41 using semantics::Symbol;
42 using SymbolRef = common::Reference<const Symbol>;
43 using SymbolVector = std::vector<SymbolRef>;
44 
45 // Forward declarations
46 struct DataRef;
47 template <typename T> struct Variable;
48 
49 // Reference a base object in memory.  This can be a Fortran symbol,
50 // static data (e.g., CHARACTER literal), or compiler-created temporary.
51 struct BaseObject {
52   EVALUATE_UNION_CLASS_BOILERPLATE(BaseObject)
53   int Rank() const;
54   int Corank() const;
55   std::optional<Expr<SubscriptInteger>> LEN() const;
56   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
57   const Symbol *symbol() const {
58     if (const auto *result{std::get_if<SymbolRef>(&u)}) {
59       return &result->get();
60     } else {
61       return nullptr;
62     }
63   }
64   std::variant<SymbolRef, StaticDataObject::Pointer> u;
65 };
66 
67 // R913 structure-component & C920: Defined to be a multi-part
68 // data-ref whose last part has no subscripts (or image-selector, although
69 // that isn't explicit in the document).  Pointer and allocatable components
70 // are not explicitly indirected in this representation.
71 // Complex components (%RE, %IM) are isolated below in ComplexPart.
72 // (Type parameter inquiries look like component references but are distinct
73 // constructs and not represented by this class.)
74 class Component {
75 public:
76   CLASS_BOILERPLATE(Component)
77   Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{c} {}
78   Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{c} {}
79   Component(common::CopyableIndirection<DataRef> &&b, const Symbol &c)
80       : base_{std::move(b)}, symbol_{c} {}
81 
82   const DataRef &base() const { return base_.value(); }
83   DataRef &base() { return base_.value(); }
84   const SymbolRef &symbol() const { return symbol_; }
85   SymbolRef &symbol() { return symbol_; }
86 
87   int Rank() const;
88   int Corank() const;
89   const Symbol &GetFirstSymbol() const;
90   const Symbol &GetLastSymbol() const { return symbol_; }
91   std::optional<Expr<SubscriptInteger>> LEN() const;
92   bool operator==(const Component &) const;
93   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
94 
95 private:
96   common::CopyableIndirection<DataRef> base_;
97   SymbolRef symbol_;
98 };
99 
100 // A NamedEntity is either a whole Symbol or a component in an instance
101 // of a derived type.  It may be a descriptor.
102 // TODO: this is basically a symbol with an optional DataRef base;
103 // could be used to replace Component.
104 class NamedEntity {
105 public:
106   CLASS_BOILERPLATE(NamedEntity)
107   explicit NamedEntity(const Symbol &symbol) : u_{symbol} {}
108   explicit NamedEntity(Component &&c) : u_{std::move(c)} {}
109 
110   bool IsSymbol() const { return std::holds_alternative<SymbolRef>(u_); }
111   const Symbol &GetFirstSymbol() const;
112   const Symbol &GetLastSymbol() const;
113   const Component &GetComponent() const { return std::get<Component>(u_); }
114   Component &GetComponent() { return std::get<Component>(u_); }
115   const SymbolRef *UnwrapSymbolRef() const; // null if a Component
116   SymbolRef *UnwrapSymbolRef();
117   const Component *UnwrapComponent() const; // null if not a Component
118   Component *UnwrapComponent();
119 
120   int Rank() const;
121   int Corank() const;
122   std::optional<Expr<SubscriptInteger>> LEN() const;
123   bool operator==(const NamedEntity &) const;
124   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
125 
126 private:
127   std::variant<SymbolRef, Component> u_;
128 };
129 
130 // R916 type-param-inquiry
131 // N.B. x%LEN for CHARACTER is rewritten in semantics to LEN(x), which is
132 // then handled via LEN() member functions in the various classes;
133 // it becomes a DescriptorInquiry with Field::Len for assumed-length
134 // CHARACTER objects.
135 // x%KIND for intrinsic types is similarly rewritten in semantics to
136 // KIND(x), which is then folded to a constant value.
137 // "Bare" type parameter references within a derived type definition do
138 // not have base objects.
139 class TypeParamInquiry {
140 public:
141   using Result = SubscriptInteger;
142   CLASS_BOILERPLATE(TypeParamInquiry)
143   TypeParamInquiry(NamedEntity &&x, const Symbol &param)
144       : base_{std::move(x)}, parameter_{param} {}
145   TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol &param)
146       : base_{std::move(x)}, parameter_{param} {}
147 
148   const std::optional<NamedEntity> &base() const { return base_; }
149   std::optional<NamedEntity> &base() { return base_; }
150   const Symbol &parameter() const { return parameter_; }
151 
152   static constexpr int Rank() { return 0; } // always scalar
153   static constexpr int Corank() { return 0; }
154   bool operator==(const TypeParamInquiry &) const;
155   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
156 
157 private:
158   std::optional<NamedEntity> base_;
159   SymbolRef parameter_;
160 };
161 
162 // R921 subscript-triplet
163 class Triplet {
164 public:
165   Triplet();
166   DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(Triplet)
167   Triplet(std::optional<Expr<SubscriptInteger>> &&,
168       std::optional<Expr<SubscriptInteger>> &&,
169       std::optional<Expr<SubscriptInteger>> &&);
170 
171   std::optional<Expr<SubscriptInteger>> lower() const;
172   const Expr<SubscriptInteger> *GetLower() const {
173     return lower_.has_value() ? &lower_->value() : nullptr;
174   }
175   Triplet &set_lower(Expr<SubscriptInteger> &&);
176   std::optional<Expr<SubscriptInteger>> upper() const;
177   const Expr<SubscriptInteger> *GetUpper() const {
178     return upper_.has_value() ? &upper_->value() : nullptr;
179   }
180   Triplet &set_upper(Expr<SubscriptInteger> &&);
181   Expr<SubscriptInteger> stride() const; // N.B. result is not optional<>
182   const Expr<SubscriptInteger> &GetStride() const { return stride_.value(); }
183   Triplet &set_stride(Expr<SubscriptInteger> &&);
184 
185   bool operator==(const Triplet &) const;
186   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
187 
188 private:
189   std::optional<IndirectSubscriptIntegerExpr> lower_, upper_;
190   IndirectSubscriptIntegerExpr stride_;
191 };
192 
193 // R919 subscript when rank 0, R923 vector-subscript when rank 1
194 struct Subscript {
195   EVALUATE_UNION_CLASS_BOILERPLATE(Subscript)
196   explicit Subscript(Expr<SubscriptInteger> &&s)
197       : u{IndirectSubscriptIntegerExpr::Make(std::move(s))} {}
198   int Rank() const;
199   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
200   std::variant<IndirectSubscriptIntegerExpr, Triplet> u;
201 };
202 
203 // R917 array-element, R918 array-section; however, the case of an
204 // array-section that is a complex-part-designator is represented here
205 // as a ComplexPart instead.  C919 & C925 require that at most one set of
206 // subscripts have rank greater than 0, but that is not explicit in
207 // these types.
208 class ArrayRef {
209 public:
210   CLASS_BOILERPLATE(ArrayRef)
211   ArrayRef(const Symbol &symbol, std::vector<Subscript> &&ss)
212       : base_{symbol}, subscript_(std::move(ss)) {}
213   ArrayRef(Component &&c, std::vector<Subscript> &&ss)
214       : base_{std::move(c)}, subscript_(std::move(ss)) {}
215   ArrayRef(NamedEntity &&base, std::vector<Subscript> &&ss)
216       : base_{std::move(base)}, subscript_(std::move(ss)) {}
217 
218   NamedEntity &base() { return base_; }
219   const NamedEntity &base() const { return base_; }
220   std::vector<Subscript> &subscript() { return subscript_; }
221   const std::vector<Subscript> &subscript() const { return subscript_; }
222 
223   int size() const { return static_cast<int>(subscript_.size()); }
224   Subscript &at(int n) { return subscript_.at(n); }
225   const Subscript &at(int n) const { return subscript_.at(n); }
226   template <typename A> common::IfNoLvalue<Subscript &, A> emplace_back(A &&x) {
227     return subscript_.emplace_back(std::move(x));
228   }
229 
230   int Rank() const;
231   int Corank() const;
232   const Symbol &GetFirstSymbol() const;
233   const Symbol &GetLastSymbol() const;
234   std::optional<Expr<SubscriptInteger>> LEN() const;
235   bool operator==(const ArrayRef &) const;
236   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
237 
238 private:
239   NamedEntity base_;
240   std::vector<Subscript> subscript_;
241 };
242 
243 // R914 coindexed-named-object
244 // R924 image-selector, R926 image-selector-spec.
245 // C825 severely limits the usage of derived types with coarray ultimate
246 // components: they can't be pointers, allocatables, arrays, coarrays, or
247 // function results.  They can be components of other derived types.
248 // Although the F'2018 Standard never prohibits multiple image-selectors
249 // per se in the same data-ref or designator, nor the presence of an
250 // image-selector after a part-ref with rank, the constraints on the
251 // derived types that would have be involved make it impossible to declare
252 // an object that could be referenced in these ways (esp. C748 & C825).
253 // C930 precludes having both TEAM= and TEAM_NUMBER=.
254 // TODO C931 prohibits the use of a coindexed object as a stat-variable.
255 class CoarrayRef {
256 public:
257   CLASS_BOILERPLATE(CoarrayRef)
258   CoarrayRef(SymbolVector &&, std::vector<Subscript> &&,
259       std::vector<Expr<SubscriptInteger>> &&);
260 
261   const SymbolVector &base() const { return base_; }
262   SymbolVector &base() { return base_; }
263   const std::vector<Subscript> &subscript() const { return subscript_; }
264   std::vector<Subscript> &subscript() { return subscript_; }
265   const std::vector<Expr<SubscriptInteger>> &cosubscript() const {
266     return cosubscript_;
267   }
268   std::vector<Expr<SubscriptInteger>> &cosubscript() { return cosubscript_; }
269 
270   // These integral expressions for STAT= and TEAM= must be variables
271   // (i.e., Designator or pointer-valued FunctionRef).
272   std::optional<Expr<SomeInteger>> stat() const;
273   CoarrayRef &set_stat(Expr<SomeInteger> &&);
274   std::optional<Expr<SomeInteger>> team() const;
275   bool teamIsTeamNumber() const { return teamIsTeamNumber_; }
276   CoarrayRef &set_team(Expr<SomeInteger> &&, bool isTeamNumber = false);
277 
278   int Rank() const;
279   int Corank() const { return 0; }
280   const Symbol &GetFirstSymbol() const;
281   const Symbol &GetLastSymbol() const;
282   NamedEntity GetBase() const;
283   std::optional<Expr<SubscriptInteger>> LEN() const;
284   bool operator==(const CoarrayRef &) const;
285   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
286 
287 private:
288   SymbolVector base_;
289   std::vector<Subscript> subscript_;
290   std::vector<Expr<SubscriptInteger>> cosubscript_;
291   std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
292   bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER=
293 };
294 
295 // R911 data-ref is defined syntactically as a series of part-refs, which
296 // would be far too expressive if the constraints were ignored.  Here, the
297 // possible outcomes are spelled out.  Note that a data-ref cannot include
298 // a terminal substring range or complex component designator; use
299 // R901 designator for that.
300 struct DataRef {
301   EVALUATE_UNION_CLASS_BOILERPLATE(DataRef)
302   int Rank() const;
303   int Corank() const;
304   const Symbol &GetFirstSymbol() const;
305   const Symbol &GetLastSymbol() const;
306   std::optional<Expr<SubscriptInteger>> LEN() const;
307   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
308 
309   std::variant<SymbolRef, Component, ArrayRef, CoarrayRef> u;
310 };
311 
312 // R908 substring, R909 parent-string, R910 substring-range.
313 // The base object of a substring can be a literal.
314 // In the F2018 standard, substrings of array sections are parsed as
315 // variants of sections instead.
316 class Substring {
317   using Parent = std::variant<DataRef, StaticDataObject::Pointer>;
318 
319 public:
320   CLASS_BOILERPLATE(Substring)
321   Substring(DataRef &&parent, std::optional<Expr<SubscriptInteger>> &&lower,
322       std::optional<Expr<SubscriptInteger>> &&upper)
323       : parent_{std::move(parent)} {
324     SetBounds(lower, upper);
325   }
326   Substring(StaticDataObject::Pointer &&parent,
327       std::optional<Expr<SubscriptInteger>> &&lower,
328       std::optional<Expr<SubscriptInteger>> &&upper)
329       : parent_{std::move(parent)} {
330     SetBounds(lower, upper);
331   }
332 
333   Expr<SubscriptInteger> lower() const;
334   const Expr<SubscriptInteger> *GetLower() const {
335     return lower_.has_value() ? &lower_->value() : nullptr;
336   }
337   Substring &set_lower(Expr<SubscriptInteger> &&);
338   std::optional<Expr<SubscriptInteger>> upper() const;
339   const Expr<SubscriptInteger> *GetUpper() const {
340     return upper_.has_value() ? &upper_->value() : nullptr;
341   }
342   Substring &set_upper(Expr<SubscriptInteger> &&);
343   const Parent &parent() const { return parent_; }
344   Parent &parent() { return parent_; }
345 
346   int Rank() const;
347   int Corank() const;
348   template <typename A> const A *GetParentIf() const {
349     return std::get_if<A>(&parent_);
350   }
351   BaseObject GetBaseObject() const;
352   const Symbol *GetLastSymbol() const;
353   std::optional<Expr<SubscriptInteger>> LEN() const;
354   bool operator==(const Substring &) const;
355   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
356 
357   std::optional<Expr<SomeCharacter>> Fold(FoldingContext &);
358 
359 private:
360   void SetBounds(std::optional<Expr<SubscriptInteger>> &,
361       std::optional<Expr<SubscriptInteger>> &);
362   Parent parent_;
363   std::optional<IndirectSubscriptIntegerExpr> lower_, upper_;
364 };
365 
366 // R915 complex-part-designator
367 // In the F2018 standard, complex parts of array sections are parsed as
368 // variants of sections instead.
369 class ComplexPart {
370 public:
371   ENUM_CLASS(Part, RE, IM)
372   CLASS_BOILERPLATE(ComplexPart)
373   ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {}
374   DataRef &complex() { return complex_; }
375   const DataRef &complex() const { return complex_; }
376   Part part() const { return part_; }
377   int Rank() const;
378   int Corank() const;
379   const Symbol &GetFirstSymbol() const { return complex_.GetFirstSymbol(); }
380   const Symbol &GetLastSymbol() const { return complex_.GetLastSymbol(); }
381   bool operator==(const ComplexPart &) const;
382   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
383 
384 private:
385   DataRef complex_;
386   Part part_;
387 };
388 
389 // R901 designator is the most general data reference object, apart from
390 // calls to pointer-valued functions.  Its variant holds everything that
391 // a DataRef can, and possibly also a substring reference or a
392 // complex component (%RE/%IM) reference.
393 template <typename T> class Designator {
394   using DataRefs = std::decay_t<decltype(DataRef::u)>;
395   using MaybeSubstring =
396       std::conditional_t<T::category == TypeCategory::Character,
397           std::variant<Substring>, std::variant<>>;
398   using MaybeComplexPart = std::conditional_t<T::category == TypeCategory::Real,
399       std::variant<ComplexPart>, std::variant<>>;
400   using Variant =
401       common::CombineVariants<DataRefs, MaybeSubstring, MaybeComplexPart>;
402 
403 public:
404   using Result = T;
405   static_assert(
406       IsSpecificIntrinsicType<Result> || std::is_same_v<Result, SomeDerived>);
407   EVALUATE_UNION_CLASS_BOILERPLATE(Designator)
408   Designator(const DataRef &that) : u{common::CopyVariant<Variant>(that.u)} {}
409   Designator(DataRef &&that)
410       : u{common::MoveVariant<Variant>(std::move(that.u))} {}
411 
412   std::optional<DynamicType> GetType() const;
413   int Rank() const;
414   int Corank() const;
415   BaseObject GetBaseObject() const;
416   const Symbol *GetLastSymbol() const;
417   std::optional<Expr<SubscriptInteger>> LEN() const;
418   llvm::raw_ostream &AsFortran(llvm::raw_ostream &o) const;
419 
420   Variant u;
421 };
422 
423 FOR_EACH_CHARACTER_KIND(extern template class Designator, )
424 
425 class DescriptorInquiry {
426 public:
427   using Result = SubscriptInteger;
428   ENUM_CLASS(Field, LowerBound, Extent, Stride, Rank, Len)
429 
430   CLASS_BOILERPLATE(DescriptorInquiry)
431   DescriptorInquiry(const NamedEntity &, Field, int = 0);
432   DescriptorInquiry(NamedEntity &&, Field, int = 0);
433 
434   NamedEntity &base() { return base_; }
435   const NamedEntity &base() const { return base_; }
436   Field field() const { return field_; }
437   int dimension() const { return dimension_; }
438 
439   static constexpr int Rank() { return 0; } // always scalar
440   static constexpr int Corank() { return 0; }
441   bool operator==(const DescriptorInquiry &) const;
442   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
443 
444 private:
445   NamedEntity base_;
446   Field field_;
447   int dimension_{0}; // zero-based
448 };
449 
450 #define INSTANTIATE_VARIABLE_TEMPLATES \
451   FOR_EACH_SPECIFIC_TYPE(template class Designator, )
452 } // namespace Fortran::evaluate
453 #endif // FORTRAN_EVALUATE_VARIABLE_H_
454