blob: 97ed321f2a2a22391262394c5660ad8f605f746f [file] [log] [blame]
CarolineConcatto64ab3302020-02-25 15:11:521//===-- 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"
Caroline Concatto8670e492020-02-28 15:11:0315#include "llvm/Support/raw_ostream.h"
CarolineConcatto64ab3302020-02-25 15:11:5216#include <string>
17
18namespace Fortran::semantics {
19
Tim Keith1f879002020-03-29 04:00:1620template <typename T>
Caroline Concatto8670e492020-02-28 15:11:0321static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) {
CarolineConcatto64ab3302020-02-25 15:11:5222 if (x) {
23 os << ' ' << label << ':' << *x;
24 }
25}
Tim Keith1f879002020-03-29 04:00:1626template <typename T>
Caroline Concatto8670e492020-02-28 15:11:0327static void DumpExpr(llvm::raw_ostream &os, const char *label,
CarolineConcatto64ab3302020-02-25 15:11:5228 const std::optional<evaluate::Expr<T>> &x) {
29 if (x) {
30 x->AsFortran(os << ' ' << label << ':');
31 }
32}
33
Caroline Concatto8670e492020-02-28 15:11:0334static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) {
CarolineConcatto64ab3302020-02-25 15:11:5235 if (x) {
36 os << ' ' << label;
37 }
38}
39
Caroline Concatto8670e492020-02-28 15:11:0340static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) {
CarolineConcatto64ab3302020-02-25 15:11:5241 char sep{' '};
42 for (const Symbol &elem : list) {
43 os << sep << elem.name();
44 sep = ',';
45 }
46}
47
Caroline Concatto8670e492020-02-28 15:11:0348static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) {
CarolineConcatto64ab3302020-02-25 15:11:5249 if (const auto *type{symbol.GetType()}) {
50 os << *type << ' ';
51 }
52}
Caroline Concatto8670e492020-02-28 15:11:0353static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) {
CarolineConcatto64ab3302020-02-25 15:11:5254 if (type) {
55 os << ' ' << *type;
56 }
57}
58
Tim Keith1f879002020-03-29 04:00:1659template <typename T>
Caroline Concatto8670e492020-02-28 15:11:0360static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
CarolineConcatto64ab3302020-02-25 15:11:5261 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
71const Scope *ModuleDetails::parent() const {
72 return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
73}
74const Scope *ModuleDetails::ancestor() const {
Tim Keith47452b92020-03-03 00:43:0175 return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr;
CarolineConcatto64ab3302020-02-25 15:11:5276}
77void 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
Caroline Concatto8670e492020-02-28 15:11:0384llvm::raw_ostream &operator<<(
85 llvm::raw_ostream &os, const SubprogramDetails &x) {
CarolineConcatto64ab3302020-02-25 15:11:5286 DumpBool(os, "isInterface", x.isInterface_);
87 DumpExpr(os, "bindName", x.bindName_);
88 if (x.result_) {
Tim Keith61b13902020-03-17 21:48:3689 DumpType(os << " result:", x.result());
90 os << x.result_->name();
CarolineConcatto64ab3302020-02-25 15:11:5291 if (!x.result_->attrs().empty()) {
92 os << ", " << x.result_->attrs();
93 }
94 }
peter klauslerc42f6312020-03-19 23:31:1095 if (x.entryScope_) {
96 os << " entry";
97 if (x.entryScope_->symbol()) {
98 os << " in " << x.entryScope_->symbol()->name();
99 }
100 }
Tim Keith61b13902020-03-17 21:48:36101 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 << '*';
CarolineConcatto64ab3302020-02-25 15:11:52111 }
CarolineConcatto64ab3302020-02-25 15:11:52112 }
Tim Keith61b13902020-03-17 21:48:36113 os << (sep == '(' ? "()" : ")");
CarolineConcatto64ab3302020-02-25 15:11:52114 return os;
115}
116
117void EntityDetails::set_type(const DeclTypeSpec &type) {
118 CHECK(!type_);
119 type_ = &type;
120}
121
122void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
123
124void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
125 CHECK(shape_.empty());
126 for (const auto &shapeSpec : shape) {
127 shape_.push_back(shapeSpec);
128 }
129}
130void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
131 CHECK(coshape_.empty());
132 for (const auto &shapeSpec : coshape) {
133 coshape_.push_back(shapeSpec);
134 }
135}
136
137ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
138 if (type()) {
139 interface_.set_type(*type());
140 }
141}
142
143const Symbol &UseDetails::module() const {
144 // owner is a module so it must have a symbol:
145 return *symbol_->owner().symbol();
146}
147
148UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
149 add_occurrence(useDetails.location(), *useDetails.module().scope());
150}
151UseErrorDetails &UseErrorDetails::add_occurrence(
152 const SourceName &location, const Scope &module) {
153 occurrences_.push_back(std::make_pair(location, &module));
154 return *this;
155}
156
157GenericDetails::GenericDetails(const SymbolVector &specificProcs)
Tim Keith1f879002020-03-29 04:00:16158 : specificProcs_{specificProcs} {}
CarolineConcatto64ab3302020-02-25 15:11:52159
160void GenericDetails::AddSpecificProc(
161 const Symbol &proc, SourceName bindingName) {
162 specificProcs_.push_back(proc);
163 bindingNames_.push_back(bindingName);
164}
165void GenericDetails::set_specific(Symbol &specific) {
166 CHECK(!specific_);
167 CHECK(!derivedType_);
168 specific_ = &specific;
169}
170void GenericDetails::set_derivedType(Symbol &derivedType) {
171 CHECK(!specific_);
172 CHECK(!derivedType_);
173 derivedType_ = &derivedType;
174}
175
176const Symbol *GenericDetails::CheckSpecific() const {
177 return const_cast<GenericDetails *>(this)->CheckSpecific();
178}
179Symbol *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
192void 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.
212std::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
239const std::string Symbol::GetDetailsName() const {
240 return DetailsToString(details_);
241}
242
243void Symbol::set_details(Details &&details) {
244 CHECK(CanReplaceDetails(details));
245 details_ = std::move(details);
246}
247
248bool Symbol::CanReplaceDetails(const Details &details) const {
249 if (has<UnknownDetails>()) {
Tim Keith1f879002020-03-29 04:00:16250 return true; // can always replace UnknownDetails
CarolineConcatto64ab3302020-02-25 15:11:52251 } 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).
272void Symbol::ReplaceName(const SourceName &name) {
273 CHECK(name == name_);
274 name_ = name;
275}
276
277void Symbol::SetType(const DeclTypeSpec &type) {
Tim Keith1f879002020-03-29 04:00:16278 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 },
CarolineConcatto64ab3302020-02-25 15:11:52286 details_);
287}
288
289bool 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
299bool 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
309bool Symbol::IsObjectArray() const {
310 const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
311 return details && details->IsArray();
312}
313
314bool 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
CarolineConcatto64ab3302020-02-25 15:11:52326bool Symbol::IsFromModFile() const {
327 return test(Flag::ModFile) ||
328 (!owner_->IsGlobal() && owner_->symbol()->IsFromModFile());
329}
330
331ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
Tim Keith1f879002020-03-29 04:00:16332 : EntityDetails(d) {}
CarolineConcatto64ab3302020-02-25 15:11:52333
Caroline Concatto8670e492020-02-28 15:11:03334llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
CarolineConcatto64ab3302020-02-25 15:11:52335 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
Caroline Concatto8670e492020-02-28 15:11:03344llvm::raw_ostream &operator<<(
345 llvm::raw_ostream &os, const ObjectEntityDetails &x) {
CarolineConcatto64ab3302020-02-25 15:11:52346 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
Caroline Concatto8670e492020-02-28 15:11:03353llvm::raw_ostream &operator<<(
354 llvm::raw_ostream &os, const AssocEntityDetails &x) {
CarolineConcatto64ab3302020-02-25 15:11:52355 os << *static_cast<const EntityDetails *>(&x);
356 DumpExpr(os, "expr", x.expr());
357 return os;
358}
359
Caroline Concatto8670e492020-02-28 15:11:03360llvm::raw_ostream &operator<<(
361 llvm::raw_ostream &os, const ProcEntityDetails &x) {
CarolineConcatto64ab3302020-02-25 15:11:52362 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
Caroline Concatto8670e492020-02-28 15:11:03379llvm::raw_ostream &operator<<(
380 llvm::raw_ostream &os, const DerivedTypeDetails &x) {
CarolineConcatto64ab3302020-02-25 15:11:52381 DumpBool(os, "sequence", x.sequence_);
382 DumpList(os, "components", x.componentNames_);
383 return os;
384}
385
Caroline Concatto8670e492020-02-28 15:11:03386llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
CarolineConcatto64ab3302020-02-25 15:11:52387 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 },
CarolineConcatto64ab3302020-02-25 15:11:52408 [&](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) {
Tim Keith54b35c062020-05-06 22:00:14437 if (x.alignment()) {
438 os << " alignment=" << x.alignment();
Tim Keith237d0e32020-05-06 18:43:06439 }
CarolineConcatto64ab3302020-02-25 15:11:52440 os << ':';
Tim Keithd5c05ce2020-05-06 19:20:07441 for (const auto &object : x.objects()) {
442 os << ' ' << object->name();
CarolineConcatto64ab3302020-02-25 15:11:52443 }
444 },
445 [&](const FinalProcDetails &) {},
446 [&](const TypeParamDetails &x) {
447 DumpOptional(os, "type", x.type());
448 os << ' ' << common::EnumToString(x.attr());
449 DumpExpr(os, "init", x.init());
450 },
451 [&](const MiscDetails &x) {
452 os << ' ' << MiscDetails::EnumToString(x.kind());
453 },
454 [&](const auto &x) { os << x; },
455 },
456 details);
457 return os;
458}
459
Caroline Concatto8670e492020-02-28 15:11:03460llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
CarolineConcatto64ab3302020-02-25 15:11:52461 return o << Symbol::EnumToString(flag);
462}
463
Caroline Concatto8670e492020-02-28 15:11:03464llvm::raw_ostream &operator<<(
465 llvm::raw_ostream &o, const Symbol::Flags &flags) {
CarolineConcatto64ab3302020-02-25 15:11:52466 std::size_t n{flags.count()};
467 std::size_t seen{0};
468 for (std::size_t j{0}; seen < n; ++j) {
469 Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
470 if (flags.test(flag)) {
471 if (seen++ > 0) {
472 o << ", ";
473 }
474 o << flag;
475 }
476 }
477 return o;
478}
479
Caroline Concatto8670e492020-02-28 15:11:03480llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
CarolineConcatto64ab3302020-02-25 15:11:52481 os << symbol.name();
482 if (!symbol.attrs().empty()) {
483 os << ", " << symbol.attrs();
484 }
485 if (!symbol.flags().empty()) {
486 os << " (" << symbol.flags() << ')';
487 }
Tim Keithc353ebb2020-04-22 22:39:24488 if (symbol.size_) {
489 os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
490 }
CarolineConcatto64ab3302020-02-25 15:11:52491 os << ": " << symbol.details_;
492 return os;
493}
494
495// Output a unique name for a scope by qualifying it with the names of
496// parent scopes. For scopes without corresponding symbols, use the kind
497// with an index (e.g. Block1, Block2, etc.).
Caroline Concatto8670e492020-02-28 15:11:03498static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
CarolineConcatto64ab3302020-02-25 15:11:52499 if (!scope.IsGlobal()) {
500 DumpUniqueName(os, scope.parent());
501 os << '/';
502 if (auto *scopeSymbol{scope.symbol()};
503 scopeSymbol && !scopeSymbol->name().empty()) {
504 os << scopeSymbol->name();
505 } else {
506 int index{1};
507 for (auto &child : scope.parent().children()) {
508 if (child == scope) {
509 break;
510 }
511 if (child.kind() == scope.kind()) {
512 ++index;
513 }
514 }
515 os << Scope::EnumToString(scope.kind()) << index;
516 }
517 }
518}
519
520// Dump a symbol for UnparseWithSymbols. This will be used for tests so the
521// format should be reasonably stable.
Caroline Concatto8670e492020-02-28 15:11:03522llvm::raw_ostream &DumpForUnparse(
523 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
CarolineConcatto64ab3302020-02-25 15:11:52524 DumpUniqueName(os, symbol.owner());
525 os << '/' << symbol.name();
526 if (isDef) {
527 if (!symbol.attrs().empty()) {
528 os << ' ' << symbol.attrs();
529 }
530 if (!symbol.flags().empty()) {
531 os << " (" << symbol.flags() << ')';
532 }
533 os << ' ' << symbol.GetDetailsName();
534 DumpType(os, symbol.GetType());
535 }
536 return os;
537}
538
539const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
540 if (const Symbol * parentComponent{GetParentComponent(scope)}) {
541 const auto &object{parentComponent->get<ObjectEntityDetails>()};
542 return &object.type()->derivedTypeSpec();
543 } else {
544 return nullptr;
545 }
546}
547
548const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
549 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
550 if (!scope) {
551 scope = scope_;
552 }
553 return dtDetails->GetParentComponent(DEREF(scope));
554 } else {
555 return nullptr;
556 }
557}
558
CarolineConcatto64ab3302020-02-25 15:11:52559void DerivedTypeDetails::add_component(const Symbol &symbol) {
560 if (symbol.test(Symbol::Flag::ParentComp)) {
561 CHECK(componentNames_.empty());
562 }
563 componentNames_.push_back(symbol.name());
564}
565
566const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
567 if (auto extends{GetParentComponentName()}) {
568 if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
569 if (const Symbol & symbol{*iter->second};
570 symbol.test(Symbol::Flag::ParentComp)) {
571 return &symbol;
572 }
573 }
574 }
575 return nullptr;
576}
577
578void TypeParamDetails::set_type(const DeclTypeSpec &type) {
579 CHECK(!type_);
580 type_ = &type;
581}
582
583bool GenericKind::IsIntrinsicOperator() const {
584 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
585 Has<common::NumericOperator>() || Has<common::RelationalOperator>();
586}
587
588bool GenericKind::IsOperator() const {
589 return IsDefinedOperator() || IsIntrinsicOperator();
590}
591
592std::string GenericKind::ToString() const {
593 return std::visit(
594 common::visitors {
595 [](const OtherKind &x) { return EnumToString(x); },
596 [](const DefinedIo &x) { return EnumToString(x); },
597#if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
598 [](const common::NumericOperator &x) {
599 return common::EnumToString(x);
600 },
601 [](const common::LogicalOperator &x) {
602 return common::EnumToString(x);
603 },
604 [](const common::RelationalOperator &x) {
605 return common::EnumToString(x);
606 },
607#else
608 [](const auto &x) { return common::EnumToString(x); },
609#endif
610 },
611 u);
612}
613
614bool GenericKind::Is(GenericKind::OtherKind x) const {
615 const OtherKind *y{std::get_if<OtherKind>(&u)};
616 return y && *y == x;
617}
618
Tim Keith1f879002020-03-29 04:00:16619} // namespace Fortran::semantics