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> ¶mNames() const { return paramNames_; }
paramDecls()227 const SymbolVector ¶mDecls() 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