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 AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
123 void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
124 
125 void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
126   CHECK(shape_.empty());
127   for (const auto &shapeSpec : shape) {
128     shape_.push_back(shapeSpec);
129   }
130 }
131 void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
132   CHECK(coshape_.empty());
133   for (const auto &shapeSpec : coshape) {
134     coshape_.push_back(shapeSpec);
135   }
136 }
137 
138 ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
139   if (type()) {
140     interface_.set_type(*type());
141   }
142 }
143 
144 UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
145   add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope());
146 }
147 UseErrorDetails &UseErrorDetails::add_occurrence(
148     const SourceName &location, const Scope &module) {
149   occurrences_.push_back(std::make_pair(location, &module));
150   return *this;
151 }
152 
153 void GenericDetails::AddSpecificProc(
154     const Symbol &proc, SourceName bindingName) {
155   specificProcs_.push_back(proc);
156   bindingNames_.push_back(bindingName);
157 }
158 void GenericDetails::set_specific(Symbol &specific) {
159   CHECK(!specific_);
160   CHECK(!derivedType_);
161   specific_ = &specific;
162 }
163 void GenericDetails::set_derivedType(Symbol &derivedType) {
164   CHECK(!specific_);
165   CHECK(!derivedType_);
166   derivedType_ = &derivedType;
167 }
168 
169 const Symbol *GenericDetails::CheckSpecific() const {
170   return const_cast<GenericDetails *>(this)->CheckSpecific();
171 }
172 Symbol *GenericDetails::CheckSpecific() {
173   if (specific_) {
174     for (const Symbol &proc : specificProcs_) {
175       if (&proc == specific_) {
176         return nullptr;
177       }
178     }
179     return specific_;
180   } else {
181     return nullptr;
182   }
183 }
184 
185 void GenericDetails::CopyFrom(const GenericDetails &from) {
186   CHECK(specificProcs_.size() == bindingNames_.size());
187   CHECK(from.specificProcs_.size() == from.bindingNames_.size());
188   if (from.specific_) {
189     CHECK(!specific_ || specific_ == from.specific_);
190     specific_ = from.specific_;
191   }
192   if (from.derivedType_) {
193     CHECK(!derivedType_ || derivedType_ == from.derivedType_);
194     derivedType_ = from.derivedType_;
195   }
196   for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
197     if (std::find_if(specificProcs_.begin(), specificProcs_.end(),
198             [&](const Symbol &mySymbol) {
199               return &mySymbol == &*from.specificProcs_[i];
200             }) == specificProcs_.end()) {
201       specificProcs_.push_back(from.specificProcs_[i]);
202       bindingNames_.push_back(from.bindingNames_[i]);
203     }
204   }
205 }
206 
207 // The name of the kind of details for this symbol.
208 // This is primarily for debugging.
209 std::string DetailsToString(const Details &details) {
210   return std::visit(
211       common::visitors{
212           [](const UnknownDetails &) { return "Unknown"; },
213           [](const MainProgramDetails &) { return "MainProgram"; },
214           [](const ModuleDetails &) { return "Module"; },
215           [](const SubprogramDetails &) { return "Subprogram"; },
216           [](const SubprogramNameDetails &) { return "SubprogramName"; },
217           [](const EntityDetails &) { return "Entity"; },
218           [](const ObjectEntityDetails &) { return "ObjectEntity"; },
219           [](const ProcEntityDetails &) { return "ProcEntity"; },
220           [](const DerivedTypeDetails &) { return "DerivedType"; },
221           [](const UseDetails &) { return "Use"; },
222           [](const UseErrorDetails &) { return "UseError"; },
223           [](const HostAssocDetails &) { return "HostAssoc"; },
224           [](const GenericDetails &) { return "Generic"; },
225           [](const ProcBindingDetails &) { return "ProcBinding"; },
226           [](const NamelistDetails &) { return "Namelist"; },
227           [](const CommonBlockDetails &) { return "CommonBlockDetails"; },
228           [](const FinalProcDetails &) { return "FinalProc"; },
229           [](const TypeParamDetails &) { return "TypeParam"; },
230           [](const MiscDetails &) { return "Misc"; },
231           [](const AssocEntityDetails &) { return "AssocEntity"; },
232       },
233       details);
234 }
235 
236 const std::string Symbol::GetDetailsName() const {
237   return DetailsToString(details_);
238 }
239 
240 void Symbol::set_details(Details &&details) {
241   CHECK(CanReplaceDetails(details));
242   details_ = std::move(details);
243 }
244 
245 bool Symbol::CanReplaceDetails(const Details &details) const {
246   if (has<UnknownDetails>()) {
247     return true; // can always replace UnknownDetails
248   } else {
249     return std::visit(
250         common::visitors{
251             [](const UseErrorDetails &) { return true; },
252             [&](const ObjectEntityDetails &) { return has<EntityDetails>(); },
253             [&](const ProcEntityDetails &) { return has<EntityDetails>(); },
254             [&](const SubprogramDetails &) {
255               return has<SubprogramNameDetails>() || has<EntityDetails>();
256             },
257             [&](const DerivedTypeDetails &) {
258               auto *derived{detailsIf<DerivedTypeDetails>()};
259               return derived && derived->isForwardReferenced();
260             },
261             [](const auto &) { return false; },
262         },
263         details);
264   }
265 }
266 
267 // Usually a symbol's name is the first occurrence in the source, but sometimes
268 // we want to replace it with one at a different location (but same characters).
269 void Symbol::ReplaceName(const SourceName &name) {
270   CHECK(name == name_);
271   name_ = name;
272 }
273 
274 void Symbol::SetType(const DeclTypeSpec &type) {
275   std::visit(common::visitors{
276                  [&](EntityDetails &x) { x.set_type(type); },
277                  [&](ObjectEntityDetails &x) { x.set_type(type); },
278                  [&](AssocEntityDetails &x) { x.set_type(type); },
279                  [&](ProcEntityDetails &x) { x.interface().set_type(type); },
280                  [&](TypeParamDetails &x) { x.set_type(type); },
281                  [](auto &) {},
282              },
283       details_);
284 }
285 
286 bool Symbol::IsFuncResult() const {
287   return std::visit(
288       common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
289           [](const ObjectEntityDetails &x) { return x.isFuncResult(); },
290           [](const ProcEntityDetails &x) { return x.isFuncResult(); },
291           [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
292           [](const auto &) { return false; }},
293       details_);
294 }
295 
296 bool Symbol::IsObjectArray() const {
297   const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
298   return details && details->IsArray();
299 }
300 
301 bool Symbol::IsSubprogram() const {
302   return std::visit(
303       common::visitors{
304           [](const SubprogramDetails &) { return true; },
305           [](const SubprogramNameDetails &) { return true; },
306           [](const GenericDetails &) { return true; },
307           [](const UseDetails &x) { return x.symbol().IsSubprogram(); },
308           [](const auto &) { return false; },
309       },
310       details_);
311 }
312 
313 bool Symbol::IsFromModFile() const {
314   return test(Flag::ModFile) ||
315       (!owner_->IsGlobal() && owner_->symbol()->IsFromModFile());
316 }
317 
318 ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
319     : EntityDetails(d) {}
320 
321 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
322   DumpBool(os, "dummy", x.isDummy());
323   DumpBool(os, "funcResult", x.isFuncResult());
324   if (x.type()) {
325     os << " type: " << *x.type();
326   }
327   DumpExpr(os, "bindName", x.bindName_);
328   return os;
329 }
330 
331 llvm::raw_ostream &operator<<(
332     llvm::raw_ostream &os, const ObjectEntityDetails &x) {
333   os << *static_cast<const EntityDetails *>(&x);
334   DumpList(os, "shape", x.shape());
335   DumpList(os, "coshape", x.coshape());
336   DumpExpr(os, "init", x.init_);
337   return os;
338 }
339 
340 llvm::raw_ostream &operator<<(
341     llvm::raw_ostream &os, const AssocEntityDetails &x) {
342   os << *static_cast<const EntityDetails *>(&x);
343   if (auto assocRank{x.rank()}) {
344     os << " rank: " << *assocRank;
345   }
346   DumpExpr(os, "expr", x.expr());
347   return os;
348 }
349 
350 llvm::raw_ostream &operator<<(
351     llvm::raw_ostream &os, const ProcEntityDetails &x) {
352   if (auto *symbol{x.interface_.symbol()}) {
353     os << ' ' << symbol->name();
354   } else {
355     DumpType(os, x.interface_.type());
356   }
357   DumpExpr(os, "bindName", x.bindName());
358   DumpOptional(os, "passName", x.passName());
359   if (x.init()) {
360     if (const Symbol * target{*x.init()}) {
361       os << " => " << target->name();
362     } else {
363       os << " => NULL()";
364     }
365   }
366   return os;
367 }
368 
369 llvm::raw_ostream &operator<<(
370     llvm::raw_ostream &os, const DerivedTypeDetails &x) {
371   DumpBool(os, "sequence", x.sequence_);
372   DumpList(os, "components", x.componentNames_);
373   return os;
374 }
375 
376 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
377   os << DetailsToString(details);
378   std::visit( //
379       common::visitors{
380           [&](const UnknownDetails &) {},
381           [&](const MainProgramDetails &) {},
382           [&](const ModuleDetails &x) {
383             if (x.isSubmodule()) {
384               os << " (";
385               if (x.ancestor()) {
386                 auto ancestor{x.ancestor()->GetName().value()};
387                 os << ancestor;
388                 if (x.parent()) {
389                   auto parent{x.parent()->GetName().value()};
390                   if (ancestor != parent) {
391                     os << ':' << parent;
392                   }
393                 }
394               }
395               os << ")";
396             }
397           },
398           [&](const SubprogramNameDetails &x) {
399             os << ' ' << EnumToString(x.kind());
400           },
401           [&](const UseDetails &x) {
402             os << " from " << x.symbol().name() << " in "
403                << GetUsedModule(x).name();
404           },
405           [&](const UseErrorDetails &x) {
406             os << " uses:";
407             for (const auto &[location, module] : x.occurrences()) {
408               os << " from " << module->GetName().value() << " at " << location;
409             }
410           },
411           [](const HostAssocDetails &) {},
412           [&](const GenericDetails &x) {
413             os << ' ' << x.kind().ToString();
414             DumpBool(os, "(specific)", x.specific() != nullptr);
415             DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
416             os << " procs:";
417             DumpSymbolVector(os, x.specificProcs());
418           },
419           [&](const ProcBindingDetails &x) {
420             os << " => " << x.symbol().name();
421             DumpOptional(os, "passName", x.passName());
422           },
423           [&](const NamelistDetails &x) {
424             os << ':';
425             DumpSymbolVector(os, x.objects());
426           },
427           [&](const CommonBlockDetails &x) {
428             if (x.alignment()) {
429               os << " alignment=" << x.alignment();
430             }
431             os << ':';
432             for (const auto &object : x.objects()) {
433               os << ' ' << object->name();
434             }
435           },
436           [&](const FinalProcDetails &) {},
437           [&](const TypeParamDetails &x) {
438             DumpOptional(os, "type", x.type());
439             os << ' ' << common::EnumToString(x.attr());
440             DumpExpr(os, "init", x.init());
441           },
442           [&](const MiscDetails &x) {
443             os << ' ' << MiscDetails::EnumToString(x.kind());
444           },
445           [&](const auto &x) { os << x; },
446       },
447       details);
448   return os;
449 }
450 
451 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
452   return o << Symbol::EnumToString(flag);
453 }
454 
455 llvm::raw_ostream &operator<<(
456     llvm::raw_ostream &o, const Symbol::Flags &flags) {
457   std::size_t n{flags.count()};
458   std::size_t seen{0};
459   for (std::size_t j{0}; seen < n; ++j) {
460     Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
461     if (flags.test(flag)) {
462       if (seen++ > 0) {
463         o << ", ";
464       }
465       o << flag;
466     }
467   }
468   return o;
469 }
470 
471 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
472   os << symbol.name();
473   if (!symbol.attrs().empty()) {
474     os << ", " << symbol.attrs();
475   }
476   if (!symbol.flags().empty()) {
477     os << " (" << symbol.flags() << ')';
478   }
479   if (symbol.size_) {
480     os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
481   }
482   os << ": " << symbol.details_;
483   return os;
484 }
485 
486 // Output a unique name for a scope by qualifying it with the names of
487 // parent scopes. For scopes without corresponding symbols, use the kind
488 // with an index (e.g. Block1, Block2, etc.).
489 static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
490   if (!scope.IsGlobal()) {
491     DumpUniqueName(os, scope.parent());
492     os << '/';
493     if (auto *scopeSymbol{scope.symbol()};
494         scopeSymbol && !scopeSymbol->name().empty()) {
495       os << scopeSymbol->name();
496     } else {
497       int index{1};
498       for (auto &child : scope.parent().children()) {
499         if (child == scope) {
500           break;
501         }
502         if (child.kind() == scope.kind()) {
503           ++index;
504         }
505       }
506       os << Scope::EnumToString(scope.kind()) << index;
507     }
508   }
509 }
510 
511 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the
512 // format should be reasonably stable.
513 llvm::raw_ostream &DumpForUnparse(
514     llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
515   DumpUniqueName(os, symbol.owner());
516   os << '/' << symbol.name();
517   if (isDef) {
518     if (!symbol.attrs().empty()) {
519       os << ' ' << symbol.attrs();
520     }
521     if (!symbol.flags().empty()) {
522       os << " (" << symbol.flags() << ')';
523     }
524     os << ' ' << symbol.GetDetailsName();
525     DumpType(os, symbol.GetType());
526   }
527   return os;
528 }
529 
530 const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
531   if (const Symbol * parentComponent{GetParentComponent(scope)}) {
532     const auto &object{parentComponent->get<ObjectEntityDetails>()};
533     return &object.type()->derivedTypeSpec();
534   } else {
535     return nullptr;
536   }
537 }
538 
539 const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
540   if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
541     if (!scope) {
542       scope = scope_;
543     }
544     return dtDetails->GetParentComponent(DEREF(scope));
545   } else {
546     return nullptr;
547   }
548 }
549 
550 void DerivedTypeDetails::add_component(const Symbol &symbol) {
551   if (symbol.test(Symbol::Flag::ParentComp)) {
552     CHECK(componentNames_.empty());
553   }
554   componentNames_.push_back(symbol.name());
555 }
556 
557 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
558   if (auto extends{GetParentComponentName()}) {
559     if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
560       if (const Symbol & symbol{*iter->second};
561           symbol.test(Symbol::Flag::ParentComp)) {
562         return &symbol;
563       }
564     }
565   }
566   return nullptr;
567 }
568 
569 void TypeParamDetails::set_type(const DeclTypeSpec &type) {
570   CHECK(!type_);
571   type_ = &type;
572 }
573 
574 bool GenericKind::IsIntrinsicOperator() const {
575   return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
576       Has<common::NumericOperator>() || Has<common::RelationalOperator>();
577 }
578 
579 bool GenericKind::IsOperator() const {
580   return IsDefinedOperator() || IsIntrinsicOperator();
581 }
582 
583 std::string GenericKind::ToString() const {
584   return std::visit(
585       common::visitors {
586         [](const OtherKind &x) { return EnumToString(x); },
587             [](const DefinedIo &x) { return EnumToString(x); },
588 #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
589             [](const common::NumericOperator &x) {
590               return common::EnumToString(x);
591             },
592             [](const common::LogicalOperator &x) {
593               return common::EnumToString(x);
594             },
595             [](const common::RelationalOperator &x) {
596               return common::EnumToString(x);
597             },
598 #else
599             [](const auto &x) { return common::EnumToString(x); },
600 #endif
601       },
602       u);
603 }
604 
605 bool GenericKind::Is(GenericKind::OtherKind x) const {
606   const OtherKind *y{std::get_if<OtherKind>(&u)};
607   return y && *y == x;
608 }
609 
610 } // namespace Fortran::semantics
611