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