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