1 // Copyright (c) 2018-2019, NVIDIA CORPORATION.  All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef FORTRAN_SEMANTICS_SYMBOL_H_
16 #define FORTRAN_SEMANTICS_SYMBOL_H_
17 
18 #include "type.h"
19 #include "../common/Fortran.h"
20 #include "../common/enum-set.h"
21 #include <functional>
22 #include <list>
23 #include <optional>
24 #include <vector>
25 
26 namespace Fortran::semantics {
27 
28 /// A Symbol consists of common information (name, owner, and attributes)
29 /// and details information specific to the kind of symbol, represented by the
30 /// *Details classes.
31 
32 class Scope;
33 class Symbol;
34 
35 using SymbolVector = std::vector<const Symbol *>;
36 
37 // A module or submodule.
38 class ModuleDetails {
39 public:
40   ModuleDetails(bool isSubmodule = false) : isSubmodule_{isSubmodule} {}
isSubmodule()41   bool isSubmodule() const { return isSubmodule_; }
scope()42   const Scope *scope() const { return scope_; }
43   const Scope *ancestor() const;  // for submodule; nullptr for module
44   const Scope *parent() const;  // for submodule; nullptr for module
45   void set_scope(const Scope *);
46 
47 private:
48   bool isSubmodule_;
49   const Scope *scope_{nullptr};
50 };
51 
52 class MainProgramDetails {
53 public:
54 private:
55 };
56 
57 class SubprogramDetails {
58 public:
SubprogramDetails()59   SubprogramDetails() {}
SubprogramDetails(const SubprogramDetails & that)60   SubprogramDetails(const SubprogramDetails &that)
61     : dummyArgs_{that.dummyArgs_}, result_{that.result_} {}
62 
isFunction()63   bool isFunction() const { return result_ != nullptr; }
isInterface()64   bool isInterface() const { return isInterface_; }
65   void set_isInterface(bool value = true) { isInterface_ = value; }
bindName()66   MaybeExpr bindName() const { return bindName_; }
set_bindName(MaybeExpr && expr)67   void set_bindName(MaybeExpr &&expr) { bindName_ = std::move(expr); }
result()68   const Symbol &result() const {
69     CHECK(isFunction());
70     return *result_;
71   }
set_result(Symbol & result)72   void set_result(Symbol &result) {
73     CHECK(result_ == nullptr);
74     result_ = &result;
75   }
dummyArgs()76   const std::vector<Symbol *> &dummyArgs() const { return dummyArgs_; }
add_dummyArg(Symbol & symbol)77   void add_dummyArg(Symbol &symbol) { dummyArgs_.push_back(&symbol); }
add_alternateReturn()78   void add_alternateReturn() { dummyArgs_.push_back(nullptr); }
79 
80 private:
81   bool isInterface_{false};  // true if this represents an interface-body
82   MaybeExpr bindName_;
83   std::vector<Symbol *> dummyArgs_;  // nullptr -> alternate return indicator
84   Symbol *result_{nullptr};
85   friend std::ostream &operator<<(std::ostream &, const SubprogramDetails &);
86 };
87 
88 // For SubprogramNameDetails, the kind indicates whether it is the name
89 // of a module subprogram or internal subprogram.
ENUM_CLASS(SubprogramKind,Module,Internal)90 ENUM_CLASS(SubprogramKind, Module, Internal)
91 
92 // Symbol with SubprogramNameDetails is created when we scan for module and
93 // internal procedure names, to record that there is a subprogram with this
94 // name. Later they are replaced by SubprogramDetails with dummy and result
95 // type information.
96 class SubprogramNameDetails {
97 public:
98   SubprogramNameDetails(SubprogramKind kind) : kind_{kind} {}
99   SubprogramNameDetails() = delete;
100   SubprogramKind kind() const { return kind_; }
101 
102 private:
103   SubprogramKind kind_;
104 };
105 
106 // A name from an entity-decl -- could be object or function.
107 class EntityDetails {
108 public:
109   explicit EntityDetails(bool isDummy = false) : isDummy_{isDummy} {}
type()110   const DeclTypeSpec *type() const { return type_; }
111   void set_type(const DeclTypeSpec &);
112   void ReplaceType(const DeclTypeSpec &);
isDummy()113   bool isDummy() const { return isDummy_; }
isFuncResult()114   bool isFuncResult() const { return isFuncResult_; }
set_funcResult(bool x)115   void set_funcResult(bool x) { isFuncResult_ = x; }
bindName()116   MaybeExpr bindName() const { return bindName_; }
set_bindName(MaybeExpr && expr)117   void set_bindName(MaybeExpr &&expr) { bindName_ = std::move(expr); }
118 
119 private:
120   bool isDummy_;
121   bool isFuncResult_{false};
122   const DeclTypeSpec *type_{nullptr};
123   MaybeExpr bindName_;
124   friend std::ostream &operator<<(std::ostream &, const EntityDetails &);
125 };
126 
127 // Symbol is associated with a name or expression in a SELECT TYPE or ASSOCIATE.
128 class AssocEntityDetails : public EntityDetails {
129 public:
AssocEntityDetails()130   AssocEntityDetails() {}
AssocEntityDetails(SomeExpr && expr)131   explicit AssocEntityDetails(SomeExpr &&expr) : expr_{std::move(expr)} {}
132   AssocEntityDetails(const AssocEntityDetails &) = default;
133   AssocEntityDetails(AssocEntityDetails &&) = default;
134   AssocEntityDetails &operator=(const AssocEntityDetails &) = default;
135   AssocEntityDetails &operator=(AssocEntityDetails &&) = default;
expr()136   const MaybeExpr &expr() const { return expr_; }
137 
138 private:
139   MaybeExpr expr_;
140 };
141 
142 // An entity known to be an object.
143 class ObjectEntityDetails : public EntityDetails {
144 public:
145   explicit ObjectEntityDetails(EntityDetails &&);
146   ObjectEntityDetails(const ObjectEntityDetails &) = default;
147   ObjectEntityDetails &operator=(const ObjectEntityDetails &) = default;
EntityDetails(isDummy)148   ObjectEntityDetails(bool isDummy = false) : EntityDetails(isDummy) {}
init()149   MaybeExpr &init() { return init_; }
init()150   const MaybeExpr &init() const { return init_; }
set_init(MaybeExpr && expr)151   void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
initWasValidated()152   bool initWasValidated() const { return initWasValidated_; }
153   void set_initWasValidated(bool yes = true) { initWasValidated_ = yes; }
shape()154   ArraySpec &shape() { return shape_; }
shape()155   const ArraySpec &shape() const { return shape_; }
coshape()156   ArraySpec &coshape() { return coshape_; }
coshape()157   const ArraySpec &coshape() const { return coshape_; }
158   void set_shape(const ArraySpec &);
159   void set_coshape(const ArraySpec &);
commonBlock()160   const Symbol *commonBlock() const { return commonBlock_; }
set_commonBlock(const Symbol & commonBlock)161   void set_commonBlock(const Symbol &commonBlock) {
162     commonBlock_ = &commonBlock;
163   }
IsArray()164   bool IsArray() const { return !shape_.empty(); }
IsCoarray()165   bool IsCoarray() const { return !coshape_.empty(); }
IsAssumedShape()166   bool IsAssumedShape() const { return isDummy() && shape_.IsAssumedShape(); }
IsDeferredShape()167   bool IsDeferredShape() const {
168     return !isDummy() && shape_.IsDeferredShape();
169   }
IsAssumedSize()170   bool IsAssumedSize() const { return isDummy() && shape_.IsAssumedSize(); }
IsAssumedRank()171   bool IsAssumedRank() const { return isDummy() && shape_.IsAssumedRank(); }
172 
173 private:
174   MaybeExpr init_;
175   bool initWasValidated_{false};
176   ArraySpec shape_;
177   ArraySpec coshape_;
178   const Symbol *commonBlock_{nullptr};  // common block this object is in
179   friend std::ostream &operator<<(std::ostream &, const ObjectEntityDetails &);
180 };
181 
182 // Mixin for details with passed-object dummy argument.
183 // passIndex is set based on passName or the PASS attr.
184 class WithPassArg {
185 public:
passName()186   const std::optional<SourceName> &passName() const { return passName_; }
set_passName(const SourceName & passName)187   void set_passName(const SourceName &passName) { passName_ = passName; }
passIndex()188   std::optional<int> passIndex() const { return passIndex_; }
set_passIndex(int index)189   void set_passIndex(int index) { passIndex_ = index; }
190 
191 private:
192   std::optional<SourceName> passName_;
193   std::optional<int> passIndex_;
194 };
195 
196 // A procedure pointer, dummy procedure, or external procedure
197 class ProcEntityDetails : public EntityDetails, public WithPassArg {
198 public:
199   ProcEntityDetails() = default;
200   explicit ProcEntityDetails(EntityDetails &&d);
201 
interface()202   const ProcInterface &interface() const { return interface_; }
interface()203   ProcInterface &interface() { return interface_; }
set_interface(const ProcInterface & interface)204   void set_interface(const ProcInterface &interface) { interface_ = interface; }
205   inline bool HasExplicitInterface() const;
206 
207   // Be advised: !init().has_value() => uninitialized pointer,
208   // while *init() == nullptr => explicit NULL() initialization.
init()209   std::optional<const Symbol *> init() const { return init_; }
set_init(const Symbol & symbol)210   void set_init(const Symbol &symbol) { init_ = &symbol; }
set_init(std::nullptr_t)211   void set_init(std::nullptr_t) { init_ = nullptr; }
212 
213 private:
214   ProcInterface interface_;
215   std::optional<const Symbol *> init_;
216   friend std::ostream &operator<<(std::ostream &, const ProcEntityDetails &);
217 };
218 
219 // These derived type details represent the characteristics of a derived
220 // type definition that are shared by all instantiations of that type.
221 // The DerivedTypeSpec instances whose type symbols share these details
222 // each own a scope into which the components' symbols have been cloned
223 // and specialized for each distinct set of type parameter values.
224 class DerivedTypeDetails {
225 public:
paramNames()226   const std::list<SourceName> &paramNames() const { return paramNames_; }
paramDecls()227   const SymbolVector &paramDecls() const { return paramDecls_; }
sequence()228   bool sequence() const { return sequence_; }
add_paramName(const SourceName & name)229   void add_paramName(const SourceName &name) { paramNames_.push_back(name); }
add_paramDecl(const Symbol & symbol)230   void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(&symbol); }
231   void add_component(const Symbol &);
232   void set_sequence(bool x = true) { sequence_ = x; }
componentNames()233   const std::list<SourceName> &componentNames() const {
234     return componentNames_;
235   }
236 
237   // If this derived type extends another, locate the parent component's symbol.
238   const Symbol *GetParentComponent(const Scope &) const;
239 
GetParentComponentName()240   std::optional<SourceName> GetParentComponentName() const {
241     if (componentNames_.empty()) {
242       return std::nullopt;
243     } else {
244       return componentNames_.front();
245     }
246   }
247 
248 private:
249   // These are (1) the names of the derived type parameters in the order
250   // in which they appear on the type definition statement(s), and (2) the
251   // symbols that correspond to those names in the order in which their
252   // declarations appear in the derived type definition(s).
253   std::list<SourceName> paramNames_;
254   SymbolVector paramDecls_;
255   // These are the names of the derived type's components in component
256   // order.  A parent component, if any, appears first in this list.
257   std::list<SourceName> componentNames_;
258   bool sequence_{false};
259   friend std::ostream &operator<<(std::ostream &, const DerivedTypeDetails &);
260 };
261 
262 class ProcBindingDetails : public WithPassArg {
263 public:
ProcBindingDetails(const Symbol & symbol)264   explicit ProcBindingDetails(const Symbol &symbol) : symbol_{&symbol} {}
symbol()265   const Symbol &symbol() const { return *symbol_; }
266 
267 private:
268   const Symbol *symbol_;  // procedure bound to; may be forward
269 };
270 
ENUM_CLASS(GenericKind,Name,DefinedOp,Assignment,OpPower,OpMultiply,OpDivide,OpAdd,OpSubtract,OpConcat,OpLT,OpLE,OpEQ,OpNE,OpGE,OpGT,OpNOT,OpAND,OpOR,OpXOR,OpEQV,OpNEQV,ReadFormatted,ReadUnformatted,WriteFormatted,WriteUnformatted)271 ENUM_CLASS(GenericKind,  // Kinds of generic-spec
272     Name, DefinedOp,  // these have a Name associated with them
273     Assignment,  // user-defined assignment
274     OpPower, OpMultiply, OpDivide, OpAdd, OpSubtract, OpConcat, OpLT, OpLE,
275     OpEQ, OpNE, OpGE, OpGT, OpNOT, OpAND, OpOR, OpXOR, OpEQV, OpNEQV,
276     ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
277 
278 class GenericBindingDetails {
279 public:
280   GenericBindingDetails() {}
281   GenericKind kind() const { return kind_; }
282   void set_kind(GenericKind kind) { kind_ = kind; }
283   const SymbolVector &specificProcs() const { return specificProcs_; }
284   void add_specificProc(const Symbol &proc) { specificProcs_.push_back(&proc); }
285 
286 private:
287   GenericKind kind_{GenericKind::Name};
288   SymbolVector specificProcs_;
289 };
290 
291 class NamelistDetails {
292 public:
objects()293   const SymbolVector &objects() const { return objects_; }
add_object(const Symbol & object)294   void add_object(const Symbol &object) { objects_.push_back(&object); }
add_objects(const SymbolVector & objects)295   void add_objects(const SymbolVector &objects) {
296     objects_.insert(objects_.end(), objects.begin(), objects.end());
297   }
298 
299 private:
300   SymbolVector objects_;
301 };
302 
303 class CommonBlockDetails {
304 public:
objects()305   std::list<Symbol *> &objects() { return objects_; }
objects()306   const std::list<Symbol *> &objects() const { return objects_; }
add_object(Symbol & object)307   void add_object(Symbol &object) { objects_.push_back(&object); }
bindName()308   MaybeExpr bindName() const { return bindName_; }
set_bindName(MaybeExpr && expr)309   void set_bindName(MaybeExpr &&expr) { bindName_ = std::move(expr); }
310 
311 private:
312   std::list<Symbol *> objects_;
313   MaybeExpr bindName_;
314 };
315 
316 class FinalProcDetails {};
317 
318 class MiscDetails {
319 public:
320   ENUM_CLASS(Kind, None, ConstructName, ScopeName, PassName, ComplexPartRe,
321       ComplexPartIm, KindParamInquiry, LenParamInquiry,
322       SelectTypeAssociateName);
MiscDetails(Kind kind)323   MiscDetails(Kind kind) : kind_{kind} {}
kind()324   Kind kind() const { return kind_; }
325 
326 private:
327   Kind kind_;
328 };
329 
330 class TypeParamDetails {
331 public:
TypeParamDetails(common::TypeParamAttr attr)332   explicit TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {}
333   TypeParamDetails(const TypeParamDetails &) = default;
attr()334   common::TypeParamAttr attr() const { return attr_; }
init()335   MaybeIntExpr &init() { return init_; }
init()336   const MaybeIntExpr &init() const { return init_; }
set_init(MaybeIntExpr && expr)337   void set_init(MaybeIntExpr &&expr) { init_ = std::move(expr); }
type()338   const DeclTypeSpec *type() const { return type_; }
339   void set_type(const DeclTypeSpec &);
340   void ReplaceType(const DeclTypeSpec &);
341 
342 private:
343   common::TypeParamAttr attr_;
344   MaybeIntExpr init_;
345   const DeclTypeSpec *type_{nullptr};
346 };
347 
348 // Record the USE of a symbol: location is where (USE statement or renaming);
349 // symbol is the USEd module.
350 class UseDetails {
351 public:
UseDetails(const SourceName & location,const Symbol & symbol)352   UseDetails(const SourceName &location, const Symbol &symbol)
353     : location_{location}, symbol_{&symbol} {}
location()354   const SourceName &location() const { return location_; }
symbol()355   const Symbol &symbol() const { return *symbol_; }
356   const Symbol &module() const;
357 
358 private:
359   SourceName location_;
360   const Symbol *symbol_;
361 };
362 
363 // A symbol with ambiguous use-associations. Record where they were so
364 // we can report the error if it is used.
365 class UseErrorDetails {
366 public:
367   UseErrorDetails(const UseDetails &);
368   UseErrorDetails &add_occurrence(const SourceName &, const Scope &);
369   using listType = std::list<std::pair<SourceName, const Scope *>>;
occurrences()370   const listType occurrences() const { return occurrences_; };
371 
372 private:
373   listType occurrences_;
374 };
375 
376 // A symbol host-associated from an enclosing scope.
377 class HostAssocDetails {
378 public:
HostAssocDetails(const Symbol & symbol)379   HostAssocDetails(const Symbol &symbol) : symbol_{&symbol} {}
symbol()380   const Symbol &symbol() const { return *symbol_; }
381 
382 private:
383   const Symbol *symbol_;
384 };
385 
386 class GenericDetails {
387 public:
GenericDetails()388   GenericDetails() {}
389   GenericDetails(const SymbolVector &specificProcs);
390 
kind()391   GenericKind kind() const { return kind_; }
set_kind(GenericKind kind)392   void set_kind(GenericKind kind) { kind_ = kind; }
393 
specificProcs()394   const SymbolVector &specificProcs() const { return specificProcs_; }
add_specificProc(const Symbol & proc)395   void add_specificProc(const Symbol &proc) { specificProcs_.push_back(&proc); }
396 
397   // specific and derivedType indicate a specific procedure or derived type
398   // with the same name as this generic. Only one of them may be set.
specific()399   Symbol *specific() { return specific_; }
specific()400   const Symbol *specific() const { return specific_; }
401   void set_specific(Symbol &specific);
derivedType()402   Symbol *derivedType() { return derivedType_; }
derivedType()403   const Symbol *derivedType() const { return derivedType_; }
404   void set_derivedType(Symbol &derivedType);
405 
406   // Copy in specificProcs, specific, and derivedType from another generic
407   void CopyFrom(const GenericDetails &);
408 
409   // Check that specific is one of the specificProcs. If not, return the
410   // specific as a raw pointer.
411   const Symbol *CheckSpecific() const;
412   Symbol *CheckSpecific();
413 
useDetails()414   const std::optional<UseDetails> &useDetails() const { return useDetails_; }
set_useDetails(const UseDetails & details)415   void set_useDetails(const UseDetails &details) { useDetails_ = details; }
416 
417 private:
418   GenericKind kind_{GenericKind::Name};
419   // all of the specific procedures for this generic
420   SymbolVector specificProcs_;
421   // a specific procedure with the same name as this generic, if any
422   Symbol *specific_{nullptr};
423   // a derived type with the same name as this generic, if any
424   Symbol *derivedType_{nullptr};
425   // If two USEs of generics were merged to form this one, this is the
426   // UseDetails for one of them. Used for reporting USE errors.
427   std::optional<UseDetails> useDetails_;
428 };
429 
430 class UnknownDetails {};
431 
432 using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
433     SubprogramDetails, SubprogramNameDetails, EntityDetails,
434     ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
435     DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
436     GenericDetails, ProcBindingDetails, GenericBindingDetails, NamelistDetails,
437     CommonBlockDetails, FinalProcDetails, TypeParamDetails, MiscDetails>;
438 std::ostream &operator<<(std::ostream &, const Details &);
439 std::string DetailsToString(const Details &);
440 
441 class Symbol {
442 public:
443   ENUM_CLASS(Flag,
444       Error,  // an error has been reported on this symbol
445       Function,  // symbol is a function
446       Subroutine,  // symbol is a subroutine
447       Implicit,  // symbol is implicitly typed
448       ModFile,  // symbol came from .mod file
449       ParentComp,  // symbol is the "parent component" of an extended type
450       CrayPointer, CrayPointee,
451       LocalityLocal,  // named in LOCAL locality-spec
452       LocalityLocalInit,  // named in LOCAL_INIT locality-spec
453       LocalityShared  // named in SHARED locality-spec
454   );
455   using Flags = common::EnumSet<Flag, Flag_enumSize>;
456 
owner()457   const Scope &owner() const { return *owner_; }
name()458   const SourceName &name() const { return name_; }
attrs()459   Attrs &attrs() { return attrs_; }
attrs()460   const Attrs &attrs() const { return attrs_; }
flags()461   Flags &flags() { return flags_; }
flags()462   const Flags &flags() const { return flags_; }
test(Flag flag)463   bool test(Flag flag) const { return flags_.test(flag); }
464   void set(Flag flag, bool value = true) { flags_.set(flag, value); }
465   // The Scope introduced by this symbol, if any.
scope()466   Scope *scope() { return scope_; }
scope()467   const Scope *scope() const { return scope_; }
set_scope(Scope * scope)468   void set_scope(Scope *scope) { scope_ = scope; }
469   // Give the symbol a name with a different source location but same chars.
470   void ReplaceName(const SourceName &);
471 
472   // Does symbol have this type of details?
has()473   template<typename D> bool has() const {
474     return std::holds_alternative<D>(details_);
475   }
476 
477   // Return a non-owning pointer to details if it is type D, else nullptr.
detailsIf()478   template<typename D> D *detailsIf() { return std::get_if<D>(&details_); }
detailsIf()479   template<typename D> const D *detailsIf() const {
480     return std::get_if<D>(&details_);
481   }
482 
483   // Return a reference to the details which must be of type D.
get()484   template<typename D> D &get() {
485     return const_cast<D &>(const_cast<const Symbol *>(this)->get<D>());
486   }
get()487   template<typename D> const D &get() const {
488     const auto *p{detailsIf<D>()};
489     CHECK(p != nullptr);
490     return *p;
491   }
492 
details()493   Details &details() { return details_; }
details()494   const Details &details() const { return details_; }
495   // Assign the details of the symbol from one of the variants.
496   // Only allowed in certain cases.
497   void set_details(Details &&);
498 
499   // Can the details of this symbol be replaced with the given details?
500   bool CanReplaceDetails(const Details &details) const;
501 
502   // Follow use-associations and host-associations to get the ultimate entity.
GetUltimate()503   Symbol &GetUltimate() {
504     return const_cast<Symbol &>(
505         const_cast<const Symbol *>(this)->GetUltimate());
506   }
GetUltimate()507   const Symbol &GetUltimate() const {
508     if (const auto *details{detailsIf<UseDetails>()}) {
509       return details->symbol().GetUltimate();
510     } else if (const auto *details{detailsIf<HostAssocDetails>()}) {
511       return details->symbol().GetUltimate();
512     } else {
513       return *this;
514     }
515   }
516 
GetType()517   DeclTypeSpec *GetType() {
518     return const_cast<DeclTypeSpec *>(
519         const_cast<const Symbol *>(this)->GetType());
520   }
GetType()521   const DeclTypeSpec *GetType() const {
522     return std::visit(
523         common::visitors{
524             [](const EntityDetails &x) { return x.type(); },
525             [](const ObjectEntityDetails &x) { return x.type(); },
526             [](const AssocEntityDetails &x) { return x.type(); },
527             [](const SubprogramDetails &x) {
528               return x.isFunction() ? x.result().GetType() : nullptr;
529             },
530             [](const ProcEntityDetails &x) {
531               if (const Symbol * symbol{x.interface().symbol()}) {
532                 return symbol->GetType();
533               } else {
534                 return x.interface().type();
535               }
536             },
537             [&](const ProcBindingDetails &x) { return x.symbol().GetType(); },
538             [](const TypeParamDetails &x) { return x.type(); },
539             [](const UseDetails &x) { return x.symbol().GetType(); },
540             [](const HostAssocDetails &x) { return x.symbol().GetType(); },
541             [](const auto &) -> const DeclTypeSpec * { return nullptr; },
542         },
543         details_);
544   }
545 
546   void SetType(const DeclTypeSpec &);
547 
548   bool IsDummy() const;
549   bool IsFuncResult() const;
550   bool IsObjectArray() const;
551   bool IsSubprogram() const;
552   bool IsSeparateModuleProc() const;
553   bool IsFromModFile() const;
HasExplicitInterface()554   bool HasExplicitInterface() const {
555     return std::visit(
556         common::visitors{
557             [](const SubprogramDetails &) { return true; },
558             [](const SubprogramNameDetails &) { return true; },
559             [&](const ProcEntityDetails &x) {
560               return attrs_.test(Attr::INTRINSIC) || x.HasExplicitInterface();
561             },
562             [](const ProcBindingDetails &x) {
563               return x.symbol().HasExplicitInterface();
564             },
565             [](const UseDetails &x) {
566               return x.symbol().HasExplicitInterface();
567             },
568             [](const HostAssocDetails &x) {
569               return x.symbol().HasExplicitInterface();
570             },
571             [](const auto &) { return false; },
572         },
573         details_);
574   }
575 
576   bool operator==(const Symbol &that) const { return this == &that; }
577   bool operator!=(const Symbol &that) const { return this != &that; }
578 
Rank()579   int Rank() const {
580     return std::visit(
581         common::visitors{
582             [](const SubprogramDetails &sd) {
583               return sd.isFunction() ? sd.result().Rank() : 0;
584             },
585             [](const GenericDetails &) {
586               return 0; /*TODO*/
587             },
588             [](const UseDetails &x) { return x.symbol().Rank(); },
589             [](const HostAssocDetails &x) { return x.symbol().Rank(); },
590             [](const ObjectEntityDetails &oed) { return oed.shape().Rank(); },
591             [](const AssocEntityDetails &aed) {
592               if (const auto &expr{aed.expr()}) {
593                 return expr->Rank();
594               } else {
595                 return 0;
596               }
597             },
598             [](const auto &) { return 0; },
599         },
600         details_);
601   }
602 
Corank()603   int Corank() const {
604     return std::visit(
605         common::visitors{
606             [](const SubprogramDetails &sd) {
607               return sd.isFunction() ? sd.result().Corank() : 0;
608             },
609             [](const GenericDetails &) {
610               return 0; /*TODO*/
611             },
612             [](const UseDetails &x) { return x.symbol().Corank(); },
613             [](const HostAssocDetails &x) { return x.symbol().Corank(); },
614             [](const ObjectEntityDetails &oed) { return oed.coshape().Rank(); },
615             [](const auto &) { return 0; },
616         },
617         details_);
618   }
619 
620   // If there is a parent component, return a pointer to its derived type spec.
621   // The Scope * argument defaults to this->scope_ but should be overridden
622   // for a parameterized derived type instantiation with the instance's scope.
623   const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
624 
625 private:
626   const Scope *owner_;
627   SourceName name_;
628   Attrs attrs_;
629   Flags flags_;
630   Scope *scope_{nullptr};
631   Details details_;
632 
Symbol()633   Symbol() {}  // only created in class Symbols
634   const std::string GetDetailsName() const;
635   friend std::ostream &operator<<(std::ostream &, const Symbol &);
636   friend std::ostream &DumpForUnparse(std::ostream &, const Symbol &, bool);
637 
638   // If a derived type's symbol refers to an extended derived type,
639   // return the parent component's symbol.  The scope of the derived type
640   // can be overridden.
641   const Symbol *GetParentComponent(const Scope * = nullptr) const;
642 
643   template<std::size_t> friend class Symbols;
644   template<class, std::size_t> friend struct std::array;
645 };
646 
647 std::ostream &operator<<(std::ostream &, Symbol::Flag);
648 
649 // Manage memory for all symbols. BLOCK_SIZE symbols at a time are allocated.
650 // Make() returns a reference to the next available one. They are never
651 // deleted.
652 template<std::size_t BLOCK_SIZE> class Symbols {
653 public:
Make(const Scope & owner,const SourceName & name,const Attrs & attrs,Details && details)654   Symbol &Make(const Scope &owner, const SourceName &name, const Attrs &attrs,
655       Details &&details) {
656     Symbol &symbol = Get();
657     symbol.owner_ = &owner;
658     symbol.name_ = name;
659     symbol.attrs_ = attrs;
660     symbol.details_ = std::move(details);
661     return symbol;
662   }
663 
664 private:
665   using blockType = std::array<Symbol, BLOCK_SIZE>;
666   std::list<blockType *> blocks_;
667   std::size_t nextIndex_{0};
668   blockType *currBlock_{nullptr};
669 
Get()670   Symbol &Get() {
671     if (nextIndex_ == 0) {
672       blocks_.push_back(new blockType());
673       currBlock_ = blocks_.back();
674     }
675     Symbol &result = (*currBlock_)[nextIndex_];
676     if (++nextIndex_ >= BLOCK_SIZE) {
677       nextIndex_ = 0;  // allocate a new block next time
678     }
679     return result;
680   }
681 };
682 
683 // Define a few member functions here in the header so that they
684 // can be used by lib/evaluate without inducing a dependence cycle
685 // between the two shared libraries.
686 
HasExplicitInterface()687 inline bool ProcEntityDetails::HasExplicitInterface() const {
688   if (auto *symbol{interface_.symbol()}) {
689     return symbol->HasExplicitInterface();
690   }
691   return false;
692 }
693 }
694 #endif  // FORTRAN_SEMANTICS_SYMBOL_H_
695