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