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