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