xref: /llvm-project/flang/lib/Semantics/scope.cpp (revision fc97d2e68b03bc2979395e84b645e5b3ba35aecd)
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"
11af3c7241SPeter Klausler #include "flang/Semantics/semantics.h"
1264ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
1364ab3302SCarolineConcatto #include "flang/Semantics/type.h"
148670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
1564ab3302SCarolineConcatto #include <algorithm>
1664ab3302SCarolineConcatto #include <memory>
1764ab3302SCarolineConcatto 
1864ab3302SCarolineConcatto namespace Fortran::semantics {
1964ab3302SCarolineConcatto 
2064ab3302SCarolineConcatto Symbols<1024> Scope::allSymbols;
2164ab3302SCarolineConcatto 
2264ab3302SCarolineConcatto bool EquivalenceObject::operator==(const EquivalenceObject &that) const {
2364ab3302SCarolineConcatto   return symbol == that.symbol && subscripts == that.subscripts &&
2464ab3302SCarolineConcatto       substringStart == that.substringStart;
2564ab3302SCarolineConcatto }
2664ab3302SCarolineConcatto 
2764ab3302SCarolineConcatto bool EquivalenceObject::operator<(const EquivalenceObject &that) const {
2864ab3302SCarolineConcatto   return &symbol < &that.symbol ||
2964ab3302SCarolineConcatto       (&symbol == &that.symbol &&
3064ab3302SCarolineConcatto           (subscripts < that.subscripts ||
3164ab3302SCarolineConcatto               (subscripts == that.subscripts &&
3264ab3302SCarolineConcatto                   substringStart < that.substringStart)));
3364ab3302SCarolineConcatto }
3464ab3302SCarolineConcatto 
3564ab3302SCarolineConcatto std::string EquivalenceObject::AsFortran() const {
368670e499SCaroline Concatto   std::string buf;
378670e499SCaroline Concatto   llvm::raw_string_ostream ss{buf};
3864ab3302SCarolineConcatto   ss << symbol.name().ToString();
3964ab3302SCarolineConcatto   if (!subscripts.empty()) {
4064ab3302SCarolineConcatto     char sep{'('};
4164ab3302SCarolineConcatto     for (auto subscript : subscripts) {
4264ab3302SCarolineConcatto       ss << sep << subscript;
4364ab3302SCarolineConcatto       sep = ',';
4464ab3302SCarolineConcatto     }
4564ab3302SCarolineConcatto     ss << ')';
4664ab3302SCarolineConcatto   }
4764ab3302SCarolineConcatto   if (substringStart) {
4864ab3302SCarolineConcatto     ss << '(' << *substringStart << ":)";
4964ab3302SCarolineConcatto   }
50d5dd7d23SYoungsuk Kim   return buf;
5164ab3302SCarolineConcatto }
5264ab3302SCarolineConcatto 
5364ab3302SCarolineConcatto Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
5446ade6d0Speter klausler   return children_.emplace_back(*this, kind, symbol, context_);
5564ab3302SCarolineConcatto }
5664ab3302SCarolineConcatto 
57c353ebbfSTim Keith template <typename T>
58c353ebbfSTim Keith static std::vector<common::Reference<T>> GetSortedSymbols(
599d9a85e1SPeter Klausler     const std::map<SourceName, MutableSymbolRef> &symbols) {
60c353ebbfSTim Keith   std::vector<common::Reference<T>> result;
61c353ebbfSTim Keith   result.reserve(symbols.size());
62c353ebbfSTim Keith   for (auto &pair : symbols) {
63c353ebbfSTim Keith     result.push_back(*pair.second);
64c353ebbfSTim Keith   }
650d8331c0Speter klausler   std::sort(result.begin(), result.end(), SymbolSourcePositionCompare{});
66c353ebbfSTim Keith   return result;
67c353ebbfSTim Keith }
68c353ebbfSTim Keith 
69d5c05cedSTim Keith MutableSymbolVector Scope::GetSymbols() {
70c353ebbfSTim Keith   return GetSortedSymbols<Symbol>(symbols_);
71c353ebbfSTim Keith }
72c353ebbfSTim Keith SymbolVector Scope::GetSymbols() const {
73c353ebbfSTim Keith   return GetSortedSymbols<const Symbol>(symbols_);
74c353ebbfSTim Keith }
75c353ebbfSTim Keith 
7664ab3302SCarolineConcatto Scope::iterator Scope::find(const SourceName &name) {
7764ab3302SCarolineConcatto   return symbols_.find(name);
7864ab3302SCarolineConcatto }
7964ab3302SCarolineConcatto Scope::size_type Scope::erase(const SourceName &name) {
8064ab3302SCarolineConcatto   auto it{symbols_.find(name)};
8164ab3302SCarolineConcatto   if (it != end()) {
8264ab3302SCarolineConcatto     symbols_.erase(it);
8364ab3302SCarolineConcatto     return 1;
8464ab3302SCarolineConcatto   } else {
8564ab3302SCarolineConcatto     return 0;
8664ab3302SCarolineConcatto   }
8764ab3302SCarolineConcatto }
8864ab3302SCarolineConcatto Symbol *Scope::FindSymbol(const SourceName &name) const {
8964ab3302SCarolineConcatto   auto it{find(name)};
9064ab3302SCarolineConcatto   if (it != end()) {
9164ab3302SCarolineConcatto     return &*it->second;
92f7be1aadSPeter Klausler   } else if (IsSubmodule()) {
93f7be1aadSPeter Klausler     const Scope *parent{symbol_->get<ModuleDetails>().parent()};
94f7be1aadSPeter Klausler     return parent ? parent->FindSymbol(name) : nullptr;
9564ab3302SCarolineConcatto   } else if (CanImport(name)) {
9627f71807SPeter Klausler     return parent_->FindSymbol(name);
9764ab3302SCarolineConcatto   } else {
9864ab3302SCarolineConcatto     return nullptr;
9964ab3302SCarolineConcatto   }
10064ab3302SCarolineConcatto }
10164ab3302SCarolineConcatto 
10264ab3302SCarolineConcatto Symbol *Scope::FindComponent(SourceName name) const {
10364ab3302SCarolineConcatto   CHECK(IsDerivedType());
10464ab3302SCarolineConcatto   auto found{find(name)};
10564ab3302SCarolineConcatto   if (found != end()) {
10664ab3302SCarolineConcatto     return &*found->second;
10764ab3302SCarolineConcatto   } else if (const Scope * parent{GetDerivedTypeParent()}) {
10864ab3302SCarolineConcatto     return parent->FindComponent(name);
10964ab3302SCarolineConcatto   } else {
11064ab3302SCarolineConcatto     return nullptr;
11164ab3302SCarolineConcatto   }
11264ab3302SCarolineConcatto }
11364ab3302SCarolineConcatto 
1146ab50745STim Keith bool Scope::Contains(const Scope &that) const {
1156ab50745STim Keith   for (const Scope *scope{&that};; scope = &scope->parent()) {
1166ab50745STim Keith     if (*scope == *this) {
1176ab50745STim Keith       return true;
1186ab50745STim Keith     }
1196ab50745STim Keith     if (scope->IsGlobal()) {
1206ab50745STim Keith       return false;
1216ab50745STim Keith     }
1226ab50745STim Keith   }
1236ab50745STim Keith }
1246ab50745STim Keith 
125824d198eSTim Keith Symbol *Scope::CopySymbol(const Symbol &symbol) {
126824d198eSTim Keith   auto pair{try_emplace(symbol.name(), symbol.attrs())};
127824d198eSTim Keith   if (!pair.second) {
128824d198eSTim Keith     return nullptr; // already exists
129824d198eSTim Keith   } else {
130824d198eSTim Keith     Symbol &result{*pair.first->second};
131824d198eSTim Keith     result.flags() = symbol.flags();
132824d198eSTim Keith     result.set_details(common::Clone(symbol.details()));
133824d198eSTim Keith     return &result;
134824d198eSTim Keith   }
135824d198eSTim Keith }
136824d198eSTim Keith 
13764ab3302SCarolineConcatto void Scope::add_equivalenceSet(EquivalenceSet &&set) {
13864ab3302SCarolineConcatto   equivalenceSets_.emplace_back(std::move(set));
13964ab3302SCarolineConcatto }
14064ab3302SCarolineConcatto 
14164ab3302SCarolineConcatto void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
14264ab3302SCarolineConcatto   CHECK(pointer.test(Symbol::Flag::CrayPointer));
14364ab3302SCarolineConcatto   crayPointers_.emplace(name, pointer);
14464ab3302SCarolineConcatto }
14564ab3302SCarolineConcatto 
14664ab3302SCarolineConcatto Symbol &Scope::MakeCommonBlock(const SourceName &name) {
14764ab3302SCarolineConcatto   const auto it{commonBlocks_.find(name)};
14864ab3302SCarolineConcatto   if (it != commonBlocks_.end()) {
14964ab3302SCarolineConcatto     return *it->second;
15064ab3302SCarolineConcatto   } else {
15164ab3302SCarolineConcatto     Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
15264ab3302SCarolineConcatto     commonBlocks_.emplace(name, symbol);
15364ab3302SCarolineConcatto     return symbol;
15464ab3302SCarolineConcatto   }
15564ab3302SCarolineConcatto }
1567d1397f7SRenaud-K Symbol *Scope::FindCommonBlock(const SourceName &name) const {
15764ab3302SCarolineConcatto   const auto it{commonBlocks_.find(name)};
15864ab3302SCarolineConcatto   return it != commonBlocks_.end() ? &*it->second : nullptr;
15964ab3302SCarolineConcatto }
16064ab3302SCarolineConcatto 
16164ab3302SCarolineConcatto Scope *Scope::FindSubmodule(const SourceName &name) const {
16264ab3302SCarolineConcatto   auto it{submodules_.find(name)};
16364ab3302SCarolineConcatto   if (it == submodules_.end()) {
16464ab3302SCarolineConcatto     return nullptr;
16564ab3302SCarolineConcatto   } else {
16664ab3302SCarolineConcatto     return &*it->second;
16764ab3302SCarolineConcatto   }
16864ab3302SCarolineConcatto }
16964ab3302SCarolineConcatto bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
17064ab3302SCarolineConcatto   return submodules_.emplace(name, submodule).second;
17164ab3302SCarolineConcatto }
17264ab3302SCarolineConcatto 
17364ab3302SCarolineConcatto const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {
17464ab3302SCarolineConcatto   auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)};
17564ab3302SCarolineConcatto   return it != declTypeSpecs_.end() ? &*it : nullptr;
17664ab3302SCarolineConcatto }
17764ab3302SCarolineConcatto 
17864ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeNumericType(
17964ab3302SCarolineConcatto     TypeCategory category, KindExpr &&kind) {
18064ab3302SCarolineConcatto   return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)});
18164ab3302SCarolineConcatto }
18264ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) {
18364ab3302SCarolineConcatto   return MakeLengthlessType(LogicalTypeSpec{std::move(kind)});
18464ab3302SCarolineConcatto }
18564ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeTypeStarType() {
18664ab3302SCarolineConcatto   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar});
18764ab3302SCarolineConcatto }
18864ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeClassStarType() {
18964ab3302SCarolineConcatto   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar});
19064ab3302SCarolineConcatto }
19164ab3302SCarolineConcatto // Types that can't have length parameters can be reused without having to
19264ab3302SCarolineConcatto // compare length expressions. They are stored in the global scope.
19364ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) {
19464ab3302SCarolineConcatto   const auto *found{FindType(type)};
19564ab3302SCarolineConcatto   return found ? *found : declTypeSpecs_.emplace_back(std::move(type));
19664ab3302SCarolineConcatto }
19764ab3302SCarolineConcatto 
19864ab3302SCarolineConcatto const DeclTypeSpec &Scope::MakeCharacterType(
19964ab3302SCarolineConcatto     ParamValue &&length, KindExpr &&kind) {
20064ab3302SCarolineConcatto   return declTypeSpecs_.emplace_back(
20164ab3302SCarolineConcatto       CharacterTypeSpec{std::move(length), std::move(kind)});
20264ab3302SCarolineConcatto }
20364ab3302SCarolineConcatto 
20464ab3302SCarolineConcatto DeclTypeSpec &Scope::MakeDerivedType(
20564ab3302SCarolineConcatto     DeclTypeSpec::Category category, DerivedTypeSpec &&spec) {
20664ab3302SCarolineConcatto   return declTypeSpecs_.emplace_back(category, std::move(spec));
20764ab3302SCarolineConcatto }
20864ab3302SCarolineConcatto 
209ebe74d95Speter klausler const DeclTypeSpec *Scope::GetType(const SomeExpr &expr) {
210ebe74d95Speter klausler   if (auto dyType{expr.GetType()}) {
211ebe74d95Speter klausler     if (dyType->IsAssumedType()) {
212ebe74d95Speter klausler       return &MakeTypeStarType();
213ebe74d95Speter klausler     } else if (dyType->IsUnlimitedPolymorphic()) {
214ebe74d95Speter klausler       return &MakeClassStarType();
215ebe74d95Speter klausler     } else {
216ebe74d95Speter klausler       switch (dyType->category()) {
217ebe74d95Speter klausler       case TypeCategory::Integer:
218*fc97d2e6SPeter Klausler       case TypeCategory::Unsigned:
219ebe74d95Speter klausler       case TypeCategory::Real:
220ebe74d95Speter klausler       case TypeCategory::Complex:
221ebe74d95Speter klausler         return &MakeNumericType(dyType->category(), KindExpr{dyType->kind()});
222ebe74d95Speter klausler       case TypeCategory::Character:
223ac964175Speter klausler         if (const ParamValue * lenParam{dyType->charLengthParamValue()}) {
224ebe74d95Speter klausler           return &MakeCharacterType(
225ebe74d95Speter klausler               ParamValue{*lenParam}, KindExpr{dyType->kind()});
226ebe74d95Speter klausler         } else {
227ebe74d95Speter klausler           auto lenExpr{dyType->GetCharLength()};
228ebe74d95Speter klausler           if (!lenExpr) {
229ebe74d95Speter klausler             lenExpr =
230ebe74d95Speter klausler                 std::get<evaluate::Expr<evaluate::SomeCharacter>>(expr.u).LEN();
231ebe74d95Speter klausler           }
232ebe74d95Speter klausler           if (lenExpr) {
233ebe74d95Speter klausler             return &MakeCharacterType(
234ebe74d95Speter klausler                 ParamValue{SomeIntExpr{std::move(*lenExpr)},
235ebe74d95Speter klausler                     common::TypeParamAttr::Len},
236ebe74d95Speter klausler                 KindExpr{dyType->kind()});
237ebe74d95Speter klausler           }
238ebe74d95Speter klausler         }
239ebe74d95Speter klausler         break;
240ebe74d95Speter klausler       case TypeCategory::Logical:
241ebe74d95Speter klausler         return &MakeLogicalType(KindExpr{dyType->kind()});
242ebe74d95Speter klausler       case TypeCategory::Derived:
243ebe74d95Speter klausler         return &MakeDerivedType(dyType->IsPolymorphic()
244ebe74d95Speter klausler                 ? DeclTypeSpec::ClassDerived
245ebe74d95Speter klausler                 : DeclTypeSpec::TypeDerived,
246ebe74d95Speter klausler             DerivedTypeSpec{dyType->GetDerivedTypeSpec()});
247ebe74d95Speter klausler       }
248ebe74d95Speter klausler     }
249ebe74d95Speter klausler   }
250ebe74d95Speter klausler   return nullptr;
251ebe74d95Speter klausler }
252ebe74d95Speter klausler 
25364ab3302SCarolineConcatto Scope::ImportKind Scope::GetImportKind() const {
25464ab3302SCarolineConcatto   if (importKind_) {
25564ab3302SCarolineConcatto     return *importKind_;
25664ab3302SCarolineConcatto   }
25764ab3302SCarolineConcatto   if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) {
25864ab3302SCarolineConcatto     if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) {
25964ab3302SCarolineConcatto       if (details->isInterface()) {
26064ab3302SCarolineConcatto         return ImportKind::None; // default for non-mod-proc interface body
26164ab3302SCarolineConcatto       }
26264ab3302SCarolineConcatto     }
26364ab3302SCarolineConcatto   }
26464ab3302SCarolineConcatto   return ImportKind::Default;
26564ab3302SCarolineConcatto }
26664ab3302SCarolineConcatto 
26764ab3302SCarolineConcatto std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) {
26864ab3302SCarolineConcatto   if (!importKind_) {
26964ab3302SCarolineConcatto     importKind_ = kind;
27064ab3302SCarolineConcatto     return std::nullopt;
27164ab3302SCarolineConcatto   }
27264ab3302SCarolineConcatto   bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None};
27364ab3302SCarolineConcatto   bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All};
27464ab3302SCarolineConcatto   // Check C8100 and C898: constraints on multiple IMPORT statements
27564ab3302SCarolineConcatto   if (hasNone || hasAll) {
27664ab3302SCarolineConcatto     return hasNone
27764ab3302SCarolineConcatto         ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
27864ab3302SCarolineConcatto         : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US;
27964ab3302SCarolineConcatto   } else if (kind != *importKind_ &&
280051bf9cdSShivam Gupta       (kind != ImportKind::Only && *importKind_ != ImportKind::Only)) {
28164ab3302SCarolineConcatto     return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US;
28264ab3302SCarolineConcatto   } else {
28364ab3302SCarolineConcatto     return std::nullopt;
28464ab3302SCarolineConcatto   }
28564ab3302SCarolineConcatto }
28664ab3302SCarolineConcatto 
28764ab3302SCarolineConcatto void Scope::add_importName(const SourceName &name) {
28864ab3302SCarolineConcatto   importNames_.insert(name);
28964ab3302SCarolineConcatto }
29064ab3302SCarolineConcatto 
29164ab3302SCarolineConcatto // true if name can be imported or host-associated from parent scope.
29264ab3302SCarolineConcatto bool Scope::CanImport(const SourceName &name) const {
29327f71807SPeter Klausler   if (IsTopLevel() || parent_->IsTopLevel()) {
29464ab3302SCarolineConcatto     return false;
29564ab3302SCarolineConcatto   }
29664ab3302SCarolineConcatto   switch (GetImportKind()) {
29764ab3302SCarolineConcatto     SWITCH_COVERS_ALL_CASES
2981f879005STim Keith   case ImportKind::None:
2991f879005STim Keith     return false;
30064ab3302SCarolineConcatto   case ImportKind::All:
3011f879005STim Keith   case ImportKind::Default:
3021f879005STim Keith     return true;
3031f879005STim Keith   case ImportKind::Only:
3041f879005STim Keith     return importNames_.count(name) > 0;
30564ab3302SCarolineConcatto   }
30664ab3302SCarolineConcatto }
30764ab3302SCarolineConcatto 
308af3c7241SPeter Klausler void Scope::AddSourceRange(parser::CharBlock source) {
309af3c7241SPeter Klausler   if (source.empty()) {
310af3c7241SPeter Klausler     return;
311af3c7241SPeter Klausler   }
312af3c7241SPeter Klausler   const parser::AllCookedSources &allCookedSources{context_.allCookedSources()};
313af3c7241SPeter Klausler   const parser::CookedSource *cooked{allCookedSources.Find(source)};
314af3c7241SPeter Klausler   if (!cooked) {
315af3c7241SPeter Klausler     CHECK(context_.IsTempName(source.ToString()));
316af3c7241SPeter Klausler     return;
317af3c7241SPeter Klausler   }
318af3c7241SPeter Klausler   for (auto *scope{this}; !scope->IsTopLevel(); scope = &scope->parent()) {
319af3c7241SPeter Klausler     CHECK(scope->sourceRange_.empty() == (scope->cookedSource_ == nullptr));
320af3c7241SPeter Klausler     if (!scope->cookedSource_) {
321e727bda1SPeter Klausler       context_.UpdateScopeIndex(*scope, source);
322af3c7241SPeter Klausler       scope->cookedSource_ = cooked;
323af3c7241SPeter Klausler       scope->sourceRange_ = source;
324af3c7241SPeter Klausler     } else if (scope->cookedSource_ == cooked) {
325e727bda1SPeter Klausler       auto combined{scope->sourceRange()};
326e727bda1SPeter Klausler       combined.ExtendToCover(source);
327e727bda1SPeter Klausler       context_.UpdateScopeIndex(*scope, combined);
328e727bda1SPeter Klausler       scope->sourceRange_ = combined;
329af3c7241SPeter Klausler     } else {
330af3c7241SPeter Klausler       // There's a bug that will be hard to fix; crash informatively
331af3c7241SPeter Klausler       const parser::AllSources &allSources{allCookedSources.allSources()};
332af3c7241SPeter Klausler       const auto describe{[&](parser::CharBlock src) {
333af3c7241SPeter Klausler         if (auto range{allCookedSources.GetProvenanceRange(src)}) {
334af3c7241SPeter Klausler           std::size_t offset;
335af3c7241SPeter Klausler           if (const parser::SourceFile *
336af3c7241SPeter Klausler               file{allSources.GetSourceFile(range->start(), &offset)}) {
337af3c7241SPeter Klausler             return "'"s + file->path() + "' at " + std::to_string(offset) +
338af3c7241SPeter Klausler                 " for " + std::to_string(range->size());
339af3c7241SPeter Klausler           } else {
340af3c7241SPeter Klausler             return "(GetSourceFile failed)"s;
341af3c7241SPeter Klausler           }
342af3c7241SPeter Klausler         } else {
343af3c7241SPeter Klausler           return "(GetProvenanceRange failed)"s;
344af3c7241SPeter Klausler         }
345af3c7241SPeter Klausler       }};
346af3c7241SPeter Klausler       std::string scopeDesc{describe(scope->sourceRange_)};
347af3c7241SPeter Klausler       std::string newDesc{describe(source)};
348af3c7241SPeter Klausler       common::die("AddSourceRange would have combined ranges from distinct "
349af3c7241SPeter Klausler                   "source files \"%s\" and \"%s\"",
350af3c7241SPeter Klausler           scopeDesc.c_str(), newDesc.c_str());
351af3c7241SPeter Klausler     }
352e727bda1SPeter Klausler     // Note: If the "break;" here were unconditional (or, equivalently, if
353e727bda1SPeter Klausler     // there were no loop at all) then the source ranges of parent scopes
354e727bda1SPeter Klausler     // would not enclose the source ranges of their children.  Timing
355e727bda1SPeter Klausler     // shows that it's cheap to maintain this property, with the exceptions
356e727bda1SPeter Klausler     // of top-level scopes and for (sub)modules and their descendant
357e727bda1SPeter Klausler     // submodules.
358af3c7241SPeter Klausler     if (scope->IsSubmodule()) {
359af3c7241SPeter Klausler       break; // Submodules are child scopes but not contained ranges
360af3c7241SPeter Klausler     }
36164ab3302SCarolineConcatto   }
36264ab3302SCarolineConcatto }
36364ab3302SCarolineConcatto 
3648670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {
36564ab3302SCarolineConcatto   os << Scope::EnumToString(scope.kind()) << " scope: ";
36664ab3302SCarolineConcatto   if (auto *symbol{scope.symbol()}) {
36764ab3302SCarolineConcatto     os << *symbol << ' ';
36864ab3302SCarolineConcatto   }
369c353ebbfSTim Keith   if (scope.derivedTypeSpec_) {
370c353ebbfSTim Keith     os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';
371c353ebbfSTim Keith   }
37264ab3302SCarolineConcatto   os << scope.children_.size() << " children\n";
37364ab3302SCarolineConcatto   for (const auto &pair : scope.symbols_) {
37464ab3302SCarolineConcatto     const Symbol &symbol{*pair.second};
37564ab3302SCarolineConcatto     os << "  " << symbol << '\n';
37664ab3302SCarolineConcatto   }
37764ab3302SCarolineConcatto   if (!scope.equivalenceSets_.empty()) {
37864ab3302SCarolineConcatto     os << "  Equivalence Sets:\n";
37964ab3302SCarolineConcatto     for (const auto &set : scope.equivalenceSets_) {
38064ab3302SCarolineConcatto       os << "   ";
38164ab3302SCarolineConcatto       for (const auto &object : set) {
38264ab3302SCarolineConcatto         os << ' ' << object.AsFortran();
38364ab3302SCarolineConcatto       }
38464ab3302SCarolineConcatto       os << '\n';
38564ab3302SCarolineConcatto     }
38664ab3302SCarolineConcatto   }
38764ab3302SCarolineConcatto   for (const auto &pair : scope.commonBlocks_) {
38864ab3302SCarolineConcatto     const Symbol &symbol{*pair.second};
38964ab3302SCarolineConcatto     os << "  " << symbol << '\n';
39064ab3302SCarolineConcatto   }
39164ab3302SCarolineConcatto   return os;
39264ab3302SCarolineConcatto }
39364ab3302SCarolineConcatto 
3947454acdfSTim Keith bool Scope::IsStmtFunction() const {
3957454acdfSTim Keith   return symbol_ && symbol_->test(Symbol::Flag::StmtFunction);
3967454acdfSTim Keith }
3977454acdfSTim Keith 
3983d63d211SJean Perier template <common::TypeParamAttr... ParamAttr> struct IsTypeParamHelper {
3993d63d211SJean Perier   static_assert(sizeof...(ParamAttr) == 0, "must have one or zero template");
4003d63d211SJean Perier   static bool IsParam(const Symbol &symbol) {
4013d63d211SJean Perier     return symbol.has<TypeParamDetails>();
4023d63d211SJean Perier   }
4033d63d211SJean Perier };
4043d63d211SJean Perier 
4053d63d211SJean Perier template <common::TypeParamAttr ParamAttr> struct IsTypeParamHelper<ParamAttr> {
4063d63d211SJean Perier   static bool IsParam(const Symbol &symbol) {
4073d63d211SJean Perier     if (const auto *typeParam{symbol.detailsIf<TypeParamDetails>()}) {
4083d63d211SJean Perier       return typeParam->attr() == ParamAttr;
4093d63d211SJean Perier     }
41064ab3302SCarolineConcatto     return false;
41164ab3302SCarolineConcatto   }
4123d63d211SJean Perier };
4133d63d211SJean Perier 
4143d63d211SJean Perier template <common::TypeParamAttr... ParamAttr>
4153d63d211SJean Perier static bool IsParameterizedDerivedTypeHelper(const Scope &scope) {
4163d63d211SJean Perier   if (scope.IsDerivedType()) {
4173d63d211SJean Perier     if (const Scope * parent{scope.GetDerivedTypeParent()}) {
4183d63d211SJean Perier       if (IsParameterizedDerivedTypeHelper<ParamAttr...>(*parent)) {
41964ab3302SCarolineConcatto         return true;
42064ab3302SCarolineConcatto       }
42164ab3302SCarolineConcatto     }
4223d63d211SJean Perier     for (const auto &nameAndSymbolPair : scope) {
4233d63d211SJean Perier       if (IsTypeParamHelper<ParamAttr...>::IsParam(*nameAndSymbolPair.second)) {
42464ab3302SCarolineConcatto         return true;
42564ab3302SCarolineConcatto       }
42664ab3302SCarolineConcatto     }
4273d63d211SJean Perier   }
42864ab3302SCarolineConcatto   return false;
42964ab3302SCarolineConcatto }
43064ab3302SCarolineConcatto 
4313d63d211SJean Perier bool Scope::IsParameterizedDerivedType() const {
4323d63d211SJean Perier   return IsParameterizedDerivedTypeHelper<>(*this);
4333d63d211SJean Perier }
4343d63d211SJean Perier bool Scope::IsDerivedTypeWithLengthParameter() const {
4353d63d211SJean Perier   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Len>(*this);
4363d63d211SJean Perier }
437f2da8f5eSJean Perier bool Scope::IsDerivedTypeWithKindParameter() const {
4383d63d211SJean Perier   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Kind>(*this);
439f88a9497SJean Perier }
440f88a9497SJean Perier 
44164ab3302SCarolineConcatto const DeclTypeSpec *Scope::FindInstantiatedDerivedType(
44264ab3302SCarolineConcatto     const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {
44364ab3302SCarolineConcatto   DeclTypeSpec type{category, spec};
44464ab3302SCarolineConcatto   if (const auto *result{FindType(type)}) {
44564ab3302SCarolineConcatto     return result;
44664ab3302SCarolineConcatto   } else if (IsGlobal()) {
44764ab3302SCarolineConcatto     return nullptr;
44864ab3302SCarolineConcatto   } else {
44964ab3302SCarolineConcatto     return parent().FindInstantiatedDerivedType(spec, category);
45064ab3302SCarolineConcatto   }
45164ab3302SCarolineConcatto }
45264ab3302SCarolineConcatto 
45364ab3302SCarolineConcatto const Scope *Scope::GetDerivedTypeParent() const {
45464ab3302SCarolineConcatto   if (const Symbol * symbol{GetSymbol()}) {
45564ab3302SCarolineConcatto     if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) {
45664ab3302SCarolineConcatto       return parent->scope();
45764ab3302SCarolineConcatto     }
45864ab3302SCarolineConcatto   }
45964ab3302SCarolineConcatto   return nullptr;
46064ab3302SCarolineConcatto }
46164ab3302SCarolineConcatto 
4622b790490SPete Steinfeld const Scope &Scope::GetDerivedTypeBase() const {
4632b790490SPete Steinfeld   const Scope *child{this};
4642b790490SPete Steinfeld   for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
4652b790490SPete Steinfeld        parent = child->GetDerivedTypeParent()) {
4662b790490SPete Steinfeld     child = parent;
4672b790490SPete Steinfeld   }
4682b790490SPete Steinfeld   return *child;
4692b790490SPete Steinfeld }
4702b790490SPete Steinfeld 
47146ade6d0Speter klausler void Scope::InstantiateDerivedTypes() {
47264ab3302SCarolineConcatto   for (DeclTypeSpec &type : declTypeSpecs_) {
47364ab3302SCarolineConcatto     if (type.category() == DeclTypeSpec::TypeDerived ||
47464ab3302SCarolineConcatto         type.category() == DeclTypeSpec::ClassDerived) {
4755091671cSpeter klausler       type.derivedTypeSpec().Instantiate(*this);
47664ab3302SCarolineConcatto     }
47764ab3302SCarolineConcatto   }
47864ab3302SCarolineConcatto }
4791f879005STim Keith } // namespace Fortran::semantics
480