xref: /llvm-project/flang/lib/Semantics/resolve-names-utils.cpp (revision 2f22656db541e4e5c3401e7bbab25277c8438a23)
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 &param) { (*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 &copy{*pair.first->second};
72111d07d9eSPeter Klausler           map_.symbolMap[symbol] = &copy;
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, &copy)};
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 &copy;
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