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