xref: /llvm-project/flang/lib/Evaluate/variable.cpp (revision 3a8a52f4a52e0c301a5f3d6acce684c7fd4a6d57)
164ab3302SCarolineConcatto //===-- lib/Evaluate/variable.cpp -----------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "flang/Evaluate/variable.h"
1064ab3302SCarolineConcatto #include "flang/Common/idioms.h"
118f0f9eadSpeter klausler #include "flang/Evaluate/check-expression.h"
1264ab3302SCarolineConcatto #include "flang/Evaluate/fold.h"
1364ab3302SCarolineConcatto #include "flang/Evaluate/tools.h"
1464ab3302SCarolineConcatto #include "flang/Parser/char-block.h"
1564ab3302SCarolineConcatto #include "flang/Parser/characters.h"
1664ab3302SCarolineConcatto #include "flang/Parser/message.h"
176f3d322fSpeter klausler #include "flang/Semantics/scope.h"
1864ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
1964ab3302SCarolineConcatto #include <type_traits>
2064ab3302SCarolineConcatto 
2164ab3302SCarolineConcatto using namespace Fortran::parser::literals;
2264ab3302SCarolineConcatto 
2364ab3302SCarolineConcatto namespace Fortran::evaluate {
2464ab3302SCarolineConcatto 
2564ab3302SCarolineConcatto // Constructors, accessors, mutators
2664ab3302SCarolineConcatto 
2764ab3302SCarolineConcatto Triplet::Triplet() : stride_{Expr<SubscriptInteger>{1}} {}
2864ab3302SCarolineConcatto 
2964ab3302SCarolineConcatto Triplet::Triplet(std::optional<Expr<SubscriptInteger>> &&l,
3064ab3302SCarolineConcatto     std::optional<Expr<SubscriptInteger>> &&u,
3164ab3302SCarolineConcatto     std::optional<Expr<SubscriptInteger>> &&s)
3264ab3302SCarolineConcatto     : stride_{s ? std::move(*s) : Expr<SubscriptInteger>{1}} {
3364ab3302SCarolineConcatto   if (l) {
3464ab3302SCarolineConcatto     lower_.emplace(std::move(*l));
3564ab3302SCarolineConcatto   }
3664ab3302SCarolineConcatto   if (u) {
3764ab3302SCarolineConcatto     upper_.emplace(std::move(*u));
3864ab3302SCarolineConcatto   }
3964ab3302SCarolineConcatto }
4064ab3302SCarolineConcatto 
4164ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Triplet::lower() const {
4264ab3302SCarolineConcatto   if (lower_) {
4364ab3302SCarolineConcatto     return {lower_.value().value()};
4464ab3302SCarolineConcatto   }
4564ab3302SCarolineConcatto   return std::nullopt;
4664ab3302SCarolineConcatto }
4764ab3302SCarolineConcatto 
4864ab3302SCarolineConcatto Triplet &Triplet::set_lower(Expr<SubscriptInteger> &&expr) {
4964ab3302SCarolineConcatto   lower_.emplace(std::move(expr));
5064ab3302SCarolineConcatto   return *this;
5164ab3302SCarolineConcatto }
5264ab3302SCarolineConcatto 
5364ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Triplet::upper() const {
5464ab3302SCarolineConcatto   if (upper_) {
5564ab3302SCarolineConcatto     return {upper_.value().value()};
5664ab3302SCarolineConcatto   }
5764ab3302SCarolineConcatto   return std::nullopt;
5864ab3302SCarolineConcatto }
5964ab3302SCarolineConcatto 
6064ab3302SCarolineConcatto Triplet &Triplet::set_upper(Expr<SubscriptInteger> &&expr) {
6164ab3302SCarolineConcatto   upper_.emplace(std::move(expr));
6264ab3302SCarolineConcatto   return *this;
6364ab3302SCarolineConcatto }
6464ab3302SCarolineConcatto 
6564ab3302SCarolineConcatto Expr<SubscriptInteger> Triplet::stride() const { return stride_.value(); }
6664ab3302SCarolineConcatto 
6764ab3302SCarolineConcatto Triplet &Triplet::set_stride(Expr<SubscriptInteger> &&expr) {
6864ab3302SCarolineConcatto   stride_.value() = std::move(expr);
6964ab3302SCarolineConcatto   return *this;
7064ab3302SCarolineConcatto }
7164ab3302SCarolineConcatto 
7264ab3302SCarolineConcatto CoarrayRef::CoarrayRef(SymbolVector &&base, std::vector<Subscript> &&ss,
7364ab3302SCarolineConcatto     std::vector<Expr<SubscriptInteger>> &&css)
7464ab3302SCarolineConcatto     : base_{std::move(base)}, subscript_(std::move(ss)),
7564ab3302SCarolineConcatto       cosubscript_(std::move(css)) {
7664ab3302SCarolineConcatto   CHECK(!base_.empty());
7764ab3302SCarolineConcatto   CHECK(!cosubscript_.empty());
7864ab3302SCarolineConcatto }
7964ab3302SCarolineConcatto 
8064ab3302SCarolineConcatto std::optional<Expr<SomeInteger>> CoarrayRef::stat() const {
8164ab3302SCarolineConcatto   if (stat_) {
8264ab3302SCarolineConcatto     return stat_.value().value();
8364ab3302SCarolineConcatto   } else {
8464ab3302SCarolineConcatto     return std::nullopt;
8564ab3302SCarolineConcatto   }
8664ab3302SCarolineConcatto }
8764ab3302SCarolineConcatto 
8864ab3302SCarolineConcatto std::optional<Expr<SomeInteger>> CoarrayRef::team() const {
8964ab3302SCarolineConcatto   if (team_) {
9064ab3302SCarolineConcatto     return team_.value().value();
9164ab3302SCarolineConcatto   } else {
9264ab3302SCarolineConcatto     return std::nullopt;
9364ab3302SCarolineConcatto   }
9464ab3302SCarolineConcatto }
9564ab3302SCarolineConcatto 
9664ab3302SCarolineConcatto CoarrayRef &CoarrayRef::set_stat(Expr<SomeInteger> &&v) {
9764ab3302SCarolineConcatto   CHECK(IsVariable(v));
9864ab3302SCarolineConcatto   stat_.emplace(std::move(v));
9964ab3302SCarolineConcatto   return *this;
10064ab3302SCarolineConcatto }
10164ab3302SCarolineConcatto 
10264ab3302SCarolineConcatto CoarrayRef &CoarrayRef::set_team(Expr<SomeInteger> &&v, bool isTeamNumber) {
10364ab3302SCarolineConcatto   CHECK(IsVariable(v));
10464ab3302SCarolineConcatto   team_.emplace(std::move(v));
10564ab3302SCarolineConcatto   teamIsTeamNumber_ = isTeamNumber;
10664ab3302SCarolineConcatto   return *this;
10764ab3302SCarolineConcatto }
10864ab3302SCarolineConcatto 
10964ab3302SCarolineConcatto const Symbol &CoarrayRef::GetFirstSymbol() const { return base_.front(); }
11064ab3302SCarolineConcatto 
11164ab3302SCarolineConcatto const Symbol &CoarrayRef::GetLastSymbol() const { return base_.back(); }
11264ab3302SCarolineConcatto 
11364ab3302SCarolineConcatto void Substring::SetBounds(std::optional<Expr<SubscriptInteger>> &lower,
11464ab3302SCarolineConcatto     std::optional<Expr<SubscriptInteger>> &upper) {
11564ab3302SCarolineConcatto   if (lower) {
11664ab3302SCarolineConcatto     set_lower(std::move(lower.value()));
11764ab3302SCarolineConcatto   }
11864ab3302SCarolineConcatto   if (upper) {
11964ab3302SCarolineConcatto     set_upper(std::move(upper.value()));
12064ab3302SCarolineConcatto   }
12164ab3302SCarolineConcatto }
12264ab3302SCarolineConcatto 
12364ab3302SCarolineConcatto Expr<SubscriptInteger> Substring::lower() const {
12464ab3302SCarolineConcatto   if (lower_) {
12564ab3302SCarolineConcatto     return lower_.value().value();
12664ab3302SCarolineConcatto   } else {
12764ab3302SCarolineConcatto     return AsExpr(Constant<SubscriptInteger>{1});
12864ab3302SCarolineConcatto   }
12964ab3302SCarolineConcatto }
13064ab3302SCarolineConcatto 
13164ab3302SCarolineConcatto Substring &Substring::set_lower(Expr<SubscriptInteger> &&expr) {
13264ab3302SCarolineConcatto   lower_.emplace(std::move(expr));
13364ab3302SCarolineConcatto   return *this;
13464ab3302SCarolineConcatto }
13564ab3302SCarolineConcatto 
13664ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Substring::upper() const {
13764ab3302SCarolineConcatto   if (upper_) {
13864ab3302SCarolineConcatto     return upper_.value().value();
13964ab3302SCarolineConcatto   } else {
140cd03e96fSPeter Klausler     return common::visit(
14164ab3302SCarolineConcatto         common::visitors{
14264ab3302SCarolineConcatto             [](const DataRef &dataRef) { return dataRef.LEN(); },
14364ab3302SCarolineConcatto             [](const StaticDataObject::Pointer &object)
14464ab3302SCarolineConcatto                 -> std::optional<Expr<SubscriptInteger>> {
14564ab3302SCarolineConcatto               return AsExpr(Constant<SubscriptInteger>{object->data().size()});
14664ab3302SCarolineConcatto             },
14764ab3302SCarolineConcatto         },
14864ab3302SCarolineConcatto         parent_);
14964ab3302SCarolineConcatto   }
15064ab3302SCarolineConcatto }
15164ab3302SCarolineConcatto 
15264ab3302SCarolineConcatto Substring &Substring::set_upper(Expr<SubscriptInteger> &&expr) {
15364ab3302SCarolineConcatto   upper_.emplace(std::move(expr));
15464ab3302SCarolineConcatto   return *this;
15564ab3302SCarolineConcatto }
15664ab3302SCarolineConcatto 
15764ab3302SCarolineConcatto std::optional<Expr<SomeCharacter>> Substring::Fold(FoldingContext &context) {
15864ab3302SCarolineConcatto   if (!upper_) {
15964ab3302SCarolineConcatto     upper_ = upper();
16064ab3302SCarolineConcatto     if (!upper_) {
16164ab3302SCarolineConcatto       return std::nullopt;
16264ab3302SCarolineConcatto     }
16364ab3302SCarolineConcatto   }
16464ab3302SCarolineConcatto   upper_.value() = evaluate::Fold(context, std::move(upper_.value().value()));
165bd859cb4SPeter Klausler   std::optional<ConstantSubscript> ubi{ToInt64(upper_.value().value())};
166bd859cb4SPeter Klausler   if (!ubi) {
167bd859cb4SPeter Klausler     return std::nullopt;
16864ab3302SCarolineConcatto   }
169bd859cb4SPeter Klausler   if (!lower_) {
170bd859cb4SPeter Klausler     lower_ = AsExpr(Constant<SubscriptInteger>{1});
17164ab3302SCarolineConcatto   }
172bd859cb4SPeter Klausler   lower_.value() = evaluate::Fold(context, std::move(lower_.value().value()));
173bd859cb4SPeter Klausler   std::optional<ConstantSubscript> lbi{ToInt64(lower_.value().value())};
174bd859cb4SPeter Klausler   if (!lbi) {
175bd859cb4SPeter Klausler     return std::nullopt;
17664ab3302SCarolineConcatto   }
177bd859cb4SPeter Klausler   if (*lbi > *ubi) { // empty result; canonicalize
178bd859cb4SPeter Klausler     *lbi = 1;
179bd859cb4SPeter Klausler     *ubi = 0;
18064ab3302SCarolineConcatto     lower_ = AsExpr(Constant<SubscriptInteger>{*lbi});
18164ab3302SCarolineConcatto     upper_ = AsExpr(Constant<SubscriptInteger>{*ubi});
18264ab3302SCarolineConcatto   }
183bd859cb4SPeter Klausler   std::optional<ConstantSubscript> length;
184bd859cb4SPeter Klausler   std::optional<Expr<SomeCharacter>> strings; // a Constant<Character>
185bd859cb4SPeter Klausler   if (const auto *literal{std::get_if<StaticDataObject::Pointer>(&parent_)}) {
186bd859cb4SPeter Klausler     length = (*literal)->data().size();
187bd859cb4SPeter Klausler     if (auto str{(*literal)->AsString()}) {
188bd859cb4SPeter Klausler       strings =
189bd859cb4SPeter Klausler           Expr<SomeCharacter>(Expr<Ascii>(Constant<Ascii>{std::move(*str)}));
190dd3eb3f3SPeter Steinfeld     }
191bd859cb4SPeter Klausler   } else if (const auto *dataRef{std::get_if<DataRef>(&parent_)}) {
192bd859cb4SPeter Klausler     if (auto expr{AsGenericExpr(DataRef{*dataRef})}) {
193bd859cb4SPeter Klausler       auto folded{evaluate::Fold(context, std::move(*expr))};
194bd859cb4SPeter Klausler       if (IsActuallyConstant(folded)) {
195bd859cb4SPeter Klausler         if (const auto *value{UnwrapExpr<Expr<SomeCharacter>>(folded)}) {
196bd859cb4SPeter Klausler           strings = *value;
19764ab3302SCarolineConcatto         }
19864ab3302SCarolineConcatto       }
19964ab3302SCarolineConcatto     }
20064ab3302SCarolineConcatto   }
201bd859cb4SPeter Klausler   std::optional<Expr<SomeCharacter>> result;
202bd859cb4SPeter Klausler   if (strings) {
203cd03e96fSPeter Klausler     result = common::visit(
204bd859cb4SPeter Klausler         [&](const auto &expr) -> std::optional<Expr<SomeCharacter>> {
205bd859cb4SPeter Klausler           using Type = typename std::decay_t<decltype(expr)>::Result;
206bd859cb4SPeter Klausler           if (const auto *cc{std::get_if<Constant<Type>>(&expr.u)}) {
207bd859cb4SPeter Klausler             if (auto substr{cc->Substring(*lbi, *ubi)}) {
208bd859cb4SPeter Klausler               return Expr<SomeCharacter>{Expr<Type>{*substr}};
209bd859cb4SPeter Klausler             }
210bd859cb4SPeter Klausler           }
21164ab3302SCarolineConcatto           return std::nullopt;
212bd859cb4SPeter Klausler         },
213bd859cb4SPeter Klausler         strings->u);
214bd859cb4SPeter Klausler   }
215bd859cb4SPeter Klausler   if (!result) { // error cases
216bd859cb4SPeter Klausler     if (*lbi < 1) {
217505f6da1SPeter Klausler       if (context.languageFeatures().ShouldWarn(common::UsageWarning::Bounds)) {
2180f973ac7SPeter Klausler         context.messages().Say(common::UsageWarning::Bounds,
219a53967cdSPeter Klausler             "Lower bound (%jd) on substring is less than one"_warn_en_US,
220bd859cb4SPeter Klausler             static_cast<std::intmax_t>(*lbi));
221505f6da1SPeter Klausler       }
222bd859cb4SPeter Klausler       *lbi = 1;
223bd859cb4SPeter Klausler       lower_ = AsExpr(Constant<SubscriptInteger>{1});
224bd859cb4SPeter Klausler     }
225bd859cb4SPeter Klausler     if (length && *ubi > *length) {
226505f6da1SPeter Klausler       if (context.languageFeatures().ShouldWarn(common::UsageWarning::Bounds)) {
2270f973ac7SPeter Klausler         context.messages().Say(common::UsageWarning::Bounds,
228a53967cdSPeter Klausler             "Upper bound (%jd) on substring is greater than character length (%jd)"_warn_en_US,
229bd859cb4SPeter Klausler             static_cast<std::intmax_t>(*ubi),
230bd859cb4SPeter Klausler             static_cast<std::intmax_t>(*length));
231505f6da1SPeter Klausler       }
232bd859cb4SPeter Klausler       *ubi = *length;
233bd859cb4SPeter Klausler       upper_ = AsExpr(Constant<SubscriptInteger>{*ubi});
234bd859cb4SPeter Klausler     }
235bd859cb4SPeter Klausler   }
236bd859cb4SPeter Klausler   return result;
23764ab3302SCarolineConcatto }
23864ab3302SCarolineConcatto 
23964ab3302SCarolineConcatto DescriptorInquiry::DescriptorInquiry(
24064ab3302SCarolineConcatto     const NamedEntity &base, Field field, int dim)
24164ab3302SCarolineConcatto     : base_{base}, field_{field}, dimension_{dim} {
24264ab3302SCarolineConcatto   const Symbol &last{base_.GetLastSymbol()};
24364ab3302SCarolineConcatto   CHECK(IsDescriptor(last));
2449245f355Speter klausler   CHECK(((field == Field::Len || field == Field::Rank) && dim == 0) ||
24564ab3302SCarolineConcatto       (field != Field::Len && dim >= 0 && dim < last.Rank()));
24664ab3302SCarolineConcatto }
24764ab3302SCarolineConcatto 
24864ab3302SCarolineConcatto DescriptorInquiry::DescriptorInquiry(NamedEntity &&base, Field field, int dim)
24964ab3302SCarolineConcatto     : base_{std::move(base)}, field_{field}, dimension_{dim} {
25064ab3302SCarolineConcatto   const Symbol &last{base_.GetLastSymbol()};
25164ab3302SCarolineConcatto   CHECK(IsDescriptor(last));
25264ab3302SCarolineConcatto   CHECK((field == Field::Len && dim == 0) ||
253ff567a4eSPeter Klausler       (field != Field::Len && dim >= 0 &&
254ff567a4eSPeter Klausler           (dim < last.Rank() || IsAssumedRank(last))));
25564ab3302SCarolineConcatto }
25664ab3302SCarolineConcatto 
25764ab3302SCarolineConcatto // LEN()
2586f3d322fSpeter klausler static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &symbol) {
2596f3d322fSpeter klausler   const Symbol &ultimate{symbol.GetUltimate()};
2606f3d322fSpeter klausler   if (const auto *assoc{ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
2616f3d322fSpeter klausler     if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(assoc->expr())}) {
2626f3d322fSpeter klausler       return chExpr->LEN();
2636f3d322fSpeter klausler     }
2646f3d322fSpeter klausler   }
26578d60094SPeter Klausler   if (auto dyType{DynamicType::From(ultimate)}) {
2668fed620eSPeter Klausler     auto len{dyType->GetCharLength()};
2678fed620eSPeter Klausler     if (!len && ultimate.attrs().test(semantics::Attr::PARAMETER)) {
2688fed620eSPeter Klausler       // Its initializer determines the length of an implied-length named
2698fed620eSPeter Klausler       // constant.
2708fed620eSPeter Klausler       if (const auto *object{
2718fed620eSPeter Klausler               ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {
2728fed620eSPeter Klausler         if (object->init()) {
2738fed620eSPeter Klausler           if (auto dyType2{DynamicType::From(*object->init())}) {
2748fed620eSPeter Klausler             len = dyType2->GetCharLength();
2758fed620eSPeter Klausler           }
2768fed620eSPeter Klausler         }
2778fed620eSPeter Klausler       }
2788fed620eSPeter Klausler     }
2798fed620eSPeter Klausler     if (len) {
280b70f507cSPeter Klausler       if (auto constLen{ToInt64(*len)}) {
281b70f507cSPeter Klausler         return Expr<SubscriptInteger>{std::max<std::int64_t>(*constLen, 0)};
282b70f507cSPeter Klausler       } else if (ultimate.owner().IsDerivedType() ||
283b70f507cSPeter Klausler           IsScopeInvariantExpr(*len)) {
28478d60094SPeter Klausler         return AsExpr(Extremum<SubscriptInteger>{
28578d60094SPeter Klausler             Ordering::Greater, Expr<SubscriptInteger>{0}, std::move(*len)});
28678d60094SPeter Klausler       }
28778d60094SPeter Klausler     }
28878d60094SPeter Klausler   }
28978d60094SPeter Klausler   if (IsDescriptor(ultimate) && !ultimate.owner().IsDerivedType()) {
29078d60094SPeter Klausler     return Expr<SubscriptInteger>{
29178d60094SPeter Klausler         DescriptorInquiry{NamedEntity{symbol}, DescriptorInquiry::Field::Len}};
29264ab3302SCarolineConcatto   }
29364ab3302SCarolineConcatto   return std::nullopt;
29464ab3302SCarolineConcatto }
29564ab3302SCarolineConcatto 
29664ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> BaseObject::LEN() const {
297cd03e96fSPeter Klausler   return common::visit(
29864ab3302SCarolineConcatto       common::visitors{
29964ab3302SCarolineConcatto           [](const Symbol &symbol) { return SymbolLEN(symbol); },
30064ab3302SCarolineConcatto           [](const StaticDataObject::Pointer &object)
30164ab3302SCarolineConcatto               -> std::optional<Expr<SubscriptInteger>> {
30264ab3302SCarolineConcatto             return AsExpr(Constant<SubscriptInteger>{object->data().size()});
30364ab3302SCarolineConcatto           },
30464ab3302SCarolineConcatto       },
30564ab3302SCarolineConcatto       u);
30664ab3302SCarolineConcatto }
30764ab3302SCarolineConcatto 
30864ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Component::LEN() const {
30964ab3302SCarolineConcatto   return SymbolLEN(GetLastSymbol());
31064ab3302SCarolineConcatto }
31164ab3302SCarolineConcatto 
31264ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> NamedEntity::LEN() const {
31364ab3302SCarolineConcatto   return SymbolLEN(GetLastSymbol());
31464ab3302SCarolineConcatto }
31564ab3302SCarolineConcatto 
31664ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> ArrayRef::LEN() const {
31764ab3302SCarolineConcatto   return base_.LEN();
31864ab3302SCarolineConcatto }
31964ab3302SCarolineConcatto 
32064ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> CoarrayRef::LEN() const {
32164ab3302SCarolineConcatto   return SymbolLEN(GetLastSymbol());
32264ab3302SCarolineConcatto }
32364ab3302SCarolineConcatto 
32464ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> DataRef::LEN() const {
325cd03e96fSPeter Klausler   return common::visit(common::visitors{
32664ab3302SCarolineConcatto                            [](SymbolRef symbol) { return SymbolLEN(symbol); },
32764ab3302SCarolineConcatto                            [](const auto &x) { return x.LEN(); },
32864ab3302SCarolineConcatto                        },
32964ab3302SCarolineConcatto       u);
33064ab3302SCarolineConcatto }
33164ab3302SCarolineConcatto 
33264ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Substring::LEN() const {
33364ab3302SCarolineConcatto   if (auto top{upper()}) {
33464ab3302SCarolineConcatto     return AsExpr(Extremum<SubscriptInteger>{Ordering::Greater,
33564ab3302SCarolineConcatto         AsExpr(Constant<SubscriptInteger>{0}),
33664ab3302SCarolineConcatto         *std::move(top) - lower() + AsExpr(Constant<SubscriptInteger>{1})});
33764ab3302SCarolineConcatto   } else {
33864ab3302SCarolineConcatto     return std::nullopt;
33964ab3302SCarolineConcatto   }
34064ab3302SCarolineConcatto }
34164ab3302SCarolineConcatto 
34264ab3302SCarolineConcatto template <typename T>
34364ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Designator<T>::LEN() const {
34464ab3302SCarolineConcatto   if constexpr (T::category == TypeCategory::Character) {
345cd03e96fSPeter Klausler     return common::visit(common::visitors{
34664ab3302SCarolineConcatto                              [](SymbolRef symbol) { return SymbolLEN(symbol); },
34764ab3302SCarolineConcatto                              [](const auto &x) { return x.LEN(); },
34864ab3302SCarolineConcatto                          },
34964ab3302SCarolineConcatto         u);
35064ab3302SCarolineConcatto   } else {
35164ab3302SCarolineConcatto     common::die("Designator<non-char>::LEN() called");
35264ab3302SCarolineConcatto     return std::nullopt;
35364ab3302SCarolineConcatto   }
35464ab3302SCarolineConcatto }
35564ab3302SCarolineConcatto 
35664ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> ProcedureDesignator::LEN() const {
35764ab3302SCarolineConcatto   using T = std::optional<Expr<SubscriptInteger>>;
358cd03e96fSPeter Klausler   return common::visit(
35964ab3302SCarolineConcatto       common::visitors{
36064ab3302SCarolineConcatto           [](SymbolRef symbol) -> T { return SymbolLEN(symbol); },
36164ab3302SCarolineConcatto           [](const common::CopyableIndirection<Component> &c) -> T {
36264ab3302SCarolineConcatto             return c.value().LEN();
36364ab3302SCarolineConcatto           },
36464ab3302SCarolineConcatto           [](const SpecificIntrinsic &i) -> T {
365ac964175Speter klausler             // Some cases whose results' lengths can be determined
36664ab3302SCarolineConcatto             // from the lengths of their arguments are handled in
367ac964175Speter klausler             // ProcedureRef::LEN() before coming here.
368ac964175Speter klausler             if (const auto &result{i.characteristics.value().functionResult}) {
369ac964175Speter klausler               if (const auto *type{result->GetTypeAndShape()}) {
370ac964175Speter klausler                 if (auto length{type->type().GetCharLength()}) {
371ac964175Speter klausler                   return std::move(*length);
372ac964175Speter klausler                 }
373ac964175Speter klausler               }
374ac964175Speter klausler             }
37564ab3302SCarolineConcatto             return std::nullopt;
37664ab3302SCarolineConcatto           },
37764ab3302SCarolineConcatto       },
37864ab3302SCarolineConcatto       u);
37964ab3302SCarolineConcatto }
38064ab3302SCarolineConcatto 
38164ab3302SCarolineConcatto // Rank()
38264ab3302SCarolineConcatto int BaseObject::Rank() const {
383cd03e96fSPeter Klausler   return common::visit(common::visitors{
38464ab3302SCarolineConcatto                            [](SymbolRef symbol) { return symbol->Rank(); },
38564ab3302SCarolineConcatto                            [](const StaticDataObject::Pointer &) { return 0; },
38664ab3302SCarolineConcatto                        },
38764ab3302SCarolineConcatto       u);
38864ab3302SCarolineConcatto }
38964ab3302SCarolineConcatto 
39064ab3302SCarolineConcatto int Component::Rank() const {
39164ab3302SCarolineConcatto   if (int rank{symbol_->Rank()}; rank > 0) {
39264ab3302SCarolineConcatto     return rank;
39364ab3302SCarolineConcatto   }
39464ab3302SCarolineConcatto   return base().Rank();
39564ab3302SCarolineConcatto }
39664ab3302SCarolineConcatto 
39764ab3302SCarolineConcatto int NamedEntity::Rank() const {
398cd03e96fSPeter Klausler   return common::visit(common::visitors{
39964ab3302SCarolineConcatto                            [](const SymbolRef s) { return s->Rank(); },
40064ab3302SCarolineConcatto                            [](const Component &c) { return c.Rank(); },
40164ab3302SCarolineConcatto                        },
40264ab3302SCarolineConcatto       u_);
40364ab3302SCarolineConcatto }
40464ab3302SCarolineConcatto 
40564ab3302SCarolineConcatto int Subscript::Rank() const {
406cd03e96fSPeter Klausler   return common::visit(common::visitors{
40764ab3302SCarolineConcatto                            [](const IndirectSubscriptIntegerExpr &x) {
40864ab3302SCarolineConcatto                              return x.value().Rank();
40964ab3302SCarolineConcatto                            },
41064ab3302SCarolineConcatto                            [](const Triplet &) { return 1; },
41164ab3302SCarolineConcatto                        },
41264ab3302SCarolineConcatto       u);
41364ab3302SCarolineConcatto }
41464ab3302SCarolineConcatto 
41564ab3302SCarolineConcatto int ArrayRef::Rank() const {
41664ab3302SCarolineConcatto   int rank{0};
41764ab3302SCarolineConcatto   for (const auto &expr : subscript_) {
41864ab3302SCarolineConcatto     rank += expr.Rank();
41964ab3302SCarolineConcatto   }
42064ab3302SCarolineConcatto   if (rank > 0) {
42164ab3302SCarolineConcatto     return rank;
42264ab3302SCarolineConcatto   } else if (const Component * component{base_.UnwrapComponent()}) {
42364ab3302SCarolineConcatto     return component->base().Rank();
42464ab3302SCarolineConcatto   } else {
42564ab3302SCarolineConcatto     return 0;
42664ab3302SCarolineConcatto   }
42764ab3302SCarolineConcatto }
42864ab3302SCarolineConcatto 
42964ab3302SCarolineConcatto int CoarrayRef::Rank() const {
43064ab3302SCarolineConcatto   if (!subscript_.empty()) {
43164ab3302SCarolineConcatto     int rank{0};
43264ab3302SCarolineConcatto     for (const auto &expr : subscript_) {
43364ab3302SCarolineConcatto       rank += expr.Rank();
43464ab3302SCarolineConcatto     }
43564ab3302SCarolineConcatto     return rank;
43664ab3302SCarolineConcatto   } else {
43764ab3302SCarolineConcatto     return base_.back()->Rank();
43864ab3302SCarolineConcatto   }
43964ab3302SCarolineConcatto }
44064ab3302SCarolineConcatto 
44164ab3302SCarolineConcatto int DataRef::Rank() const {
442cd03e96fSPeter Klausler   return common::visit(common::visitors{
44364ab3302SCarolineConcatto                            [](SymbolRef symbol) { return symbol->Rank(); },
44464ab3302SCarolineConcatto                            [](const auto &x) { return x.Rank(); },
44564ab3302SCarolineConcatto                        },
44664ab3302SCarolineConcatto       u);
44764ab3302SCarolineConcatto }
44864ab3302SCarolineConcatto 
44964ab3302SCarolineConcatto int Substring::Rank() const {
450cd03e96fSPeter Klausler   return common::visit(
451cd03e96fSPeter Klausler       common::visitors{
45264ab3302SCarolineConcatto           [](const DataRef &dataRef) { return dataRef.Rank(); },
45364ab3302SCarolineConcatto           [](const StaticDataObject::Pointer &) { return 0; },
45464ab3302SCarolineConcatto       },
45564ab3302SCarolineConcatto       parent_);
45664ab3302SCarolineConcatto }
45764ab3302SCarolineConcatto 
45864ab3302SCarolineConcatto int ComplexPart::Rank() const { return complex_.Rank(); }
45964ab3302SCarolineConcatto 
46064ab3302SCarolineConcatto template <typename T> int Designator<T>::Rank() const {
461cd03e96fSPeter Klausler   return common::visit(common::visitors{
46264ab3302SCarolineConcatto                            [](SymbolRef symbol) { return symbol->Rank(); },
46364ab3302SCarolineConcatto                            [](const auto &x) { return x.Rank(); },
46464ab3302SCarolineConcatto                        },
46564ab3302SCarolineConcatto       u);
46664ab3302SCarolineConcatto }
46764ab3302SCarolineConcatto 
468*3a8a52f4SPeter Klausler // Corank()
469*3a8a52f4SPeter Klausler int BaseObject::Corank() const {
470*3a8a52f4SPeter Klausler   return common::visit(common::visitors{
471*3a8a52f4SPeter Klausler                            [](SymbolRef symbol) { return symbol->Corank(); },
472*3a8a52f4SPeter Klausler                            [](const StaticDataObject::Pointer &) { return 0; },
473*3a8a52f4SPeter Klausler                        },
474*3a8a52f4SPeter Klausler       u);
475*3a8a52f4SPeter Klausler }
476*3a8a52f4SPeter Klausler 
477*3a8a52f4SPeter Klausler int Component::Corank() const {
478*3a8a52f4SPeter Klausler   if (int corank{symbol_->Corank()}; corank > 0) {
479*3a8a52f4SPeter Klausler     return corank;
480*3a8a52f4SPeter Klausler   }
481*3a8a52f4SPeter Klausler   return base().Corank();
482*3a8a52f4SPeter Klausler }
483*3a8a52f4SPeter Klausler 
484*3a8a52f4SPeter Klausler int NamedEntity::Corank() const {
485*3a8a52f4SPeter Klausler   return common::visit(common::visitors{
486*3a8a52f4SPeter Klausler                            [](const SymbolRef s) { return s->Corank(); },
487*3a8a52f4SPeter Klausler                            [](const Component &c) { return c.Corank(); },
488*3a8a52f4SPeter Klausler                        },
489*3a8a52f4SPeter Klausler       u_);
490*3a8a52f4SPeter Klausler }
491*3a8a52f4SPeter Klausler 
492*3a8a52f4SPeter Klausler int ArrayRef::Corank() const { return base().Corank(); }
493*3a8a52f4SPeter Klausler 
494*3a8a52f4SPeter Klausler int DataRef::Corank() const {
495*3a8a52f4SPeter Klausler   return common::visit(common::visitors{
496*3a8a52f4SPeter Klausler                            [](SymbolRef symbol) { return symbol->Corank(); },
497*3a8a52f4SPeter Klausler                            [](const auto &x) { return x.Corank(); },
498*3a8a52f4SPeter Klausler                        },
499*3a8a52f4SPeter Klausler       u);
500*3a8a52f4SPeter Klausler }
501*3a8a52f4SPeter Klausler 
502*3a8a52f4SPeter Klausler int Substring::Corank() const {
503*3a8a52f4SPeter Klausler   return common::visit(
504*3a8a52f4SPeter Klausler       common::visitors{
505*3a8a52f4SPeter Klausler           [](const DataRef &dataRef) { return dataRef.Corank(); },
506*3a8a52f4SPeter Klausler           [](const StaticDataObject::Pointer &) { return 0; },
507*3a8a52f4SPeter Klausler       },
508*3a8a52f4SPeter Klausler       parent_);
509*3a8a52f4SPeter Klausler }
510*3a8a52f4SPeter Klausler 
511*3a8a52f4SPeter Klausler int ComplexPart::Corank() const { return complex_.Corank(); }
512*3a8a52f4SPeter Klausler 
513*3a8a52f4SPeter Klausler template <typename T> int Designator<T>::Corank() const {
514*3a8a52f4SPeter Klausler   return common::visit(common::visitors{
515*3a8a52f4SPeter Klausler                            [](SymbolRef symbol) { return symbol->Corank(); },
516*3a8a52f4SPeter Klausler                            [](const auto &x) { return x.Corank(); },
517*3a8a52f4SPeter Klausler                        },
518*3a8a52f4SPeter Klausler       u);
519*3a8a52f4SPeter Klausler }
520*3a8a52f4SPeter Klausler 
52164ab3302SCarolineConcatto // GetBaseObject(), GetFirstSymbol(), GetLastSymbol(), &c.
52264ab3302SCarolineConcatto const Symbol &Component::GetFirstSymbol() const {
52364ab3302SCarolineConcatto   return base_.value().GetFirstSymbol();
52464ab3302SCarolineConcatto }
52564ab3302SCarolineConcatto 
52664ab3302SCarolineConcatto const Symbol &NamedEntity::GetFirstSymbol() const {
527cd03e96fSPeter Klausler   return common::visit(common::visitors{
52864ab3302SCarolineConcatto                            [](SymbolRef s) -> const Symbol & { return s; },
52964ab3302SCarolineConcatto                            [](const Component &c) -> const Symbol & {
53064ab3302SCarolineConcatto                              return c.GetFirstSymbol();
53164ab3302SCarolineConcatto                            },
53264ab3302SCarolineConcatto                        },
53364ab3302SCarolineConcatto       u_);
53464ab3302SCarolineConcatto }
53564ab3302SCarolineConcatto 
53664ab3302SCarolineConcatto const Symbol &NamedEntity::GetLastSymbol() const {
537cd03e96fSPeter Klausler   return common::visit(common::visitors{
53864ab3302SCarolineConcatto                            [](SymbolRef s) -> const Symbol & { return s; },
53964ab3302SCarolineConcatto                            [](const Component &c) -> const Symbol & {
54064ab3302SCarolineConcatto                              return c.GetLastSymbol();
54164ab3302SCarolineConcatto                            },
54264ab3302SCarolineConcatto                        },
54364ab3302SCarolineConcatto       u_);
54464ab3302SCarolineConcatto }
54564ab3302SCarolineConcatto 
5469e855a6cSPeter Klausler const SymbolRef *NamedEntity::UnwrapSymbolRef() const {
5479e855a6cSPeter Klausler   return common::visit(
5489e855a6cSPeter Klausler       common::visitors{
5499e855a6cSPeter Klausler           [](const SymbolRef &s) { return &s; },
5509e855a6cSPeter Klausler           [](const Component &) -> const SymbolRef * { return nullptr; },
5519e855a6cSPeter Klausler       },
5529e855a6cSPeter Klausler       u_);
5539e855a6cSPeter Klausler }
5549e855a6cSPeter Klausler 
5559e855a6cSPeter Klausler SymbolRef *NamedEntity::UnwrapSymbolRef() {
5569e855a6cSPeter Klausler   return common::visit(common::visitors{
5579e855a6cSPeter Klausler                            [](SymbolRef &s) { return &s; },
5589e855a6cSPeter Klausler                            [](Component &) -> SymbolRef * { return nullptr; },
5599e855a6cSPeter Klausler                        },
5609e855a6cSPeter Klausler       u_);
5619e855a6cSPeter Klausler }
5629e855a6cSPeter Klausler 
56364ab3302SCarolineConcatto const Component *NamedEntity::UnwrapComponent() const {
564cd03e96fSPeter Klausler   return common::visit(
565cd03e96fSPeter Klausler       common::visitors{
56664ab3302SCarolineConcatto           [](SymbolRef) -> const Component * { return nullptr; },
56764ab3302SCarolineConcatto           [](const Component &c) { return &c; },
56864ab3302SCarolineConcatto       },
56964ab3302SCarolineConcatto       u_);
57064ab3302SCarolineConcatto }
57164ab3302SCarolineConcatto 
57264ab3302SCarolineConcatto Component *NamedEntity::UnwrapComponent() {
573cd03e96fSPeter Klausler   return common::visit(common::visitors{
57464ab3302SCarolineConcatto                            [](SymbolRef &) -> Component * { return nullptr; },
57564ab3302SCarolineConcatto                            [](Component &c) { return &c; },
57664ab3302SCarolineConcatto                        },
57764ab3302SCarolineConcatto       u_);
57864ab3302SCarolineConcatto }
57964ab3302SCarolineConcatto 
58064ab3302SCarolineConcatto const Symbol &ArrayRef::GetFirstSymbol() const {
58164ab3302SCarolineConcatto   return base_.GetFirstSymbol();
58264ab3302SCarolineConcatto }
58364ab3302SCarolineConcatto 
58464ab3302SCarolineConcatto const Symbol &ArrayRef::GetLastSymbol() const { return base_.GetLastSymbol(); }
58564ab3302SCarolineConcatto 
58664ab3302SCarolineConcatto const Symbol &DataRef::GetFirstSymbol() const {
587cd03e96fSPeter Klausler   return *common::visit(common::visitors{
58864ab3302SCarolineConcatto                             [](SymbolRef symbol) { return &*symbol; },
58964ab3302SCarolineConcatto                             [](const auto &x) { return &x.GetFirstSymbol(); },
59064ab3302SCarolineConcatto                         },
59164ab3302SCarolineConcatto       u);
59264ab3302SCarolineConcatto }
59364ab3302SCarolineConcatto 
59464ab3302SCarolineConcatto const Symbol &DataRef::GetLastSymbol() const {
595cd03e96fSPeter Klausler   return *common::visit(common::visitors{
59664ab3302SCarolineConcatto                             [](SymbolRef symbol) { return &*symbol; },
59764ab3302SCarolineConcatto                             [](const auto &x) { return &x.GetLastSymbol(); },
59864ab3302SCarolineConcatto                         },
59964ab3302SCarolineConcatto       u);
60064ab3302SCarolineConcatto }
60164ab3302SCarolineConcatto 
60264ab3302SCarolineConcatto BaseObject Substring::GetBaseObject() const {
603cd03e96fSPeter Klausler   return common::visit(common::visitors{
60464ab3302SCarolineConcatto                            [](const DataRef &dataRef) {
60564ab3302SCarolineConcatto                              return BaseObject{dataRef.GetFirstSymbol()};
60664ab3302SCarolineConcatto                            },
60764ab3302SCarolineConcatto                            [](StaticDataObject::Pointer pointer) {
60864ab3302SCarolineConcatto                              return BaseObject{std::move(pointer)};
60964ab3302SCarolineConcatto                            },
61064ab3302SCarolineConcatto                        },
61164ab3302SCarolineConcatto       parent_);
61264ab3302SCarolineConcatto }
61364ab3302SCarolineConcatto 
61464ab3302SCarolineConcatto const Symbol *Substring::GetLastSymbol() const {
615cd03e96fSPeter Klausler   return common::visit(
61664ab3302SCarolineConcatto       common::visitors{
61764ab3302SCarolineConcatto           [](const DataRef &dataRef) { return &dataRef.GetLastSymbol(); },
61864ab3302SCarolineConcatto           [](const auto &) -> const Symbol * { return nullptr; },
61964ab3302SCarolineConcatto       },
62064ab3302SCarolineConcatto       parent_);
62164ab3302SCarolineConcatto }
62264ab3302SCarolineConcatto 
62364ab3302SCarolineConcatto template <typename T> BaseObject Designator<T>::GetBaseObject() const {
624cd03e96fSPeter Klausler   return common::visit(
62564ab3302SCarolineConcatto       common::visitors{
62664ab3302SCarolineConcatto           [](SymbolRef symbol) { return BaseObject{symbol}; },
62764ab3302SCarolineConcatto           [](const Substring &sstring) { return sstring.GetBaseObject(); },
62874e59e77SBrad Smith           [](const auto &x) { return BaseObject{x.GetFirstSymbol()}; },
62964ab3302SCarolineConcatto       },
63064ab3302SCarolineConcatto       u);
63164ab3302SCarolineConcatto }
63264ab3302SCarolineConcatto 
63364ab3302SCarolineConcatto template <typename T> const Symbol *Designator<T>::GetLastSymbol() const {
634cd03e96fSPeter Klausler   return common::visit(
63564ab3302SCarolineConcatto       common::visitors{
63664ab3302SCarolineConcatto           [](SymbolRef symbol) { return &*symbol; },
63764ab3302SCarolineConcatto           [](const Substring &sstring) { return sstring.GetLastSymbol(); },
63874e59e77SBrad Smith           [](const auto &x) { return &x.GetLastSymbol(); },
63964ab3302SCarolineConcatto       },
64064ab3302SCarolineConcatto       u);
64164ab3302SCarolineConcatto }
64264ab3302SCarolineConcatto 
6431f879005STim Keith template <typename T>
6441f879005STim Keith std::optional<DynamicType> Designator<T>::GetType() const {
64564ab3302SCarolineConcatto   if constexpr (IsLengthlessIntrinsicType<Result>) {
64619d7cc2eSPeter Steinfeld     return Result::GetType();
64764ab3302SCarolineConcatto   }
64850960e93SPeter Klausler   if constexpr (Result::category == TypeCategory::Character) {
64950960e93SPeter Klausler     if (std::holds_alternative<Substring>(u)) {
65050960e93SPeter Klausler       if (auto len{LEN()}) {
65150960e93SPeter Klausler         if (auto n{ToInt64(*len)}) {
65250960e93SPeter Klausler           return DynamicType{T::kind, *n};
65350960e93SPeter Klausler         }
65450960e93SPeter Klausler       }
65550960e93SPeter Klausler       return DynamicType{TypeCategory::Character, T::kind};
65650960e93SPeter Klausler     }
65750960e93SPeter Klausler   }
65850960e93SPeter Klausler   if (const Symbol * symbol{GetLastSymbol()}) {
65950960e93SPeter Klausler     return DynamicType::From(*symbol);
66064ab3302SCarolineConcatto   }
66119d7cc2eSPeter Steinfeld   return std::nullopt;
66219d7cc2eSPeter Steinfeld }
66364ab3302SCarolineConcatto 
66464ab3302SCarolineConcatto static NamedEntity AsNamedEntity(const SymbolVector &x) {
66564ab3302SCarolineConcatto   CHECK(!x.empty());
66664ab3302SCarolineConcatto   NamedEntity result{x.front()};
66764ab3302SCarolineConcatto   int j{0};
66864ab3302SCarolineConcatto   for (const Symbol &symbol : x) {
66964ab3302SCarolineConcatto     if (j++ != 0) {
67064ab3302SCarolineConcatto       DataRef base{result.IsSymbol() ? DataRef{result.GetLastSymbol()}
67164ab3302SCarolineConcatto                                      : DataRef{result.GetComponent()}};
67264ab3302SCarolineConcatto       result = NamedEntity{Component{std::move(base), symbol}};
67364ab3302SCarolineConcatto     }
67464ab3302SCarolineConcatto   }
67564ab3302SCarolineConcatto   return result;
67664ab3302SCarolineConcatto }
67764ab3302SCarolineConcatto 
67864ab3302SCarolineConcatto NamedEntity CoarrayRef::GetBase() const { return AsNamedEntity(base_); }
67964ab3302SCarolineConcatto 
68064ab3302SCarolineConcatto // Equality testing
68164ab3302SCarolineConcatto 
68264ab3302SCarolineConcatto // For the purposes of comparing type parameter expressions while
68364ab3302SCarolineConcatto // testing the compatibility of procedure characteristics, two
6840c0b2ea9SPeter Klausler // dummy arguments with the same position are considered equal.
6850c0b2ea9SPeter Klausler static std::optional<int> GetDummyArgPosition(const Symbol &original) {
6860c0b2ea9SPeter Klausler   const Symbol &symbol(original.GetUltimate());
6870c0b2ea9SPeter Klausler   if (IsDummy(symbol)) {
6880c0b2ea9SPeter Klausler     if (const Symbol * proc{symbol.owner().symbol()}) {
6890c0b2ea9SPeter Klausler       if (const auto *subp{proc->detailsIf<semantics::SubprogramDetails>()}) {
6900c0b2ea9SPeter Klausler         int j{0};
6910c0b2ea9SPeter Klausler         for (const Symbol *arg : subp->dummyArgs()) {
6920c0b2ea9SPeter Klausler           if (arg == &symbol) {
6930c0b2ea9SPeter Klausler             return j;
6940c0b2ea9SPeter Klausler           }
6950c0b2ea9SPeter Klausler           ++j;
6960c0b2ea9SPeter Klausler         }
6970c0b2ea9SPeter Klausler       }
6980c0b2ea9SPeter Klausler     }
6990c0b2ea9SPeter Klausler   }
7000c0b2ea9SPeter Klausler   return std::nullopt;
7010c0b2ea9SPeter Klausler }
7020c0b2ea9SPeter Klausler 
703e03b20e6Speter klausler static bool AreSameSymbol(const Symbol &x, const Symbol &y) {
70464ab3302SCarolineConcatto   if (&x == &y) {
70564ab3302SCarolineConcatto     return true;
70664ab3302SCarolineConcatto   }
7070c0b2ea9SPeter Klausler   if (auto xPos{GetDummyArgPosition(x)}) {
7080c0b2ea9SPeter Klausler     if (auto yPos{GetDummyArgPosition(y)}) {
7090c0b2ea9SPeter Klausler       return *xPos == *yPos;
71064ab3302SCarolineConcatto     }
71164ab3302SCarolineConcatto   }
71264ab3302SCarolineConcatto   return false;
71364ab3302SCarolineConcatto }
71464ab3302SCarolineConcatto 
715e03b20e6Speter klausler // Implements operator==() for a union type, using special case handling
716e03b20e6Speter klausler // for Symbol references.
717e03b20e6Speter klausler template <typename A> static bool TestVariableEquality(const A &x, const A &y) {
718e03b20e6Speter klausler   const SymbolRef *xSymbol{std::get_if<SymbolRef>(&x.u)};
719e03b20e6Speter klausler   if (const SymbolRef * ySymbol{std::get_if<SymbolRef>(&y.u)}) {
720e03b20e6Speter klausler     return xSymbol && AreSameSymbol(*xSymbol, *ySymbol);
721e03b20e6Speter klausler   } else {
722e03b20e6Speter klausler     return x.u == y.u;
723e03b20e6Speter klausler   }
724e03b20e6Speter klausler }
725e03b20e6Speter klausler 
72664ab3302SCarolineConcatto bool BaseObject::operator==(const BaseObject &that) const {
72764ab3302SCarolineConcatto   return TestVariableEquality(*this, that);
72864ab3302SCarolineConcatto }
72964ab3302SCarolineConcatto bool Component::operator==(const Component &that) const {
73064ab3302SCarolineConcatto   return base_ == that.base_ && &*symbol_ == &*that.symbol_;
73164ab3302SCarolineConcatto }
73264ab3302SCarolineConcatto bool NamedEntity::operator==(const NamedEntity &that) const {
73364ab3302SCarolineConcatto   if (IsSymbol()) {
73464ab3302SCarolineConcatto     return that.IsSymbol() &&
73564ab3302SCarolineConcatto         AreSameSymbol(GetFirstSymbol(), that.GetFirstSymbol());
73664ab3302SCarolineConcatto   } else {
73764ab3302SCarolineConcatto     return !that.IsSymbol() && GetComponent() == that.GetComponent();
73864ab3302SCarolineConcatto   }
73964ab3302SCarolineConcatto }
7404cbfd93aSpeter klausler bool TypeParamInquiry::operator==(const TypeParamInquiry &that) const {
74164ab3302SCarolineConcatto   return &*parameter_ == &*that.parameter_ && base_ == that.base_;
74264ab3302SCarolineConcatto }
74364ab3302SCarolineConcatto bool Triplet::operator==(const Triplet &that) const {
74464ab3302SCarolineConcatto   return lower_ == that.lower_ && upper_ == that.upper_ &&
74564ab3302SCarolineConcatto       stride_ == that.stride_;
74664ab3302SCarolineConcatto }
747e03b20e6Speter klausler bool Subscript::operator==(const Subscript &that) const { return u == that.u; }
74864ab3302SCarolineConcatto bool ArrayRef::operator==(const ArrayRef &that) const {
74964ab3302SCarolineConcatto   return base_ == that.base_ && subscript_ == that.subscript_;
75064ab3302SCarolineConcatto }
75164ab3302SCarolineConcatto bool CoarrayRef::operator==(const CoarrayRef &that) const {
75264ab3302SCarolineConcatto   return base_ == that.base_ && subscript_ == that.subscript_ &&
75364ab3302SCarolineConcatto       cosubscript_ == that.cosubscript_ && stat_ == that.stat_ &&
75464ab3302SCarolineConcatto       team_ == that.team_ && teamIsTeamNumber_ == that.teamIsTeamNumber_;
75564ab3302SCarolineConcatto }
75664ab3302SCarolineConcatto bool DataRef::operator==(const DataRef &that) const {
75764ab3302SCarolineConcatto   return TestVariableEquality(*this, that);
75864ab3302SCarolineConcatto }
75964ab3302SCarolineConcatto bool Substring::operator==(const Substring &that) const {
76064ab3302SCarolineConcatto   return parent_ == that.parent_ && lower_ == that.lower_ &&
76164ab3302SCarolineConcatto       upper_ == that.upper_;
76264ab3302SCarolineConcatto }
76364ab3302SCarolineConcatto bool ComplexPart::operator==(const ComplexPart &that) const {
76464ab3302SCarolineConcatto   return part_ == that.part_ && complex_ == that.complex_;
76564ab3302SCarolineConcatto }
76664ab3302SCarolineConcatto bool ProcedureRef::operator==(const ProcedureRef &that) const {
76764ab3302SCarolineConcatto   return proc_ == that.proc_ && arguments_ == that.arguments_;
76864ab3302SCarolineConcatto }
769e03b20e6Speter klausler template <typename T>
770e03b20e6Speter klausler bool Designator<T>::operator==(const Designator<T> &that) const {
771e03b20e6Speter klausler   return TestVariableEquality(*this, that);
772e03b20e6Speter klausler }
77364ab3302SCarolineConcatto bool DescriptorInquiry::operator==(const DescriptorInquiry &that) const {
77464ab3302SCarolineConcatto   return field_ == that.field_ && base_ == that.base_ &&
77564ab3302SCarolineConcatto       dimension_ == that.dimension_;
77664ab3302SCarolineConcatto }
77764ab3302SCarolineConcatto 
7785c5bde1bSPeter Klausler #ifdef _MSC_VER // disable bogus warning about missing definitions
7795c5bde1bSPeter Klausler #pragma warning(disable : 4661)
7805c5bde1bSPeter Klausler #endif
78164ab3302SCarolineConcatto INSTANTIATE_VARIABLE_TEMPLATES
7821f879005STim Keith } // namespace Fortran::evaluate
78364ab3302SCarolineConcatto 
78464ab3302SCarolineConcatto template class Fortran::common::Indirection<Fortran::evaluate::Component, true>;
785