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/symbol.h" 12 #include "flang/Semantics/type.h" 13 #include <algorithm> 14 #include <memory> 15 #include <sstream> 16 17 namespace Fortran::semantics { 18 19 Symbols<1024> Scope::allSymbols; 20 21 bool EquivalenceObject::operator==(const EquivalenceObject &that) const { 22 return symbol == that.symbol && subscripts == that.subscripts && 23 substringStart == that.substringStart; 24 } 25 26 bool EquivalenceObject::operator<(const EquivalenceObject &that) const { 27 return &symbol < &that.symbol || 28 (&symbol == &that.symbol && 29 (subscripts < that.subscripts || 30 (subscripts == that.subscripts && 31 substringStart < that.substringStart))); 32 } 33 34 std::string EquivalenceObject::AsFortran() const { 35 std::stringstream ss; 36 ss << symbol.name().ToString(); 37 if (!subscripts.empty()) { 38 char sep{'('}; 39 for (auto subscript : subscripts) { 40 ss << sep << subscript; 41 sep = ','; 42 } 43 ss << ')'; 44 } 45 if (substringStart) { 46 ss << '(' << *substringStart << ":)"; 47 } 48 return ss.str(); 49 } 50 51 bool Scope::IsModule() const { 52 return kind_ == Kind::Module && !symbol_->get<ModuleDetails>().isSubmodule(); 53 } 54 55 Scope &Scope::MakeScope(Kind kind, Symbol *symbol) { 56 return children_.emplace_back(*this, kind, symbol); 57 } 58 59 Scope::iterator Scope::find(const SourceName &name) { 60 return symbols_.find(name); 61 } 62 Scope::size_type Scope::erase(const SourceName &name) { 63 auto it{symbols_.find(name)}; 64 if (it != end()) { 65 symbols_.erase(it); 66 return 1; 67 } else { 68 return 0; 69 } 70 } 71 Symbol *Scope::FindSymbol(const SourceName &name) const { 72 auto it{find(name)}; 73 if (it != end()) { 74 return &*it->second; 75 } else if (CanImport(name)) { 76 return parent_.FindSymbol(name); 77 } else { 78 return nullptr; 79 } 80 } 81 82 Symbol *Scope::FindComponent(SourceName name) const { 83 CHECK(IsDerivedType()); 84 auto found{find(name)}; 85 if (found != end()) { 86 return &*found->second; 87 } else if (const Scope * parent{GetDerivedTypeParent()}) { 88 return parent->FindComponent(name); 89 } else { 90 return nullptr; 91 } 92 } 93 94 std::optional<SourceName> Scope::GetName() const { 95 if (const auto *sym{GetSymbol()}) { 96 return sym->name(); 97 } else { 98 return std::nullopt; 99 } 100 } 101 102 bool Scope::Contains(const Scope &that) const { 103 for (const Scope *scope{&that};; scope = &scope->parent()) { 104 if (*scope == *this) { 105 return true; 106 } 107 if (scope->IsGlobal()) { 108 return false; 109 } 110 } 111 } 112 113 const std::list<EquivalenceSet> &Scope::equivalenceSets() const { 114 return equivalenceSets_; 115 } 116 void Scope::add_equivalenceSet(EquivalenceSet &&set) { 117 equivalenceSets_.emplace_back(std::move(set)); 118 } 119 120 void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) { 121 CHECK(pointer.test(Symbol::Flag::CrayPointer)); 122 crayPointers_.emplace(name, pointer); 123 } 124 125 Symbol &Scope::MakeCommonBlock(const SourceName &name) { 126 const auto it{commonBlocks_.find(name)}; 127 if (it != commonBlocks_.end()) { 128 return *it->second; 129 } else { 130 Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})}; 131 commonBlocks_.emplace(name, symbol); 132 return symbol; 133 } 134 } 135 Symbol *Scope::FindCommonBlock(const SourceName &name) { 136 const auto it{commonBlocks_.find(name)}; 137 return it != commonBlocks_.end() ? &*it->second : nullptr; 138 } 139 140 Scope *Scope::FindSubmodule(const SourceName &name) const { 141 auto it{submodules_.find(name)}; 142 if (it == submodules_.end()) { 143 return nullptr; 144 } else { 145 return &*it->second; 146 } 147 } 148 bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) { 149 return submodules_.emplace(name, submodule).second; 150 } 151 152 const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const { 153 auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)}; 154 return it != declTypeSpecs_.end() ? &*it : nullptr; 155 } 156 157 const DeclTypeSpec &Scope::MakeNumericType( 158 TypeCategory category, KindExpr &&kind) { 159 return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)}); 160 } 161 const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) { 162 return MakeLengthlessType(LogicalTypeSpec{std::move(kind)}); 163 } 164 const DeclTypeSpec &Scope::MakeTypeStarType() { 165 return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar}); 166 } 167 const DeclTypeSpec &Scope::MakeClassStarType() { 168 return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar}); 169 } 170 // Types that can't have length parameters can be reused without having to 171 // compare length expressions. They are stored in the global scope. 172 const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) { 173 const auto *found{FindType(type)}; 174 return found ? *found : declTypeSpecs_.emplace_back(std::move(type)); 175 } 176 177 const DeclTypeSpec &Scope::MakeCharacterType( 178 ParamValue &&length, KindExpr &&kind) { 179 return declTypeSpecs_.emplace_back( 180 CharacterTypeSpec{std::move(length), std::move(kind)}); 181 } 182 183 DeclTypeSpec &Scope::MakeDerivedType( 184 DeclTypeSpec::Category category, DerivedTypeSpec &&spec) { 185 return declTypeSpecs_.emplace_back(category, std::move(spec)); 186 } 187 188 void Scope::set_chars(parser::CookedSource &cooked) { 189 CHECK(kind_ == Kind::Module); 190 CHECK(parent_.IsGlobal() || parent_.IsModuleFile()); 191 CHECK(DEREF(symbol_).test(Symbol::Flag::ModFile)); 192 // TODO: Preserve the CookedSource rather than acquiring its string. 193 chars_ = cooked.AcquireData(); 194 } 195 196 Scope::ImportKind Scope::GetImportKind() const { 197 if (importKind_) { 198 return *importKind_; 199 } 200 if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) { 201 if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) { 202 if (details->isInterface()) { 203 return ImportKind::None; // default for non-mod-proc interface body 204 } 205 } 206 } 207 return ImportKind::Default; 208 } 209 210 std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) { 211 if (!importKind_) { 212 importKind_ = kind; 213 return std::nullopt; 214 } 215 bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None}; 216 bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All}; 217 // Check C8100 and C898: constraints on multiple IMPORT statements 218 if (hasNone || hasAll) { 219 return hasNone 220 ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US 221 : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US; 222 } else if (kind != *importKind_ && 223 (kind != ImportKind::Only || kind != ImportKind::Only)) { 224 return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US; 225 } else { 226 return std::nullopt; 227 } 228 } 229 230 void Scope::add_importName(const SourceName &name) { 231 importNames_.insert(name); 232 } 233 234 // true if name can be imported or host-associated from parent scope. 235 bool Scope::CanImport(const SourceName &name) const { 236 if (IsGlobal() || parent_.IsGlobal()) { 237 return false; 238 } 239 switch (GetImportKind()) { 240 SWITCH_COVERS_ALL_CASES 241 case ImportKind::None: return false; 242 case ImportKind::All: 243 case ImportKind::Default: return true; 244 case ImportKind::Only: return importNames_.count(name) > 0; 245 } 246 } 247 248 const Scope *Scope::FindScope(parser::CharBlock source) const { 249 return const_cast<Scope *>(this)->FindScope(source); 250 } 251 252 Scope *Scope::FindScope(parser::CharBlock source) { 253 bool isContained{sourceRange_.Contains(source)}; 254 if (!isContained && !IsGlobal() && !IsModuleFile()) { 255 return nullptr; 256 } 257 for (auto &child : children_) { 258 if (auto *scope{child.FindScope(source)}) { 259 return scope; 260 } 261 } 262 return isContained ? this : nullptr; 263 } 264 265 void Scope::AddSourceRange(const parser::CharBlock &source) { 266 for (auto *scope = this; !scope->IsGlobal(); scope = &scope->parent()) { 267 scope->sourceRange_.ExtendToCover(source); 268 } 269 } 270 271 std::ostream &operator<<(std::ostream &os, const Scope &scope) { 272 os << Scope::EnumToString(scope.kind()) << " scope: "; 273 if (auto *symbol{scope.symbol()}) { 274 os << *symbol << ' '; 275 } 276 os << scope.children_.size() << " children\n"; 277 for (const auto &pair : scope.symbols_) { 278 const Symbol &symbol{*pair.second}; 279 os << " " << symbol << '\n'; 280 } 281 if (!scope.equivalenceSets_.empty()) { 282 os << " Equivalence Sets:\n"; 283 for (const auto &set : scope.equivalenceSets_) { 284 os << " "; 285 for (const auto &object : set) { 286 os << ' ' << object.AsFortran(); 287 } 288 os << '\n'; 289 } 290 } 291 for (const auto &pair : scope.commonBlocks_) { 292 const Symbol &symbol{*pair.second}; 293 os << " " << symbol << '\n'; 294 } 295 return os; 296 } 297 298 bool Scope::IsParameterizedDerivedType() const { 299 if (!IsDerivedType()) { 300 return false; 301 } 302 if (const Scope * parent{GetDerivedTypeParent()}) { 303 if (parent->IsParameterizedDerivedType()) { 304 return true; 305 } 306 } 307 for (const auto &pair : symbols_) { 308 if (pair.second->has<TypeParamDetails>()) { 309 return true; 310 } 311 } 312 return false; 313 } 314 315 const DeclTypeSpec *Scope::FindInstantiatedDerivedType( 316 const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const { 317 DeclTypeSpec type{category, spec}; 318 if (const auto *result{FindType(type)}) { 319 return result; 320 } else if (IsGlobal()) { 321 return nullptr; 322 } else { 323 return parent().FindInstantiatedDerivedType(spec, category); 324 } 325 } 326 327 const Symbol *Scope::GetSymbol() const { 328 if (symbol_) { 329 return symbol_; 330 } 331 if (derivedTypeSpec_) { 332 return &derivedTypeSpec_->typeSymbol(); 333 } 334 return nullptr; 335 } 336 337 const Scope *Scope::GetDerivedTypeParent() const { 338 if (const Symbol * symbol{GetSymbol()}) { 339 if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) { 340 return parent->scope(); 341 } 342 } 343 return nullptr; 344 } 345 346 void Scope::InstantiateDerivedTypes(SemanticsContext &context) { 347 for (DeclTypeSpec &type : declTypeSpecs_) { 348 if (type.category() == DeclTypeSpec::TypeDerived || 349 type.category() == DeclTypeSpec::ClassDerived) { 350 type.derivedTypeSpec().Instantiate(*this, context); 351 } 352 } 353 } 354 } 355