1 //===-- lib/Semantics/symbol.cpp ------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Semantics/symbol.h"
10 #include "flang/Common/idioms.h"
11 #include "flang/Evaluate/expression.h"
12 #include "flang/Semantics/scope.h"
13 #include "flang/Semantics/semantics.h"
14 #include "flang/Semantics/tools.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include <string>
17 #include <type_traits>
18 
19 namespace Fortran::semantics {
20 
21 template <typename T>
22 static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) {
23   if (x) {
24     os << ' ' << label << ':' << *x;
25   }
26 }
27 template <typename T>
28 static void DumpExpr(llvm::raw_ostream &os, const char *label,
29     const std::optional<evaluate::Expr<T>> &x) {
30   if (x) {
31     x->AsFortran(os << ' ' << label << ':');
32   }
33 }
34 
35 static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) {
36   if (x) {
37     os << ' ' << label;
38   }
39 }
40 
41 static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) {
42   char sep{' '};
43   for (const Symbol &elem : list) {
44     os << sep << elem.name();
45     sep = ',';
46   }
47 }
48 
49 static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) {
50   if (const auto *type{symbol.GetType()}) {
51     os << *type << ' ';
52   }
53 }
54 static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) {
55   if (type) {
56     os << ' ' << *type;
57   }
58 }
59 
60 template <typename T>
61 static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
62   if (!list.empty()) {
63     os << ' ' << label << ':';
64     char sep{' '};
65     for (const auto &elem : list) {
66       os << sep << elem;
67       sep = ',';
68     }
69   }
70 }
71 
72 const Scope *ModuleDetails::parent() const {
73   return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
74 }
75 const Scope *ModuleDetails::ancestor() const {
76   return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr;
77 }
78 void ModuleDetails::set_scope(const Scope *scope) {
79   CHECK(!scope_);
80   bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
81   CHECK(isSubmodule_ == scopeIsSubmodule);
82   scope_ = scope;
83 }
84 
85 llvm::raw_ostream &operator<<(
86     llvm::raw_ostream &os, const SubprogramDetails &x) {
87   DumpBool(os, "isInterface", x.isInterface_);
88   DumpBool(os, "dummy", x.isDummy_);
89   DumpOptional(os, "bindName", x.bindName());
90   if (x.result_) {
91     DumpType(os << " result:", x.result());
92     os << x.result_->name();
93     if (!x.result_->attrs().empty()) {
94       os << ", " << x.result_->attrs();
95     }
96   }
97   if (x.entryScope_) {
98     os << " entry";
99     if (x.entryScope_->symbol()) {
100       os << " in " << x.entryScope_->symbol()->name();
101     }
102   }
103   char sep{'('};
104   os << ' ';
105   for (const Symbol *arg : x.dummyArgs_) {
106     os << sep;
107     sep = ',';
108     if (arg) {
109       DumpType(os, *arg);
110       os << arg->name();
111     } else {
112       os << '*';
113     }
114   }
115   os << (sep == '(' ? "()" : ")");
116   if (x.stmtFunction_) {
117     os << " -> " << x.stmtFunction_->AsFortran();
118   }
119   return os;
120 }
121 
122 void EntityDetails::set_type(const DeclTypeSpec &type) {
123   CHECK(!type_);
124   type_ = &type;
125 }
126 
127 void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
128 void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
129 
130 void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
131   CHECK(shape_.empty());
132   for (const auto &shapeSpec : shape) {
133     shape_.push_back(shapeSpec);
134   }
135 }
136 void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
137   CHECK(coshape_.empty());
138   for (const auto &shapeSpec : coshape) {
139     coshape_.push_back(shapeSpec);
140   }
141 }
142 
143 ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
144   if (type()) {
145     interface_.set_type(*type());
146   }
147 }
148 
149 UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
150   add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope());
151 }
152 UseErrorDetails &UseErrorDetails::add_occurrence(
153     const SourceName &location, const Scope &module) {
154   occurrences_.push_back(std::make_pair(location, &module));
155   return *this;
156 }
157 
158 void GenericDetails::AddSpecificProc(
159     const Symbol &proc, SourceName bindingName) {
160   specificProcs_.push_back(proc);
161   bindingNames_.push_back(bindingName);
162 }
163 void GenericDetails::set_specific(Symbol &specific) {
164   CHECK(!specific_);
165   CHECK(!derivedType_);
166   specific_ = &specific;
167 }
168 void GenericDetails::set_derivedType(Symbol &derivedType) {
169   CHECK(!specific_);
170   CHECK(!derivedType_);
171   derivedType_ = &derivedType;
172 }
173 void GenericDetails::AddUse(const Symbol &use) {
174   CHECK(use.has<UseDetails>());
175   uses_.push_back(use);
176 }
177 
178 const Symbol *GenericDetails::CheckSpecific() const {
179   return const_cast<GenericDetails *>(this)->CheckSpecific();
180 }
181 Symbol *GenericDetails::CheckSpecific() {
182   if (specific_) {
183     for (const Symbol &proc : specificProcs_) {
184       if (&proc == specific_) {
185         return nullptr;
186       }
187     }
188     return specific_;
189   } else {
190     return nullptr;
191   }
192 }
193 
194 void GenericDetails::CopyFrom(const GenericDetails &from) {
195   CHECK(specificProcs_.size() == bindingNames_.size());
196   CHECK(from.specificProcs_.size() == from.bindingNames_.size());
197   kind_ = from.kind_;
198   if (from.derivedType_) {
199     CHECK(!derivedType_ || derivedType_ == from.derivedType_);
200     derivedType_ = from.derivedType_;
201   }
202   for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
203     if (std::find_if(specificProcs_.begin(), specificProcs_.end(),
204             [&](const Symbol &mySymbol) {
205               return &mySymbol == &*from.specificProcs_[i];
206             }) == specificProcs_.end()) {
207       specificProcs_.push_back(from.specificProcs_[i]);
208       bindingNames_.push_back(from.bindingNames_[i]);
209     }
210   }
211 }
212 
213 // The name of the kind of details for this symbol.
214 // This is primarily for debugging.
215 std::string DetailsToString(const Details &details) {
216   return std::visit(
217       common::visitors{
218           [](const UnknownDetails &) { return "Unknown"; },
219           [](const MainProgramDetails &) { return "MainProgram"; },
220           [](const ModuleDetails &) { return "Module"; },
221           [](const SubprogramDetails &) { return "Subprogram"; },
222           [](const SubprogramNameDetails &) { return "SubprogramName"; },
223           [](const EntityDetails &) { return "Entity"; },
224           [](const ObjectEntityDetails &) { return "ObjectEntity"; },
225           [](const ProcEntityDetails &) { return "ProcEntity"; },
226           [](const DerivedTypeDetails &) { return "DerivedType"; },
227           [](const UseDetails &) { return "Use"; },
228           [](const UseErrorDetails &) { return "UseError"; },
229           [](const HostAssocDetails &) { return "HostAssoc"; },
230           [](const GenericDetails &) { return "Generic"; },
231           [](const ProcBindingDetails &) { return "ProcBinding"; },
232           [](const NamelistDetails &) { return "Namelist"; },
233           [](const CommonBlockDetails &) { return "CommonBlockDetails"; },
234           [](const TypeParamDetails &) { return "TypeParam"; },
235           [](const MiscDetails &) { return "Misc"; },
236           [](const AssocEntityDetails &) { return "AssocEntity"; },
237       },
238       details);
239 }
240 
241 const std::string Symbol::GetDetailsName() const {
242   return DetailsToString(details_);
243 }
244 
245 void Symbol::set_details(Details &&details) {
246   CHECK(CanReplaceDetails(details));
247   details_ = std::move(details);
248 }
249 
250 bool Symbol::CanReplaceDetails(const Details &details) const {
251   if (has<UnknownDetails>()) {
252     return true; // can always replace UnknownDetails
253   } else {
254     return std::visit(
255         common::visitors{
256             [](const UseErrorDetails &) { return true; },
257             [&](const ObjectEntityDetails &) { return has<EntityDetails>(); },
258             [&](const ProcEntityDetails &) { return has<EntityDetails>(); },
259             [&](const SubprogramDetails &) {
260               return has<SubprogramNameDetails>() || has<EntityDetails>();
261             },
262             [&](const DerivedTypeDetails &) {
263               const auto *derived{this->detailsIf<DerivedTypeDetails>()};
264               return derived && derived->isForwardReferenced();
265             },
266             [&](const UseDetails &x) {
267               const auto *use{this->detailsIf<UseDetails>()};
268               return use && use->symbol() == x.symbol();
269             },
270             [](const auto &) { return false; },
271         },
272         details);
273   }
274 }
275 
276 // Usually a symbol's name is the first occurrence in the source, but sometimes
277 // we want to replace it with one at a different location (but same characters).
278 void Symbol::ReplaceName(const SourceName &name) {
279   CHECK(name == name_);
280   name_ = name;
281 }
282 
283 void Symbol::SetType(const DeclTypeSpec &type) {
284   std::visit(common::visitors{
285                  [&](EntityDetails &x) { x.set_type(type); },
286                  [&](ObjectEntityDetails &x) { x.set_type(type); },
287                  [&](AssocEntityDetails &x) { x.set_type(type); },
288                  [&](ProcEntityDetails &x) { x.interface().set_type(type); },
289                  [&](TypeParamDetails &x) { x.set_type(type); },
290                  [](auto &) {},
291              },
292       details_);
293 }
294 
295 template <typename T>
296 constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>};
297 
298 const std::string *Symbol::GetBindName() const {
299   return std::visit(
300       [&](auto &x) -> const std::string * {
301         if constexpr (HasBindName<decltype(&x)>) {
302           return x.bindName();
303         } else {
304           return nullptr;
305         }
306       },
307       details_);
308 }
309 
310 void Symbol::SetBindName(std::string &&name) {
311   std::visit(
312       [&](auto &x) {
313         if constexpr (HasBindName<decltype(&x)>) {
314           x.set_bindName(std::move(name));
315         } else {
316           DIE("bind name not allowed on this kind of symbol");
317         }
318       },
319       details_);
320 }
321 
322 bool Symbol::IsFuncResult() const {
323   return std::visit(
324       common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
325           [](const ObjectEntityDetails &x) { return x.isFuncResult(); },
326           [](const ProcEntityDetails &x) { return x.isFuncResult(); },
327           [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
328           [](const auto &) { return false; }},
329       details_);
330 }
331 
332 bool Symbol::IsObjectArray() const {
333   const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
334   return details && details->IsArray();
335 }
336 
337 bool Symbol::IsSubprogram() const {
338   return std::visit(
339       common::visitors{
340           [](const SubprogramDetails &) { return true; },
341           [](const SubprogramNameDetails &) { return true; },
342           [](const GenericDetails &) { return true; },
343           [](const UseDetails &x) { return x.symbol().IsSubprogram(); },
344           [](const auto &) { return false; },
345       },
346       details_);
347 }
348 
349 bool Symbol::IsFromModFile() const {
350   return test(Flag::ModFile) ||
351       (!owner_->IsGlobal() && owner_->symbol()->IsFromModFile());
352 }
353 
354 ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
355     : EntityDetails(d) {}
356 
357 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
358   DumpBool(os, "dummy", x.isDummy());
359   DumpBool(os, "funcResult", x.isFuncResult());
360   if (x.type()) {
361     os << " type: " << *x.type();
362   }
363   DumpOptional(os, "bindName", x.bindName());
364   return os;
365 }
366 
367 llvm::raw_ostream &operator<<(
368     llvm::raw_ostream &os, const ObjectEntityDetails &x) {
369   os << *static_cast<const EntityDetails *>(&x);
370   DumpList(os, "shape", x.shape());
371   DumpList(os, "coshape", x.coshape());
372   DumpExpr(os, "init", x.init_);
373   return os;
374 }
375 
376 llvm::raw_ostream &operator<<(
377     llvm::raw_ostream &os, const AssocEntityDetails &x) {
378   os << *static_cast<const EntityDetails *>(&x);
379   if (auto assocRank{x.rank()}) {
380     os << " rank: " << *assocRank;
381   }
382   DumpExpr(os, "expr", x.expr());
383   return os;
384 }
385 
386 llvm::raw_ostream &operator<<(
387     llvm::raw_ostream &os, const ProcEntityDetails &x) {
388   if (auto *symbol{x.interface_.symbol()}) {
389     os << ' ' << symbol->name();
390   } else {
391     DumpType(os, x.interface_.type());
392   }
393   DumpOptional(os, "bindName", x.bindName());
394   DumpOptional(os, "passName", x.passName());
395   if (x.init()) {
396     if (const Symbol * target{*x.init()}) {
397       os << " => " << target->name();
398     } else {
399       os << " => NULL()";
400     }
401   }
402   return os;
403 }
404 
405 llvm::raw_ostream &operator<<(
406     llvm::raw_ostream &os, const DerivedTypeDetails &x) {
407   DumpBool(os, "sequence", x.sequence_);
408   DumpList(os, "components", x.componentNames_);
409   return os;
410 }
411 
412 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) {
413   os << ' ' << x.kind().ToString();
414   DumpBool(os, "(specific)", x.specific() != nullptr);
415   DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
416   if (const auto &uses{x.uses()}; !uses.empty()) {
417     os << " (uses:";
418     char sep{' '};
419     for (const Symbol &use : uses) {
420       const Symbol &ultimate{use.GetUltimate()};
421       os << sep << ultimate.name() << "->"
422          << ultimate.owner().GetName().value();
423       sep = ',';
424     }
425     os << ')';
426   }
427   os << " procs:";
428   DumpSymbolVector(os, x.specificProcs());
429   return os;
430 }
431 
432 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
433   os << DetailsToString(details);
434   std::visit( //
435       common::visitors{
436           [&](const UnknownDetails &) {},
437           [&](const MainProgramDetails &) {},
438           [&](const ModuleDetails &x) {
439             if (x.isSubmodule()) {
440               os << " (";
441               if (x.ancestor()) {
442                 auto ancestor{x.ancestor()->GetName().value()};
443                 os << ancestor;
444                 if (x.parent()) {
445                   auto parent{x.parent()->GetName().value()};
446                   if (ancestor != parent) {
447                     os << ':' << parent;
448                   }
449                 }
450               }
451               os << ")";
452             }
453           },
454           [&](const SubprogramNameDetails &x) {
455             os << ' ' << EnumToString(x.kind());
456           },
457           [&](const UseDetails &x) {
458             os << " from " << x.symbol().name() << " in "
459                << GetUsedModule(x).name();
460           },
461           [&](const UseErrorDetails &x) {
462             os << " uses:";
463             char sep{':'};
464             for (const auto &[location, module] : x.occurrences()) {
465               os << sep << " from " << module->GetName().value() << " at "
466                  << location;
467               sep = ',';
468             }
469           },
470           [](const HostAssocDetails &) {},
471           [&](const ProcBindingDetails &x) {
472             os << " => " << x.symbol().name();
473             DumpOptional(os, "passName", x.passName());
474           },
475           [&](const NamelistDetails &x) {
476             os << ':';
477             DumpSymbolVector(os, x.objects());
478           },
479           [&](const CommonBlockDetails &x) {
480             DumpOptional(os, "bindName", x.bindName());
481             if (x.alignment()) {
482               os << " alignment=" << x.alignment();
483             }
484             os << ':';
485             for (const auto &object : x.objects()) {
486               os << ' ' << object->name();
487             }
488           },
489           [&](const TypeParamDetails &x) {
490             DumpOptional(os, "type", x.type());
491             os << ' ' << common::EnumToString(x.attr());
492             DumpExpr(os, "init", x.init());
493           },
494           [&](const MiscDetails &x) {
495             os << ' ' << MiscDetails::EnumToString(x.kind());
496           },
497           [&](const auto &x) { os << x; },
498       },
499       details);
500   return os;
501 }
502 
503 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
504   return o << Symbol::EnumToString(flag);
505 }
506 
507 llvm::raw_ostream &operator<<(
508     llvm::raw_ostream &o, const Symbol::Flags &flags) {
509   std::size_t n{flags.count()};
510   std::size_t seen{0};
511   for (std::size_t j{0}; seen < n; ++j) {
512     Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
513     if (flags.test(flag)) {
514       if (seen++ > 0) {
515         o << ", ";
516       }
517       o << flag;
518     }
519   }
520   return o;
521 }
522 
523 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
524   os << symbol.name();
525   if (!symbol.attrs().empty()) {
526     os << ", " << symbol.attrs();
527   }
528   if (!symbol.flags().empty()) {
529     os << " (" << symbol.flags() << ')';
530   }
531   if (symbol.size_) {
532     os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
533   }
534   os << ": " << symbol.details_;
535   return os;
536 }
537 
538 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
539 void Symbol::dump() const { llvm::errs() << *this << '\n'; }
540 #endif
541 
542 // Output a unique name for a scope by qualifying it with the names of
543 // parent scopes. For scopes without corresponding symbols, use the kind
544 // with an index (e.g. Block1, Block2, etc.).
545 static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
546   if (!scope.IsGlobal()) {
547     DumpUniqueName(os, scope.parent());
548     os << '/';
549     if (auto *scopeSymbol{scope.symbol()};
550         scopeSymbol && !scopeSymbol->name().empty()) {
551       os << scopeSymbol->name();
552     } else {
553       int index{1};
554       for (auto &child : scope.parent().children()) {
555         if (child == scope) {
556           break;
557         }
558         if (child.kind() == scope.kind()) {
559           ++index;
560         }
561       }
562       os << Scope::EnumToString(scope.kind()) << index;
563     }
564   }
565 }
566 
567 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the
568 // format should be reasonably stable.
569 llvm::raw_ostream &DumpForUnparse(
570     llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
571   DumpUniqueName(os, symbol.owner());
572   os << '/' << symbol.name();
573   if (isDef) {
574     if (!symbol.attrs().empty()) {
575       os << ' ' << symbol.attrs();
576     }
577     if (!symbol.flags().empty()) {
578       os << " (" << symbol.flags() << ')';
579     }
580     os << ' ' << symbol.GetDetailsName();
581     DumpType(os, symbol.GetType());
582   }
583   return os;
584 }
585 
586 const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
587   if (const Symbol * parentComponent{GetParentComponent(scope)}) {
588     const auto &object{parentComponent->get<ObjectEntityDetails>()};
589     return &object.type()->derivedTypeSpec();
590   } else {
591     return nullptr;
592   }
593 }
594 
595 const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
596   if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
597     if (const Scope * localScope{scope ? scope : scope_}) {
598       return dtDetails->GetParentComponent(DEREF(localScope));
599     }
600   }
601   return nullptr;
602 }
603 
604 void DerivedTypeDetails::add_component(const Symbol &symbol) {
605   if (symbol.test(Symbol::Flag::ParentComp)) {
606     CHECK(componentNames_.empty());
607   }
608   componentNames_.push_back(symbol.name());
609 }
610 
611 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
612   if (auto extends{GetParentComponentName()}) {
613     if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
614       if (const Symbol & symbol{*iter->second};
615           symbol.test(Symbol::Flag::ParentComp)) {
616         return &symbol;
617       }
618     }
619   }
620   return nullptr;
621 }
622 
623 const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
624   for (const auto &pair : finals_) {
625     const Symbol &symbol{*pair.second};
626     if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) {
627       if (details->dummyArgs().size() == 1) {
628         if (const Symbol * arg{details->dummyArgs().at(0)}) {
629           if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) {
630             if (rank == object->shape().Rank() || object->IsAssumedRank() ||
631                 symbol.attrs().test(Attr::ELEMENTAL)) {
632               return &symbol;
633             }
634           }
635         }
636       }
637     }
638   }
639   return nullptr;
640 }
641 
642 void TypeParamDetails::set_type(const DeclTypeSpec &type) {
643   CHECK(!type_);
644   type_ = &type;
645 }
646 
647 bool GenericKind::IsIntrinsicOperator() const {
648   return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
649       Has<common::NumericOperator>() || Has<common::RelationalOperator>();
650 }
651 
652 bool GenericKind::IsOperator() const {
653   return IsDefinedOperator() || IsIntrinsicOperator();
654 }
655 
656 std::string GenericKind::ToString() const {
657   return std::visit(
658       common::visitors {
659         [](const OtherKind &x) { return EnumToString(x); },
660             [](const DefinedIo &x) { return EnumToString(x); },
661 #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
662             [](const common::NumericOperator &x) {
663               return common::EnumToString(x);
664             },
665             [](const common::LogicalOperator &x) {
666               return common::EnumToString(x);
667             },
668             [](const common::RelationalOperator &x) {
669               return common::EnumToString(x);
670             },
671 #else
672             [](const auto &x) { return common::EnumToString(x); },
673 #endif
674       },
675       u);
676 }
677 
678 bool GenericKind::Is(GenericKind::OtherKind x) const {
679   const OtherKind *y{std::get_if<OtherKind>(&u)};
680   return y && *y == x;
681 }
682 
683 bool SymbolOffsetCompare::operator()(
684     const SymbolRef &x, const SymbolRef &y) const {
685   const Symbol *xCommon{FindCommonBlockContaining(*x)};
686   const Symbol *yCommon{FindCommonBlockContaining(*y)};
687   if (xCommon) {
688     if (yCommon) {
689       const SymbolSourcePositionCompare sourceCmp;
690       if (sourceCmp(*xCommon, *yCommon)) {
691         return true;
692       } else if (sourceCmp(*yCommon, *xCommon)) {
693         return false;
694       } else if (x->offset() == y->offset()) {
695         return x->size() > y->size();
696       } else {
697         return x->offset() < y->offset();
698       }
699     } else {
700       return false;
701     }
702   } else if (yCommon) {
703     return true;
704   } else if (x->offset() == y->offset()) {
705     return x->size() > y->size();
706   } else {
707     return x->offset() < y->offset();
708   }
709   return x->GetSemanticsContext().allCookedSources().Precedes(
710       x->name(), y->name());
711 }
712 bool SymbolOffsetCompare::operator()(
713     const MutableSymbolRef &x, const MutableSymbolRef &y) const {
714   return (*this)(SymbolRef{*x}, SymbolRef{*y});
715 }
716 
717 } // namespace Fortran::semantics
718