1 //===-- lib/Semantics/scope.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/scope.h"
10 #include "flang/Parser/characters.h"
11 #include "flang/Semantics/symbol.h"
12 #include "flang/Semantics/type.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include <algorithm>
15 #include <memory>
16 
17 namespace Fortran::semantics {
18 
19 Symbols<1024> Scope::allSymbols;
20 
21 bool EquivalenceObject::operator==(const EquivalenceObject &that) const {
22   return symbol == that.symbol && subscripts == that.subscripts &&
23       substringStart == that.substringStart;
24 }
25 
26 bool EquivalenceObject::operator<(const EquivalenceObject &that) const {
27   return &symbol < &that.symbol ||
28       (&symbol == &that.symbol &&
29           (subscripts < that.subscripts ||
30               (subscripts == that.subscripts &&
31                   substringStart < that.substringStart)));
32 }
33 
34 std::string EquivalenceObject::AsFortran() const {
35   std::string buf;
36   llvm::raw_string_ostream ss{buf};
37   ss << symbol.name().ToString();
38   if (!subscripts.empty()) {
39     char sep{'('};
40     for (auto subscript : subscripts) {
41       ss << sep << subscript;
42       sep = ',';
43     }
44     ss << ')';
45   }
46   if (substringStart) {
47     ss << '(' << *substringStart << ":)";
48   }
49   return ss.str();
50 }
51 
52 bool Scope::IsModule() const {
53   return kind_ == Kind::Module && !symbol_->get<ModuleDetails>().isSubmodule();
54 }
55 bool Scope::IsSubmodule() const {
56   return kind_ == Kind::Module && symbol_->get<ModuleDetails>().isSubmodule();
57 }
58 
59 Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
60   return children_.emplace_back(*this, kind, symbol);
61 }
62 
63 template <typename T>
64 static std::vector<common::Reference<T>> GetSortedSymbols(
65     std::map<SourceName, common::Reference<Symbol>> symbols) {
66   std::vector<common::Reference<T>> result;
67   result.reserve(symbols.size());
68   for (auto &pair : symbols) {
69     result.push_back(*pair.second);
70   }
71   std::sort(result.begin(), result.end());
72   return result;
73 }
74 
75 std::vector<common::Reference<Symbol>> Scope::GetSymbols() {
76   return GetSortedSymbols<Symbol>(symbols_);
77 }
78 SymbolVector Scope::GetSymbols() const {
79   return GetSortedSymbols<const Symbol>(symbols_);
80 }
81 
82 Scope::iterator Scope::find(const SourceName &name) {
83   return symbols_.find(name);
84 }
85 Scope::size_type Scope::erase(const SourceName &name) {
86   auto it{symbols_.find(name)};
87   if (it != end()) {
88     symbols_.erase(it);
89     return 1;
90   } else {
91     return 0;
92   }
93 }
94 Symbol *Scope::FindSymbol(const SourceName &name) const {
95   auto it{find(name)};
96   if (it != end()) {
97     return &*it->second;
98   } else if (CanImport(name)) {
99     return parent_.FindSymbol(name);
100   } else {
101     return nullptr;
102   }
103 }
104 
105 Symbol *Scope::FindComponent(SourceName name) const {
106   CHECK(IsDerivedType());
107   auto found{find(name)};
108   if (found != end()) {
109     return &*found->second;
110   } else if (const Scope * parent{GetDerivedTypeParent()}) {
111     return parent->FindComponent(name);
112   } else {
113     return nullptr;
114   }
115 }
116 
117 std::optional<SourceName> Scope::GetName() const {
118   if (const auto *sym{GetSymbol()}) {
119     return sym->name();
120   } else {
121     return std::nullopt;
122   }
123 }
124 
125 bool Scope::Contains(const Scope &that) const {
126   for (const Scope *scope{&that};; scope = &scope->parent()) {
127     if (*scope == *this) {
128       return true;
129     }
130     if (scope->IsGlobal()) {
131       return false;
132     }
133   }
134 }
135 
136 Symbol *Scope::CopySymbol(const Symbol &symbol) {
137   auto pair{try_emplace(symbol.name(), symbol.attrs())};
138   if (!pair.second) {
139     return nullptr; // already exists
140   } else {
141     Symbol &result{*pair.first->second};
142     result.flags() = symbol.flags();
143     result.set_details(common::Clone(symbol.details()));
144     return &result;
145   }
146 }
147 
148 const std::list<EquivalenceSet> &Scope::equivalenceSets() const {
149   return equivalenceSets_;
150 }
151 void Scope::add_equivalenceSet(EquivalenceSet &&set) {
152   equivalenceSets_.emplace_back(std::move(set));
153 }
154 
155 void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
156   CHECK(pointer.test(Symbol::Flag::CrayPointer));
157   crayPointers_.emplace(name, pointer);
158 }
159 
160 Symbol &Scope::MakeCommonBlock(const SourceName &name) {
161   const auto it{commonBlocks_.find(name)};
162   if (it != commonBlocks_.end()) {
163     return *it->second;
164   } else {
165     Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
166     commonBlocks_.emplace(name, symbol);
167     return symbol;
168   }
169 }
170 Symbol *Scope::FindCommonBlock(const SourceName &name) {
171   const auto it{commonBlocks_.find(name)};
172   return it != commonBlocks_.end() ? &*it->second : nullptr;
173 }
174 
175 Scope *Scope::FindSubmodule(const SourceName &name) const {
176   auto it{submodules_.find(name)};
177   if (it == submodules_.end()) {
178     return nullptr;
179   } else {
180     return &*it->second;
181   }
182 }
183 bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
184   return submodules_.emplace(name, submodule).second;
185 }
186 
187 const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {
188   auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)};
189   return it != declTypeSpecs_.end() ? &*it : nullptr;
190 }
191 
192 const DeclTypeSpec &Scope::MakeNumericType(
193     TypeCategory category, KindExpr &&kind) {
194   return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)});
195 }
196 const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) {
197   return MakeLengthlessType(LogicalTypeSpec{std::move(kind)});
198 }
199 const DeclTypeSpec &Scope::MakeTypeStarType() {
200   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar});
201 }
202 const DeclTypeSpec &Scope::MakeClassStarType() {
203   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar});
204 }
205 // Types that can't have length parameters can be reused without having to
206 // compare length expressions. They are stored in the global scope.
207 const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) {
208   const auto *found{FindType(type)};
209   return found ? *found : declTypeSpecs_.emplace_back(std::move(type));
210 }
211 
212 const DeclTypeSpec &Scope::MakeCharacterType(
213     ParamValue &&length, KindExpr &&kind) {
214   return declTypeSpecs_.emplace_back(
215       CharacterTypeSpec{std::move(length), std::move(kind)});
216 }
217 
218 DeclTypeSpec &Scope::MakeDerivedType(
219     DeclTypeSpec::Category category, DerivedTypeSpec &&spec) {
220   return declTypeSpecs_.emplace_back(category, std::move(spec));
221 }
222 
223 void Scope::set_chars(parser::CookedSource &cooked) {
224   CHECK(kind_ == Kind::Module);
225   CHECK(parent_.IsGlobal() || parent_.IsModuleFile());
226   CHECK(DEREF(symbol_).test(Symbol::Flag::ModFile));
227   // TODO: Preserve the CookedSource rather than acquiring its string.
228   chars_ = cooked.AcquireData();
229 }
230 
231 Scope::ImportKind Scope::GetImportKind() const {
232   if (importKind_) {
233     return *importKind_;
234   }
235   if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) {
236     if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) {
237       if (details->isInterface()) {
238         return ImportKind::None; // default for non-mod-proc interface body
239       }
240     }
241   }
242   return ImportKind::Default;
243 }
244 
245 std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) {
246   if (!importKind_) {
247     importKind_ = kind;
248     return std::nullopt;
249   }
250   bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None};
251   bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All};
252   // Check C8100 and C898: constraints on multiple IMPORT statements
253   if (hasNone || hasAll) {
254     return hasNone
255         ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
256         : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US;
257   } else if (kind != *importKind_ &&
258       (kind != ImportKind::Only || kind != ImportKind::Only)) {
259     return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US;
260   } else {
261     return std::nullopt;
262   }
263 }
264 
265 void Scope::add_importName(const SourceName &name) {
266   importNames_.insert(name);
267 }
268 
269 // true if name can be imported or host-associated from parent scope.
270 bool Scope::CanImport(const SourceName &name) const {
271   if (IsGlobal() || parent_.IsGlobal()) {
272     return false;
273   }
274   switch (GetImportKind()) {
275     SWITCH_COVERS_ALL_CASES
276   case ImportKind::None:
277     return false;
278   case ImportKind::All:
279   case ImportKind::Default:
280     return true;
281   case ImportKind::Only:
282     return importNames_.count(name) > 0;
283   }
284 }
285 
286 const Scope *Scope::FindScope(parser::CharBlock source) const {
287   return const_cast<Scope *>(this)->FindScope(source);
288 }
289 
290 Scope *Scope::FindScope(parser::CharBlock source) {
291   bool isContained{sourceRange_.Contains(source)};
292   if (!isContained && !IsGlobal() && !IsModuleFile()) {
293     return nullptr;
294   }
295   for (auto &child : children_) {
296     if (auto *scope{child.FindScope(source)}) {
297       return scope;
298     }
299   }
300   return isContained ? this : nullptr;
301 }
302 
303 void Scope::AddSourceRange(const parser::CharBlock &source) {
304   for (auto *scope = this; !scope->IsGlobal(); scope = &scope->parent()) {
305     scope->sourceRange_.ExtendToCover(source);
306   }
307 }
308 
309 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {
310   os << Scope::EnumToString(scope.kind()) << " scope: ";
311   if (auto *symbol{scope.symbol()}) {
312     os << *symbol << ' ';
313   }
314   if (scope.derivedTypeSpec_) {
315     os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';
316   }
317   os << scope.children_.size() << " children\n";
318   for (const auto &pair : scope.symbols_) {
319     const Symbol &symbol{*pair.second};
320     os << "  " << symbol << '\n';
321   }
322   if (!scope.equivalenceSets_.empty()) {
323     os << "  Equivalence Sets:\n";
324     for (const auto &set : scope.equivalenceSets_) {
325       os << "   ";
326       for (const auto &object : set) {
327         os << ' ' << object.AsFortran();
328       }
329       os << '\n';
330     }
331   }
332   for (const auto &pair : scope.commonBlocks_) {
333     const Symbol &symbol{*pair.second};
334     os << "  " << symbol << '\n';
335   }
336   return os;
337 }
338 
339 bool Scope::IsParameterizedDerivedType() const {
340   if (!IsDerivedType()) {
341     return false;
342   }
343   if (const Scope * parent{GetDerivedTypeParent()}) {
344     if (parent->IsParameterizedDerivedType()) {
345       return true;
346     }
347   }
348   for (const auto &pair : symbols_) {
349     if (pair.second->has<TypeParamDetails>()) {
350       return true;
351     }
352   }
353   return false;
354 }
355 
356 const DeclTypeSpec *Scope::FindInstantiatedDerivedType(
357     const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {
358   DeclTypeSpec type{category, spec};
359   if (const auto *result{FindType(type)}) {
360     return result;
361   } else if (IsGlobal()) {
362     return nullptr;
363   } else {
364     return parent().FindInstantiatedDerivedType(spec, category);
365   }
366 }
367 
368 const Symbol *Scope::GetSymbol() const {
369   if (symbol_) {
370     return symbol_;
371   }
372   if (derivedTypeSpec_) {
373     return &derivedTypeSpec_->typeSymbol();
374   }
375   return nullptr;
376 }
377 
378 const Scope *Scope::GetDerivedTypeParent() const {
379   if (const Symbol * symbol{GetSymbol()}) {
380     if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) {
381       return parent->scope();
382     }
383   }
384   return nullptr;
385 }
386 
387 const Scope &Scope::GetDerivedTypeBase() const {
388   const Scope *child{this};
389   for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
390        parent = child->GetDerivedTypeParent()) {
391     child = parent;
392   }
393   return *child;
394 }
395 
396 void Scope::InstantiateDerivedTypes(SemanticsContext &context) {
397   for (DeclTypeSpec &type : declTypeSpecs_) {
398     if (type.category() == DeclTypeSpec::TypeDerived ||
399         type.category() == DeclTypeSpec::ClassDerived) {
400       type.derivedTypeSpec().Instantiate(*this, context);
401     }
402   }
403 }
404 } // namespace Fortran::semantics
405