164ab3302SCarolineConcatto //===-- lib/Semantics/resolve-names-utils.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 "resolve-names-utils.h" 1064ab3302SCarolineConcatto #include "flang/Common/Fortran-features.h" 116bd72fa6SPeter Klausler #include "flang/Common/Fortran.h" 1264ab3302SCarolineConcatto #include "flang/Common/idioms.h" 1364ab3302SCarolineConcatto #include "flang/Common/indirection.h" 1464ab3302SCarolineConcatto #include "flang/Evaluate/fold.h" 1564ab3302SCarolineConcatto #include "flang/Evaluate/tools.h" 169e855a6cSPeter Klausler #include "flang/Evaluate/traverse.h" 1764ab3302SCarolineConcatto #include "flang/Evaluate/type.h" 1864ab3302SCarolineConcatto #include "flang/Parser/char-block.h" 1964ab3302SCarolineConcatto #include "flang/Parser/parse-tree.h" 2064ab3302SCarolineConcatto #include "flang/Semantics/expression.h" 2164ab3302SCarolineConcatto #include "flang/Semantics/semantics.h" 2264ab3302SCarolineConcatto #include "flang/Semantics/tools.h" 2364ab3302SCarolineConcatto #include <initializer_list> 2464ab3302SCarolineConcatto #include <variant> 2564ab3302SCarolineConcatto 2664ab3302SCarolineConcatto namespace Fortran::semantics { 2764ab3302SCarolineConcatto 2864ab3302SCarolineConcatto using common::LanguageFeature; 2964ab3302SCarolineConcatto using common::LogicalOperator; 3064ab3302SCarolineConcatto using common::NumericOperator; 3164ab3302SCarolineConcatto using common::RelationalOperator; 3264ab3302SCarolineConcatto using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator; 3364ab3302SCarolineConcatto 3464ab3302SCarolineConcatto static GenericKind MapIntrinsicOperator(IntrinsicOperator); 3564ab3302SCarolineConcatto 3664ab3302SCarolineConcatto Symbol *Resolve(const parser::Name &name, Symbol *symbol) { 3764ab3302SCarolineConcatto if (symbol && !name.symbol) { 3864ab3302SCarolineConcatto name.symbol = symbol; 3964ab3302SCarolineConcatto } 4064ab3302SCarolineConcatto return symbol; 4164ab3302SCarolineConcatto } 4264ab3302SCarolineConcatto Symbol &Resolve(const parser::Name &name, Symbol &symbol) { 4364ab3302SCarolineConcatto return *Resolve(name, &symbol); 4464ab3302SCarolineConcatto } 4564ab3302SCarolineConcatto 462895771fSPeter Klausler parser::MessageFixedText WithSeverity( 472895771fSPeter Klausler const parser::MessageFixedText &msg, parser::Severity severity) { 4864ab3302SCarolineConcatto return parser::MessageFixedText{ 492895771fSPeter Klausler msg.text().begin(), msg.text().size(), severity}; 5064ab3302SCarolineConcatto } 5164ab3302SCarolineConcatto 5264ab3302SCarolineConcatto bool IsIntrinsicOperator( 5364ab3302SCarolineConcatto const SemanticsContext &context, const SourceName &name) { 5464ab3302SCarolineConcatto std::string str{name.ToString()}; 5564ab3302SCarolineConcatto for (int i{0}; i != common::LogicalOperator_enumSize; ++i) { 5664ab3302SCarolineConcatto auto names{context.languageFeatures().GetNames(LogicalOperator{i})}; 5706b551c9SKazu Hirata if (llvm::is_contained(names, str)) { 5864ab3302SCarolineConcatto return true; 5964ab3302SCarolineConcatto } 6064ab3302SCarolineConcatto } 6164ab3302SCarolineConcatto for (int i{0}; i != common::RelationalOperator_enumSize; ++i) { 6264ab3302SCarolineConcatto auto names{context.languageFeatures().GetNames(RelationalOperator{i})}; 6306b551c9SKazu Hirata if (llvm::is_contained(names, str)) { 6464ab3302SCarolineConcatto return true; 6564ab3302SCarolineConcatto } 6664ab3302SCarolineConcatto } 6764ab3302SCarolineConcatto return false; 6864ab3302SCarolineConcatto } 6964ab3302SCarolineConcatto 7064ab3302SCarolineConcatto bool IsLogicalConstant( 7164ab3302SCarolineConcatto const SemanticsContext &context, const SourceName &name) { 7264ab3302SCarolineConcatto std::string str{name.ToString()}; 7364ab3302SCarolineConcatto return str == ".true." || str == ".false." || 7464ab3302SCarolineConcatto (context.IsEnabled(LanguageFeature::LogicalAbbreviations) && 7564ab3302SCarolineConcatto (str == ".t" || str == ".f.")); 7664ab3302SCarolineConcatto } 7764ab3302SCarolineConcatto 7864ab3302SCarolineConcatto void GenericSpecInfo::Resolve(Symbol *symbol) const { 7964ab3302SCarolineConcatto if (symbol) { 8064ab3302SCarolineConcatto if (auto *details{symbol->detailsIf<GenericDetails>()}) { 8164ab3302SCarolineConcatto details->set_kind(kind_); 8264ab3302SCarolineConcatto } 8364ab3302SCarolineConcatto if (parseName_) { 8464ab3302SCarolineConcatto semantics::Resolve(*parseName_, symbol); 8564ab3302SCarolineConcatto } 8664ab3302SCarolineConcatto } 8764ab3302SCarolineConcatto } 8864ab3302SCarolineConcatto 8964ab3302SCarolineConcatto void GenericSpecInfo::Analyze(const parser::DefinedOpName &name) { 9064ab3302SCarolineConcatto kind_ = GenericKind::OtherKind::DefinedOp; 9164ab3302SCarolineConcatto parseName_ = &name.v; 9264ab3302SCarolineConcatto symbolName_ = name.v.source; 9364ab3302SCarolineConcatto } 9464ab3302SCarolineConcatto 9564ab3302SCarolineConcatto void GenericSpecInfo::Analyze(const parser::GenericSpec &x) { 9664ab3302SCarolineConcatto symbolName_ = x.source; 97cd03e96fSPeter Klausler kind_ = common::visit( 9864ab3302SCarolineConcatto common::visitors{ 9964ab3302SCarolineConcatto [&](const parser::Name &y) -> GenericKind { 10064ab3302SCarolineConcatto parseName_ = &y; 10164ab3302SCarolineConcatto symbolName_ = y.source; 10264ab3302SCarolineConcatto return GenericKind::OtherKind::Name; 10364ab3302SCarolineConcatto }, 10464ab3302SCarolineConcatto [&](const parser::DefinedOperator &y) { 105cd03e96fSPeter Klausler return common::visit( 10664ab3302SCarolineConcatto common::visitors{ 10764ab3302SCarolineConcatto [&](const parser::DefinedOpName &z) -> GenericKind { 10864ab3302SCarolineConcatto Analyze(z); 10964ab3302SCarolineConcatto return GenericKind::OtherKind::DefinedOp; 11064ab3302SCarolineConcatto }, 11164ab3302SCarolineConcatto [&](const IntrinsicOperator &z) { 11264ab3302SCarolineConcatto return MapIntrinsicOperator(z); 11364ab3302SCarolineConcatto }, 11464ab3302SCarolineConcatto }, 11564ab3302SCarolineConcatto y.u); 11664ab3302SCarolineConcatto }, 11764ab3302SCarolineConcatto [&](const parser::GenericSpec::Assignment &) -> GenericKind { 11864ab3302SCarolineConcatto return GenericKind::OtherKind::Assignment; 11964ab3302SCarolineConcatto }, 12064ab3302SCarolineConcatto [&](const parser::GenericSpec::ReadFormatted &) -> GenericKind { 1217cf1608bSPeter Klausler return common::DefinedIo::ReadFormatted; 12264ab3302SCarolineConcatto }, 12364ab3302SCarolineConcatto [&](const parser::GenericSpec::ReadUnformatted &) -> GenericKind { 1247cf1608bSPeter Klausler return common::DefinedIo::ReadUnformatted; 12564ab3302SCarolineConcatto }, 12664ab3302SCarolineConcatto [&](const parser::GenericSpec::WriteFormatted &) -> GenericKind { 1277cf1608bSPeter Klausler return common::DefinedIo::WriteFormatted; 12864ab3302SCarolineConcatto }, 12964ab3302SCarolineConcatto [&](const parser::GenericSpec::WriteUnformatted &) -> GenericKind { 1307cf1608bSPeter Klausler return common::DefinedIo::WriteUnformatted; 13164ab3302SCarolineConcatto }, 13264ab3302SCarolineConcatto }, 13364ab3302SCarolineConcatto x.u); 13464ab3302SCarolineConcatto } 13564ab3302SCarolineConcatto 1367082de56STim Keith llvm::raw_ostream &operator<<( 1377082de56STim Keith llvm::raw_ostream &os, const GenericSpecInfo &info) { 1387082de56STim Keith os << "GenericSpecInfo: kind=" << info.kind_.ToString(); 1397082de56STim Keith os << " parseName=" 1407082de56STim Keith << (info.parseName_ ? info.parseName_->ToString() : "null"); 1417082de56STim Keith os << " symbolName=" 1427082de56STim Keith << (info.symbolName_ ? info.symbolName_->ToString() : "null"); 1437082de56STim Keith return os; 1447082de56STim Keith } 1457082de56STim Keith 14664ab3302SCarolineConcatto // parser::DefinedOperator::IntrinsicOperator -> GenericKind 14764ab3302SCarolineConcatto static GenericKind MapIntrinsicOperator(IntrinsicOperator op) { 14864ab3302SCarolineConcatto switch (op) { 14964ab3302SCarolineConcatto SWITCH_COVERS_ALL_CASES 1501f879005STim Keith case IntrinsicOperator::Concat: 1511f879005STim Keith return GenericKind::OtherKind::Concat; 1521f879005STim Keith case IntrinsicOperator::Power: 1531f879005STim Keith return NumericOperator::Power; 1541f879005STim Keith case IntrinsicOperator::Multiply: 1551f879005STim Keith return NumericOperator::Multiply; 1561f879005STim Keith case IntrinsicOperator::Divide: 1571f879005STim Keith return NumericOperator::Divide; 1581f879005STim Keith case IntrinsicOperator::Add: 1591f879005STim Keith return NumericOperator::Add; 1601f879005STim Keith case IntrinsicOperator::Subtract: 1611f879005STim Keith return NumericOperator::Subtract; 1621f879005STim Keith case IntrinsicOperator::AND: 1631f879005STim Keith return LogicalOperator::And; 1641f879005STim Keith case IntrinsicOperator::OR: 1651f879005STim Keith return LogicalOperator::Or; 1661f879005STim Keith case IntrinsicOperator::EQV: 1671f879005STim Keith return LogicalOperator::Eqv; 1681f879005STim Keith case IntrinsicOperator::NEQV: 1691f879005STim Keith return LogicalOperator::Neqv; 1701f879005STim Keith case IntrinsicOperator::NOT: 1711f879005STim Keith return LogicalOperator::Not; 1721f879005STim Keith case IntrinsicOperator::LT: 1731f879005STim Keith return RelationalOperator::LT; 1741f879005STim Keith case IntrinsicOperator::LE: 1751f879005STim Keith return RelationalOperator::LE; 1761f879005STim Keith case IntrinsicOperator::EQ: 1771f879005STim Keith return RelationalOperator::EQ; 1781f879005STim Keith case IntrinsicOperator::NE: 1791f879005STim Keith return RelationalOperator::NE; 1801f879005STim Keith case IntrinsicOperator::GE: 1811f879005STim Keith return RelationalOperator::GE; 1821f879005STim Keith case IntrinsicOperator::GT: 1831f879005STim Keith return RelationalOperator::GT; 18464ab3302SCarolineConcatto } 18564ab3302SCarolineConcatto } 18664ab3302SCarolineConcatto 18764ab3302SCarolineConcatto class ArraySpecAnalyzer { 18864ab3302SCarolineConcatto public: 18964ab3302SCarolineConcatto ArraySpecAnalyzer(SemanticsContext &context) : context_{context} {} 19064ab3302SCarolineConcatto ArraySpec Analyze(const parser::ArraySpec &); 191bebbe640SPeter Steinfeld ArraySpec AnalyzeDeferredShapeSpecList(const parser::DeferredShapeSpecList &); 19264ab3302SCarolineConcatto ArraySpec Analyze(const parser::ComponentArraySpec &); 19364ab3302SCarolineConcatto ArraySpec Analyze(const parser::CoarraySpec &); 19464ab3302SCarolineConcatto 19564ab3302SCarolineConcatto private: 19664ab3302SCarolineConcatto SemanticsContext &context_; 19764ab3302SCarolineConcatto ArraySpec arraySpec_; 19864ab3302SCarolineConcatto 19964ab3302SCarolineConcatto template <typename T> void Analyze(const std::list<T> &list) { 20064ab3302SCarolineConcatto for (const auto &elem : list) { 20164ab3302SCarolineConcatto Analyze(elem); 20264ab3302SCarolineConcatto } 20364ab3302SCarolineConcatto } 20464ab3302SCarolineConcatto void Analyze(const parser::AssumedShapeSpec &); 20564ab3302SCarolineConcatto void Analyze(const parser::ExplicitShapeSpec &); 20664ab3302SCarolineConcatto void Analyze(const parser::AssumedImpliedSpec &); 20764ab3302SCarolineConcatto void Analyze(const parser::DeferredShapeSpecList &); 20864ab3302SCarolineConcatto void Analyze(const parser::AssumedRankSpec &); 20964ab3302SCarolineConcatto void MakeExplicit(const std::optional<parser::SpecificationExpr> &, 21064ab3302SCarolineConcatto const parser::SpecificationExpr &); 21164ab3302SCarolineConcatto void MakeImplied(const std::optional<parser::SpecificationExpr> &); 21264ab3302SCarolineConcatto void MakeDeferred(int); 21364ab3302SCarolineConcatto Bound GetBound(const std::optional<parser::SpecificationExpr> &); 21464ab3302SCarolineConcatto Bound GetBound(const parser::SpecificationExpr &); 21564ab3302SCarolineConcatto }; 21664ab3302SCarolineConcatto 21764ab3302SCarolineConcatto ArraySpec AnalyzeArraySpec( 21864ab3302SCarolineConcatto SemanticsContext &context, const parser::ArraySpec &arraySpec) { 21964ab3302SCarolineConcatto return ArraySpecAnalyzer{context}.Analyze(arraySpec); 22064ab3302SCarolineConcatto } 22164ab3302SCarolineConcatto ArraySpec AnalyzeArraySpec( 22264ab3302SCarolineConcatto SemanticsContext &context, const parser::ComponentArraySpec &arraySpec) { 22364ab3302SCarolineConcatto return ArraySpecAnalyzer{context}.Analyze(arraySpec); 22464ab3302SCarolineConcatto } 225bebbe640SPeter Steinfeld ArraySpec AnalyzeDeferredShapeSpecList(SemanticsContext &context, 226bebbe640SPeter Steinfeld const parser::DeferredShapeSpecList &deferredShapeSpecs) { 227bebbe640SPeter Steinfeld return ArraySpecAnalyzer{context}.AnalyzeDeferredShapeSpecList( 228bebbe640SPeter Steinfeld deferredShapeSpecs); 229bebbe640SPeter Steinfeld } 23064ab3302SCarolineConcatto ArraySpec AnalyzeCoarraySpec( 23164ab3302SCarolineConcatto SemanticsContext &context, const parser::CoarraySpec &coarraySpec) { 23264ab3302SCarolineConcatto return ArraySpecAnalyzer{context}.Analyze(coarraySpec); 23364ab3302SCarolineConcatto } 23464ab3302SCarolineConcatto 23564ab3302SCarolineConcatto ArraySpec ArraySpecAnalyzer::Analyze(const parser::ComponentArraySpec &x) { 236cd03e96fSPeter Klausler common::visit([this](const auto &y) { Analyze(y); }, x.u); 23764ab3302SCarolineConcatto CHECK(!arraySpec_.empty()); 23864ab3302SCarolineConcatto return arraySpec_; 23964ab3302SCarolineConcatto } 24064ab3302SCarolineConcatto ArraySpec ArraySpecAnalyzer::Analyze(const parser::ArraySpec &x) { 241cd03e96fSPeter Klausler common::visit(common::visitors{ 24264ab3302SCarolineConcatto [&](const parser::AssumedSizeSpec &y) { 243cd03e96fSPeter Klausler Analyze( 244cd03e96fSPeter Klausler std::get<std::list<parser::ExplicitShapeSpec>>(y.t)); 24564ab3302SCarolineConcatto Analyze(std::get<parser::AssumedImpliedSpec>(y.t)); 24664ab3302SCarolineConcatto }, 24764ab3302SCarolineConcatto [&](const parser::ImpliedShapeSpec &y) { Analyze(y.v); }, 24864ab3302SCarolineConcatto [&](const auto &y) { Analyze(y); }, 24964ab3302SCarolineConcatto }, 25064ab3302SCarolineConcatto x.u); 25164ab3302SCarolineConcatto CHECK(!arraySpec_.empty()); 25264ab3302SCarolineConcatto return arraySpec_; 25364ab3302SCarolineConcatto } 254bebbe640SPeter Steinfeld ArraySpec ArraySpecAnalyzer::AnalyzeDeferredShapeSpecList( 255bebbe640SPeter Steinfeld const parser::DeferredShapeSpecList &x) { 256bebbe640SPeter Steinfeld Analyze(x); 257bebbe640SPeter Steinfeld CHECK(!arraySpec_.empty()); 258bebbe640SPeter Steinfeld return arraySpec_; 259bebbe640SPeter Steinfeld } 26064ab3302SCarolineConcatto ArraySpec ArraySpecAnalyzer::Analyze(const parser::CoarraySpec &x) { 261cd03e96fSPeter Klausler common::visit( 26264ab3302SCarolineConcatto common::visitors{ 26364ab3302SCarolineConcatto [&](const parser::DeferredCoshapeSpecList &y) { MakeDeferred(y.v); }, 26464ab3302SCarolineConcatto [&](const parser::ExplicitCoshapeSpec &y) { 26564ab3302SCarolineConcatto Analyze(std::get<std::list<parser::ExplicitShapeSpec>>(y.t)); 26664ab3302SCarolineConcatto MakeImplied( 26764ab3302SCarolineConcatto std::get<std::optional<parser::SpecificationExpr>>(y.t)); 26864ab3302SCarolineConcatto }, 26964ab3302SCarolineConcatto }, 27064ab3302SCarolineConcatto x.u); 27164ab3302SCarolineConcatto CHECK(!arraySpec_.empty()); 27264ab3302SCarolineConcatto return arraySpec_; 27364ab3302SCarolineConcatto } 27464ab3302SCarolineConcatto 27564ab3302SCarolineConcatto void ArraySpecAnalyzer::Analyze(const parser::AssumedShapeSpec &x) { 27644bc97c8SPeter Klausler arraySpec_.push_back(ShapeSpec::MakeAssumedShape(GetBound(x.v))); 27764ab3302SCarolineConcatto } 27864ab3302SCarolineConcatto void ArraySpecAnalyzer::Analyze(const parser::ExplicitShapeSpec &x) { 27964ab3302SCarolineConcatto MakeExplicit(std::get<std::optional<parser::SpecificationExpr>>(x.t), 28064ab3302SCarolineConcatto std::get<parser::SpecificationExpr>(x.t)); 28164ab3302SCarolineConcatto } 28264ab3302SCarolineConcatto void ArraySpecAnalyzer::Analyze(const parser::AssumedImpliedSpec &x) { 28364ab3302SCarolineConcatto MakeImplied(x.v); 28464ab3302SCarolineConcatto } 28564ab3302SCarolineConcatto void ArraySpecAnalyzer::Analyze(const parser::DeferredShapeSpecList &x) { 28664ab3302SCarolineConcatto MakeDeferred(x.v); 28764ab3302SCarolineConcatto } 28864ab3302SCarolineConcatto void ArraySpecAnalyzer::Analyze(const parser::AssumedRankSpec &) { 28964ab3302SCarolineConcatto arraySpec_.push_back(ShapeSpec::MakeAssumedRank()); 29064ab3302SCarolineConcatto } 29164ab3302SCarolineConcatto 29264ab3302SCarolineConcatto void ArraySpecAnalyzer::MakeExplicit( 29364ab3302SCarolineConcatto const std::optional<parser::SpecificationExpr> &lb, 29464ab3302SCarolineConcatto const parser::SpecificationExpr &ub) { 29564ab3302SCarolineConcatto arraySpec_.push_back(ShapeSpec::MakeExplicit(GetBound(lb), GetBound(ub))); 29664ab3302SCarolineConcatto } 29764ab3302SCarolineConcatto void ArraySpecAnalyzer::MakeImplied( 29864ab3302SCarolineConcatto const std::optional<parser::SpecificationExpr> &lb) { 29964ab3302SCarolineConcatto arraySpec_.push_back(ShapeSpec::MakeImplied(GetBound(lb))); 30064ab3302SCarolineConcatto } 30164ab3302SCarolineConcatto void ArraySpecAnalyzer::MakeDeferred(int n) { 30264ab3302SCarolineConcatto for (int i = 0; i < n; ++i) { 30364ab3302SCarolineConcatto arraySpec_.push_back(ShapeSpec::MakeDeferred()); 30464ab3302SCarolineConcatto } 30564ab3302SCarolineConcatto } 30664ab3302SCarolineConcatto 30764ab3302SCarolineConcatto Bound ArraySpecAnalyzer::GetBound( 30864ab3302SCarolineConcatto const std::optional<parser::SpecificationExpr> &x) { 30964ab3302SCarolineConcatto return x ? GetBound(*x) : Bound{1}; 31064ab3302SCarolineConcatto } 31164ab3302SCarolineConcatto Bound ArraySpecAnalyzer::GetBound(const parser::SpecificationExpr &x) { 31264ab3302SCarolineConcatto MaybeSubscriptIntExpr expr; 31364ab3302SCarolineConcatto if (MaybeExpr maybeExpr{AnalyzeExpr(context_, x.v)}) { 31464ab3302SCarolineConcatto if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) { 31564ab3302SCarolineConcatto expr = evaluate::Fold(context_.foldingContext(), 31664ab3302SCarolineConcatto evaluate::ConvertToType<evaluate::SubscriptInteger>( 31764ab3302SCarolineConcatto std::move(*intExpr))); 31864ab3302SCarolineConcatto } 31964ab3302SCarolineConcatto } 32064ab3302SCarolineConcatto return Bound{std::move(expr)}; 32164ab3302SCarolineConcatto } 32264ab3302SCarolineConcatto 323e7b8e18fSSlava Zakharin // If src is SAVE (explicitly or implicitly), 324e7b8e18fSSlava Zakharin // set SAVE attribute on all members of dst. 32564ab3302SCarolineConcatto static void PropagateSaveAttr( 32664ab3302SCarolineConcatto const EquivalenceObject &src, EquivalenceSet &dst) { 327e7b8e18fSSlava Zakharin if (IsSaved(src.symbol)) { 32864ab3302SCarolineConcatto for (auto &obj : dst) { 3293f6e0c24SPeter Klausler if (!obj.symbol.attrs().test(Attr::SAVE)) { 33064ab3302SCarolineConcatto obj.symbol.attrs().set(Attr::SAVE); 331e7b8e18fSSlava Zakharin // If the other equivalenced symbol itself is not SAVE, 332e7b8e18fSSlava Zakharin // then adding SAVE here implies that it has to be implicit. 3333f6e0c24SPeter Klausler obj.symbol.implicitAttrs().set(Attr::SAVE); 3343f6e0c24SPeter Klausler } 3353f6e0c24SPeter Klausler } 33664ab3302SCarolineConcatto } 33764ab3302SCarolineConcatto } 33864ab3302SCarolineConcatto static void PropagateSaveAttr(const EquivalenceSet &src, EquivalenceSet &dst) { 33964ab3302SCarolineConcatto if (!src.empty()) { 34064ab3302SCarolineConcatto PropagateSaveAttr(src.front(), dst); 34164ab3302SCarolineConcatto } 34264ab3302SCarolineConcatto } 34364ab3302SCarolineConcatto 34464ab3302SCarolineConcatto void EquivalenceSets::AddToSet(const parser::Designator &designator) { 34564ab3302SCarolineConcatto if (CheckDesignator(designator)) { 34670d1844aSPeter Klausler if (Symbol * symbol{currObject_.symbol}) { 34764ab3302SCarolineConcatto if (!currSet_.empty()) { 34864ab3302SCarolineConcatto // check this symbol against first of set for compatibility 34964ab3302SCarolineConcatto Symbol &first{currSet_.front().symbol}; 35070d1844aSPeter Klausler CheckCanEquivalence(designator.source, first, *symbol) && 35170d1844aSPeter Klausler CheckCanEquivalence(designator.source, *symbol, first); 35264ab3302SCarolineConcatto } 35364ab3302SCarolineConcatto auto subscripts{currObject_.subscripts}; 35470d1844aSPeter Klausler if (subscripts.empty()) { 35570d1844aSPeter Klausler if (const ArraySpec * shape{symbol->GetShape()}; 35670d1844aSPeter Klausler shape && shape->IsExplicitShape()) { 35764ab3302SCarolineConcatto // record a whole array as its first element 35870d1844aSPeter Klausler for (const ShapeSpec &spec : *shape) { 35970d1844aSPeter Klausler if (auto lbound{spec.lbound().GetExplicit()}) { 36070d1844aSPeter Klausler if (auto lbValue{evaluate::ToInt64(*lbound)}) { 36170d1844aSPeter Klausler subscripts.push_back(*lbValue); 36270d1844aSPeter Klausler continue; 36370d1844aSPeter Klausler } 36470d1844aSPeter Klausler } 36570d1844aSPeter Klausler subscripts.clear(); // error recovery 36670d1844aSPeter Klausler break; 36770d1844aSPeter Klausler } 36864ab3302SCarolineConcatto } 36964ab3302SCarolineConcatto } 37064ab3302SCarolineConcatto auto substringStart{currObject_.substringStart}; 37131e6cd28Speter klausler currSet_.emplace_back( 37270d1844aSPeter Klausler *symbol, subscripts, substringStart, designator.source); 37364ab3302SCarolineConcatto PropagateSaveAttr(currSet_.back(), currSet_); 37464ab3302SCarolineConcatto } 37570d1844aSPeter Klausler } 37664ab3302SCarolineConcatto currObject_ = {}; 37764ab3302SCarolineConcatto } 37864ab3302SCarolineConcatto 37964ab3302SCarolineConcatto void EquivalenceSets::FinishSet(const parser::CharBlock &source) { 38064ab3302SCarolineConcatto std::set<std::size_t> existing; // indices of sets intersecting this one 38164ab3302SCarolineConcatto for (auto &obj : currSet_) { 38264ab3302SCarolineConcatto auto it{objectToSet_.find(obj)}; 38364ab3302SCarolineConcatto if (it != objectToSet_.end()) { 38464ab3302SCarolineConcatto existing.insert(it->second); // symbol already in this set 38564ab3302SCarolineConcatto } 38664ab3302SCarolineConcatto } 38764ab3302SCarolineConcatto if (existing.empty()) { 38864ab3302SCarolineConcatto sets_.push_back({}); // create a new equivalence set 38964ab3302SCarolineConcatto MergeInto(source, currSet_, sets_.size() - 1); 39064ab3302SCarolineConcatto } else { 39164ab3302SCarolineConcatto auto it{existing.begin()}; 39264ab3302SCarolineConcatto std::size_t dstIndex{*it}; 39364ab3302SCarolineConcatto MergeInto(source, currSet_, dstIndex); 39464ab3302SCarolineConcatto while (++it != existing.end()) { 39564ab3302SCarolineConcatto MergeInto(source, sets_[*it], dstIndex); 39664ab3302SCarolineConcatto } 39764ab3302SCarolineConcatto } 39864ab3302SCarolineConcatto currSet_.clear(); 39964ab3302SCarolineConcatto } 40064ab3302SCarolineConcatto 4016bd72fa6SPeter Klausler // Report an error or warning if sym1 and sym2 cannot be in the same equivalence 4026bd72fa6SPeter Klausler // set. 40364ab3302SCarolineConcatto bool EquivalenceSets::CheckCanEquivalence( 40464ab3302SCarolineConcatto const parser::CharBlock &source, const Symbol &sym1, const Symbol &sym2) { 405*0f973ac7SPeter Klausler std::optional<common::LanguageFeature> feature; 40664ab3302SCarolineConcatto std::optional<parser::MessageFixedText> msg; 40764ab3302SCarolineConcatto const DeclTypeSpec *type1{sym1.GetType()}; 40864ab3302SCarolineConcatto const DeclTypeSpec *type2{sym2.GetType()}; 4096bd72fa6SPeter Klausler bool isDefaultNum1{IsDefaultNumericSequenceType(type1)}; 4106bd72fa6SPeter Klausler bool isAnyNum1{IsAnyNumericSequenceType(type1)}; 4116bd72fa6SPeter Klausler bool isDefaultNum2{IsDefaultNumericSequenceType(type2)}; 4126bd72fa6SPeter Klausler bool isAnyNum2{IsAnyNumericSequenceType(type2)}; 41364ab3302SCarolineConcatto bool isChar1{IsCharacterSequenceType(type1)}; 41464ab3302SCarolineConcatto bool isChar2{IsCharacterSequenceType(type2)}; 41564ab3302SCarolineConcatto if (sym1.attrs().test(Attr::PROTECTED) && 41664ab3302SCarolineConcatto !sym2.attrs().test(Attr::PROTECTED)) { // C8114 41764ab3302SCarolineConcatto msg = "Equivalence set cannot contain '%s'" 41864ab3302SCarolineConcatto " with PROTECTED attribute and '%s' without"_err_en_US; 4196bd72fa6SPeter Klausler } else if ((isDefaultNum1 && isDefaultNum2) || (isChar1 && isChar2)) { 4206bd72fa6SPeter Klausler // ok & standard conforming 4216bd72fa6SPeter Klausler } else if (!(isAnyNum1 || isChar1) && 4226bd72fa6SPeter Klausler !(isAnyNum2 || isChar2)) { // C8110 - C8113 4236bd72fa6SPeter Klausler if (AreTkCompatibleTypes(type1, type2)) { 424a53967cdSPeter Klausler msg = 425*0f973ac7SPeter Klausler "nonstandard: Equivalence set contains '%s' and '%s' with same type that is neither numeric nor character sequence type"_port_en_US; 426*0f973ac7SPeter Klausler feature = LanguageFeature::EquivalenceSameNonSequence; 4276bd72fa6SPeter Klausler } else { 4286bd72fa6SPeter Klausler msg = "Equivalence set cannot contain '%s' and '%s' with distinct types " 4296bd72fa6SPeter Klausler "that are not both numeric or character sequence types"_err_en_US; 4306bd72fa6SPeter Klausler } 4316bd72fa6SPeter Klausler } else if (isAnyNum1) { 43264ab3302SCarolineConcatto if (isChar2) { 433*0f973ac7SPeter Klausler msg = 434*0f973ac7SPeter Klausler "nonstandard: Equivalence set contains '%s' that is numeric sequence type and '%s' that is character"_port_en_US; 435*0f973ac7SPeter Klausler feature = LanguageFeature::EquivalenceNumericWithCharacter; 436*0f973ac7SPeter Klausler } else if (isAnyNum2) { 4376bd72fa6SPeter Klausler if (isDefaultNum1) { 4386bd72fa6SPeter Klausler msg = 4396bd72fa6SPeter Klausler "nonstandard: Equivalence set contains '%s' that is a default " 440a53967cdSPeter Klausler "numeric sequence type and '%s' that is numeric with non-default kind"_port_en_US; 4416bd72fa6SPeter Klausler } else if (!isDefaultNum2) { 4426bd72fa6SPeter Klausler msg = "nonstandard: Equivalence set contains '%s' and '%s' that are " 443a53967cdSPeter Klausler "numeric sequence types with non-default kinds"_port_en_US; 44464ab3302SCarolineConcatto } 445*0f973ac7SPeter Klausler feature = LanguageFeature::EquivalenceNonDefaultNumeric; 44664ab3302SCarolineConcatto } 44764ab3302SCarolineConcatto } 448*0f973ac7SPeter Klausler if (msg) { 449*0f973ac7SPeter Klausler if (feature) { 450*0f973ac7SPeter Klausler context_.Warn( 451*0f973ac7SPeter Klausler *feature, source, std::move(*msg), sym1.name(), sym2.name()); 452*0f973ac7SPeter Klausler } else { 45364ab3302SCarolineConcatto context_.Say(source, std::move(*msg), sym1.name(), sym2.name()); 454*0f973ac7SPeter Klausler } 45564ab3302SCarolineConcatto return false; 45664ab3302SCarolineConcatto } 45764ab3302SCarolineConcatto return true; 45864ab3302SCarolineConcatto } 45964ab3302SCarolineConcatto 46064ab3302SCarolineConcatto // Move objects from src to sets_[dstIndex] 46164ab3302SCarolineConcatto void EquivalenceSets::MergeInto(const parser::CharBlock &source, 46264ab3302SCarolineConcatto EquivalenceSet &src, std::size_t dstIndex) { 46364ab3302SCarolineConcatto EquivalenceSet &dst{sets_[dstIndex]}; 46464ab3302SCarolineConcatto PropagateSaveAttr(dst, src); 46564ab3302SCarolineConcatto for (const auto &obj : src) { 46664ab3302SCarolineConcatto dst.push_back(obj); 46764ab3302SCarolineConcatto objectToSet_[obj] = dstIndex; 46864ab3302SCarolineConcatto } 46964ab3302SCarolineConcatto PropagateSaveAttr(src, dst); 47064ab3302SCarolineConcatto src.clear(); 47164ab3302SCarolineConcatto } 47264ab3302SCarolineConcatto 47364ab3302SCarolineConcatto // If set has an object with this symbol, return it. 47464ab3302SCarolineConcatto const EquivalenceObject *EquivalenceSets::Find( 47564ab3302SCarolineConcatto const EquivalenceSet &set, const Symbol &symbol) { 47664ab3302SCarolineConcatto for (const auto &obj : set) { 47764ab3302SCarolineConcatto if (obj.symbol == symbol) { 47864ab3302SCarolineConcatto return &obj; 47964ab3302SCarolineConcatto } 48064ab3302SCarolineConcatto } 48164ab3302SCarolineConcatto return nullptr; 48264ab3302SCarolineConcatto } 48364ab3302SCarolineConcatto 48464ab3302SCarolineConcatto bool EquivalenceSets::CheckDesignator(const parser::Designator &designator) { 485cd03e96fSPeter Klausler return common::visit( 48664ab3302SCarolineConcatto common::visitors{ 48764ab3302SCarolineConcatto [&](const parser::DataRef &x) { 48864ab3302SCarolineConcatto return CheckDataRef(designator.source, x); 48964ab3302SCarolineConcatto }, 49064ab3302SCarolineConcatto [&](const parser::Substring &x) { 49164ab3302SCarolineConcatto const auto &dataRef{std::get<parser::DataRef>(x.t)}; 49264ab3302SCarolineConcatto const auto &range{std::get<parser::SubstringRange>(x.t)}; 49364ab3302SCarolineConcatto bool ok{CheckDataRef(designator.source, dataRef)}; 49464ab3302SCarolineConcatto if (const auto &lb{std::get<0>(range.t)}) { 49564ab3302SCarolineConcatto ok &= CheckSubstringBound(lb->thing.thing.value(), true); 49664ab3302SCarolineConcatto } else { 49764ab3302SCarolineConcatto currObject_.substringStart = 1; 49864ab3302SCarolineConcatto } 49964ab3302SCarolineConcatto if (const auto &ub{std::get<1>(range.t)}) { 50064ab3302SCarolineConcatto ok &= CheckSubstringBound(ub->thing.thing.value(), false); 50164ab3302SCarolineConcatto } 50264ab3302SCarolineConcatto return ok; 50364ab3302SCarolineConcatto }, 50464ab3302SCarolineConcatto }, 50564ab3302SCarolineConcatto designator.u); 50664ab3302SCarolineConcatto } 50764ab3302SCarolineConcatto 50864ab3302SCarolineConcatto bool EquivalenceSets::CheckDataRef( 50964ab3302SCarolineConcatto const parser::CharBlock &source, const parser::DataRef &x) { 510cd03e96fSPeter Klausler return common::visit( 51164ab3302SCarolineConcatto common::visitors{ 51264ab3302SCarolineConcatto [&](const parser::Name &name) { return CheckObject(name); }, 51364ab3302SCarolineConcatto [&](const common::Indirection<parser::StructureComponent> &) { 51464ab3302SCarolineConcatto context_.Say(source, // C8107 51564ab3302SCarolineConcatto "Derived type component '%s' is not allowed in an equivalence set"_err_en_US, 51664ab3302SCarolineConcatto source); 51764ab3302SCarolineConcatto return false; 51864ab3302SCarolineConcatto }, 51964ab3302SCarolineConcatto [&](const common::Indirection<parser::ArrayElement> &elem) { 52064ab3302SCarolineConcatto bool ok{CheckDataRef(source, elem.value().base)}; 52164ab3302SCarolineConcatto for (const auto &subscript : elem.value().subscripts) { 522cd03e96fSPeter Klausler ok &= common::visit( 52364ab3302SCarolineConcatto common::visitors{ 52464ab3302SCarolineConcatto [&](const parser::SubscriptTriplet &) { 52564ab3302SCarolineConcatto context_.Say(source, // C924, R872 52664ab3302SCarolineConcatto "Array section '%s' is not allowed in an equivalence set"_err_en_US, 52764ab3302SCarolineConcatto source); 52864ab3302SCarolineConcatto return false; 52964ab3302SCarolineConcatto }, 53064ab3302SCarolineConcatto [&](const parser::IntExpr &y) { 53164ab3302SCarolineConcatto return CheckArrayBound(y.thing.value()); 53264ab3302SCarolineConcatto }, 53364ab3302SCarolineConcatto }, 53464ab3302SCarolineConcatto subscript.u); 53564ab3302SCarolineConcatto } 53664ab3302SCarolineConcatto return ok; 53764ab3302SCarolineConcatto }, 53864ab3302SCarolineConcatto [&](const common::Indirection<parser::CoindexedNamedObject> &) { 53964ab3302SCarolineConcatto context_.Say(source, // C924 (R872) 54064ab3302SCarolineConcatto "Coindexed object '%s' is not allowed in an equivalence set"_err_en_US, 54164ab3302SCarolineConcatto source); 54264ab3302SCarolineConcatto return false; 54364ab3302SCarolineConcatto }, 54464ab3302SCarolineConcatto }, 54564ab3302SCarolineConcatto x.u); 54664ab3302SCarolineConcatto } 54764ab3302SCarolineConcatto 54864ab3302SCarolineConcatto bool EquivalenceSets::CheckObject(const parser::Name &name) { 54964ab3302SCarolineConcatto currObject_.symbol = name.symbol; 550d742c2aaSPeter Klausler return currObject_.symbol != nullptr; 55164ab3302SCarolineConcatto } 55264ab3302SCarolineConcatto 55364ab3302SCarolineConcatto bool EquivalenceSets::CheckArrayBound(const parser::Expr &bound) { 55464ab3302SCarolineConcatto MaybeExpr expr{ 55564ab3302SCarolineConcatto evaluate::Fold(context_.foldingContext(), AnalyzeExpr(context_, bound))}; 55664ab3302SCarolineConcatto if (!expr) { 55764ab3302SCarolineConcatto return false; 55864ab3302SCarolineConcatto } 55964ab3302SCarolineConcatto if (expr->Rank() > 0) { 56064ab3302SCarolineConcatto context_.Say(bound.source, // C924, R872 56164ab3302SCarolineConcatto "Array with vector subscript '%s' is not allowed in an equivalence set"_err_en_US, 56264ab3302SCarolineConcatto bound.source); 56364ab3302SCarolineConcatto return false; 56464ab3302SCarolineConcatto } 56564ab3302SCarolineConcatto auto subscript{evaluate::ToInt64(*expr)}; 56664ab3302SCarolineConcatto if (!subscript) { 56764ab3302SCarolineConcatto context_.Say(bound.source, // C8109 56864ab3302SCarolineConcatto "Array with nonconstant subscript '%s' is not allowed in an equivalence set"_err_en_US, 56964ab3302SCarolineConcatto bound.source); 57064ab3302SCarolineConcatto return false; 57164ab3302SCarolineConcatto } 57264ab3302SCarolineConcatto currObject_.subscripts.push_back(*subscript); 57364ab3302SCarolineConcatto return true; 57464ab3302SCarolineConcatto } 57564ab3302SCarolineConcatto 57664ab3302SCarolineConcatto bool EquivalenceSets::CheckSubstringBound( 57764ab3302SCarolineConcatto const parser::Expr &bound, bool isStart) { 57864ab3302SCarolineConcatto MaybeExpr expr{ 57964ab3302SCarolineConcatto evaluate::Fold(context_.foldingContext(), AnalyzeExpr(context_, bound))}; 58064ab3302SCarolineConcatto if (!expr) { 58164ab3302SCarolineConcatto return false; 58264ab3302SCarolineConcatto } 58364ab3302SCarolineConcatto auto subscript{evaluate::ToInt64(*expr)}; 58464ab3302SCarolineConcatto if (!subscript) { 58564ab3302SCarolineConcatto context_.Say(bound.source, // C8109 58664ab3302SCarolineConcatto "Substring with nonconstant bound '%s' is not allowed in an equivalence set"_err_en_US, 58764ab3302SCarolineConcatto bound.source); 58864ab3302SCarolineConcatto return false; 58964ab3302SCarolineConcatto } 59064ab3302SCarolineConcatto if (!isStart) { 59164ab3302SCarolineConcatto auto start{currObject_.substringStart}; 59264ab3302SCarolineConcatto if (*subscript < (start ? *start : 1)) { 59364ab3302SCarolineConcatto context_.Say(bound.source, // C8116 59464ab3302SCarolineConcatto "Substring with zero length is not allowed in an equivalence set"_err_en_US); 59564ab3302SCarolineConcatto return false; 59664ab3302SCarolineConcatto } 59764ab3302SCarolineConcatto } else if (*subscript != 1) { 59864ab3302SCarolineConcatto currObject_.substringStart = *subscript; 59964ab3302SCarolineConcatto } 60064ab3302SCarolineConcatto return true; 60164ab3302SCarolineConcatto } 60264ab3302SCarolineConcatto 60364ab3302SCarolineConcatto bool EquivalenceSets::IsCharacterSequenceType(const DeclTypeSpec *type) { 60464ab3302SCarolineConcatto return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) { 60564ab3302SCarolineConcatto auto kind{evaluate::ToInt64(type.kind())}; 60664ab3302SCarolineConcatto return type.category() == TypeCategory::Character && kind && 60764ab3302SCarolineConcatto kind.value() == context_.GetDefaultKind(TypeCategory::Character); 60864ab3302SCarolineConcatto }); 60964ab3302SCarolineConcatto } 61064ab3302SCarolineConcatto 61164ab3302SCarolineConcatto // Numeric or logical type of default kind or DOUBLE PRECISION or DOUBLE COMPLEX 61264ab3302SCarolineConcatto bool EquivalenceSets::IsDefaultKindNumericType(const IntrinsicTypeSpec &type) { 61364ab3302SCarolineConcatto if (auto kind{evaluate::ToInt64(type.kind())}) { 6146bd72fa6SPeter Klausler switch (type.category()) { 61564ab3302SCarolineConcatto case TypeCategory::Integer: 6161f879005STim Keith case TypeCategory::Logical: 6176bd72fa6SPeter Klausler return *kind == context_.GetDefaultKind(TypeCategory::Integer); 61864ab3302SCarolineConcatto case TypeCategory::Real: 61964ab3302SCarolineConcatto case TypeCategory::Complex: 6206bd72fa6SPeter Klausler return *kind == context_.GetDefaultKind(TypeCategory::Real) || 6216bd72fa6SPeter Klausler *kind == context_.doublePrecisionKind(); 6221f879005STim Keith default: 6231f879005STim Keith return false; 62464ab3302SCarolineConcatto } 62564ab3302SCarolineConcatto } 62664ab3302SCarolineConcatto return false; 62764ab3302SCarolineConcatto } 62864ab3302SCarolineConcatto 6296bd72fa6SPeter Klausler bool EquivalenceSets::IsDefaultNumericSequenceType(const DeclTypeSpec *type) { 63064ab3302SCarolineConcatto return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) { 63164ab3302SCarolineConcatto return IsDefaultKindNumericType(type); 63264ab3302SCarolineConcatto }); 63364ab3302SCarolineConcatto } 63464ab3302SCarolineConcatto 6356bd72fa6SPeter Klausler bool EquivalenceSets::IsAnyNumericSequenceType(const DeclTypeSpec *type) { 6366bd72fa6SPeter Klausler return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) { 6376bd72fa6SPeter Klausler return type.category() == TypeCategory::Logical || 6386bd72fa6SPeter Klausler common::IsNumericTypeCategory(type.category()); 6396bd72fa6SPeter Klausler }); 6406bd72fa6SPeter Klausler } 6416bd72fa6SPeter Klausler 64264ab3302SCarolineConcatto // Is type an intrinsic type that satisfies predicate or a sequence type 64364ab3302SCarolineConcatto // whose components do. 64464ab3302SCarolineConcatto bool EquivalenceSets::IsSequenceType(const DeclTypeSpec *type, 64564ab3302SCarolineConcatto std::function<bool(const IntrinsicTypeSpec &)> predicate) { 64664ab3302SCarolineConcatto if (!type) { 64764ab3302SCarolineConcatto return false; 64864ab3302SCarolineConcatto } else if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) { 64964ab3302SCarolineConcatto return predicate(*intrinsic); 65064ab3302SCarolineConcatto } else if (const DerivedTypeSpec * derived{type->AsDerived()}) { 65164ab3302SCarolineConcatto for (const auto &pair : *derived->typeSymbol().scope()) { 65264ab3302SCarolineConcatto const Symbol &component{*pair.second}; 65364ab3302SCarolineConcatto if (IsAllocatableOrPointer(component) || 65464ab3302SCarolineConcatto !IsSequenceType(component.GetType(), predicate)) { 65564ab3302SCarolineConcatto return false; 65664ab3302SCarolineConcatto } 65764ab3302SCarolineConcatto } 65864ab3302SCarolineConcatto return true; 65964ab3302SCarolineConcatto } else { 66064ab3302SCarolineConcatto return false; 66164ab3302SCarolineConcatto } 66264ab3302SCarolineConcatto } 66364ab3302SCarolineConcatto 6649e855a6cSPeter Klausler // MapSubprogramToNewSymbols() relies on the following recursive symbol/scope 6659e855a6cSPeter Klausler // copying infrastructure to duplicate an interface's symbols and map all 6669e855a6cSPeter Klausler // of the symbol references in their contained expressions and interfaces 6679e855a6cSPeter Klausler // to the new symbols. 6689e855a6cSPeter Klausler 6699e855a6cSPeter Klausler struct SymbolAndTypeMappings { 6709e855a6cSPeter Klausler std::map<const Symbol *, const Symbol *> symbolMap; 6719e855a6cSPeter Klausler std::map<const DeclTypeSpec *, const DeclTypeSpec *> typeMap; 6729e855a6cSPeter Klausler }; 6739e855a6cSPeter Klausler 6749e855a6cSPeter Klausler class SymbolMapper : public evaluate::AnyTraverse<SymbolMapper, bool> { 6759e855a6cSPeter Klausler public: 6769e855a6cSPeter Klausler using Base = evaluate::AnyTraverse<SymbolMapper, bool>; 6779e855a6cSPeter Klausler SymbolMapper(Scope &scope, SymbolAndTypeMappings &map) 6789e855a6cSPeter Klausler : Base{*this}, scope_{scope}, map_{map} {} 6799e855a6cSPeter Klausler using Base::operator(); 680c93312a6SPeter Klausler bool operator()(const SymbolRef &ref) { 6819e855a6cSPeter Klausler if (const Symbol *mapped{MapSymbol(*ref)}) { 6829e855a6cSPeter Klausler const_cast<SymbolRef &>(ref) = *mapped; 683c93312a6SPeter Klausler } else if (ref->has<UseDetails>()) { 684c93312a6SPeter Klausler CopySymbol(&*ref); 6859e855a6cSPeter Klausler } 6869e855a6cSPeter Klausler return false; 6879e855a6cSPeter Klausler } 688c93312a6SPeter Klausler bool operator()(const Symbol &x) { 6899e855a6cSPeter Klausler if (MapSymbol(x)) { 6909e855a6cSPeter Klausler DIE("SymbolMapper hit symbol outside SymbolRef"); 6919e855a6cSPeter Klausler } 6929e855a6cSPeter Klausler return false; 6939e855a6cSPeter Klausler } 6949e855a6cSPeter Klausler void MapSymbolExprs(Symbol &); 69511d07d9eSPeter Klausler Symbol *CopySymbol(const Symbol *); 6969e855a6cSPeter Klausler 6979e855a6cSPeter Klausler private: 698c93312a6SPeter Klausler void MapParamValue(ParamValue ¶m) { (*this)(param.GetExplicit()); } 699c93312a6SPeter Klausler void MapBound(Bound &bound) { (*this)(bound.GetExplicit()); } 700c93312a6SPeter Klausler void MapShapeSpec(ShapeSpec &spec) { 7019e855a6cSPeter Klausler MapBound(spec.lbound()); 7029e855a6cSPeter Klausler MapBound(spec.ubound()); 7039e855a6cSPeter Klausler } 7049e855a6cSPeter Klausler const Symbol *MapSymbol(const Symbol &) const; 7059e855a6cSPeter Klausler const Symbol *MapSymbol(const Symbol *) const; 7069e855a6cSPeter Klausler const DeclTypeSpec *MapType(const DeclTypeSpec &); 7079e855a6cSPeter Klausler const DeclTypeSpec *MapType(const DeclTypeSpec *); 7089e855a6cSPeter Klausler const Symbol *MapInterface(const Symbol *); 7099e855a6cSPeter Klausler 7109e855a6cSPeter Klausler Scope &scope_; 7119e855a6cSPeter Klausler SymbolAndTypeMappings &map_; 7129e855a6cSPeter Klausler }; 7139e855a6cSPeter Klausler 71411d07d9eSPeter Klausler Symbol *SymbolMapper::CopySymbol(const Symbol *symbol) { 71511d07d9eSPeter Klausler if (symbol) { 71611d07d9eSPeter Klausler if (auto *subp{symbol->detailsIf<SubprogramDetails>()}) { 71711d07d9eSPeter Klausler if (subp->isInterface()) { 71811d07d9eSPeter Klausler if (auto pair{scope_.try_emplace(symbol->name(), symbol->attrs())}; 71911d07d9eSPeter Klausler pair.second) { 72011d07d9eSPeter Klausler Symbol ©{*pair.first->second}; 72111d07d9eSPeter Klausler map_.symbolMap[symbol] = © 72211d07d9eSPeter Klausler copy.set(symbol->test(Symbol::Flag::Subroutine) 72311d07d9eSPeter Klausler ? Symbol::Flag::Subroutine 72411d07d9eSPeter Klausler : Symbol::Flag::Function); 72511d07d9eSPeter Klausler Scope &newScope{scope_.MakeScope(Scope::Kind::Subprogram, ©)}; 72611d07d9eSPeter Klausler copy.set_scope(&newScope); 72711d07d9eSPeter Klausler copy.set_details(SubprogramDetails{}); 72811d07d9eSPeter Klausler auto &newSubp{copy.get<SubprogramDetails>()}; 72911d07d9eSPeter Klausler newSubp.set_isInterface(true); 73011d07d9eSPeter Klausler newSubp.set_isDummy(subp->isDummy()); 73111d07d9eSPeter Klausler newSubp.set_defaultIgnoreTKR(subp->defaultIgnoreTKR()); 73211d07d9eSPeter Klausler MapSubprogramToNewSymbols(*symbol, copy, newScope, &map_); 73311d07d9eSPeter Klausler return © 73411d07d9eSPeter Klausler } 73511d07d9eSPeter Klausler } 73611d07d9eSPeter Klausler } else if (Symbol * copy{scope_.CopySymbol(*symbol)}) { 73711d07d9eSPeter Klausler map_.symbolMap[symbol] = copy; 73811d07d9eSPeter Klausler return copy; 73911d07d9eSPeter Klausler } 74011d07d9eSPeter Klausler } 74111d07d9eSPeter Klausler return nullptr; 74211d07d9eSPeter Klausler } 74311d07d9eSPeter Klausler 7449e855a6cSPeter Klausler void SymbolMapper::MapSymbolExprs(Symbol &symbol) { 745635656f4SPeter Klausler common::visit( 746635656f4SPeter Klausler common::visitors{[&](ObjectEntityDetails &object) { 74711d07d9eSPeter Klausler if (const DeclTypeSpec * type{object.type()}) { 74811d07d9eSPeter Klausler if (const DeclTypeSpec * newType{MapType(*type)}) { 74911d07d9eSPeter Klausler object.ReplaceType(*newType); 75011d07d9eSPeter Klausler } 75111d07d9eSPeter Klausler } 7529e855a6cSPeter Klausler for (ShapeSpec &spec : object.shape()) { 7539e855a6cSPeter Klausler MapShapeSpec(spec); 7549e855a6cSPeter Klausler } 7559e855a6cSPeter Klausler for (ShapeSpec &spec : object.coshape()) { 7569e855a6cSPeter Klausler MapShapeSpec(spec); 7579e855a6cSPeter Klausler } 7589e855a6cSPeter Klausler }, 7599e855a6cSPeter Klausler [&](ProcEntityDetails &proc) { 760635656f4SPeter Klausler if (const Symbol * 76183ca78deSPeter Klausler mappedSymbol{MapInterface(proc.rawProcInterface())}) { 76283ca78deSPeter Klausler proc.set_procInterfaces( 76383ca78deSPeter Klausler *mappedSymbol, BypassGeneric(mappedSymbol->GetUltimate())); 764635656f4SPeter Klausler } else if (const DeclTypeSpec * mappedType{MapType(proc.type())}) { 765635656f4SPeter Klausler proc.set_type(*mappedType); 7669e855a6cSPeter Klausler } 7679e855a6cSPeter Klausler if (proc.init()) { 7689e855a6cSPeter Klausler if (const Symbol * mapped{MapSymbol(*proc.init())}) { 7699e855a6cSPeter Klausler proc.set_init(*mapped); 7709e855a6cSPeter Klausler } 7719e855a6cSPeter Klausler } 7729e855a6cSPeter Klausler }, 7739e855a6cSPeter Klausler [&](const HostAssocDetails &hostAssoc) { 7749e855a6cSPeter Klausler if (const Symbol * mapped{MapSymbol(hostAssoc.symbol())}) { 7759e855a6cSPeter Klausler symbol.set_details(HostAssocDetails{*mapped}); 7769e855a6cSPeter Klausler } 7779e855a6cSPeter Klausler }, 7789e855a6cSPeter Klausler [](const auto &) {}}, 7799e855a6cSPeter Klausler symbol.details()); 7809e855a6cSPeter Klausler } 7819e855a6cSPeter Klausler 7829e855a6cSPeter Klausler const Symbol *SymbolMapper::MapSymbol(const Symbol &symbol) const { 7839e855a6cSPeter Klausler if (auto iter{map_.symbolMap.find(&symbol)}; iter != map_.symbolMap.end()) { 7849e855a6cSPeter Klausler return iter->second; 7859e855a6cSPeter Klausler } 7869e855a6cSPeter Klausler return nullptr; 7879e855a6cSPeter Klausler } 7889e855a6cSPeter Klausler 7899e855a6cSPeter Klausler const Symbol *SymbolMapper::MapSymbol(const Symbol *symbol) const { 7909e855a6cSPeter Klausler return symbol ? MapSymbol(*symbol) : nullptr; 7919e855a6cSPeter Klausler } 7929e855a6cSPeter Klausler 7939e855a6cSPeter Klausler const DeclTypeSpec *SymbolMapper::MapType(const DeclTypeSpec &type) { 7949e855a6cSPeter Klausler if (auto iter{map_.typeMap.find(&type)}; iter != map_.typeMap.end()) { 7959e855a6cSPeter Klausler return iter->second; 7969e855a6cSPeter Klausler } 7979e855a6cSPeter Klausler const DeclTypeSpec *newType{nullptr}; 7989e855a6cSPeter Klausler if (type.category() == DeclTypeSpec::Category::Character) { 7999e855a6cSPeter Klausler const CharacterTypeSpec &charType{type.characterTypeSpec()}; 8009e855a6cSPeter Klausler if (charType.length().GetExplicit()) { 8019e855a6cSPeter Klausler ParamValue newLen{charType.length()}; 8029e855a6cSPeter Klausler (*this)(newLen.GetExplicit()); 8039e855a6cSPeter Klausler newType = &scope_.MakeCharacterType( 8049e855a6cSPeter Klausler std::move(newLen), KindExpr{charType.kind()}); 8059e855a6cSPeter Klausler } 8069e855a6cSPeter Klausler } else if (const DerivedTypeSpec *derived{type.AsDerived()}) { 8079e855a6cSPeter Klausler if (!derived->parameters().empty()) { 8089e855a6cSPeter Klausler DerivedTypeSpec newDerived{derived->name(), derived->typeSymbol()}; 8099e855a6cSPeter Klausler newDerived.CookParameters(scope_.context().foldingContext()); 8109e855a6cSPeter Klausler for (const auto &[paramName, paramValue] : derived->parameters()) { 8119e855a6cSPeter Klausler ParamValue newParamValue{paramValue}; 8129e855a6cSPeter Klausler MapParamValue(newParamValue); 8139e855a6cSPeter Klausler newDerived.AddParamValue(paramName, std::move(newParamValue)); 8149e855a6cSPeter Klausler } 8159e855a6cSPeter Klausler // Scope::InstantiateDerivedTypes() instantiates it later. 8169e855a6cSPeter Klausler newType = &scope_.MakeDerivedType(type.category(), std::move(newDerived)); 8179e855a6cSPeter Klausler } 8189e855a6cSPeter Klausler } 8199e855a6cSPeter Klausler if (newType) { 8209e855a6cSPeter Klausler map_.typeMap[&type] = newType; 8219e855a6cSPeter Klausler } 8229e855a6cSPeter Klausler return newType; 8239e855a6cSPeter Klausler } 8249e855a6cSPeter Klausler 8259e855a6cSPeter Klausler const DeclTypeSpec *SymbolMapper::MapType(const DeclTypeSpec *type) { 8269e855a6cSPeter Klausler return type ? MapType(*type) : nullptr; 8279e855a6cSPeter Klausler } 8289e855a6cSPeter Klausler 8299e855a6cSPeter Klausler const Symbol *SymbolMapper::MapInterface(const Symbol *interface) { 8309e855a6cSPeter Klausler if (const Symbol *mapped{MapSymbol(interface)}) { 8319e855a6cSPeter Klausler return mapped; 8329e855a6cSPeter Klausler } 8339e855a6cSPeter Klausler if (interface) { 8349e855a6cSPeter Klausler if (&interface->owner() != &scope_) { 8359e855a6cSPeter Klausler return interface; 8369e855a6cSPeter Klausler } else if (const auto *subp{interface->detailsIf<SubprogramDetails>()}; 8379e855a6cSPeter Klausler subp && subp->isInterface()) { 83811d07d9eSPeter Klausler return CopySymbol(interface); 8399e855a6cSPeter Klausler } 8409e855a6cSPeter Klausler } 8419e855a6cSPeter Klausler return nullptr; 8429e855a6cSPeter Klausler } 8439e855a6cSPeter Klausler 8449e855a6cSPeter Klausler void MapSubprogramToNewSymbols(const Symbol &oldSymbol, Symbol &newSymbol, 8459e855a6cSPeter Klausler Scope &newScope, SymbolAndTypeMappings *mappings) { 8469e855a6cSPeter Klausler SymbolAndTypeMappings newMappings; 8479e855a6cSPeter Klausler if (!mappings) { 8489e855a6cSPeter Klausler mappings = &newMappings; 8499e855a6cSPeter Klausler } 8509e855a6cSPeter Klausler mappings->symbolMap[&oldSymbol] = &newSymbol; 8519e855a6cSPeter Klausler const auto &oldDetails{oldSymbol.get<SubprogramDetails>()}; 8529e855a6cSPeter Klausler auto &newDetails{newSymbol.get<SubprogramDetails>()}; 85311d07d9eSPeter Klausler SymbolMapper mapper{newScope, *mappings}; 8549e855a6cSPeter Klausler for (const Symbol *dummyArg : oldDetails.dummyArgs()) { 8559e855a6cSPeter Klausler if (!dummyArg) { 8569e855a6cSPeter Klausler newDetails.add_alternateReturn(); 85711d07d9eSPeter Klausler } else if (Symbol * copy{mapper.CopySymbol(dummyArg)}) { 858078b1c42SPeter Klausler copy->set(Symbol::Flag::Implicit, false); 8599e855a6cSPeter Klausler newDetails.add_dummyArg(*copy); 8609e855a6cSPeter Klausler mappings->symbolMap[dummyArg] = copy; 8619e855a6cSPeter Klausler } 8629e855a6cSPeter Klausler } 8639e855a6cSPeter Klausler if (oldDetails.isFunction()) { 8649e855a6cSPeter Klausler newScope.erase(newSymbol.name()); 86511d07d9eSPeter Klausler const Symbol &result{oldDetails.result()}; 86611d07d9eSPeter Klausler if (Symbol * copy{mapper.CopySymbol(&result)}) { 8679e855a6cSPeter Klausler newDetails.set_result(*copy); 86811d07d9eSPeter Klausler mappings->symbolMap[&result] = copy; 8699e855a6cSPeter Klausler } 8709e855a6cSPeter Klausler } 8719e855a6cSPeter Klausler for (auto &[_, ref] : newScope) { 8729e855a6cSPeter Klausler mapper.MapSymbolExprs(*ref); 8739e855a6cSPeter Klausler } 8749e855a6cSPeter Klausler newScope.InstantiateDerivedTypes(); 8759e855a6cSPeter Klausler } 8769e855a6cSPeter Klausler 8771f879005STim Keith } // namespace Fortran::semantics 878