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