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