[lldb] Add ability to hide the root name of a value
[llvm-project.git] / flang / lib / Semantics / symbol.cpp
blob348ca338fa58c7e7697567cd8aa0558248f6e3ae
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 //===----------------------------------------------------------------------===//
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 <cstring>
17 #include <string>
18 #include <type_traits>
20 namespace Fortran::semantics {
22 template <typename T>
23 static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) {
24 if (x) {
25 os << ' ' << label << ':' << *x;
28 template <typename T>
29 static void DumpExpr(llvm::raw_ostream &os, const char *label,
30 const std::optional<evaluate::Expr<T>> &x) {
31 if (x) {
32 x->AsFortran(os << ' ' << label << ':');
36 static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) {
37 if (x) {
38 os << ' ' << label;
42 static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) {
43 char sep{' '};
44 for (const Symbol &elem : list) {
45 os << sep << elem.name();
46 sep = ',';
50 static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) {
51 if (const auto *type{symbol.GetType()}) {
52 os << *type << ' ';
55 static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) {
56 if (type) {
57 os << ' ' << *type;
61 template <typename T>
62 static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
63 if (!list.empty()) {
64 os << ' ' << label << ':';
65 char sep{' '};
66 for (const auto &elem : list) {
67 os << sep << elem;
68 sep = ',';
73 void SubprogramDetails::set_moduleInterface(Symbol &symbol) {
74 CHECK(!moduleInterface_);
75 moduleInterface_ = &symbol;
78 const Scope *ModuleDetails::parent() const {
79 return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
81 const Scope *ModuleDetails::ancestor() const {
82 return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr;
84 void ModuleDetails::set_scope(const Scope *scope) {
85 CHECK(!scope_);
86 bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
87 CHECK(isSubmodule_ == scopeIsSubmodule);
88 scope_ = scope;
91 llvm::raw_ostream &operator<<(
92 llvm::raw_ostream &os, const SubprogramDetails &x) {
93 DumpBool(os, "isInterface", x.isInterface_);
94 DumpBool(os, "dummy", x.isDummy_);
95 DumpOptional(os, "bindName", x.bindName());
96 if (x.result_) {
97 DumpType(os << " result:", x.result());
98 os << x.result_->name();
99 if (!x.result_->attrs().empty()) {
100 os << ", " << x.result_->attrs();
103 if (x.entryScope_) {
104 os << " entry";
105 if (x.entryScope_->symbol()) {
106 os << " in " << x.entryScope_->symbol()->name();
109 char sep{'('};
110 os << ' ';
111 for (const Symbol *arg : x.dummyArgs_) {
112 os << sep;
113 sep = ',';
114 if (arg) {
115 DumpType(os, *arg);
116 os << arg->name();
117 } else {
118 os << '*';
121 os << (sep == '(' ? "()" : ")");
122 if (x.stmtFunction_) {
123 os << " -> " << x.stmtFunction_->AsFortran();
125 if (x.moduleInterface_) {
126 os << " moduleInterface: " << *x.moduleInterface_;
128 return os;
131 void EntityDetails::set_type(const DeclTypeSpec &type) {
132 CHECK(!type_);
133 type_ = &type;
136 void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
137 void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
139 ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
140 : EntityDetails(std::move(d)) {}
142 void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
143 CHECK(shape_.empty());
144 for (const auto &shapeSpec : shape) {
145 shape_.push_back(shapeSpec);
148 void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
149 CHECK(coshape_.empty());
150 for (const auto &shapeSpec : coshape) {
151 coshape_.push_back(shapeSpec);
155 ProcEntityDetails::ProcEntityDetails(EntityDetails &&d)
156 : EntityDetails(std::move(d)) {}
158 UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
159 add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope());
161 UseErrorDetails &UseErrorDetails::add_occurrence(
162 const SourceName &location, const Scope &module) {
163 occurrences_.push_back(std::make_pair(location, &module));
164 return *this;
167 void GenericDetails::AddSpecificProc(
168 const Symbol &proc, SourceName bindingName) {
169 specificProcs_.push_back(proc);
170 bindingNames_.push_back(bindingName);
172 void GenericDetails::set_specific(Symbol &specific) {
173 CHECK(!specific_);
174 CHECK(!derivedType_);
175 specific_ = &specific;
177 void GenericDetails::clear_specific() { specific_ = nullptr; }
178 void GenericDetails::set_derivedType(Symbol &derivedType) {
179 CHECK(!specific_);
180 CHECK(!derivedType_);
181 derivedType_ = &derivedType;
183 void GenericDetails::clear_derivedType() { derivedType_ = nullptr; }
184 void GenericDetails::AddUse(const Symbol &use) {
185 CHECK(use.has<UseDetails>());
186 uses_.push_back(use);
189 const Symbol *GenericDetails::CheckSpecific() const {
190 return const_cast<GenericDetails *>(this)->CheckSpecific();
192 Symbol *GenericDetails::CheckSpecific() {
193 if (specific_) {
194 for (const Symbol &proc : specificProcs_) {
195 if (&proc == specific_) {
196 return nullptr;
199 return specific_;
200 } else {
201 return nullptr;
205 void GenericDetails::CopyFrom(const GenericDetails &from) {
206 CHECK(specificProcs_.size() == bindingNames_.size());
207 CHECK(from.specificProcs_.size() == from.bindingNames_.size());
208 kind_ = from.kind_;
209 if (from.derivedType_) {
210 CHECK(!derivedType_ || derivedType_ == from.derivedType_);
211 derivedType_ = from.derivedType_;
213 for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
214 if (std::find_if(specificProcs_.begin(), specificProcs_.end(),
215 [&](const Symbol &mySymbol) {
216 return &mySymbol.GetUltimate() ==
217 &from.specificProcs_[i]->GetUltimate();
218 }) == specificProcs_.end()) {
219 specificProcs_.push_back(from.specificProcs_[i]);
220 bindingNames_.push_back(from.bindingNames_[i]);
225 // The name of the kind of details for this symbol.
226 // This is primarily for debugging.
227 std::string DetailsToString(const Details &details) {
228 return common::visit(
229 common::visitors{
230 [](const UnknownDetails &) { return "Unknown"; },
231 [](const MainProgramDetails &) { return "MainProgram"; },
232 [](const ModuleDetails &) { return "Module"; },
233 [](const SubprogramDetails &) { return "Subprogram"; },
234 [](const SubprogramNameDetails &) { return "SubprogramName"; },
235 [](const EntityDetails &) { return "Entity"; },
236 [](const ObjectEntityDetails &) { return "ObjectEntity"; },
237 [](const ProcEntityDetails &) { return "ProcEntity"; },
238 [](const DerivedTypeDetails &) { return "DerivedType"; },
239 [](const UseDetails &) { return "Use"; },
240 [](const UseErrorDetails &) { return "UseError"; },
241 [](const HostAssocDetails &) { return "HostAssoc"; },
242 [](const GenericDetails &) { return "Generic"; },
243 [](const ProcBindingDetails &) { return "ProcBinding"; },
244 [](const NamelistDetails &) { return "Namelist"; },
245 [](const CommonBlockDetails &) { return "CommonBlockDetails"; },
246 [](const TypeParamDetails &) { return "TypeParam"; },
247 [](const MiscDetails &) { return "Misc"; },
248 [](const AssocEntityDetails &) { return "AssocEntity"; },
250 details);
253 std::string Symbol::GetDetailsName() const { return DetailsToString(details_); }
255 void Symbol::set_details(Details &&details) {
256 CHECK(CanReplaceDetails(details));
257 details_ = std::move(details);
260 bool Symbol::CanReplaceDetails(const Details &details) const {
261 if (has<UnknownDetails>()) {
262 return true; // can always replace UnknownDetails
263 } else {
264 return common::visit(
265 common::visitors{
266 [](const UseErrorDetails &) { return true; },
267 [&](const ObjectEntityDetails &) { return has<EntityDetails>(); },
268 [&](const ProcEntityDetails &) { return has<EntityDetails>(); },
269 [&](const SubprogramDetails &) {
270 return has<SubprogramNameDetails>() || has<EntityDetails>();
272 [&](const DerivedTypeDetails &) {
273 const auto *derived{this->detailsIf<DerivedTypeDetails>()};
274 return derived && derived->isForwardReferenced();
276 [&](const UseDetails &x) {
277 const auto *use{this->detailsIf<UseDetails>()};
278 return use && use->symbol() == x.symbol();
280 [&](const HostAssocDetails &) {
281 return this->has<HostAssocDetails>();
283 [](const auto &) { return false; },
285 details);
289 // Usually a symbol's name is the first occurrence in the source, but sometimes
290 // we want to replace it with one at a different location (but same characters).
291 void Symbol::ReplaceName(const SourceName &name) {
292 CHECK(name == name_);
293 name_ = name;
296 void Symbol::SetType(const DeclTypeSpec &type) {
297 common::visit(common::visitors{
298 [&](EntityDetails &x) { x.set_type(type); },
299 [&](ObjectEntityDetails &x) { x.set_type(type); },
300 [&](AssocEntityDetails &x) { x.set_type(type); },
301 [&](ProcEntityDetails &x) { x.set_type(type); },
302 [&](TypeParamDetails &x) { x.set_type(type); },
303 [](auto &) {},
305 details_);
308 template <typename T>
309 constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>};
311 const std::string *Symbol::GetBindName() const {
312 return common::visit(
313 [&](auto &x) -> const std::string * {
314 if constexpr (HasBindName<decltype(&x)>) {
315 return x.bindName();
316 } else {
317 return nullptr;
320 details_);
323 void Symbol::SetBindName(std::string &&name) {
324 common::visit(
325 [&](auto &x) {
326 if constexpr (HasBindName<decltype(&x)>) {
327 x.set_bindName(std::move(name));
328 } else {
329 DIE("bind name not allowed on this kind of symbol");
332 details_);
335 bool Symbol::GetIsExplicitBindName() const {
336 return common::visit(
337 [&](auto &x) -> bool {
338 if constexpr (HasBindName<decltype(&x)>) {
339 return x.isExplicitBindName();
340 } else {
341 return false;
344 details_);
347 void Symbol::SetIsExplicitBindName(bool yes) {
348 common::visit(
349 [&](auto &x) {
350 if constexpr (HasBindName<decltype(&x)>) {
351 x.set_isExplicitBindName(yes);
352 } else {
353 DIE("bind name not allowed on this kind of symbol");
356 details_);
359 bool Symbol::IsFuncResult() const {
360 return common::visit(
361 common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
362 [](const ObjectEntityDetails &x) { return x.isFuncResult(); },
363 [](const ProcEntityDetails &x) { return x.isFuncResult(); },
364 [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
365 [](const auto &) { return false; }},
366 details_);
369 bool Symbol::IsObjectArray() const {
370 const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
371 return details && details->IsArray();
374 bool Symbol::IsSubprogram() const {
375 return common::visit(
376 common::visitors{
377 [](const SubprogramDetails &) { return true; },
378 [](const SubprogramNameDetails &) { return true; },
379 [](const GenericDetails &) { return true; },
380 [](const UseDetails &x) { return x.symbol().IsSubprogram(); },
381 [](const auto &) { return false; },
383 details_);
386 bool Symbol::IsFromModFile() const {
387 return test(Flag::ModFile) ||
388 (!owner_->IsTopLevel() && owner_->symbol()->IsFromModFile());
391 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
392 DumpBool(os, "dummy", x.isDummy());
393 DumpBool(os, "funcResult", x.isFuncResult());
394 if (x.type()) {
395 os << " type: " << *x.type();
397 DumpOptional(os, "bindName", x.bindName());
398 return os;
401 llvm::raw_ostream &operator<<(
402 llvm::raw_ostream &os, const ObjectEntityDetails &x) {
403 os << *static_cast<const EntityDetails *>(&x);
404 DumpList(os, "shape", x.shape());
405 DumpList(os, "coshape", x.coshape());
406 DumpExpr(os, "init", x.init_);
407 if (x.unanalyzedPDTComponentInit()) {
408 os << " (has unanalyzedPDTComponentInit)";
410 return os;
413 llvm::raw_ostream &operator<<(
414 llvm::raw_ostream &os, const AssocEntityDetails &x) {
415 os << *static_cast<const EntityDetails *>(&x);
416 if (auto assocRank{x.rank()}) {
417 os << " rank: " << *assocRank;
419 DumpExpr(os, "expr", x.expr());
420 return os;
423 llvm::raw_ostream &operator<<(
424 llvm::raw_ostream &os, const ProcEntityDetails &x) {
425 if (x.procInterface_) {
426 os << ' ' << x.procInterface_->name();
427 } else {
428 DumpType(os, x.type());
430 DumpOptional(os, "bindName", x.bindName());
431 DumpOptional(os, "passName", x.passName());
432 if (x.init()) {
433 if (const Symbol * target{*x.init()}) {
434 os << " => " << target->name();
435 } else {
436 os << " => NULL()";
439 return os;
442 llvm::raw_ostream &operator<<(
443 llvm::raw_ostream &os, const DerivedTypeDetails &x) {
444 DumpBool(os, "sequence", x.sequence_);
445 DumpList(os, "components", x.componentNames_);
446 return os;
449 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) {
450 os << ' ' << x.kind().ToString();
451 DumpBool(os, "(specific)", x.specific() != nullptr);
452 DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
453 if (const auto &uses{x.uses()}; !uses.empty()) {
454 os << " (uses:";
455 char sep{' '};
456 for (const Symbol &use : uses) {
457 const Symbol &ultimate{use.GetUltimate()};
458 os << sep << ultimate.name() << "->"
459 << ultimate.owner().GetName().value();
460 sep = ',';
462 os << ')';
464 os << " procs:";
465 DumpSymbolVector(os, x.specificProcs());
466 return os;
469 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
470 os << DetailsToString(details);
471 common::visit( //
472 common::visitors{
473 [&](const UnknownDetails &) {},
474 [&](const MainProgramDetails &) {},
475 [&](const ModuleDetails &x) {
476 if (x.isSubmodule()) {
477 os << " (";
478 if (x.ancestor()) {
479 auto ancestor{x.ancestor()->GetName().value()};
480 os << ancestor;
481 if (x.parent()) {
482 auto parent{x.parent()->GetName().value()};
483 if (ancestor != parent) {
484 os << ':' << parent;
488 os << ")";
491 [&](const SubprogramNameDetails &x) {
492 os << ' ' << EnumToString(x.kind());
494 [&](const UseDetails &x) {
495 os << " from " << x.symbol().name() << " in "
496 << GetUsedModule(x).name();
498 [&](const UseErrorDetails &x) {
499 os << " uses:";
500 char sep{':'};
501 for (const auto &[location, module] : x.occurrences()) {
502 os << sep << " from " << module->GetName().value() << " at "
503 << location;
504 sep = ',';
507 [](const HostAssocDetails &) {},
508 [&](const ProcBindingDetails &x) {
509 os << " => " << x.symbol().name();
510 DumpOptional(os, "passName", x.passName());
512 [&](const NamelistDetails &x) {
513 os << ':';
514 DumpSymbolVector(os, x.objects());
516 [&](const CommonBlockDetails &x) {
517 DumpOptional(os, "bindName", x.bindName());
518 if (x.alignment()) {
519 os << " alignment=" << x.alignment();
521 os << ':';
522 for (const auto &object : x.objects()) {
523 os << ' ' << object->name();
526 [&](const TypeParamDetails &x) {
527 DumpOptional(os, "type", x.type());
528 os << ' ' << common::EnumToString(x.attr());
529 DumpExpr(os, "init", x.init());
531 [&](const MiscDetails &x) {
532 os << ' ' << MiscDetails::EnumToString(x.kind());
534 [&](const auto &x) { os << x; },
536 details);
537 return os;
540 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
541 return o << Symbol::EnumToString(flag);
544 llvm::raw_ostream &operator<<(
545 llvm::raw_ostream &o, const Symbol::Flags &flags) {
546 std::size_t n{flags.count()};
547 std::size_t seen{0};
548 for (std::size_t j{0}; seen < n; ++j) {
549 Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
550 if (flags.test(flag)) {
551 if (seen++ > 0) {
552 o << ", ";
554 o << flag;
557 return o;
560 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
561 os << symbol.name();
562 if (!symbol.attrs().empty()) {
563 os << ", " << symbol.attrs();
565 if (!symbol.flags().empty()) {
566 os << " (" << symbol.flags() << ')';
568 if (symbol.size_) {
569 os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
571 os << ": " << symbol.details_;
572 return os;
575 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
576 void Symbol::dump() const { llvm::errs() << *this << '\n'; }
577 #endif
579 // Output a unique name for a scope by qualifying it with the names of
580 // parent scopes. For scopes without corresponding symbols, use the kind
581 // with an index (e.g. Block1, Block2, etc.).
582 static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
583 if (!scope.IsTopLevel()) {
584 DumpUniqueName(os, scope.parent());
585 os << '/';
586 if (auto *scopeSymbol{scope.symbol()};
587 scopeSymbol && !scopeSymbol->name().empty()) {
588 os << scopeSymbol->name();
589 } else {
590 int index{1};
591 for (auto &child : scope.parent().children()) {
592 if (child == scope) {
593 break;
595 if (child.kind() == scope.kind()) {
596 ++index;
599 os << Scope::EnumToString(scope.kind()) << index;
604 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the
605 // format should be reasonably stable.
606 llvm::raw_ostream &DumpForUnparse(
607 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
608 DumpUniqueName(os, symbol.owner());
609 os << '/' << symbol.name();
610 if (isDef) {
611 if (!symbol.attrs().empty()) {
612 os << ' ' << symbol.attrs();
614 if (!symbol.flags().empty()) {
615 os << " (" << symbol.flags() << ')';
617 os << ' ' << symbol.GetDetailsName();
618 DumpType(os, symbol.GetType());
620 return os;
623 const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
624 if (const Symbol * parentComponent{GetParentComponent(scope)}) {
625 const auto &object{parentComponent->get<ObjectEntityDetails>()};
626 return &object.type()->derivedTypeSpec();
627 } else {
628 return nullptr;
632 const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
633 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
634 if (const Scope * localScope{scope ? scope : scope_}) {
635 return dtDetails->GetParentComponent(DEREF(localScope));
638 return nullptr;
641 void DerivedTypeDetails::add_component(const Symbol &symbol) {
642 if (symbol.test(Symbol::Flag::ParentComp)) {
643 CHECK(componentNames_.empty());
645 componentNames_.push_back(symbol.name());
648 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
649 if (auto extends{GetParentComponentName()}) {
650 if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
651 if (const Symbol & symbol{*iter->second};
652 symbol.test(Symbol::Flag::ParentComp)) {
653 return &symbol;
657 return nullptr;
660 const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
661 for (const auto &pair : finals_) {
662 const Symbol &symbol{*pair.second};
663 if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) {
664 if (details->dummyArgs().size() == 1) {
665 if (const Symbol * arg{details->dummyArgs().at(0)}) {
666 if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) {
667 if (rank == object->shape().Rank() || object->IsAssumedRank() ||
668 IsElementalProcedure(symbol)) {
669 return &symbol;
676 return nullptr;
679 void TypeParamDetails::set_type(const DeclTypeSpec &type) {
680 CHECK(!type_);
681 type_ = &type;
684 bool GenericKind::IsIntrinsicOperator() const {
685 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
686 Has<common::NumericOperator>() || Has<common::RelationalOperator>();
689 bool GenericKind::IsOperator() const {
690 return IsDefinedOperator() || IsIntrinsicOperator();
693 std::string GenericKind::ToString() const {
694 return common::visit(
695 common::visitors {
696 [](const OtherKind &x) { return std::string{EnumToString(x)}; },
697 [](const DefinedIo &x) { return AsFortran(x).ToString(); },
698 #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
699 [](const common::NumericOperator &x) {
700 return std::string{common::EnumToString(x)};
702 [](const common::LogicalOperator &x) {
703 return std::string{common::EnumToString(x)};
705 [](const common::RelationalOperator &x) {
706 return std::string{common::EnumToString(x)};
708 #else
709 [](const auto &x) { return std::string{common::EnumToString(x)}; },
710 #endif
715 SourceName GenericKind::AsFortran(DefinedIo x) {
716 const char *name{nullptr};
717 switch (x) {
718 SWITCH_COVERS_ALL_CASES
719 case DefinedIo::ReadFormatted:
720 name = "read(formatted)";
721 break;
722 case DefinedIo::ReadUnformatted:
723 name = "read(unformatted)";
724 break;
725 case DefinedIo::WriteFormatted:
726 name = "write(formatted)";
727 break;
728 case DefinedIo::WriteUnformatted:
729 name = "write(unformatted)";
730 break;
732 return {name, std::strlen(name)};
735 bool GenericKind::Is(GenericKind::OtherKind x) const {
736 const OtherKind *y{std::get_if<OtherKind>(&u)};
737 return y && *y == x;
740 bool SymbolOffsetCompare::operator()(
741 const SymbolRef &x, const SymbolRef &y) const {
742 const Symbol *xCommon{FindCommonBlockContaining(*x)};
743 const Symbol *yCommon{FindCommonBlockContaining(*y)};
744 if (xCommon) {
745 if (yCommon) {
746 const SymbolSourcePositionCompare sourceCmp;
747 if (sourceCmp(*xCommon, *yCommon)) {
748 return true;
749 } else if (sourceCmp(*yCommon, *xCommon)) {
750 return false;
751 } else if (x->offset() == y->offset()) {
752 return x->size() > y->size();
753 } else {
754 return x->offset() < y->offset();
756 } else {
757 return false;
759 } else if (yCommon) {
760 return true;
761 } else if (x->offset() == y->offset()) {
762 return x->size() > y->size();
763 } else {
764 return x->offset() < y->offset();
766 return x->GetSemanticsContext().allCookedSources().Precedes(
767 x->name(), y->name());
770 bool SymbolOffsetCompare::operator()(
771 const MutableSymbolRef &x, const MutableSymbolRef &y) const {
772 return (*this)(SymbolRef{*x}, SymbolRef{*y});
775 } // namespace Fortran::semantics