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