1 //===-- lib/Semantics/symbol.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/symbol.h" 10 #include "flang/Common/idioms.h" 11 #include "flang/Evaluate/expression.h" 12 #include "flang/Semantics/scope.h" 13 #include "flang/Semantics/semantics.h" 14 #include "flang/Semantics/tools.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include <string> 17 18 namespace Fortran::semantics { 19 20 template <typename T> 21 static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) { 22 if (x) { 23 os << ' ' << label << ':' << *x; 24 } 25 } 26 template <typename T> 27 static void DumpExpr(llvm::raw_ostream &os, const char *label, 28 const std::optional<evaluate::Expr<T>> &x) { 29 if (x) { 30 x->AsFortran(os << ' ' << label << ':'); 31 } 32 } 33 34 static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) { 35 if (x) { 36 os << ' ' << label; 37 } 38 } 39 40 static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) { 41 char sep{' '}; 42 for (const Symbol &elem : list) { 43 os << sep << elem.name(); 44 sep = ','; 45 } 46 } 47 48 static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) { 49 if (const auto *type{symbol.GetType()}) { 50 os << *type << ' '; 51 } 52 } 53 static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) { 54 if (type) { 55 os << ' ' << *type; 56 } 57 } 58 59 template <typename T> 60 static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) { 61 if (!list.empty()) { 62 os << ' ' << label << ':'; 63 char sep{' '}; 64 for (const auto &elem : list) { 65 os << sep << elem; 66 sep = ','; 67 } 68 } 69 } 70 71 const Scope *ModuleDetails::parent() const { 72 return isSubmodule_ && scope_ ? &scope_->parent() : nullptr; 73 } 74 const Scope *ModuleDetails::ancestor() const { 75 return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr; 76 } 77 void ModuleDetails::set_scope(const Scope *scope) { 78 CHECK(!scope_); 79 bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module}; 80 CHECK(isSubmodule_ == scopeIsSubmodule); 81 scope_ = scope; 82 } 83 84 llvm::raw_ostream &operator<<( 85 llvm::raw_ostream &os, const SubprogramDetails &x) { 86 DumpBool(os, "isInterface", x.isInterface_); 87 DumpExpr(os, "bindName", x.bindName_); 88 if (x.result_) { 89 DumpType(os << " result:", x.result()); 90 os << x.result_->name(); 91 if (!x.result_->attrs().empty()) { 92 os << ", " << x.result_->attrs(); 93 } 94 } 95 if (x.entryScope_) { 96 os << " entry"; 97 if (x.entryScope_->symbol()) { 98 os << " in " << x.entryScope_->symbol()->name(); 99 } 100 } 101 char sep{'('}; 102 os << ' '; 103 for (const Symbol *arg : x.dummyArgs_) { 104 os << sep; 105 sep = ','; 106 if (arg) { 107 DumpType(os, *arg); 108 os << arg->name(); 109 } else { 110 os << '*'; 111 } 112 } 113 os << (sep == '(' ? "()" : ")"); 114 return os; 115 } 116 117 void EntityDetails::set_type(const DeclTypeSpec &type) { 118 CHECK(!type_); 119 type_ = &type; 120 } 121 122 void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; } 123 124 void ObjectEntityDetails::set_shape(const ArraySpec &shape) { 125 CHECK(shape_.empty()); 126 for (const auto &shapeSpec : shape) { 127 shape_.push_back(shapeSpec); 128 } 129 } 130 void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) { 131 CHECK(coshape_.empty()); 132 for (const auto &shapeSpec : coshape) { 133 coshape_.push_back(shapeSpec); 134 } 135 } 136 137 ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) { 138 if (type()) { 139 interface_.set_type(*type()); 140 } 141 } 142 143 const Symbol &UseDetails::module() const { 144 // owner is a module so it must have a symbol: 145 return *symbol_->owner().symbol(); 146 } 147 148 UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) { 149 add_occurrence(useDetails.location(), *useDetails.module().scope()); 150 } 151 UseErrorDetails &UseErrorDetails::add_occurrence( 152 const SourceName &location, const Scope &module) { 153 occurrences_.push_back(std::make_pair(location, &module)); 154 return *this; 155 } 156 157 GenericDetails::GenericDetails(const SymbolVector &specificProcs) 158 : specificProcs_{specificProcs} {} 159 160 void GenericDetails::AddSpecificProc( 161 const Symbol &proc, SourceName bindingName) { 162 specificProcs_.push_back(proc); 163 bindingNames_.push_back(bindingName); 164 } 165 void GenericDetails::set_specific(Symbol &specific) { 166 CHECK(!specific_); 167 CHECK(!derivedType_); 168 specific_ = &specific; 169 } 170 void GenericDetails::set_derivedType(Symbol &derivedType) { 171 CHECK(!specific_); 172 CHECK(!derivedType_); 173 derivedType_ = &derivedType; 174 } 175 176 const Symbol *GenericDetails::CheckSpecific() const { 177 return const_cast<GenericDetails *>(this)->CheckSpecific(); 178 } 179 Symbol *GenericDetails::CheckSpecific() { 180 if (specific_) { 181 for (const Symbol &proc : specificProcs_) { 182 if (&proc == specific_) { 183 return nullptr; 184 } 185 } 186 return specific_; 187 } else { 188 return nullptr; 189 } 190 } 191 192 void GenericDetails::CopyFrom(const GenericDetails &from) { 193 if (from.specific_) { 194 CHECK(!specific_ || specific_ == from.specific_); 195 specific_ = from.specific_; 196 } 197 if (from.derivedType_) { 198 CHECK(!derivedType_ || derivedType_ == from.derivedType_); 199 derivedType_ = from.derivedType_; 200 } 201 for (const Symbol &symbol : from.specificProcs_) { 202 if (std::find_if(specificProcs_.begin(), specificProcs_.end(), 203 [&](const Symbol &mySymbol) { return &mySymbol == &symbol; }) == 204 specificProcs_.end()) { 205 specificProcs_.push_back(symbol); 206 } 207 } 208 } 209 210 // The name of the kind of details for this symbol. 211 // This is primarily for debugging. 212 std::string DetailsToString(const Details &details) { 213 return std::visit( 214 common::visitors{ 215 [](const UnknownDetails &) { return "Unknown"; }, 216 [](const MainProgramDetails &) { return "MainProgram"; }, 217 [](const ModuleDetails &) { return "Module"; }, 218 [](const SubprogramDetails &) { return "Subprogram"; }, 219 [](const SubprogramNameDetails &) { return "SubprogramName"; }, 220 [](const EntityDetails &) { return "Entity"; }, 221 [](const ObjectEntityDetails &) { return "ObjectEntity"; }, 222 [](const ProcEntityDetails &) { return "ProcEntity"; }, 223 [](const DerivedTypeDetails &) { return "DerivedType"; }, 224 [](const UseDetails &) { return "Use"; }, 225 [](const UseErrorDetails &) { return "UseError"; }, 226 [](const HostAssocDetails &) { return "HostAssoc"; }, 227 [](const GenericDetails &) { return "Generic"; }, 228 [](const ProcBindingDetails &) { return "ProcBinding"; }, 229 [](const NamelistDetails &) { return "Namelist"; }, 230 [](const CommonBlockDetails &) { return "CommonBlockDetails"; }, 231 [](const FinalProcDetails &) { return "FinalProc"; }, 232 [](const TypeParamDetails &) { return "TypeParam"; }, 233 [](const MiscDetails &) { return "Misc"; }, 234 [](const AssocEntityDetails &) { return "AssocEntity"; }, 235 }, 236 details); 237 } 238 239 const std::string Symbol::GetDetailsName() const { 240 return DetailsToString(details_); 241 } 242 243 void Symbol::set_details(Details &&details) { 244 CHECK(CanReplaceDetails(details)); 245 details_ = std::move(details); 246 } 247 248 bool Symbol::CanReplaceDetails(const Details &details) const { 249 if (has<UnknownDetails>()) { 250 return true; // can always replace UnknownDetails 251 } else { 252 return std::visit( 253 common::visitors{ 254 [](const UseErrorDetails &) { return true; }, 255 [&](const ObjectEntityDetails &) { return has<EntityDetails>(); }, 256 [&](const ProcEntityDetails &) { return has<EntityDetails>(); }, 257 [&](const SubprogramDetails &) { 258 return has<SubprogramNameDetails>() || has<EntityDetails>(); 259 }, 260 [&](const DerivedTypeDetails &) { 261 auto *derived{detailsIf<DerivedTypeDetails>()}; 262 return derived && derived->isForwardReferenced(); 263 }, 264 [](const auto &) { return false; }, 265 }, 266 details); 267 } 268 } 269 270 // Usually a symbol's name is the first occurrence in the source, but sometimes 271 // we want to replace it with one at a different location (but same characters). 272 void Symbol::ReplaceName(const SourceName &name) { 273 CHECK(name == name_); 274 name_ = name; 275 } 276 277 void Symbol::SetType(const DeclTypeSpec &type) { 278 std::visit(common::visitors{ 279 [&](EntityDetails &x) { x.set_type(type); }, 280 [&](ObjectEntityDetails &x) { x.set_type(type); }, 281 [&](AssocEntityDetails &x) { x.set_type(type); }, 282 [&](ProcEntityDetails &x) { x.interface().set_type(type); }, 283 [&](TypeParamDetails &x) { x.set_type(type); }, 284 [](auto &) {}, 285 }, 286 details_); 287 } 288 289 bool Symbol::IsDummy() const { 290 return std::visit( 291 common::visitors{[](const EntityDetails &x) { return x.isDummy(); }, 292 [](const ObjectEntityDetails &x) { return x.isDummy(); }, 293 [](const ProcEntityDetails &x) { return x.isDummy(); }, 294 [](const HostAssocDetails &x) { return x.symbol().IsDummy(); }, 295 [](const auto &) { return false; }}, 296 details_); 297 } 298 299 bool Symbol::IsFuncResult() const { 300 return std::visit( 301 common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); }, 302 [](const ObjectEntityDetails &x) { return x.isFuncResult(); }, 303 [](const ProcEntityDetails &x) { return x.isFuncResult(); }, 304 [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); }, 305 [](const auto &) { return false; }}, 306 details_); 307 } 308 309 bool Symbol::IsObjectArray() const { 310 const auto *details{std::get_if<ObjectEntityDetails>(&details_)}; 311 return details && details->IsArray(); 312 } 313 314 bool Symbol::IsSubprogram() const { 315 return std::visit( 316 common::visitors{ 317 [](const SubprogramDetails &) { return true; }, 318 [](const SubprogramNameDetails &) { return true; }, 319 [](const GenericDetails &) { return true; }, 320 [](const UseDetails &x) { return x.symbol().IsSubprogram(); }, 321 [](const auto &) { return false; }, 322 }, 323 details_); 324 } 325 326 bool Symbol::IsFromModFile() const { 327 return test(Flag::ModFile) || 328 (!owner_->IsGlobal() && owner_->symbol()->IsFromModFile()); 329 } 330 331 ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d) 332 : EntityDetails(d) {} 333 334 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) { 335 DumpBool(os, "dummy", x.isDummy()); 336 DumpBool(os, "funcResult", x.isFuncResult()); 337 if (x.type()) { 338 os << " type: " << *x.type(); 339 } 340 DumpExpr(os, "bindName", x.bindName_); 341 return os; 342 } 343 344 llvm::raw_ostream &operator<<( 345 llvm::raw_ostream &os, const ObjectEntityDetails &x) { 346 os << *static_cast<const EntityDetails *>(&x); 347 DumpList(os, "shape", x.shape()); 348 DumpList(os, "coshape", x.coshape()); 349 DumpExpr(os, "init", x.init_); 350 return os; 351 } 352 353 llvm::raw_ostream &operator<<( 354 llvm::raw_ostream &os, const AssocEntityDetails &x) { 355 os << *static_cast<const EntityDetails *>(&x); 356 DumpExpr(os, "expr", x.expr()); 357 return os; 358 } 359 360 llvm::raw_ostream &operator<<( 361 llvm::raw_ostream &os, const ProcEntityDetails &x) { 362 if (auto *symbol{x.interface_.symbol()}) { 363 os << ' ' << symbol->name(); 364 } else { 365 DumpType(os, x.interface_.type()); 366 } 367 DumpExpr(os, "bindName", x.bindName()); 368 DumpOptional(os, "passName", x.passName()); 369 if (x.init()) { 370 if (const Symbol * target{*x.init()}) { 371 os << " => " << target->name(); 372 } else { 373 os << " => NULL()"; 374 } 375 } 376 return os; 377 } 378 379 llvm::raw_ostream &operator<<( 380 llvm::raw_ostream &os, const DerivedTypeDetails &x) { 381 DumpBool(os, "sequence", x.sequence_); 382 DumpList(os, "components", x.componentNames_); 383 return os; 384 } 385 386 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) { 387 os << DetailsToString(details); 388 std::visit( 389 common::visitors{ 390 [&](const UnknownDetails &) {}, 391 [&](const MainProgramDetails &) {}, 392 [&](const ModuleDetails &x) { 393 if (x.isSubmodule()) { 394 os << " ("; 395 if (x.ancestor()) { 396 auto ancestor{x.ancestor()->GetName().value()}; 397 os << ancestor; 398 if (x.parent()) { 399 auto parent{x.parent()->GetName().value()}; 400 if (ancestor != parent) { 401 os << ':' << parent; 402 } 403 } 404 } 405 os << ")"; 406 } 407 }, 408 [&](const SubprogramNameDetails &x) { 409 os << ' ' << EnumToString(x.kind()); 410 }, 411 [&](const UseDetails &x) { 412 os << " from " << x.symbol().name() << " in " << x.module().name(); 413 }, 414 [&](const UseErrorDetails &x) { 415 os << " uses:"; 416 for (const auto &[location, module] : x.occurrences()) { 417 os << " from " << module->GetName().value() << " at " << location; 418 } 419 }, 420 [](const HostAssocDetails &) {}, 421 [&](const GenericDetails &x) { 422 os << ' ' << x.kind().ToString(); 423 DumpBool(os, "(specific)", x.specific() != nullptr); 424 DumpBool(os, "(derivedType)", x.derivedType() != nullptr); 425 os << " procs:"; 426 DumpSymbolVector(os, x.specificProcs()); 427 }, 428 [&](const ProcBindingDetails &x) { 429 os << " => " << x.symbol().name(); 430 DumpOptional(os, "passName", x.passName()); 431 }, 432 [&](const NamelistDetails &x) { 433 os << ':'; 434 DumpSymbolVector(os, x.objects()); 435 }, 436 [&](const CommonBlockDetails &x) { 437 os << ':'; 438 for (const Symbol &object : x.objects()) { 439 os << ' ' << object.name(); 440 } 441 }, 442 [&](const FinalProcDetails &) {}, 443 [&](const TypeParamDetails &x) { 444 DumpOptional(os, "type", x.type()); 445 os << ' ' << common::EnumToString(x.attr()); 446 DumpExpr(os, "init", x.init()); 447 }, 448 [&](const MiscDetails &x) { 449 os << ' ' << MiscDetails::EnumToString(x.kind()); 450 }, 451 [&](const auto &x) { os << x; }, 452 }, 453 details); 454 return os; 455 } 456 457 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) { 458 return o << Symbol::EnumToString(flag); 459 } 460 461 llvm::raw_ostream &operator<<( 462 llvm::raw_ostream &o, const Symbol::Flags &flags) { 463 std::size_t n{flags.count()}; 464 std::size_t seen{0}; 465 for (std::size_t j{0}; seen < n; ++j) { 466 Symbol::Flag flag{static_cast<Symbol::Flag>(j)}; 467 if (flags.test(flag)) { 468 if (seen++ > 0) { 469 o << ", "; 470 } 471 o << flag; 472 } 473 } 474 return o; 475 } 476 477 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) { 478 os << symbol.name(); 479 if (!symbol.attrs().empty()) { 480 os << ", " << symbol.attrs(); 481 } 482 if (!symbol.flags().empty()) { 483 os << " (" << symbol.flags() << ')'; 484 } 485 os << ": " << symbol.details_; 486 return os; 487 } 488 489 // Output a unique name for a scope by qualifying it with the names of 490 // parent scopes. For scopes without corresponding symbols, use the kind 491 // with an index (e.g. Block1, Block2, etc.). 492 static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) { 493 if (!scope.IsGlobal()) { 494 DumpUniqueName(os, scope.parent()); 495 os << '/'; 496 if (auto *scopeSymbol{scope.symbol()}; 497 scopeSymbol && !scopeSymbol->name().empty()) { 498 os << scopeSymbol->name(); 499 } else { 500 int index{1}; 501 for (auto &child : scope.parent().children()) { 502 if (child == scope) { 503 break; 504 } 505 if (child.kind() == scope.kind()) { 506 ++index; 507 } 508 } 509 os << Scope::EnumToString(scope.kind()) << index; 510 } 511 } 512 } 513 514 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the 515 // format should be reasonably stable. 516 llvm::raw_ostream &DumpForUnparse( 517 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) { 518 DumpUniqueName(os, symbol.owner()); 519 os << '/' << symbol.name(); 520 if (isDef) { 521 if (!symbol.attrs().empty()) { 522 os << ' ' << symbol.attrs(); 523 } 524 if (!symbol.flags().empty()) { 525 os << " (" << symbol.flags() << ')'; 526 } 527 os << ' ' << symbol.GetDetailsName(); 528 DumpType(os, symbol.GetType()); 529 } 530 return os; 531 } 532 533 const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const { 534 if (const Symbol * parentComponent{GetParentComponent(scope)}) { 535 const auto &object{parentComponent->get<ObjectEntityDetails>()}; 536 return &object.type()->derivedTypeSpec(); 537 } else { 538 return nullptr; 539 } 540 } 541 542 const Symbol *Symbol::GetParentComponent(const Scope *scope) const { 543 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) { 544 if (!scope) { 545 scope = scope_; 546 } 547 return dtDetails->GetParentComponent(DEREF(scope)); 548 } else { 549 return nullptr; 550 } 551 } 552 553 // Utility routine for InstantiateComponent(): applies type 554 // parameter values to an intrinsic type spec. 555 static const DeclTypeSpec &InstantiateIntrinsicType(Scope &scope, 556 const DeclTypeSpec &spec, SemanticsContext &semanticsContext) { 557 const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())}; 558 if (evaluate::ToInt64(intrinsic.kind())) { 559 return spec; // KIND is already a known constant 560 } 561 // The expression was not originally constant, but now it must be so 562 // in the context of a parameterized derived type instantiation. 563 KindExpr copy{intrinsic.kind()}; 564 evaluate::FoldingContext &foldingContext{semanticsContext.foldingContext()}; 565 copy = evaluate::Fold(foldingContext, std::move(copy)); 566 int kind{semanticsContext.GetDefaultKind(intrinsic.category())}; 567 if (auto value{evaluate::ToInt64(copy)}) { 568 if (evaluate::IsValidKindOfIntrinsicType(intrinsic.category(), *value)) { 569 kind = *value; 570 } else { 571 foldingContext.messages().Say( 572 "KIND parameter value (%jd) of intrinsic type %s " 573 "did not resolve to a supported value"_err_en_US, 574 *value, 575 parser::ToUpperCaseLetters( 576 common::EnumToString(intrinsic.category()))); 577 } 578 } 579 switch (spec.category()) { 580 case DeclTypeSpec::Numeric: 581 return scope.MakeNumericType(intrinsic.category(), KindExpr{kind}); 582 case DeclTypeSpec::Logical: // 583 return scope.MakeLogicalType(KindExpr{kind}); 584 case DeclTypeSpec::Character: 585 return scope.MakeCharacterType( 586 ParamValue{spec.characterTypeSpec().length()}, KindExpr{kind}); 587 default: 588 CRASH_NO_CASE; 589 } 590 } 591 592 Symbol &Symbol::InstantiateComponent( 593 Scope &scope, SemanticsContext &context) const { 594 auto &foldingContext{context.foldingContext()}; 595 auto pair{scope.try_emplace(name(), attrs())}; 596 Symbol &result{*pair.first->second}; 597 if (!pair.second) { 598 // Symbol was already present in the scope, which can only happen 599 // in the case of type parameters. 600 CHECK(has<TypeParamDetails>()); 601 return result; 602 } 603 result.attrs() = attrs(); 604 result.flags() = flags(); 605 result.set_details(common::Clone(details())); 606 if (auto *details{result.detailsIf<ObjectEntityDetails>()}) { 607 if (DeclTypeSpec * origType{result.GetType()}) { 608 if (const DerivedTypeSpec * derived{origType->AsDerived()}) { 609 DerivedTypeSpec newSpec{*derived}; 610 newSpec.CookParameters(foldingContext); // enables AddParamValue() 611 if (test(Symbol::Flag::ParentComp)) { 612 // Forward any explicit type parameter values from the 613 // derived type spec under instantiation that define type parameters 614 // of the parent component to the derived type spec of the 615 // parent component. 616 const DerivedTypeSpec &instanceSpec{ 617 DEREF(foldingContext.pdtInstance())}; 618 for (const auto &[name, value] : instanceSpec.parameters()) { 619 if (scope.find(name) == scope.end()) { 620 newSpec.AddParamValue(name, ParamValue{value}); 621 } 622 } 623 } 624 details->ReplaceType(FindOrInstantiateDerivedType( 625 scope, std::move(newSpec), context, origType->category())); 626 } else if (origType->AsIntrinsic()) { 627 details->ReplaceType( 628 InstantiateIntrinsicType(scope, *origType, context)); 629 } else if (origType->category() != DeclTypeSpec::ClassStar) { 630 DIE("instantiated component has type that is " 631 "neither intrinsic, derived, nor CLASS(*)"); 632 } 633 } 634 details->set_init( 635 evaluate::Fold(foldingContext, std::move(details->init()))); 636 for (ShapeSpec &dim : details->shape()) { 637 if (dim.lbound().isExplicit()) { 638 dim.lbound().SetExplicit( 639 Fold(foldingContext, std::move(dim.lbound().GetExplicit()))); 640 } 641 if (dim.ubound().isExplicit()) { 642 dim.ubound().SetExplicit( 643 Fold(foldingContext, std::move(dim.ubound().GetExplicit()))); 644 } 645 } 646 for (ShapeSpec &dim : details->coshape()) { 647 if (dim.lbound().isExplicit()) { 648 dim.lbound().SetExplicit( 649 Fold(foldingContext, std::move(dim.lbound().GetExplicit()))); 650 } 651 if (dim.ubound().isExplicit()) { 652 dim.ubound().SetExplicit( 653 Fold(foldingContext, std::move(dim.ubound().GetExplicit()))); 654 } 655 } 656 } else if (!attrs_.test(Attr::NOPASS)) { 657 std::visit( 658 [&result](const auto &x) { 659 using Ty = std::decay_t<decltype(x)>; 660 if constexpr (std::is_base_of_v<WithPassArg, Ty>) { 661 if (auto passName{x.passName()}) { 662 result.get<Ty>().set_passName(*passName); 663 } 664 } 665 }, 666 details_); 667 } 668 return result; 669 } 670 671 void DerivedTypeDetails::add_component(const Symbol &symbol) { 672 if (symbol.test(Symbol::Flag::ParentComp)) { 673 CHECK(componentNames_.empty()); 674 } 675 componentNames_.push_back(symbol.name()); 676 } 677 678 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const { 679 if (auto extends{GetParentComponentName()}) { 680 if (auto iter{scope.find(*extends)}; iter != scope.cend()) { 681 if (const Symbol & symbol{*iter->second}; 682 symbol.test(Symbol::Flag::ParentComp)) { 683 return &symbol; 684 } 685 } 686 } 687 return nullptr; 688 } 689 690 void TypeParamDetails::set_type(const DeclTypeSpec &type) { 691 CHECK(!type_); 692 type_ = &type; 693 } 694 695 bool GenericKind::IsIntrinsicOperator() const { 696 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() || 697 Has<common::NumericOperator>() || Has<common::RelationalOperator>(); 698 } 699 700 bool GenericKind::IsOperator() const { 701 return IsDefinedOperator() || IsIntrinsicOperator(); 702 } 703 704 std::string GenericKind::ToString() const { 705 return std::visit( 706 common::visitors { 707 [](const OtherKind &x) { return EnumToString(x); }, 708 [](const DefinedIo &x) { return EnumToString(x); }, 709 #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2 710 [](const common::NumericOperator &x) { 711 return common::EnumToString(x); 712 }, 713 [](const common::LogicalOperator &x) { 714 return common::EnumToString(x); 715 }, 716 [](const common::RelationalOperator &x) { 717 return common::EnumToString(x); 718 }, 719 #else 720 [](const auto &x) { return common::EnumToString(x); }, 721 #endif 722 }, 723 u); 724 } 725 726 bool GenericKind::Is(GenericKind::OtherKind x) const { 727 const OtherKind *y{std::get_if<OtherKind>(&u)}; 728 return y && *y == x; 729 } 730 731 } // namespace Fortran::semantics 732