FLANG
expression.h
1//===-- include/flang/Evaluate/expression.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_EXPRESSION_H_
10#define FORTRAN_EVALUATE_EXPRESSION_H_
11
12// Represent Fortran expressions in a type-safe manner.
13// Expressions are the sole owners of their constituents; i.e., there is no
14// context-independent hash table or sharing of common subexpressions, and
15// thus these are trees, not DAGs. Both deep copy and move semantics are
16// supported for expression construction. Expressions may be compared
17// for equality.
18
19#include "common.h"
20#include "constant.h"
21#include "formatting.h"
22#include "type.h"
23#include "variable.h"
24#include "flang/Common/idioms.h"
25#include "flang/Common/indirection.h"
26#include "flang/Common/template.h"
27#include "flang/Parser/char-block.h"
28#include "flang/Support/Fortran.h"
29#include <algorithm>
30#include <tuple>
31#include <type_traits>
32#include <variant>
33
34namespace llvm {
35class raw_ostream;
36}
37
38namespace Fortran::evaluate {
39
40using common::LogicalOperator;
41using common::RelationalOperator;
42
43// Expressions are represented by specializations of the class template Expr.
44// Each of these specializations wraps a single data member "u" that
45// is a std::variant<> discriminated union over all of the representational
46// types for the constants, variables, operations, and other entities that
47// can be valid expressions in that context:
48// - Expr<Type<CATEGORY>> represents an expression whose result is of a
49// specific intrinsic type category, e.g. Type<TypeCategory::Real>
50// - Expr<SomeDerived> wraps data and procedure references that result in an
51// instance of a derived type (or CLASS(*) unlimited polymorphic)
52// - Expr<SomeKind<CATEGORY>> is equivalent to Expr<Type<CATEGORY>>
53// - Expr<SomeType> is a union of Expr<SomeKind<CATEGORY>> over the five
54// intrinsic type categories of Fortran. It represents any valid expression.
55//
56// Everything that can appear in, or as, a valid Fortran expression must be
57// represented with an instance of some class containing a Result typedef that
58// maps to some instantiation of Type<CATEGORY>, SomeKind<CATEGORY>,
59// or SomeType. (Exception: BOZ literal constants in generic Expr<SomeType>.)
60template <typename A> using ResultType = typename std::decay_t<A>::Result;
61template <typename A> constexpr int ResultKind = std::decay_t<A>::kind();
62
63// Common Expr<> behaviors: every Expr<T> derives from ExpressionBase<T>.
64template <typename RESULT> class ExpressionBase {
65public:
66 using Result = RESULT;
67
68 int kind() const;
69
70private:
71 using Derived = Expr<Result>;
72#if defined(__APPLE__) && defined(__GNUC__)
73 Derived &derived();
74 const Derived &derived() const;
75#else
76 Derived &derived() { return *static_cast<Derived *>(this); }
77 const Derived &derived() const { return *static_cast<const Derived *>(this); }
78#endif
79
80public:
81 template <typename A> Derived &operator=(const A &x) {
82 Derived &d{derived()};
83 d.u = x;
84 return d;
85 }
86
87 template <typename A> common::IfNoLvalue<Derived &, A> operator=(A &&x) {
88 Derived &d{derived()};
89 d.u = std::move(x);
90 return d;
91 }
92
93 std::optional<DynamicType> GetType() const;
94 int Rank() const;
95 int Corank() const;
96 std::string AsFortran() const;
97#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
98 LLVM_DUMP_METHOD void dump() const;
99#endif
100 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
101 static Derived Rewrite(FoldingContext &, Derived &&);
102};
103
104// Operations always have specific Fortran result types (i.e., with known
105// intrinsic type category and kind parameter value). The classes that
106// represent the operations all inherit from this Operation<> base class
107// template. Note that Operation has as its first type parameter (DERIVED) a
108// "curiously recurring template pattern (CRTP)" reference to the specific
109// operation class being derived from Operation; e.g., Add is defined with
110// struct Add : public Operation<Add, ...>. Uses of instances of Operation<>,
111// including its own member functions, can access each specific class derived
112// from it via its derived() member function with compile-time type safety.
113template <typename DERIVED, typename RESULT, typename... OPERANDS>
114class Operation {
115 // The extra final member is a dummy that allows a safe unused reference
116 // to element 1 to arise indirectly in the definition of "right()" below
117 // when the operation has but a single operand.
118 using OperandTypes = std::tuple<OPERANDS..., std::monostate>;
119
120public:
121 using Derived = DERIVED;
122 using Result = RESULT;
123 static constexpr std::size_t operands{sizeof...(OPERANDS)};
124 // Allow specific intrinsic types and Parentheses<SomeDerived>
125 static_assert(IsSpecificIntrinsicType<Result> ||
126 (operands == 1 && std::is_same_v<Result, SomeDerived>));
127 template <int J> using Operand = std::tuple_element_t<J, OperandTypes>;
128
129 constexpr int kind() const { return kind_; }
130
131 // Unary operations wrap a single Expr with a CopyableIndirection.
132 // Binary operations wrap a tuple of CopyableIndirections to Exprs.
133private:
134 using Container = std::conditional_t<operands == 1,
135 common::CopyableIndirection<Expr<Operand<0>>>,
136 std::tuple<common::CopyableIndirection<Expr<OPERANDS>>...>>;
137
138public:
139 CLASS_BOILERPLATE(Operation)
140 explicit Operation(int kind, const Expr<OPERANDS> &...x)
141 : kind_{kind}, operand_{x...} {
142 CHECK_KIND(kind, RESULT);
143 }
144 explicit Operation(int kind, Expr<OPERANDS> &&...x)
145 : kind_{kind}, operand_{std::move(x)...} {
146 CHECK_KIND(kind, RESULT);
147 }
148
149 Derived &derived() { return *static_cast<Derived *>(this); }
150 const Derived &derived() const { return *static_cast<const Derived *>(this); }
151
152 // References to operand expressions from member functions of derived
153 // classes for specific operators can be made by index, e.g. operand<0>(),
154 // which must be spelled like "this->template operand<0>()" when
155 // inherited in a derived class template. There are convenience aliases
156 // left() and right() that are not templates.
157 template <int J> Expr<Operand<J>> &operand() {
158 if constexpr (operands == 1) {
159 static_assert(J == 0);
160 return operand_.value();
161 } else {
162 return std::get<J>(operand_).value();
163 }
164 }
165 template <int J> const Expr<Operand<J>> &operand() const {
166 if constexpr (operands == 1) {
167 static_assert(J == 0);
168 return operand_.value();
169 } else {
170 return std::get<J>(operand_).value();
171 }
172 }
173
174 Expr<Operand<0>> &left() { return operand<0>(); }
175 const Expr<Operand<0>> &left() const { return operand<0>(); }
176
177 std::conditional_t<(operands > 1), Expr<Operand<1>> &, void> right() {
178 if constexpr (operands > 1) {
179 return operand<1>();
180 }
181 }
182 std::conditional_t<(operands > 1), const Expr<Operand<1>> &, void>
183 right() const {
184 if constexpr (operands > 1) {
185 return operand<1>();
186 }
187 }
188
189 constexpr std::optional<DynamicType> GetType() const {
190 return DynamicType{Result::category, kind()};
191 }
192 int Rank() const {
193 int rank{left().Rank()};
194 if constexpr (operands > 1) {
195 return std::max(rank, right().Rank());
196 } else {
197 return rank;
198 }
199 }
200 static constexpr int Corank() { return 0; }
201
202 bool operator==(const Operation &that) const {
203 return kind() == that.kind() && operand_ == that.operand_;
204 }
205
206 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
207
208private:
209 int kind_;
210 Container operand_;
211};
212
213// Unary operations
214
215// Conversions to specific types from expressions of known category and
216// dynamic kind.
217template <typename TO, TypeCategory FROMCAT = TO::category>
218struct Convert : public Operation<Convert<TO, FROMCAT>, TO, SomeKind<FROMCAT>> {
219 // Fortran doesn't have conversions between kinds of CHARACTER apart from
220 // assignments, and in those the data must be convertible to/from 7-bit ASCII.
221 static_assert(
222 ((TO::category == TypeCategory::Integer ||
223 TO::category == TypeCategory::Real ||
224 TO::category == TypeCategory::Unsigned) &&
225 (FROMCAT == TypeCategory::Integer || FROMCAT == TypeCategory::Real ||
226 FROMCAT == TypeCategory::Unsigned)) ||
227 TO::category == FROMCAT);
228 using Result = TO;
229 using Operand = SomeKind<FROMCAT>;
230 using Base = Operation<Convert, Result, Operand>;
231 using Base::Base;
232 using Base::kind;
233 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
234};
235
236template <typename A>
237struct Parentheses : public Operation<Parentheses<A>, A, A> {
238 using Result = A;
239 using Operand = A;
240 using Base = Operation<Parentheses, A, A>;
241 using Base::Base;
242
243 explicit Parentheses(const Expr<A> &x) : Base{x.kind(), x} {}
244 explicit Parentheses(Expr<A> &&x) : Base{x.kind(), std::move(x)} {}
245};
246
247template <>
248struct Parentheses<SomeDerived>
249 : public Operation<Parentheses<SomeDerived>, SomeDerived, SomeDerived> {
250public:
251 using Result = SomeDerived;
252 using Operand = SomeDerived;
253 using Base = Operation<Parentheses, SomeDerived, SomeDerived>;
254 using Base::Base;
255 DynamicType GetType() const;
256
257 explicit Parentheses(const Expr<SomeDerived> &x);
258 explicit Parentheses(Expr<SomeDerived> &&x);
259};
260
261template <typename A> struct Negate : public Operation<Negate<A>, A, A> {
262 using Result = A;
263 using Operand = A;
264 using Base = Operation<Negate, A, A>;
265 using Base::Base;
266
267 explicit Negate(const Expr<A> &x) : Base{x.kind(), x} {}
268 explicit Negate(Expr<A> &&x) : Base{x.kind(), std::move(x)} {}
269};
270
271struct ComplexComponent
272 : public Operation<ComplexComponent, Type<TypeCategory::Real>,
273 Type<TypeCategory::Complex>> {
274 using Result = Type<TypeCategory::Real>;
275 using Operand = Type<TypeCategory::Complex>;
276 using Base = Operation<ComplexComponent, Result, Operand>;
277 CLASS_BOILERPLATE(ComplexComponent)
278 ComplexComponent(bool isImaginary, const Expr<Operand> &x);
279 ComplexComponent(bool isImaginary, Expr<Operand> &&x);
280
281 bool isImaginaryPart{true};
282};
283
284struct Not : public Operation<Not, Type<TypeCategory::Logical>,
285 Type<TypeCategory::Logical>> {
286 using Result = Type<TypeCategory::Logical>;
287 using Operand = Result;
288 using Base = Operation<Not, Result, Operand>;
289 using Base::Base;
290};
291
292// Character lengths are determined by context in Fortran and do not
293// have explicit syntax for changing them. Expressions represent
294// changes of length (e.g., for assignments and structure constructors)
295// with this operation.
296struct SetLength : public Operation<SetLength, Type<TypeCategory::Character>,
297 Type<TypeCategory::Character>, SubscriptInteger> {
298 using Result = Type<TypeCategory::Character>;
299 using CharacterOperand = Result;
300 using LengthOperand = SubscriptInteger;
301 using Base = Operation<SetLength, Result, CharacterOperand, LengthOperand>;
302 using Base::Base;
303};
304
305// Binary operations
306
307template <typename A> struct Add : public Operation<Add<A>, A, A, A> {
308 using Result = A;
309 using Operand = A;
310 using Base = Operation<Add, A, A, A>;
311 using Base::Base;
312};
313
314template <typename A> struct Subtract : public Operation<Subtract<A>, A, A, A> {
315 using Result = A;
316 using Operand = A;
317 using Base = Operation<Subtract, A, A, A>;
318 using Base::Base;
319};
320
321template <typename A> struct Multiply : public Operation<Multiply<A>, A, A, A> {
322 using Result = A;
323 using Operand = A;
324 using Base = Operation<Multiply, A, A, A>;
325 using Base::Base;
326};
327
328template <typename A> struct Divide : public Operation<Divide<A>, A, A, A> {
329 using Result = A;
330 using Operand = A;
331 using Base = Operation<Divide, A, A, A>;
332 using Base::Base;
333};
334
335template <typename A> struct Power : public Operation<Power<A>, A, A, A> {
336 using Result = A;
337 using Operand = A;
338 using Base = Operation<Power, A, A, A>;
339 using Base::Base;
340};
341
342template <typename A>
343struct RealToIntPower : public Operation<RealToIntPower<A>, A, A, SomeInteger> {
344 using Base = Operation<RealToIntPower, A, A, SomeInteger>;
345 using Result = A;
346 using BaseOperand = A;
347 using ExponentOperand = SomeInteger;
348 using Base::Base;
349};
350
351template <typename A> struct Extremum : public Operation<Extremum<A>, A, A, A> {
352 using Result = A;
353 using Operand = A;
354 using Base = Operation<Extremum, A, A, A>;
355 CLASS_BOILERPLATE(Extremum)
356 Extremum(Ordering ord, const Expr<Operand> &x, const Expr<Operand> &y)
357 : Base{x.kind(), x, y}, ordering{ord} {
358 CHECK(x.kind() == y.kind());
359 }
360 Extremum(Ordering ord, Expr<Operand> &&x, Expr<Operand> &&y)
361 : Base{x.kind(), std::move(x), std::move(y)}, ordering{ord} {
362 CHECK(this->left().kind() == this->right().kind());
363 }
364 bool operator==(const Extremum &) const;
365 Ordering ordering{Ordering::Greater};
366};
367
368struct ComplexConstructor
369 : public Operation<ComplexConstructor, Type<TypeCategory::Complex>,
370 Type<TypeCategory::Real>, Type<TypeCategory::Real>> {
371 using Result = Type<TypeCategory::Complex>;
372 using Operand = Type<TypeCategory::Real>;
373 using Base = Operation<ComplexConstructor, Result, Operand, Operand>;
374 using Base::Base;
375
376 ComplexConstructor(const Expr<Type<TypeCategory::Real>> &re,
377 const Expr<Type<TypeCategory::Real>> &im);
378 ComplexConstructor(
380};
381
382struct Concat
383 : public Operation<Concat, Type<TypeCategory::Character>,
384 Type<TypeCategory::Character>, Type<TypeCategory::Character>> {
385 using Result = Type<TypeCategory::Character>;
386 using Operand = Result;
387 using Base = Operation<Concat, Result, Operand, Operand>;
388 using Base::Base;
389
390 Concat(const Expr<Type<TypeCategory::Character>> &x,
394};
395
396struct LogicalOperation
397 : public Operation<LogicalOperation, Type<TypeCategory::Logical>,
398 Type<TypeCategory::Logical>, Type<TypeCategory::Logical>> {
399 using Result = Type<TypeCategory::Logical>;
400 using Operand = Result;
401 using Base = Operation<LogicalOperation, Result, Operand, Operand>;
402 CLASS_BOILERPLATE(LogicalOperation)
403 LogicalOperation(
404 LogicalOperator opr, const Expr<Operand> &x, const Expr<Operand> &y);
405 LogicalOperation(LogicalOperator opr, Expr<Operand> &&x, Expr<Operand> &&y);
406 bool operator==(const LogicalOperation &) const;
407 LogicalOperator logicalOperator;
408};
409
410// Fortran 2023 conditional expression: (cond ? val : cond ? val : ... : else)
411// All branches have the same type and rank (verified during semantic analysis).
412template <typename T> class ConditionalExpr {
413public:
414 using Result = T;
415
416 constexpr int kind() const { return kind_; }
417
418 CLASS_BOILERPLATE(ConditionalExpr)
419 ConditionalExpr(Expr<LogicalResult> &&cond, Expr<Result> &&thenVal,
420 Expr<Result> &&elseVal)
421 : kind_{thenVal.kind()}, condition_{std::move(cond)},
422 thenValue_{std::move(thenVal)}, elseValue_{std::move(elseVal)} {
423 CHECK_KIND(kind(), Result);
424 CHECK(thenValue().kind() == elseValue().kind());
425 }
426 bool operator==(const ConditionalExpr &) const;
427 Expr<LogicalResult> &condition() { return condition_.value(); }
428 const Expr<LogicalResult> &condition() const { return condition_.value(); }
429 Expr<Result> &thenValue() { return thenValue_.value(); }
430 const Expr<Result> &thenValue() const { return thenValue_.value(); }
431 Expr<Result> &elseValue() { return elseValue_.value(); }
432 const Expr<Result> &elseValue() const { return elseValue_.value(); }
433 int Rank() const { return thenValue().Rank(); }
434 std::optional<DynamicType> GetType() const {
435 const auto thenType{thenValue().GetType()};
436 if constexpr (T::category == TypeCategory::Derived) {
437 // F2023 10.1.4(7) A conditional-expr is polymorphic if any branch is
438 if (thenType && !thenType->IsPolymorphic()) {
439 if (const auto elseType{elseValue().GetType()}) {
440 if (elseType->IsPolymorphic()) {
441 return elseType;
442 }
443 }
444 }
445 }
446 return thenType;
447 }
448 static constexpr int Corank() { return 0; }
449 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
450
451private:
452 int kind_;
453 common::CopyableIndirection<Expr<LogicalResult>> condition_;
454 common::CopyableIndirection<Expr<Result>> thenValue_;
455 common::CopyableIndirection<Expr<Result>> elseValue_;
456};
457
458// Array constructors
459template <typename RESULT> class ArrayConstructorValues;
460
462 using Result = SubscriptInteger;
463 bool operator==(const ImpliedDoIndex &) const;
464
465 static constexpr int kind() { return SubscriptIntegerKind; }
466
467 static constexpr DynamicType GetType() {
468 return {TypeCategory::Integer, kind()};
469 }
470 static constexpr int Rank() { return 0; }
471 static constexpr int Corank() { return 0; }
472 parser::CharBlock name; // nested implied DOs must use distinct names
473};
474
475template <typename RESULT> class ImpliedDo {
476public:
477 using Result = RESULT;
478 using Index = ResultType<ImpliedDoIndex>;
479 ImpliedDo(parser::CharBlock name, Expr<Index> &&lower, Expr<Index> &&upper,
481 : name_{name}, lower_{std::move(lower)}, upper_{std::move(upper)},
482 stride_{std::move(stride)}, values_{std::move(values)} {}
483 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ImpliedDo)
484 bool operator==(const ImpliedDo &) const;
485 parser::CharBlock name() const { return name_; }
486 Expr<Index> &lower() { return lower_.value(); }
487 const Expr<Index> &lower() const { return lower_.value(); }
488 Expr<Index> &upper() { return upper_.value(); }
489 const Expr<Index> &upper() const { return upper_.value(); }
490 Expr<Index> &stride() { return stride_.value(); }
491 const Expr<Index> &stride() const { return stride_.value(); }
492 ArrayConstructorValues<Result> &values() { return values_.value(); }
493 const ArrayConstructorValues<Result> &values() const {
494 return values_.value();
495 }
496
497private:
498 parser::CharBlock name_;
499 common::CopyableIndirection<Expr<Index>> lower_, upper_, stride_;
500 common::CopyableIndirection<ArrayConstructorValues<Result>> values_;
501};
502
503template <typename RESULT> struct ArrayConstructorValue {
504 using Result = RESULT;
505 EVALUATE_UNION_CLASS_BOILERPLATE(ArrayConstructorValue)
506 std::variant<Expr<Result>, ImpliedDo<Result>> u;
507};
508
509template <typename RESULT> class ArrayConstructorValues {
510public:
511 using Result = RESULT;
512 using Values = std::vector<ArrayConstructorValue<Result>>;
513 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructorValues)
514 ArrayConstructorValues() {}
515
516 bool operator==(const ArrayConstructorValues &) const;
517 static constexpr int Rank() { return 1; }
518 static constexpr int Corank() { return 0; }
519 template <typename A> common::NoLvalue<A> Push(A &&x) {
520 values_.emplace_back(std::move(x));
521 }
522
523 typename Values::iterator begin() { return values_.begin(); }
524 typename Values::const_iterator begin() const { return values_.begin(); }
525 typename Values::iterator end() { return values_.end(); }
526 typename Values::const_iterator end() const { return values_.end(); }
527
528protected:
529 Values values_;
530};
531
532// Note that there are specializations of ArrayConstructor for character
533// and derived types, since they must carry additional type information,
534// but that an empty ArrayConstructor can be constructed for any type
535// given an expression from which such type information may be gleaned.
536template <typename RESULT>
537class ArrayConstructor : public ArrayConstructorValues<RESULT> {
538public:
539 using Result = RESULT;
540 using Base = ArrayConstructorValues<Result>;
541
542 constexpr int kind() const { return kind_; }
543
544 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructor)
545 explicit ArrayConstructor(int kind, Base &&values)
546 : Base{std::move(values)}, kind_{kind} {
547 CHECK_KIND(kind, RESULT);
548 }
549 template <typename T>
550 explicit ArrayConstructor(int kind, const Expr<T> &) : kind_{kind} {
551 CHECK_KIND(kind, RESULT);
552 }
553 static constexpr Result result(int kind) { return Result{kind}; }
554 DynamicType GetType() const { return {Result::category, kind_}; }
555 bool operator==(const ArrayConstructor &that) const {
556 return kind() == that.kind() && Base::operator==(that);
557 }
558 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
559
560private:
561 int kind_;
562};
563
564template <>
565class ArrayConstructor<Type<TypeCategory::Character>>
566 : public ArrayConstructorValues<Type<TypeCategory::Character>> {
567public:
568 using Result = Type<TypeCategory::Character>;
569 using Base = ArrayConstructorValues<Result>;
570
571 constexpr int kind() const { return kind_; }
572
573 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructor)
574 explicit ArrayConstructor(int kind, Base &&values)
575 : Base{std::move(values)}, kind_{kind} {
576 CHECK_KIND(kind, Result);
577 }
578 template <typename T>
579 explicit ArrayConstructor(int kind, const Expr<T> &) : kind_{kind} {
580 CHECK_KIND(kind, Result);
581 }
582 ArrayConstructor &set_LEN(Expr<SubscriptInteger> &&);
583 bool operator==(const ArrayConstructor &) const;
584 static constexpr Result result(int kind) { return Result{kind}; }
585 DynamicType GetType() const { return {Result::category, kind()}; }
586 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
587 const Expr<SubscriptInteger> *LEN() const {
588 return length_ ? &length_->value() : nullptr;
589 }
590
591private:
592 int kind_;
593 std::optional<common::CopyableIndirection<Expr<SubscriptInteger>>> length_;
594};
595
596template <>
597class ArrayConstructor<SomeDerived>
598 : public ArrayConstructorValues<SomeDerived> {
599public:
600 using Result = SomeDerived;
601 using Base = ArrayConstructorValues<Result>;
602
603 static constexpr int kind() { return 0; }
604
605 CLASS_BOILERPLATE(ArrayConstructor)
606
607 ArrayConstructor(const semantics::DerivedTypeSpec &spec, Base &&v)
608 : Base{std::move(v)}, result_{spec} {}
609 template <typename A>
610 explicit ArrayConstructor(const A &prototype)
611 : result_{prototype.GetType().value().GetDerivedTypeSpec()} {}
612 template <typename A>
613 explicit ArrayConstructor(int kind, const A &prototype)
614 : result_{prototype.GetType().value().GetDerivedTypeSpec()} {
615 CHECK(kind == 0);
616 }
617
618 bool operator==(const ArrayConstructor &) const;
619 constexpr Result result() const { return result_; }
620 constexpr DynamicType GetType() const { return result_.GetType(); }
621 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
622
623private:
624 Result result_;
625};
626
627// Expression representations for each type category.
628
629template <>
630class Expr<Type<TypeCategory::Integer>>
631 : public ExpressionBase<Type<TypeCategory::Integer>> {
632public:
633 using Result = Type<TypeCategory::Integer>;
634
635 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
636
637private:
638 using Conversions = std::tuple<Convert<Result, TypeCategory::Integer>,
641 using Operations = std::tuple<Parentheses<Result>, Negate<Result>,
644 using Indices = std::tuple<ImpliedDoIndex>;
645 using TypeParamInquiries = std::tuple<TypeParamInquiry>;
646 using DescriptorInquiries = std::tuple<DescriptorInquiry>;
647 using RankOneBoundElements = std::tuple<RankOneBoundElement>;
648 using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
650
651public:
652 common::TupleToVariant<common::CombineTuples<Operations, Conversions, Indices,
653 TypeParamInquiries, DescriptorInquiries, RankOneBoundElements, Others>>
654 u;
655};
656
657template <>
658class Expr<Type<TypeCategory::Unsigned>>
659 : public ExpressionBase<Type<TypeCategory::Unsigned>> {
660public:
661 using Result = Type<TypeCategory::Unsigned>;
662
663 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
664
665private:
666 using Conversions = std::tuple<Convert<Result, TypeCategory::Integer>,
669 using Operations = std::tuple<Parentheses<Result>, Negate<Result>,
672 using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
674
675public:
676 common::TupleToVariant<common::CombineTuples<Operations, Conversions, Others>>
677 u;
678};
679
680template <>
681class Expr<Type<TypeCategory::Real>>
682 : public ExpressionBase<Type<TypeCategory::Real>> {
683public:
684 using Result = Type<TypeCategory::Real>;
685
686 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
687 explicit Expr(int kind, const Scalar<Result> &x)
688 : u{Constant<Result>{kind, x}} {}
689
690private:
691 // N.B. Real->Complex and Complex->Real conversions are done with CMPLX
692 // and part access operations (resp.).
693 using Conversions = std::variant<Convert<Result, TypeCategory::Integer>,
696 using Operations = std::variant<ComplexComponent, Parentheses<Result>,
700 using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
702
703public:
704 common::CombineVariants<Operations, Conversions, Others> u;
705};
706
707template <>
708class Expr<Type<TypeCategory::Complex>>
709 : public ExpressionBase<Type<TypeCategory::Complex>> {
710public:
711 using Result = Type<TypeCategory::Complex>;
712 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
713 explicit Expr(int kind, const Scalar<Result> &x)
714 : u{Constant<Result>{kind, x}} {}
715 using Operations = std::variant<Parentheses<Result>, Negate<Result>,
719 using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
721
722public:
723 common::CombineVariants<Operations, Others> u;
724};
725
726template <>
727class Expr<Type<TypeCategory::Character>>
728 : public ExpressionBase<Type<TypeCategory::Character>> {
729public:
730 using Result = Type<TypeCategory::Character>;
731 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
732 explicit Expr(int kind, const Scalar<Result> &x)
733 : u{Constant<Result>{kind, x}} {}
734 explicit Expr(int kind, Scalar<Result> &&x)
735 : u{Constant<Result>{kind, std::move(x)}} {}
736
737 std::optional<Expr<SubscriptInteger>> LEN() const;
738
739 std::variant<Constant<Result>, ArrayConstructor<Result>, Designator<Result>,
742 u;
743};
744
745// The Relational class template is a helper for constructing logical
746// expressions with polymorphism over the cross product of the possible
747// categories and kinds of comparable operands.
748// Fortran defines a numeric relation with distinct types or kinds as
749// first undergoing the same operand conversions that occur with the intrinsic
750// addition operator. Character relations must have the same kind.
751// There are no relations between LOGICAL values.
752
753template <typename T>
754class Relational : public Operation<Relational<T>, LogicalResult, T, T> {
755public:
756 using Result = LogicalResult;
757 using Base = Operation<Relational, LogicalResult, T, T>;
758 using Operand = typename Base::template Operand<0>;
759 static_assert(Operand::category == TypeCategory::Integer ||
760 Operand::category == TypeCategory::Real ||
761 Operand::category == TypeCategory::Complex ||
762 Operand::category == TypeCategory::Character ||
763 Operand::category == TypeCategory::Unsigned);
764 CLASS_BOILERPLATE(Relational)
765 Relational(
766 RelationalOperator r, const Expr<Operand> &a, const Expr<Operand> &b)
767 : Base{LogicalResultKind, a, b}, opr{r} {
768 CHECK(a.kind() == b.kind());
769 }
770 Relational(RelationalOperator r, Expr<Operand> &&a, Expr<Operand> &&b)
771 : Base{LogicalResultKind, std::move(a), std::move(b)}, opr{r} {
772 CHECK(this->left().kind() == this->right().kind());
773 }
774 static constexpr std::optional<DynamicType> GetType() {
775 return DynamicType{TypeCategory::Logical, LogicalResultKind};
776 }
777 bool operator==(const Relational &) const;
778 RelationalOperator opr;
779};
780
781template <> class Relational<SomeType> {
782 using DirectlyComparableTypes = common::CombineTuples<IntegerTypes, RealTypes,
783 ComplexTypes, CharacterTypes, UnsignedTypes>;
784
785public:
786 using Result = LogicalResult;
787 EVALUATE_UNION_CLASS_BOILERPLATE(Relational)
788 int kind() const {
789 return common::visit([](const auto &x) { return x.kind(); }, u);
790 }
791 static constexpr DynamicType GetType() {
792 return {TypeCategory::Logical, LogicalResultKind};
793 }
794 int Rank() const {
795 return common::visit([](const auto &x) { return x.Rank(); }, u);
796 }
797 static constexpr int Corank() { return 0; }
798 llvm::raw_ostream &AsFortran(llvm::raw_ostream &o) const;
799 common::MapTemplate<Relational, DirectlyComparableTypes> u;
800};
801
802extern template class Relational<Type<TypeCategory::Integer>>;
803extern template class Relational<Type<TypeCategory::Unsigned>>;
804extern template class Relational<Type<TypeCategory::Real>>;
805extern template class Relational<Type<TypeCategory::Character>>;
806
807// Relational<> operations always have the default logical result kind.
808// They are included in this shared runtime-kind variant, but report
809// LogicalResultKind from their kind() member.
810template <>
811class Expr<Type<TypeCategory::Logical>>
812 : public ExpressionBase<Type<TypeCategory::Logical>> {
813public:
814 using Result = Type<TypeCategory::Logical>;
815 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
816
817 explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x.kind(), x}} {}
818 explicit Expr(int kind, const Scalar<Result> &x)
819 : u{Constant<Result>{kind, x}} {}
820 explicit Expr(int kind, bool x)
821 : u{Constant<Result>{kind, Scalar<Result>{kind, x}}} {}
822
823private:
824 using Operations = std::tuple<Convert<Result>, Parentheses<Result>, Not,
826 using Relations = std::tuple<Relational<SomeType>>;
827 using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
829
830public:
831 common::TupleToVariant<common::CombineTuples<Operations, Relations, Others>>
832 u;
833};
834
835// StructureConstructor pairs a StructureConstructorValues instance
836// (a map associating symbols with expressions) with a derived type
837// specification. There are two other similar classes:
838// - ArrayConstructor<SomeDerived> comprises a derived type spec &
839// zero or more instances of Expr<SomeDerived>; it has rank 1
840// but not (in the most general case) a known shape.
841// - Constant<SomeDerived> comprises a derived type spec, zero or more
842// homogeneous instances of StructureConstructorValues whose type
843// parameters and component expressions are all constant, and a
844// known shape (possibly scalar).
845// StructureConstructor represents a scalar value of derived type that
846// is not necessarily a constant. It is used only as an Expr<SomeDerived>
847// alternative and as the type Scalar<SomeDerived> (with an assumption
848// of constant component value expressions).
849class StructureConstructor {
850public:
851 using Result = SomeDerived;
852
853 static constexpr int kind() { return 0; }
854
855 explicit StructureConstructor(const semantics::DerivedTypeSpec &spec)
856 : result_{spec} {}
857 StructureConstructor(
858 const semantics::DerivedTypeSpec &, const StructureConstructorValues &);
859 StructureConstructor(
860 const semantics::DerivedTypeSpec &, StructureConstructorValues &&);
861 CLASS_BOILERPLATE(StructureConstructor)
862
863 constexpr Result result() const { return result_; }
864 const semantics::DerivedTypeSpec &derivedTypeSpec() const {
865 return result_.derivedTypeSpec();
866 }
867 StructureConstructorValues &values() { return values_; }
868 const StructureConstructorValues &values() const { return values_; }
869
870 bool operator==(const StructureConstructor &) const;
871
872 StructureConstructorValues::iterator begin() { return values_.begin(); }
873 StructureConstructorValues::const_iterator begin() const {
874 return values_.begin();
875 }
876 StructureConstructorValues::iterator end() { return values_.end(); }
877 StructureConstructorValues::const_iterator end() const {
878 return values_.end();
879 }
880
881 // can return nullopt
882 std::optional<Expr<SomeType>> Find(const Symbol &) const;
883
884 StructureConstructor &Add(const semantics::Symbol &, Expr<SomeType> &&);
885 static constexpr int Rank() { return 0; }
886 static constexpr int Corank() { return 0; }
887 DynamicType GetType() const;
888 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
889
890private:
891 std::optional<Expr<SomeType>> CreateParentComponent(const Symbol &) const;
892 Result result_;
893 StructureConstructorValues values_;
894};
895
896// An expression whose result has a derived type.
897template <> class Expr<SomeDerived> : public ExpressionBase<SomeDerived> {
898public:
899 using Result = SomeDerived;
900 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
901 std::variant<Constant<Result>, ArrayConstructor<Result>, StructureConstructor,
904 u;
905};
906
907// A polymorphic expression of known intrinsic type category, but dynamic
908// kind.
909// TODO: Expr<Type<CAT>> can now also hold expressions of any kind, so
910// Expr<SomeKind<CAT>> has become redundant and can be removed.
911template <TypeCategory CAT>
912class Expr<SomeKind<CAT>> : public ExpressionBase<SomeKind<CAT>> {
913public:
914 using Result = SomeKind<CAT>;
915 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
916
917 using ExpressionBase<SomeKind<CAT>>::kind;
918
919 common::MapTemplate<evaluate::Expr, CategoryTypes<CAT>> u;
920};
921
922template <> class Expr<SomeCharacter> : public ExpressionBase<SomeCharacter> {
923public:
924 using Result = SomeCharacter;
925 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
926 std::optional<Expr<SubscriptInteger>> LEN() const;
927 common::MapTemplate<Expr, CategoryTypes<TypeCategory::Character>> u;
928};
929
930// A variant comprising the Expr<> instantiations over SomeDerived and
931// SomeKind<CATEGORY>.
932using CategoryExpression = common::MapTemplate<Expr, SomeCategory>;
933
934// BOZ literal "typeless" constants must be wide enough to hold a numeric
935// value of any supported kind of INTEGER or REAL. They must also be
936// distinguishable from other integer constants, since they are permitted
937// to be used in only a few situations.
938using BOZLiteralConstant = typename LargestReal::Scalar::Word;
939inline constexpr int BOZLiteralConstantKind = LargestRealKind;
940
941// Null pointers without MOLD= arguments are typed by context.
943 static constexpr int kind() { return 0; }
944
945 constexpr bool operator==(const NullPointer &) const { return true; }
946 static constexpr int Rank() { return 0; }
947 static constexpr int Corank() { return 0; }
948};
949
950// Procedure pointer targets are treated as if they were typeless.
951// They are either procedure designators or values returned from
952// references to functions that return procedure (not object) pointers.
953using TypelessExpression = std::variant<BOZLiteralConstant, NullPointer,
955
956// A completely generic expression, polymorphic across all of the intrinsic type
957// categories and each of their kinds.
958template <> class Expr<SomeType> : public ExpressionBase<SomeType> {
959public:
960 using Result = SomeType;
961
962 static constexpr int kind() { return 0; }
963
964 EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
965
966 // Owning references to these generic expressions can appear in other
967 // compiler data structures (viz., the parse tree and symbol table), so
968 // its destructor is externalized to reduce redundant default instances.
969 ~Expr();
970
971 template <TypeCategory CAT>
972 explicit Expr(const Expr<Type<CAT>> &x) : u{Expr<SomeKind<CAT>>{x}} {}
973
974 template <TypeCategory CAT>
975 explicit Expr(Expr<Type<CAT>> &&x) : u{Expr<SomeKind<CAT>>{std::move(x)}} {}
976
977 template <TypeCategory CAT> Expr &operator=(const Expr<Type<CAT>> &x) {
978 u = Expr<SomeKind<CAT>>{x};
979 return *this;
980 }
981
982 template <TypeCategory CAT> Expr &operator=(Expr<Type<CAT>> &&x) {
983 u = Expr<SomeKind<CAT>>{std::move(x)};
984 return *this;
985 }
986
987public:
988 common::CombineVariants<TypelessExpression, CategoryExpression> u;
989};
990
991// An assignment is either intrinsic, user-defined (with a ProcedureRef to
992// specify the procedure to call), or pointer assignment (with possibly empty
993// BoundsSpec or non-empty BoundsRemapping). In all cases there are Exprs
994// representing the LHS and RHS of the assignment.
995class Assignment {
996public:
997 Assignment(Expr<SomeType> &&lhs, Expr<SomeType> &&rhs)
998 : lhs(std::move(lhs)), rhs(std::move(rhs)) {}
999
1000 struct Intrinsic {};
1001 using BoundsSpec = std::vector<Expr<SubscriptInteger>>;
1002 using BoundsRemapping =
1003 std::vector<std::pair<Expr<SubscriptInteger>, Expr<SubscriptInteger>>>;
1004 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
1005
1006 Expr<SomeType> lhs;
1007 Expr<SomeType> rhs;
1008 std::variant<Intrinsic, ProcedureRef, BoundsSpec, BoundsRemapping> u;
1009};
1010
1011// This wrapper class is used, by means of a forward reference with
1012// an owning pointer, to cache analyzed expressions in parse tree nodes.
1013struct GenericExprWrapper {
1014 GenericExprWrapper() {}
1015 explicit GenericExprWrapper(std::optional<Expr<SomeType>> &&x)
1016 : v{std::move(x)} {}
1017 ~GenericExprWrapper();
1018 static void Deleter(GenericExprWrapper *);
1019 std::optional<Expr<SomeType>> v; // vacant if error
1020};
1021
1022// Like GenericExprWrapper but for analyzed assignments
1023struct GenericAssignmentWrapper {
1024 GenericAssignmentWrapper() {}
1025 explicit GenericAssignmentWrapper(Assignment &&x) : v{std::move(x)} {}
1026 explicit GenericAssignmentWrapper(std::optional<Assignment> &&x)
1027 : v{std::move(x)} {}
1028 ~GenericAssignmentWrapper();
1029 static void Deleter(GenericAssignmentWrapper *);
1030 std::optional<Assignment> v; // vacant if error
1031};
1032
1033FOR_EACH_CATEGORY_TYPE(extern template class Expr, )
1034FOR_EACH_TYPE_AND_KIND(extern template class ExpressionBase, )
1035FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructorValues, )
1036FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructor, )
1037
1038// Template instantiations to resolve these "extern template" declarations.
1039#define INSTANTIATE_EXPRESSION_TEMPLATES \
1040 FOR_EACH_CATEGORY_TYPE(template class Expr, ) \
1041 template class Relational<Type<TypeCategory::Integer>>; \
1042 template class Relational<Type<TypeCategory::Unsigned>>; \
1043 template class Relational<Type<TypeCategory::Real>>; \
1044 template class Relational<Type<TypeCategory::Character>>; \
1045 FOR_EACH_TYPE_AND_KIND(template class ExpressionBase, ) \
1046 FOR_EACH_INTRINSIC_KIND(template class ArrayConstructorValues, ) \
1047 FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor, ) \
1048 FOR_EACH_INTRINSIC_KIND(template class ConditionalExpr, )
1049
1050template <typename T>
1051inline Expr<T> MakeConstantExpr(int kind, const Scalar<T> &v) {
1052 CHECK(kind == v.kind());
1053 return Expr<T>{Constant<T>{kind, v}};
1054}
1055
1056template <typename T> inline Expr<T> MakeConstantExpr(int kind, Scalar<T> &&v) {
1057 CHECK(kind == v.kind());
1058 return Expr<T>{Constant<T>{kind, std::move(v)}};
1059}
1060
1061template <typename T>
1062inline Expr<T> MakeConstantExpr(int kind, const Constant<T> &c) {
1063 CHECK(kind == c.kind());
1064 return Expr<T>{c};
1065}
1066
1067template <typename T>
1068inline Expr<T> MakeConstantExpr(int kind, Constant<T> &&c) {
1069 CHECK(kind == c.kind());
1070 return Expr<T>{std::move(c)};
1071}
1072
1073template <typename T,
1074 typename =
1075 std::enable_if_t<std::is_same_v<T, Type<TypeCategory::Character>>>>
1076inline Expr<T> MakeConstantExpr(int kind, const std::string &v) {
1077 return Expr<T>{MakeConstant<T>(kind, v)};
1078}
1079
1080template <typename T,
1081 typename = std::enable_if_t<std::is_same_v<T, Type<TypeCategory::Integer>>>>
1082inline Expr<T> MakeConstantExpr(int kind, int64_t v) {
1083 return Expr<T>{Constant<T>{kind, Scalar<T>{kind, v}}};
1084}
1085
1086template <typename T,
1087 typename =
1088 std::enable_if_t<std::is_same_v<T, Type<TypeCategory::Unsigned>>>>
1089inline Expr<T> MakeConstantExpr(int kind, uint64_t v) {
1090 return Expr<T>{Constant<T>{kind, Scalar<T>{kind, v}}};
1091}
1092
1093template <typename T,
1094 typename = std::enable_if_t<std::is_same_v<T, Type<TypeCategory::Logical>>>>
1095inline Expr<T> MakeConstantExpr(int kind, bool v) {
1096 return Expr<T>{Constant<T>{kind, Scalar<T>{kind, v}}};
1097}
1098
1099template <typename T> inline Expr<T> MakeZeroExpr(int kind) {
1100 return MakeConstantExpr<T>(kind, Scalar<T>::Zero(kind));
1101}
1102
1103inline Expr<SubscriptInteger> MakeSubscriptIntExpr(int64_t v) {
1104 return Expr<SubscriptInteger>{MakeSubscriptIntConstant(v)};
1105}
1106
1107inline Expr<SubscriptInteger> MakeSubscriptIntExpr(
1108 const Scalar<SubscriptInteger> &v) {
1109 return Expr<SubscriptInteger>{
1110 Constant<SubscriptInteger>{SubscriptIntegerKind, v}};
1111}
1112
1113inline Expr<SubscriptInteger> MakeSubscriptIntExpr(
1114 Scalar<SubscriptInteger> &&v) {
1115 return Expr<SubscriptInteger>{
1116 Constant<SubscriptInteger>{SubscriptIntegerKind, std::move(v)}};
1117}
1118
1119inline Expr<CInteger> MakeCIntegerExpr(int32_t v) {
1120 return Expr<CInteger>{MakeCIntegerConstant(v)};
1121}
1122
1123inline Expr<LogicalResult> MakeLogicalResultExpr(bool v) {
1124 return Expr<LogicalResult>{MakeLogicalResultConstant(v)};
1125}
1126
1127inline Expr<Ascii> MakeAsciiExpr(const std::string &v) {
1128 return Expr<Ascii>{MakeConstant<Ascii>(AsciiKind, v)};
1129}
1130
1131inline Expr<Ascii> MakeAsciiExpr(std::string &&v) {
1132 return Expr<Ascii>{MakeConstant<Ascii>(AsciiKind, std::move(v))};
1133}
1134
1135} // namespace Fortran::evaluate
1136#endif // FORTRAN_EVALUATE_EXPRESSION_H_
Definition expression.h:537
Definition expression.h:995
Definition expression.h:412
Definition constant.h:191
Definition variable.h:386
Definition type.h:101
Definition common.h:222
Definition expression.h:64
Definition common.h:224
Definition call.h:413
Definition expression.h:475
Definition call.h:348
Definition expression.h:754
Definition expression.h:849
Definition type.h:61
Definition char-block.h:27
Definition symbol.h:918
Definition call.h:34
Definition expression.h:307
Definition expression.h:503
Definition expression.h:1000
Definition expression.h:370
Definition expression.h:384
Definition expression.h:218
Definition expression.h:328
Definition expression.h:351
Definition expression.h:461
Definition expression.h:398
Definition expression.h:321
Definition expression.h:261
Definition expression.h:285
Definition expression.h:942
Definition expression.h:237
Definition expression.h:335
Definition expression.h:343
Definition expression.h:297
Definition type.h:408
Definition type.h:426
Definition expression.h:314