xref: /llvm-project/flang/lib/Semantics/scope.cpp (revision fc97d2e68b03bc2979395e84b645e5b3ba35aecd)
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/semantics.h"
12 #include "flang/Semantics/symbol.h"
13 #include "flang/Semantics/type.h"
14 #include "llvm/Support/raw_ostream.h"
15 #include <algorithm>
16 #include <memory>
17 
18 namespace Fortran::semantics {
19 
20 Symbols<1024> Scope::allSymbols;
21 
22 bool EquivalenceObject::operator==(const EquivalenceObject &that) const {
23   return symbol == that.symbol && subscripts == that.subscripts &&
24       substringStart == that.substringStart;
25 }
26 
27 bool EquivalenceObject::operator<(const EquivalenceObject &that) const {
28   return &symbol < &that.symbol ||
29       (&symbol == &that.symbol &&
30           (subscripts < that.subscripts ||
31               (subscripts == that.subscripts &&
32                   substringStart < that.substringStart)));
33 }
34 
35 std::string EquivalenceObject::AsFortran() const {
36   std::string buf;
37   llvm::raw_string_ostream ss{buf};
38   ss << symbol.name().ToString();
39   if (!subscripts.empty()) {
40     char sep{'('};
41     for (auto subscript : subscripts) {
42       ss << sep << subscript;
43       sep = ',';
44     }
45     ss << ')';
46   }
47   if (substringStart) {
48     ss << '(' << *substringStart << ":)";
49   }
50   return buf;
51 }
52 
53 Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
54   return children_.emplace_back(*this, kind, symbol, context_);
55 }
56 
57 template <typename T>
58 static std::vector<common::Reference<T>> GetSortedSymbols(
59     const std::map<SourceName, MutableSymbolRef> &symbols) {
60   std::vector<common::Reference<T>> result;
61   result.reserve(symbols.size());
62   for (auto &pair : symbols) {
63     result.push_back(*pair.second);
64   }
65   std::sort(result.begin(), result.end(), SymbolSourcePositionCompare{});
66   return result;
67 }
68 
69 MutableSymbolVector Scope::GetSymbols() {
70   return GetSortedSymbols<Symbol>(symbols_);
71 }
72 SymbolVector Scope::GetSymbols() const {
73   return GetSortedSymbols<const Symbol>(symbols_);
74 }
75 
76 Scope::iterator Scope::find(const SourceName &name) {
77   return symbols_.find(name);
78 }
79 Scope::size_type Scope::erase(const SourceName &name) {
80   auto it{symbols_.find(name)};
81   if (it != end()) {
82     symbols_.erase(it);
83     return 1;
84   } else {
85     return 0;
86   }
87 }
88 Symbol *Scope::FindSymbol(const SourceName &name) const {
89   auto it{find(name)};
90   if (it != end()) {
91     return &*it->second;
92   } else if (IsSubmodule()) {
93     const Scope *parent{symbol_->get<ModuleDetails>().parent()};
94     return parent ? parent->FindSymbol(name) : nullptr;
95   } else if (CanImport(name)) {
96     return parent_->FindSymbol(name);
97   } else {
98     return nullptr;
99   }
100 }
101 
102 Symbol *Scope::FindComponent(SourceName name) const {
103   CHECK(IsDerivedType());
104   auto found{find(name)};
105   if (found != end()) {
106     return &*found->second;
107   } else if (const Scope * parent{GetDerivedTypeParent()}) {
108     return parent->FindComponent(name);
109   } else {
110     return nullptr;
111   }
112 }
113 
114 bool Scope::Contains(const Scope &that) const {
115   for (const Scope *scope{&that};; scope = &scope->parent()) {
116     if (*scope == *this) {
117       return true;
118     }
119     if (scope->IsGlobal()) {
120       return false;
121     }
122   }
123 }
124 
125 Symbol *Scope::CopySymbol(const Symbol &symbol) {
126   auto pair{try_emplace(symbol.name(), symbol.attrs())};
127   if (!pair.second) {
128     return nullptr; // already exists
129   } else {
130     Symbol &result{*pair.first->second};
131     result.flags() = symbol.flags();
132     result.set_details(common::Clone(symbol.details()));
133     return &result;
134   }
135 }
136 
137 void Scope::add_equivalenceSet(EquivalenceSet &&set) {
138   equivalenceSets_.emplace_back(std::move(set));
139 }
140 
141 void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
142   CHECK(pointer.test(Symbol::Flag::CrayPointer));
143   crayPointers_.emplace(name, pointer);
144 }
145 
146 Symbol &Scope::MakeCommonBlock(const SourceName &name) {
147   const auto it{commonBlocks_.find(name)};
148   if (it != commonBlocks_.end()) {
149     return *it->second;
150   } else {
151     Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
152     commonBlocks_.emplace(name, symbol);
153     return symbol;
154   }
155 }
156 Symbol *Scope::FindCommonBlock(const SourceName &name) const {
157   const auto it{commonBlocks_.find(name)};
158   return it != commonBlocks_.end() ? &*it->second : nullptr;
159 }
160 
161 Scope *Scope::FindSubmodule(const SourceName &name) const {
162   auto it{submodules_.find(name)};
163   if (it == submodules_.end()) {
164     return nullptr;
165   } else {
166     return &*it->second;
167   }
168 }
169 bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
170   return submodules_.emplace(name, submodule).second;
171 }
172 
173 const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {
174   auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)};
175   return it != declTypeSpecs_.end() ? &*it : nullptr;
176 }
177 
178 const DeclTypeSpec &Scope::MakeNumericType(
179     TypeCategory category, KindExpr &&kind) {
180   return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)});
181 }
182 const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) {
183   return MakeLengthlessType(LogicalTypeSpec{std::move(kind)});
184 }
185 const DeclTypeSpec &Scope::MakeTypeStarType() {
186   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar});
187 }
188 const DeclTypeSpec &Scope::MakeClassStarType() {
189   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar});
190 }
191 // Types that can't have length parameters can be reused without having to
192 // compare length expressions. They are stored in the global scope.
193 const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) {
194   const auto *found{FindType(type)};
195   return found ? *found : declTypeSpecs_.emplace_back(std::move(type));
196 }
197 
198 const DeclTypeSpec &Scope::MakeCharacterType(
199     ParamValue &&length, KindExpr &&kind) {
200   return declTypeSpecs_.emplace_back(
201       CharacterTypeSpec{std::move(length), std::move(kind)});
202 }
203 
204 DeclTypeSpec &Scope::MakeDerivedType(
205     DeclTypeSpec::Category category, DerivedTypeSpec &&spec) {
206   return declTypeSpecs_.emplace_back(category, std::move(spec));
207 }
208 
209 const DeclTypeSpec *Scope::GetType(const SomeExpr &expr) {
210   if (auto dyType{expr.GetType()}) {
211     if (dyType->IsAssumedType()) {
212       return &MakeTypeStarType();
213     } else if (dyType->IsUnlimitedPolymorphic()) {
214       return &MakeClassStarType();
215     } else {
216       switch (dyType->category()) {
217       case TypeCategory::Integer:
218       case TypeCategory::Unsigned:
219       case TypeCategory::Real:
220       case TypeCategory::Complex:
221         return &MakeNumericType(dyType->category(), KindExpr{dyType->kind()});
222       case TypeCategory::Character:
223         if (const ParamValue * lenParam{dyType->charLengthParamValue()}) {
224           return &MakeCharacterType(
225               ParamValue{*lenParam}, KindExpr{dyType->kind()});
226         } else {
227           auto lenExpr{dyType->GetCharLength()};
228           if (!lenExpr) {
229             lenExpr =
230                 std::get<evaluate::Expr<evaluate::SomeCharacter>>(expr.u).LEN();
231           }
232           if (lenExpr) {
233             return &MakeCharacterType(
234                 ParamValue{SomeIntExpr{std::move(*lenExpr)},
235                     common::TypeParamAttr::Len},
236                 KindExpr{dyType->kind()});
237           }
238         }
239         break;
240       case TypeCategory::Logical:
241         return &MakeLogicalType(KindExpr{dyType->kind()});
242       case TypeCategory::Derived:
243         return &MakeDerivedType(dyType->IsPolymorphic()
244                 ? DeclTypeSpec::ClassDerived
245                 : DeclTypeSpec::TypeDerived,
246             DerivedTypeSpec{dyType->GetDerivedTypeSpec()});
247       }
248     }
249   }
250   return nullptr;
251 }
252 
253 Scope::ImportKind Scope::GetImportKind() const {
254   if (importKind_) {
255     return *importKind_;
256   }
257   if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) {
258     if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) {
259       if (details->isInterface()) {
260         return ImportKind::None; // default for non-mod-proc interface body
261       }
262     }
263   }
264   return ImportKind::Default;
265 }
266 
267 std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) {
268   if (!importKind_) {
269     importKind_ = kind;
270     return std::nullopt;
271   }
272   bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None};
273   bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All};
274   // Check C8100 and C898: constraints on multiple IMPORT statements
275   if (hasNone || hasAll) {
276     return hasNone
277         ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
278         : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US;
279   } else if (kind != *importKind_ &&
280       (kind != ImportKind::Only && *importKind_ != ImportKind::Only)) {
281     return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US;
282   } else {
283     return std::nullopt;
284   }
285 }
286 
287 void Scope::add_importName(const SourceName &name) {
288   importNames_.insert(name);
289 }
290 
291 // true if name can be imported or host-associated from parent scope.
292 bool Scope::CanImport(const SourceName &name) const {
293   if (IsTopLevel() || parent_->IsTopLevel()) {
294     return false;
295   }
296   switch (GetImportKind()) {
297     SWITCH_COVERS_ALL_CASES
298   case ImportKind::None:
299     return false;
300   case ImportKind::All:
301   case ImportKind::Default:
302     return true;
303   case ImportKind::Only:
304     return importNames_.count(name) > 0;
305   }
306 }
307 
308 void Scope::AddSourceRange(parser::CharBlock source) {
309   if (source.empty()) {
310     return;
311   }
312   const parser::AllCookedSources &allCookedSources{context_.allCookedSources()};
313   const parser::CookedSource *cooked{allCookedSources.Find(source)};
314   if (!cooked) {
315     CHECK(context_.IsTempName(source.ToString()));
316     return;
317   }
318   for (auto *scope{this}; !scope->IsTopLevel(); scope = &scope->parent()) {
319     CHECK(scope->sourceRange_.empty() == (scope->cookedSource_ == nullptr));
320     if (!scope->cookedSource_) {
321       context_.UpdateScopeIndex(*scope, source);
322       scope->cookedSource_ = cooked;
323       scope->sourceRange_ = source;
324     } else if (scope->cookedSource_ == cooked) {
325       auto combined{scope->sourceRange()};
326       combined.ExtendToCover(source);
327       context_.UpdateScopeIndex(*scope, combined);
328       scope->sourceRange_ = combined;
329     } else {
330       // There's a bug that will be hard to fix; crash informatively
331       const parser::AllSources &allSources{allCookedSources.allSources()};
332       const auto describe{[&](parser::CharBlock src) {
333         if (auto range{allCookedSources.GetProvenanceRange(src)}) {
334           std::size_t offset;
335           if (const parser::SourceFile *
336               file{allSources.GetSourceFile(range->start(), &offset)}) {
337             return "'"s + file->path() + "' at " + std::to_string(offset) +
338                 " for " + std::to_string(range->size());
339           } else {
340             return "(GetSourceFile failed)"s;
341           }
342         } else {
343           return "(GetProvenanceRange failed)"s;
344         }
345       }};
346       std::string scopeDesc{describe(scope->sourceRange_)};
347       std::string newDesc{describe(source)};
348       common::die("AddSourceRange would have combined ranges from distinct "
349                   "source files \"%s\" and \"%s\"",
350           scopeDesc.c_str(), newDesc.c_str());
351     }
352     // Note: If the "break;" here were unconditional (or, equivalently, if
353     // there were no loop at all) then the source ranges of parent scopes
354     // would not enclose the source ranges of their children.  Timing
355     // shows that it's cheap to maintain this property, with the exceptions
356     // of top-level scopes and for (sub)modules and their descendant
357     // submodules.
358     if (scope->IsSubmodule()) {
359       break; // Submodules are child scopes but not contained ranges
360     }
361   }
362 }
363 
364 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {
365   os << Scope::EnumToString(scope.kind()) << " scope: ";
366   if (auto *symbol{scope.symbol()}) {
367     os << *symbol << ' ';
368   }
369   if (scope.derivedTypeSpec_) {
370     os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';
371   }
372   os << scope.children_.size() << " children\n";
373   for (const auto &pair : scope.symbols_) {
374     const Symbol &symbol{*pair.second};
375     os << "  " << symbol << '\n';
376   }
377   if (!scope.equivalenceSets_.empty()) {
378     os << "  Equivalence Sets:\n";
379     for (const auto &set : scope.equivalenceSets_) {
380       os << "   ";
381       for (const auto &object : set) {
382         os << ' ' << object.AsFortran();
383       }
384       os << '\n';
385     }
386   }
387   for (const auto &pair : scope.commonBlocks_) {
388     const Symbol &symbol{*pair.second};
389     os << "  " << symbol << '\n';
390   }
391   return os;
392 }
393 
394 bool Scope::IsStmtFunction() const {
395   return symbol_ && symbol_->test(Symbol::Flag::StmtFunction);
396 }
397 
398 template <common::TypeParamAttr... ParamAttr> struct IsTypeParamHelper {
399   static_assert(sizeof...(ParamAttr) == 0, "must have one or zero template");
400   static bool IsParam(const Symbol &symbol) {
401     return symbol.has<TypeParamDetails>();
402   }
403 };
404 
405 template <common::TypeParamAttr ParamAttr> struct IsTypeParamHelper<ParamAttr> {
406   static bool IsParam(const Symbol &symbol) {
407     if (const auto *typeParam{symbol.detailsIf<TypeParamDetails>()}) {
408       return typeParam->attr() == ParamAttr;
409     }
410     return false;
411   }
412 };
413 
414 template <common::TypeParamAttr... ParamAttr>
415 static bool IsParameterizedDerivedTypeHelper(const Scope &scope) {
416   if (scope.IsDerivedType()) {
417     if (const Scope * parent{scope.GetDerivedTypeParent()}) {
418       if (IsParameterizedDerivedTypeHelper<ParamAttr...>(*parent)) {
419         return true;
420       }
421     }
422     for (const auto &nameAndSymbolPair : scope) {
423       if (IsTypeParamHelper<ParamAttr...>::IsParam(*nameAndSymbolPair.second)) {
424         return true;
425       }
426     }
427   }
428   return false;
429 }
430 
431 bool Scope::IsParameterizedDerivedType() const {
432   return IsParameterizedDerivedTypeHelper<>(*this);
433 }
434 bool Scope::IsDerivedTypeWithLengthParameter() const {
435   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Len>(*this);
436 }
437 bool Scope::IsDerivedTypeWithKindParameter() const {
438   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Kind>(*this);
439 }
440 
441 const DeclTypeSpec *Scope::FindInstantiatedDerivedType(
442     const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {
443   DeclTypeSpec type{category, spec};
444   if (const auto *result{FindType(type)}) {
445     return result;
446   } else if (IsGlobal()) {
447     return nullptr;
448   } else {
449     return parent().FindInstantiatedDerivedType(spec, category);
450   }
451 }
452 
453 const Scope *Scope::GetDerivedTypeParent() const {
454   if (const Symbol * symbol{GetSymbol()}) {
455     if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) {
456       return parent->scope();
457     }
458   }
459   return nullptr;
460 }
461 
462 const Scope &Scope::GetDerivedTypeBase() const {
463   const Scope *child{this};
464   for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
465        parent = child->GetDerivedTypeParent()) {
466     child = parent;
467   }
468   return *child;
469 }
470 
471 void Scope::InstantiateDerivedTypes() {
472   for (DeclTypeSpec &type : declTypeSpecs_) {
473     if (type.category() == DeclTypeSpec::TypeDerived ||
474         type.category() == DeclTypeSpec::ClassDerived) {
475       type.derivedTypeSpec().Instantiate(*this);
476     }
477   }
478 }
479 } // namespace Fortran::semantics
480