llvm-project
478 строк · 15.0 Кб
1//===-- lib/Semantics/scope.cpp -------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "flang/Semantics/scope.h"10#include "flang/Parser/characters.h"11#include "flang/Semantics/semantics.h"12#include "flang/Semantics/symbol.h"13#include "flang/Semantics/type.h"14#include "llvm/Support/raw_ostream.h"15#include <algorithm>16#include <memory>17
18namespace Fortran::semantics {19
20Symbols<1024> Scope::allSymbols;21
22bool EquivalenceObject::operator==(const EquivalenceObject &that) const {23return symbol == that.symbol && subscripts == that.subscripts &&24substringStart == that.substringStart;25}
26
27bool EquivalenceObject::operator<(const EquivalenceObject &that) const {28return &symbol < &that.symbol ||29(&symbol == &that.symbol &&30(subscripts < that.subscripts ||31(subscripts == that.subscripts &&32substringStart < that.substringStart)));33}
34
35std::string EquivalenceObject::AsFortran() const {36std::string buf;37llvm::raw_string_ostream ss{buf};38ss << symbol.name().ToString();39if (!subscripts.empty()) {40char sep{'('};41for (auto subscript : subscripts) {42ss << sep << subscript;43sep = ',';44}45ss << ')';46}47if (substringStart) {48ss << '(' << *substringStart << ":)";49}50return ss.str();51}
52
53Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {54return children_.emplace_back(*this, kind, symbol, context_);55}
56
57template <typename T>58static std::vector<common::Reference<T>> GetSortedSymbols(59const std::map<SourceName, MutableSymbolRef> &symbols) {60std::vector<common::Reference<T>> result;61result.reserve(symbols.size());62for (auto &pair : symbols) {63result.push_back(*pair.second);64}65std::sort(result.begin(), result.end(), SymbolSourcePositionCompare{});66return result;67}
68
69MutableSymbolVector Scope::GetSymbols() {70return GetSortedSymbols<Symbol>(symbols_);71}
72SymbolVector Scope::GetSymbols() const {73return GetSortedSymbols<const Symbol>(symbols_);74}
75
76Scope::iterator Scope::find(const SourceName &name) {77return symbols_.find(name);78}
79Scope::size_type Scope::erase(const SourceName &name) {80auto it{symbols_.find(name)};81if (it != end()) {82symbols_.erase(it);83return 1;84} else {85return 0;86}87}
88Symbol *Scope::FindSymbol(const SourceName &name) const {89auto it{find(name)};90if (it != end()) {91return &*it->second;92} else if (IsSubmodule()) {93const Scope *parent{symbol_->get<ModuleDetails>().parent()};94return parent ? parent->FindSymbol(name) : nullptr;95} else if (CanImport(name)) {96return parent_->FindSymbol(name);97} else {98return nullptr;99}100}
101
102Symbol *Scope::FindComponent(SourceName name) const {103CHECK(IsDerivedType());104auto found{find(name)};105if (found != end()) {106return &*found->second;107} else if (const Scope * parent{GetDerivedTypeParent()}) {108return parent->FindComponent(name);109} else {110return nullptr;111}112}
113
114bool Scope::Contains(const Scope &that) const {115for (const Scope *scope{&that};; scope = &scope->parent()) {116if (*scope == *this) {117return true;118}119if (scope->IsGlobal()) {120return false;121}122}123}
124
125Symbol *Scope::CopySymbol(const Symbol &symbol) {126auto pair{try_emplace(symbol.name(), symbol.attrs())};127if (!pair.second) {128return nullptr; // already exists129} else {130Symbol &result{*pair.first->second};131result.flags() = symbol.flags();132result.set_details(common::Clone(symbol.details()));133return &result;134}135}
136
137void Scope::add_equivalenceSet(EquivalenceSet &&set) {138equivalenceSets_.emplace_back(std::move(set));139}
140
141void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {142CHECK(pointer.test(Symbol::Flag::CrayPointer));143crayPointers_.emplace(name, pointer);144}
145
146Symbol &Scope::MakeCommonBlock(const SourceName &name) {147const auto it{commonBlocks_.find(name)};148if (it != commonBlocks_.end()) {149return *it->second;150} else {151Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};152commonBlocks_.emplace(name, symbol);153return symbol;154}155}
156Symbol *Scope::FindCommonBlock(const SourceName &name) const {157const auto it{commonBlocks_.find(name)};158return it != commonBlocks_.end() ? &*it->second : nullptr;159}
160
161Scope *Scope::FindSubmodule(const SourceName &name) const {162auto it{submodules_.find(name)};163if (it == submodules_.end()) {164return nullptr;165} else {166return &*it->second;167}168}
169bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {170return submodules_.emplace(name, submodule).second;171}
172
173const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {174auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)};175return it != declTypeSpecs_.end() ? &*it : nullptr;176}
177
178const DeclTypeSpec &Scope::MakeNumericType(179TypeCategory category, KindExpr &&kind) {180return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)});181}
182const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) {183return MakeLengthlessType(LogicalTypeSpec{std::move(kind)});184}
185const DeclTypeSpec &Scope::MakeTypeStarType() {186return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar});187}
188const DeclTypeSpec &Scope::MakeClassStarType() {189return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar});190}
191// Types that can't have length parameters can be reused without having to
192// compare length expressions. They are stored in the global scope.
193const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) {194const auto *found{FindType(type)};195return found ? *found : declTypeSpecs_.emplace_back(std::move(type));196}
197
198const DeclTypeSpec &Scope::MakeCharacterType(199ParamValue &&length, KindExpr &&kind) {200return declTypeSpecs_.emplace_back(201CharacterTypeSpec{std::move(length), std::move(kind)});202}
203
204DeclTypeSpec &Scope::MakeDerivedType(205DeclTypeSpec::Category category, DerivedTypeSpec &&spec) {206return declTypeSpecs_.emplace_back(category, std::move(spec));207}
208
209const DeclTypeSpec *Scope::GetType(const SomeExpr &expr) {210if (auto dyType{expr.GetType()}) {211if (dyType->IsAssumedType()) {212return &MakeTypeStarType();213} else if (dyType->IsUnlimitedPolymorphic()) {214return &MakeClassStarType();215} else {216switch (dyType->category()) {217case TypeCategory::Integer:218case TypeCategory::Real:219case TypeCategory::Complex:220return &MakeNumericType(dyType->category(), KindExpr{dyType->kind()});221case TypeCategory::Character:222if (const ParamValue * lenParam{dyType->charLengthParamValue()}) {223return &MakeCharacterType(224ParamValue{*lenParam}, KindExpr{dyType->kind()});225} else {226auto lenExpr{dyType->GetCharLength()};227if (!lenExpr) {228lenExpr =229std::get<evaluate::Expr<evaluate::SomeCharacter>>(expr.u).LEN();230}231if (lenExpr) {232return &MakeCharacterType(233ParamValue{SomeIntExpr{std::move(*lenExpr)},234common::TypeParamAttr::Len},235KindExpr{dyType->kind()});236}237}238break;239case TypeCategory::Logical:240return &MakeLogicalType(KindExpr{dyType->kind()});241case TypeCategory::Derived:242return &MakeDerivedType(dyType->IsPolymorphic()243? DeclTypeSpec::ClassDerived244: DeclTypeSpec::TypeDerived,245DerivedTypeSpec{dyType->GetDerivedTypeSpec()});246}247}248}249return nullptr;250}
251
252Scope::ImportKind Scope::GetImportKind() const {253if (importKind_) {254return *importKind_;255}256if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) {257if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) {258if (details->isInterface()) {259return ImportKind::None; // default for non-mod-proc interface body260}261}262}263return ImportKind::Default;264}
265
266std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) {267if (!importKind_) {268importKind_ = kind;269return std::nullopt;270}271bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None};272bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All};273// Check C8100 and C898: constraints on multiple IMPORT statements274if (hasNone || hasAll) {275return hasNone276? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US277: "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US;278} else if (kind != *importKind_ &&279(kind != ImportKind::Only && *importKind_ != ImportKind::Only)) {280return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US;281} else {282return std::nullopt;283}284}
285
286void Scope::add_importName(const SourceName &name) {287importNames_.insert(name);288}
289
290// true if name can be imported or host-associated from parent scope.
291bool Scope::CanImport(const SourceName &name) const {292if (IsTopLevel() || parent_->IsTopLevel()) {293return false;294}295switch (GetImportKind()) {296SWITCH_COVERS_ALL_CASES
297case ImportKind::None:298return false;299case ImportKind::All:300case ImportKind::Default:301return true;302case ImportKind::Only:303return importNames_.count(name) > 0;304}305}
306
307void Scope::AddSourceRange(parser::CharBlock source) {308if (source.empty()) {309return;310}311const parser::AllCookedSources &allCookedSources{context_.allCookedSources()};312const parser::CookedSource *cooked{allCookedSources.Find(source)};313if (!cooked) {314CHECK(context_.IsTempName(source.ToString()));315return;316}317for (auto *scope{this}; !scope->IsTopLevel(); scope = &scope->parent()) {318CHECK(scope->sourceRange_.empty() == (scope->cookedSource_ == nullptr));319if (!scope->cookedSource_) {320context_.UpdateScopeIndex(*scope, source);321scope->cookedSource_ = cooked;322scope->sourceRange_ = source;323} else if (scope->cookedSource_ == cooked) {324auto combined{scope->sourceRange()};325combined.ExtendToCover(source);326context_.UpdateScopeIndex(*scope, combined);327scope->sourceRange_ = combined;328} else {329// There's a bug that will be hard to fix; crash informatively330const parser::AllSources &allSources{allCookedSources.allSources()};331const auto describe{[&](parser::CharBlock src) {332if (auto range{allCookedSources.GetProvenanceRange(src)}) {333std::size_t offset;334if (const parser::SourceFile *335file{allSources.GetSourceFile(range->start(), &offset)}) {336return "'"s + file->path() + "' at " + std::to_string(offset) +337" for " + std::to_string(range->size());338} else {339return "(GetSourceFile failed)"s;340}341} else {342return "(GetProvenanceRange failed)"s;343}344}};345std::string scopeDesc{describe(scope->sourceRange_)};346std::string newDesc{describe(source)};347common::die("AddSourceRange would have combined ranges from distinct "348"source files \"%s\" and \"%s\"",349scopeDesc.c_str(), newDesc.c_str());350}351// Note: If the "break;" here were unconditional (or, equivalently, if352// there were no loop at all) then the source ranges of parent scopes353// would not enclose the source ranges of their children. Timing354// shows that it's cheap to maintain this property, with the exceptions355// of top-level scopes and for (sub)modules and their descendant356// submodules.357if (scope->IsSubmodule()) {358break; // Submodules are child scopes but not contained ranges359}360}361}
362
363llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {364os << Scope::EnumToString(scope.kind()) << " scope: ";365if (auto *symbol{scope.symbol()}) {366os << *symbol << ' ';367}368if (scope.derivedTypeSpec_) {369os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';370}371os << scope.children_.size() << " children\n";372for (const auto &pair : scope.symbols_) {373const Symbol &symbol{*pair.second};374os << " " << symbol << '\n';375}376if (!scope.equivalenceSets_.empty()) {377os << " Equivalence Sets:\n";378for (const auto &set : scope.equivalenceSets_) {379os << " ";380for (const auto &object : set) {381os << ' ' << object.AsFortran();382}383os << '\n';384}385}386for (const auto &pair : scope.commonBlocks_) {387const Symbol &symbol{*pair.second};388os << " " << symbol << '\n';389}390return os;391}
392
393bool Scope::IsStmtFunction() const {394return symbol_ && symbol_->test(Symbol::Flag::StmtFunction);395}
396
397template <common::TypeParamAttr... ParamAttr> struct IsTypeParamHelper {398static_assert(sizeof...(ParamAttr) == 0, "must have one or zero template");399static bool IsParam(const Symbol &symbol) {400return symbol.has<TypeParamDetails>();401}402};403
404template <common::TypeParamAttr ParamAttr> struct IsTypeParamHelper<ParamAttr> {405static bool IsParam(const Symbol &symbol) {406if (const auto *typeParam{symbol.detailsIf<TypeParamDetails>()}) {407return typeParam->attr() == ParamAttr;408}409return false;410}411};412
413template <common::TypeParamAttr... ParamAttr>414static bool IsParameterizedDerivedTypeHelper(const Scope &scope) {415if (scope.IsDerivedType()) {416if (const Scope * parent{scope.GetDerivedTypeParent()}) {417if (IsParameterizedDerivedTypeHelper<ParamAttr...>(*parent)) {418return true;419}420}421for (const auto &nameAndSymbolPair : scope) {422if (IsTypeParamHelper<ParamAttr...>::IsParam(*nameAndSymbolPair.second)) {423return true;424}425}426}427return false;428}
429
430bool Scope::IsParameterizedDerivedType() const {431return IsParameterizedDerivedTypeHelper<>(*this);432}
433bool Scope::IsDerivedTypeWithLengthParameter() const {434return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Len>(*this);435}
436bool Scope::IsDerivedTypeWithKindParameter() const {437return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Kind>(*this);438}
439
440const DeclTypeSpec *Scope::FindInstantiatedDerivedType(441const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {442DeclTypeSpec type{category, spec};443if (const auto *result{FindType(type)}) {444return result;445} else if (IsGlobal()) {446return nullptr;447} else {448return parent().FindInstantiatedDerivedType(spec, category);449}450}
451
452const Scope *Scope::GetDerivedTypeParent() const {453if (const Symbol * symbol{GetSymbol()}) {454if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) {455return parent->scope();456}457}458return nullptr;459}
460
461const Scope &Scope::GetDerivedTypeBase() const {462const Scope *child{this};463for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;464parent = child->GetDerivedTypeParent()) {465child = parent;466}467return *child;468}
469
470void Scope::InstantiateDerivedTypes() {471for (DeclTypeSpec &type : declTypeSpecs_) {472if (type.category() == DeclTypeSpec::TypeDerived ||473type.category() == DeclTypeSpec::ClassDerived) {474type.derivedTypeSpec().Instantiate(*this);475}476}477}
478} // namespace Fortran::semantics479