164ab3302SCarolineConcatto //===-- lib/Semantics/scope.cpp -------------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "flang/Semantics/scope.h"
1064ab3302SCarolineConcatto #include "flang/Parser/characters.h"
1164ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
1264ab3302SCarolineConcatto #include "flang/Semantics/type.h"
138670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
1464ab3302SCarolineConcatto #include <algorithm>
1564ab3302SCarolineConcatto #include <memory>
1664ab3302SCarolineConcatto 
1764ab3302SCarolineConcatto namespace Fortran::semantics {
1864ab3302SCarolineConcatto 
1964ab3302SCarolineConcatto Symbols<1024> Scope::allSymbols;
2064ab3302SCarolineConcatto 
operator ==(const EquivalenceObject & that) const2164ab3302SCarolineConcatto bool EquivalenceObject::operator==(const EquivalenceObject &that) const {
2264ab3302SCarolineConcatto   return symbol == that.symbol && subscripts == that.subscripts &&
2364ab3302SCarolineConcatto       substringStart == that.substringStart;
2464ab3302SCarolineConcatto }
2564ab3302SCarolineConcatto 
operator <(const EquivalenceObject & that) const2664ab3302SCarolineConcatto bool EquivalenceObject::operator<(const EquivalenceObject &that) const {
2764ab3302SCarolineConcatto   return &symbol < &that.symbol ||
2864ab3302SCarolineConcatto       (&symbol == &that.symbol &&
2964ab3302SCarolineConcatto           (subscripts < that.subscripts ||
3064ab3302SCarolineConcatto               (subscripts == that.subscripts &&
3164ab3302SCarolineConcatto                   substringStart < that.substringStart)));
3264ab3302SCarolineConcatto }
3364ab3302SCarolineConcatto 
AsFortran() const3464ab3302SCarolineConcatto std::string EquivalenceObject::AsFortran() const {
358670e499SCaroline Concatto   std::string buf;
368670e499SCaroline Concatto   llvm::raw_string_ostream ss{buf};
3764ab3302SCarolineConcatto   ss << symbol.name().ToString();
3864ab3302SCarolineConcatto   if (!subscripts.empty()) {
3964ab3302SCarolineConcatto     char sep{'('};
4064ab3302SCarolineConcatto     for (auto subscript : subscripts) {
4164ab3302SCarolineConcatto       ss << sep << subscript;
4264ab3302SCarolineConcatto       sep = ',';
4364ab3302SCarolineConcatto     }
4464ab3302SCarolineConcatto     ss << ')';
4564ab3302SCarolineConcatto   }
4664ab3302SCarolineConcatto   if (substringStart) {
4764ab3302SCarolineConcatto     ss << '(' << *substringStart << ":)";
4864ab3302SCarolineConcatto   }
4964ab3302SCarolineConcatto   return ss.str();
5064ab3302SCarolineConcatto }
5164ab3302SCarolineConcatto 
MakeScope(Kind kind,Symbol * symbol)5264ab3302SCarolineConcatto Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
5346ade6d0Speter klausler   return children_.emplace_back(*this, kind, symbol, context_);
5464ab3302SCarolineConcatto }
5564ab3302SCarolineConcatto 
56c353ebbfSTim Keith template <typename T>
GetSortedSymbols(std::map<SourceName,MutableSymbolRef> symbols)57c353ebbfSTim Keith static std::vector<common::Reference<T>> GetSortedSymbols(
58d5c05cedSTim Keith     std::map<SourceName, MutableSymbolRef> symbols) {
59c353ebbfSTim Keith   std::vector<common::Reference<T>> result;
60c353ebbfSTim Keith   result.reserve(symbols.size());
61c353ebbfSTim Keith   for (auto &pair : symbols) {
62c353ebbfSTim Keith     result.push_back(*pair.second);
63c353ebbfSTim Keith   }
640d8331c0Speter klausler   std::sort(result.begin(), result.end(), SymbolSourcePositionCompare{});
65c353ebbfSTim Keith   return result;
66c353ebbfSTim Keith }
67c353ebbfSTim Keith 
GetSymbols()68d5c05cedSTim Keith MutableSymbolVector Scope::GetSymbols() {
69c353ebbfSTim Keith   return GetSortedSymbols<Symbol>(symbols_);
70c353ebbfSTim Keith }
GetSymbols() const71c353ebbfSTim Keith SymbolVector Scope::GetSymbols() const {
72c353ebbfSTim Keith   return GetSortedSymbols<const Symbol>(symbols_);
73c353ebbfSTim Keith }
74c353ebbfSTim Keith 
find(const SourceName & name)7564ab3302SCarolineConcatto Scope::iterator Scope::find(const SourceName &name) {
7664ab3302SCarolineConcatto   return symbols_.find(name);
7764ab3302SCarolineConcatto }
erase(const SourceName & name)7864ab3302SCarolineConcatto Scope::size_type Scope::erase(const SourceName &name) {
7964ab3302SCarolineConcatto   auto it{symbols_.find(name)};
8064ab3302SCarolineConcatto   if (it != end()) {
8164ab3302SCarolineConcatto     symbols_.erase(it);
8264ab3302SCarolineConcatto     return 1;
8364ab3302SCarolineConcatto   } else {
8464ab3302SCarolineConcatto     return 0;
8564ab3302SCarolineConcatto   }
8664ab3302SCarolineConcatto }
FindSymbol(const SourceName & name) const8764ab3302SCarolineConcatto Symbol *Scope::FindSymbol(const SourceName &name) const {
8864ab3302SCarolineConcatto   auto it{find(name)};
8964ab3302SCarolineConcatto   if (it != end()) {
9064ab3302SCarolineConcatto     return &*it->second;
9164ab3302SCarolineConcatto   } else if (CanImport(name)) {
9264ab3302SCarolineConcatto     return parent_.FindSymbol(name);
9364ab3302SCarolineConcatto   } else {
9464ab3302SCarolineConcatto     return nullptr;
9564ab3302SCarolineConcatto   }
9664ab3302SCarolineConcatto }
9764ab3302SCarolineConcatto 
FindComponent(SourceName name) const9864ab3302SCarolineConcatto Symbol *Scope::FindComponent(SourceName name) const {
9964ab3302SCarolineConcatto   CHECK(IsDerivedType());
10064ab3302SCarolineConcatto   auto found{find(name)};
10164ab3302SCarolineConcatto   if (found != end()) {
10264ab3302SCarolineConcatto     return &*found->second;
10364ab3302SCarolineConcatto   } else if (const Scope * parent{GetDerivedTypeParent()}) {
10464ab3302SCarolineConcatto     return parent->FindComponent(name);
10564ab3302SCarolineConcatto   } else {
10664ab3302SCarolineConcatto     return nullptr;
10764ab3302SCarolineConcatto   }
10864ab3302SCarolineConcatto }
10964ab3302SCarolineConcatto 
Contains(const Scope & that) const1106ab50745STim Keith bool Scope::Contains(const Scope &that) const {
1116ab50745STim Keith   for (const Scope *scope{&that};; scope = &scope->parent()) {
1126ab50745STim Keith     if (*scope == *this) {
1136ab50745STim Keith       return true;
1146ab50745STim Keith     }
1156ab50745STim Keith     if (scope->IsGlobal()) {
1166ab50745STim Keith       return false;
1176ab50745STim Keith     }
1186ab50745STim Keith   }
1196ab50745STim Keith }
1206ab50745STim Keith 
CopySymbol(const Symbol & symbol)121824d198eSTim Keith Symbol *Scope::CopySymbol(const Symbol &symbol) {
122824d198eSTim Keith   auto pair{try_emplace(symbol.name(), symbol.attrs())};
123824d198eSTim Keith   if (!pair.second) {
124824d198eSTim Keith     return nullptr; // already exists
125824d198eSTim Keith   } else {
126824d198eSTim Keith     Symbol &result{*pair.first->second};
127824d198eSTim Keith     result.flags() = symbol.flags();
128824d198eSTim Keith     result.set_details(common::Clone(symbol.details()));
129824d198eSTim Keith     return &result;
130824d198eSTim Keith   }
131824d198eSTim Keith }
132824d198eSTim Keith 
add_equivalenceSet(EquivalenceSet && set)13364ab3302SCarolineConcatto void Scope::add_equivalenceSet(EquivalenceSet &&set) {
13464ab3302SCarolineConcatto   equivalenceSets_.emplace_back(std::move(set));
13564ab3302SCarolineConcatto }
13664ab3302SCarolineConcatto 
add_crayPointer(const SourceName & name,Symbol & pointer)13764ab3302SCarolineConcatto void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
13864ab3302SCarolineConcatto   CHECK(pointer.test(Symbol::Flag::CrayPointer));
13964ab3302SCarolineConcatto   crayPointers_.emplace(name, pointer);
14064ab3302SCarolineConcatto }
14164ab3302SCarolineConcatto 
MakeCommonBlock(const SourceName & name)14264ab3302SCarolineConcatto Symbol &Scope::MakeCommonBlock(const SourceName &name) {
14364ab3302SCarolineConcatto   const auto it{commonBlocks_.find(name)};
14464ab3302SCarolineConcatto   if (it != commonBlocks_.end()) {
14564ab3302SCarolineConcatto     return *it->second;
14664ab3302SCarolineConcatto   } else {
14764ab3302SCarolineConcatto     Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
14864ab3302SCarolineConcatto     commonBlocks_.emplace(name, symbol);
14964ab3302SCarolineConcatto     return symbol;
15064ab3302SCarolineConcatto   }
15164ab3302SCarolineConcatto }
FindCommonBlock(const SourceName & name) const1527d1397f7SRenaud-K Symbol *Scope::FindCommonBlock(const SourceName &name) const {
15364ab3302SCarolineConcatto   const auto it{commonBlocks_.find(name)};
15464ab3302SCarolineConcatto   return it != commonBlocks_.end() ? &*it->second : nullptr;
15564ab3302SCarolineConcatto }
15664ab3302SCarolineConcatto 
FindSubmodule(const SourceName & name) const15764ab3302SCarolineConcatto Scope *Scope::FindSubmodule(const SourceName &name) const {
15864ab3302SCarolineConcatto   auto it{submodules_.find(name)};
15964ab3302SCarolineConcatto   if (it == submodules_.end()) {
16064ab3302SCarolineConcatto     return nullptr;
16164ab3302SCarolineConcatto   } else {
16264ab3302SCarolineConcatto     return &*it->second;
16364ab3302SCarolineConcatto   }
16464ab3302SCarolineConcatto }
AddSubmodule(const SourceName & name,Scope & submodule)16564ab3302SCarolineConcatto bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
16664ab3302SCarolineConcatto   return submodules_.emplace(name, submodule).second;
16764ab3302SCarolineConcatto }
16864ab3302SCarolineConcatto 
FindType(const DeclTypeSpec & type) const16964ab3302SCarolineConcatto const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {
17064ab3302SCarolineConcatto   auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)};
17164ab3302SCarolineConcatto   return it != declTypeSpecs_.end() ? &*it : nullptr;
17264ab3302SCarolineConcatto }
17364ab3302SCarolineConcatto 
MakeNumericType(TypeCategory category,KindExpr && kind)17464ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeNumericType(
17564ab3302SCarolineConcatto     TypeCategory category, KindExpr &&kind) {
17664ab3302SCarolineConcatto   return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)});
17764ab3302SCarolineConcatto }
MakeLogicalType(KindExpr && kind)17864ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) {
17964ab3302SCarolineConcatto   return MakeLengthlessType(LogicalTypeSpec{std::move(kind)});
18064ab3302SCarolineConcatto }
MakeTypeStarType()18164ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeTypeStarType() {
18264ab3302SCarolineConcatto   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar});
18364ab3302SCarolineConcatto }
MakeClassStarType()18464ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeClassStarType() {
18564ab3302SCarolineConcatto   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar});
18664ab3302SCarolineConcatto }
18764ab3302SCarolineConcatto // Types that can't have length parameters can be reused without having to
18864ab3302SCarolineConcatto // compare length expressions. They are stored in the global scope.
MakeLengthlessType(DeclTypeSpec && type)18964ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) {
19064ab3302SCarolineConcatto   const auto *found{FindType(type)};
19164ab3302SCarolineConcatto   return found ? *found : declTypeSpecs_.emplace_back(std::move(type));
19264ab3302SCarolineConcatto }
19364ab3302SCarolineConcatto 
MakeCharacterType(ParamValue && length,KindExpr && kind)19464ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeCharacterType(
19564ab3302SCarolineConcatto     ParamValue &&length, KindExpr &&kind) {
19664ab3302SCarolineConcatto   return declTypeSpecs_.emplace_back(
19764ab3302SCarolineConcatto       CharacterTypeSpec{std::move(length), std::move(kind)});
19864ab3302SCarolineConcatto }
19964ab3302SCarolineConcatto 
MakeDerivedType(DeclTypeSpec::Category category,DerivedTypeSpec && spec)20064ab3302SCarolineConcatto DeclTypeSpec &Scope::MakeDerivedType(
20164ab3302SCarolineConcatto     DeclTypeSpec::Category category, DerivedTypeSpec &&spec) {
20264ab3302SCarolineConcatto   return declTypeSpecs_.emplace_back(category, std::move(spec));
20364ab3302SCarolineConcatto }
20464ab3302SCarolineConcatto 
GetType(const SomeExpr & expr)205ebe74d95Speter klausler const DeclTypeSpec *Scope::GetType(const SomeExpr &expr) {
206ebe74d95Speter klausler   if (auto dyType{expr.GetType()}) {
207ebe74d95Speter klausler     if (dyType->IsAssumedType()) {
208ebe74d95Speter klausler       return &MakeTypeStarType();
209ebe74d95Speter klausler     } else if (dyType->IsUnlimitedPolymorphic()) {
210ebe74d95Speter klausler       return &MakeClassStarType();
211ebe74d95Speter klausler     } else {
212ebe74d95Speter klausler       switch (dyType->category()) {
213ebe74d95Speter klausler       case TypeCategory::Integer:
214ebe74d95Speter klausler       case TypeCategory::Real:
215ebe74d95Speter klausler       case TypeCategory::Complex:
216ebe74d95Speter klausler         return &MakeNumericType(dyType->category(), KindExpr{dyType->kind()});
217ebe74d95Speter klausler       case TypeCategory::Character:
218ac964175Speter klausler         if (const ParamValue * lenParam{dyType->charLengthParamValue()}) {
219ebe74d95Speter klausler           return &MakeCharacterType(
220ebe74d95Speter klausler               ParamValue{*lenParam}, KindExpr{dyType->kind()});
221ebe74d95Speter klausler         } else {
222ebe74d95Speter klausler           auto lenExpr{dyType->GetCharLength()};
223ebe74d95Speter klausler           if (!lenExpr) {
224ebe74d95Speter klausler             lenExpr =
225ebe74d95Speter klausler                 std::get<evaluate::Expr<evaluate::SomeCharacter>>(expr.u).LEN();
226ebe74d95Speter klausler           }
227ebe74d95Speter klausler           if (lenExpr) {
228ebe74d95Speter klausler             return &MakeCharacterType(
229ebe74d95Speter klausler                 ParamValue{SomeIntExpr{std::move(*lenExpr)},
230ebe74d95Speter klausler                     common::TypeParamAttr::Len},
231ebe74d95Speter klausler                 KindExpr{dyType->kind()});
232ebe74d95Speter klausler           }
233ebe74d95Speter klausler         }
234ebe74d95Speter klausler         break;
235ebe74d95Speter klausler       case TypeCategory::Logical:
236ebe74d95Speter klausler         return &MakeLogicalType(KindExpr{dyType->kind()});
237ebe74d95Speter klausler       case TypeCategory::Derived:
238ebe74d95Speter klausler         return &MakeDerivedType(dyType->IsPolymorphic()
239ebe74d95Speter klausler                 ? DeclTypeSpec::ClassDerived
240ebe74d95Speter klausler                 : DeclTypeSpec::TypeDerived,
241ebe74d95Speter klausler             DerivedTypeSpec{dyType->GetDerivedTypeSpec()});
242ebe74d95Speter klausler       }
243ebe74d95Speter klausler     }
244ebe74d95Speter klausler   }
245ebe74d95Speter klausler   return nullptr;
246ebe74d95Speter klausler }
247ebe74d95Speter klausler 
GetImportKind() const24864ab3302SCarolineConcatto Scope::ImportKind Scope::GetImportKind() const {
24964ab3302SCarolineConcatto   if (importKind_) {
25064ab3302SCarolineConcatto     return *importKind_;
25164ab3302SCarolineConcatto   }
25264ab3302SCarolineConcatto   if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) {
25364ab3302SCarolineConcatto     if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) {
25464ab3302SCarolineConcatto       if (details->isInterface()) {
25564ab3302SCarolineConcatto         return ImportKind::None; // default for non-mod-proc interface body
25664ab3302SCarolineConcatto       }
25764ab3302SCarolineConcatto     }
25864ab3302SCarolineConcatto   }
25964ab3302SCarolineConcatto   return ImportKind::Default;
26064ab3302SCarolineConcatto }
26164ab3302SCarolineConcatto 
SetImportKind(ImportKind kind)26264ab3302SCarolineConcatto std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) {
26364ab3302SCarolineConcatto   if (!importKind_) {
26464ab3302SCarolineConcatto     importKind_ = kind;
26564ab3302SCarolineConcatto     return std::nullopt;
26664ab3302SCarolineConcatto   }
26764ab3302SCarolineConcatto   bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None};
26864ab3302SCarolineConcatto   bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All};
26964ab3302SCarolineConcatto   // Check C8100 and C898: constraints on multiple IMPORT statements
27064ab3302SCarolineConcatto   if (hasNone || hasAll) {
27164ab3302SCarolineConcatto     return hasNone
27264ab3302SCarolineConcatto         ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
27364ab3302SCarolineConcatto         : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US;
27464ab3302SCarolineConcatto   } else if (kind != *importKind_ &&
27564ab3302SCarolineConcatto       (kind != ImportKind::Only || kind != ImportKind::Only)) {
27664ab3302SCarolineConcatto     return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US;
27764ab3302SCarolineConcatto   } else {
27864ab3302SCarolineConcatto     return std::nullopt;
27964ab3302SCarolineConcatto   }
28064ab3302SCarolineConcatto }
28164ab3302SCarolineConcatto 
add_importName(const SourceName & name)28264ab3302SCarolineConcatto void Scope::add_importName(const SourceName &name) {
28364ab3302SCarolineConcatto   importNames_.insert(name);
28464ab3302SCarolineConcatto }
28564ab3302SCarolineConcatto 
28664ab3302SCarolineConcatto // true if name can be imported or host-associated from parent scope.
CanImport(const SourceName & name) const28764ab3302SCarolineConcatto bool Scope::CanImport(const SourceName &name) const {
28852a1346bSPeter Klausler   if (IsTopLevel() || parent_.IsTopLevel()) {
28964ab3302SCarolineConcatto     return false;
29064ab3302SCarolineConcatto   }
29164ab3302SCarolineConcatto   switch (GetImportKind()) {
29264ab3302SCarolineConcatto     SWITCH_COVERS_ALL_CASES
2931f879005STim Keith   case ImportKind::None:
2941f879005STim Keith     return false;
29564ab3302SCarolineConcatto   case ImportKind::All:
2961f879005STim Keith   case ImportKind::Default:
2971f879005STim Keith     return true;
2981f879005STim Keith   case ImportKind::Only:
2991f879005STim Keith     return importNames_.count(name) > 0;
30064ab3302SCarolineConcatto   }
30164ab3302SCarolineConcatto }
30264ab3302SCarolineConcatto 
FindScope(parser::CharBlock source) const30364ab3302SCarolineConcatto const Scope *Scope::FindScope(parser::CharBlock source) const {
30464ab3302SCarolineConcatto   return const_cast<Scope *>(this)->FindScope(source);
30564ab3302SCarolineConcatto }
30664ab3302SCarolineConcatto 
FindScope(parser::CharBlock source)30764ab3302SCarolineConcatto Scope *Scope::FindScope(parser::CharBlock source) {
30864ab3302SCarolineConcatto   bool isContained{sourceRange_.Contains(source)};
30952a1346bSPeter Klausler   if (!isContained && !IsTopLevel() && !IsModuleFile()) {
31064ab3302SCarolineConcatto     return nullptr;
31164ab3302SCarolineConcatto   }
31264ab3302SCarolineConcatto   for (auto &child : children_) {
31364ab3302SCarolineConcatto     if (auto *scope{child.FindScope(source)}) {
31464ab3302SCarolineConcatto       return scope;
31564ab3302SCarolineConcatto     }
31664ab3302SCarolineConcatto   }
31752a1346bSPeter Klausler   return isContained && !IsTopLevel() ? this : nullptr;
31864ab3302SCarolineConcatto }
31964ab3302SCarolineConcatto 
AddSourceRange(const parser::CharBlock & source)32064ab3302SCarolineConcatto void Scope::AddSourceRange(const parser::CharBlock &source) {
3211dff8637Speter klausler   for (auto *scope{this}; !scope->IsGlobal(); scope = &scope->parent()) {
32264ab3302SCarolineConcatto     scope->sourceRange_.ExtendToCover(source);
32364ab3302SCarolineConcatto   }
32464ab3302SCarolineConcatto }
32564ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & os,const Scope & scope)3268670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {
32764ab3302SCarolineConcatto   os << Scope::EnumToString(scope.kind()) << " scope: ";
32864ab3302SCarolineConcatto   if (auto *symbol{scope.symbol()}) {
32964ab3302SCarolineConcatto     os << *symbol << ' ';
33064ab3302SCarolineConcatto   }
331c353ebbfSTim Keith   if (scope.derivedTypeSpec_) {
332c353ebbfSTim Keith     os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';
333c353ebbfSTim Keith   }
33464ab3302SCarolineConcatto   os << scope.children_.size() << " children\n";
33564ab3302SCarolineConcatto   for (const auto &pair : scope.symbols_) {
33664ab3302SCarolineConcatto     const Symbol &symbol{*pair.second};
33764ab3302SCarolineConcatto     os << "  " << symbol << '\n';
33864ab3302SCarolineConcatto   }
33964ab3302SCarolineConcatto   if (!scope.equivalenceSets_.empty()) {
34064ab3302SCarolineConcatto     os << "  Equivalence Sets:\n";
34164ab3302SCarolineConcatto     for (const auto &set : scope.equivalenceSets_) {
34264ab3302SCarolineConcatto       os << "   ";
34364ab3302SCarolineConcatto       for (const auto &object : set) {
34464ab3302SCarolineConcatto         os << ' ' << object.AsFortran();
34564ab3302SCarolineConcatto       }
34664ab3302SCarolineConcatto       os << '\n';
34764ab3302SCarolineConcatto     }
34864ab3302SCarolineConcatto   }
34964ab3302SCarolineConcatto   for (const auto &pair : scope.commonBlocks_) {
35064ab3302SCarolineConcatto     const Symbol &symbol{*pair.second};
35164ab3302SCarolineConcatto     os << "  " << symbol << '\n';
35264ab3302SCarolineConcatto   }
35364ab3302SCarolineConcatto   return os;
35464ab3302SCarolineConcatto }
35564ab3302SCarolineConcatto 
IsStmtFunction() const3567454acdfSTim Keith bool Scope::IsStmtFunction() const {
3577454acdfSTim Keith   return symbol_ && symbol_->test(Symbol::Flag::StmtFunction);
3587454acdfSTim Keith }
3597454acdfSTim Keith 
360*3d63d211SJean Perier template <common::TypeParamAttr... ParamAttr> struct IsTypeParamHelper {
361*3d63d211SJean Perier   static_assert(sizeof...(ParamAttr) == 0, "must have one or zero template");
IsParamFortran::semantics::IsTypeParamHelper362*3d63d211SJean Perier   static bool IsParam(const Symbol &symbol) {
363*3d63d211SJean Perier     return symbol.has<TypeParamDetails>();
364*3d63d211SJean Perier   }
365*3d63d211SJean Perier };
366*3d63d211SJean Perier 
367*3d63d211SJean Perier template <common::TypeParamAttr ParamAttr> struct IsTypeParamHelper<ParamAttr> {
IsParamFortran::semantics::IsTypeParamHelper368*3d63d211SJean Perier   static bool IsParam(const Symbol &symbol) {
369*3d63d211SJean Perier     if (const auto *typeParam{symbol.detailsIf<TypeParamDetails>()}) {
370*3d63d211SJean Perier       return typeParam->attr() == ParamAttr;
371*3d63d211SJean Perier     }
37264ab3302SCarolineConcatto     return false;
37364ab3302SCarolineConcatto   }
374*3d63d211SJean Perier };
375*3d63d211SJean Perier 
376*3d63d211SJean Perier template <common::TypeParamAttr... ParamAttr>
IsParameterizedDerivedTypeHelper(const Scope & scope)377*3d63d211SJean Perier static bool IsParameterizedDerivedTypeHelper(const Scope &scope) {
378*3d63d211SJean Perier   if (scope.IsDerivedType()) {
379*3d63d211SJean Perier     if (const Scope * parent{scope.GetDerivedTypeParent()}) {
380*3d63d211SJean Perier       if (IsParameterizedDerivedTypeHelper<ParamAttr...>(*parent)) {
38164ab3302SCarolineConcatto         return true;
38264ab3302SCarolineConcatto       }
38364ab3302SCarolineConcatto     }
384*3d63d211SJean Perier     for (const auto &nameAndSymbolPair : scope) {
385*3d63d211SJean Perier       if (IsTypeParamHelper<ParamAttr...>::IsParam(*nameAndSymbolPair.second)) {
38664ab3302SCarolineConcatto         return true;
38764ab3302SCarolineConcatto       }
38864ab3302SCarolineConcatto     }
389*3d63d211SJean Perier   }
39064ab3302SCarolineConcatto   return false;
39164ab3302SCarolineConcatto }
39264ab3302SCarolineConcatto 
IsParameterizedDerivedType() const393*3d63d211SJean Perier bool Scope::IsParameterizedDerivedType() const {
394*3d63d211SJean Perier   return IsParameterizedDerivedTypeHelper<>(*this);
395*3d63d211SJean Perier }
IsDerivedTypeWithLengthParameter() const396*3d63d211SJean Perier bool Scope::IsDerivedTypeWithLengthParameter() const {
397*3d63d211SJean Perier   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Len>(*this);
398*3d63d211SJean Perier }
IsDerivedTypeWithKindParameter() const399f2da8f5eSJean Perier bool Scope::IsDerivedTypeWithKindParameter() const {
400*3d63d211SJean Perier   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Kind>(*this);
401f88a9497SJean Perier }
402f88a9497SJean Perier 
FindInstantiatedDerivedType(const DerivedTypeSpec & spec,DeclTypeSpec::Category category) const40364ab3302SCarolineConcatto const DeclTypeSpec *Scope::FindInstantiatedDerivedType(
40464ab3302SCarolineConcatto     const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {
40564ab3302SCarolineConcatto   DeclTypeSpec type{category, spec};
40664ab3302SCarolineConcatto   if (const auto *result{FindType(type)}) {
40764ab3302SCarolineConcatto     return result;
40864ab3302SCarolineConcatto   } else if (IsGlobal()) {
40964ab3302SCarolineConcatto     return nullptr;
41064ab3302SCarolineConcatto   } else {
41164ab3302SCarolineConcatto     return parent().FindInstantiatedDerivedType(spec, category);
41264ab3302SCarolineConcatto   }
41364ab3302SCarolineConcatto }
41464ab3302SCarolineConcatto 
GetDerivedTypeParent() const41564ab3302SCarolineConcatto const Scope *Scope::GetDerivedTypeParent() const {
41664ab3302SCarolineConcatto   if (const Symbol * symbol{GetSymbol()}) {
41764ab3302SCarolineConcatto     if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) {
41864ab3302SCarolineConcatto       return parent->scope();
41964ab3302SCarolineConcatto     }
42064ab3302SCarolineConcatto   }
42164ab3302SCarolineConcatto   return nullptr;
42264ab3302SCarolineConcatto }
42364ab3302SCarolineConcatto 
GetDerivedTypeBase() const4242b790490SPete Steinfeld const Scope &Scope::GetDerivedTypeBase() const {
4252b790490SPete Steinfeld   const Scope *child{this};
4262b790490SPete Steinfeld   for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
4272b790490SPete Steinfeld        parent = child->GetDerivedTypeParent()) {
4282b790490SPete Steinfeld     child = parent;
4292b790490SPete Steinfeld   }
4302b790490SPete Steinfeld   return *child;
4312b790490SPete Steinfeld }
4322b790490SPete Steinfeld 
InstantiateDerivedTypes()43346ade6d0Speter klausler void Scope::InstantiateDerivedTypes() {
43464ab3302SCarolineConcatto   for (DeclTypeSpec &type : declTypeSpecs_) {
43564ab3302SCarolineConcatto     if (type.category() == DeclTypeSpec::TypeDerived ||
43664ab3302SCarolineConcatto         type.category() == DeclTypeSpec::ClassDerived) {
4375091671cSpeter klausler       type.derivedTypeSpec().Instantiate(*this);
43864ab3302SCarolineConcatto     }
43964ab3302SCarolineConcatto   }
44064ab3302SCarolineConcatto }
4411f879005STim Keith } // namespace Fortran::semantics
442