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 
operator ==(const EquivalenceObject & that) const21 bool EquivalenceObject::operator==(const EquivalenceObject &that) const {
22   return symbol == that.symbol && subscripts == that.subscripts &&
23       substringStart == that.substringStart;
24 }
25 
operator <(const EquivalenceObject & that) const26 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 
AsFortran() const34 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 
MakeScope(Kind kind,Symbol * symbol)52 Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
53   return children_.emplace_back(*this, kind, symbol, context_);
54 }
55 
56 template <typename T>
GetSortedSymbols(std::map<SourceName,MutableSymbolRef> symbols)57 static std::vector<common::Reference<T>> GetSortedSymbols(
58     std::map<SourceName, MutableSymbolRef> symbols) {
59   std::vector<common::Reference<T>> result;
60   result.reserve(symbols.size());
61   for (auto &pair : symbols) {
62     result.push_back(*pair.second);
63   }
64   std::sort(result.begin(), result.end(), SymbolSourcePositionCompare{});
65   return result;
66 }
67 
GetSymbols()68 MutableSymbolVector Scope::GetSymbols() {
69   return GetSortedSymbols<Symbol>(symbols_);
70 }
GetSymbols() const71 SymbolVector Scope::GetSymbols() const {
72   return GetSortedSymbols<const Symbol>(symbols_);
73 }
74 
find(const SourceName & name)75 Scope::iterator Scope::find(const SourceName &name) {
76   return symbols_.find(name);
77 }
erase(const SourceName & name)78 Scope::size_type Scope::erase(const SourceName &name) {
79   auto it{symbols_.find(name)};
80   if (it != end()) {
81     symbols_.erase(it);
82     return 1;
83   } else {
84     return 0;
85   }
86 }
FindSymbol(const SourceName & name) const87 Symbol *Scope::FindSymbol(const SourceName &name) const {
88   auto it{find(name)};
89   if (it != end()) {
90     return &*it->second;
91   } else if (CanImport(name)) {
92     return parent_.FindSymbol(name);
93   } else {
94     return nullptr;
95   }
96 }
97 
FindComponent(SourceName name) const98 Symbol *Scope::FindComponent(SourceName name) const {
99   CHECK(IsDerivedType());
100   auto found{find(name)};
101   if (found != end()) {
102     return &*found->second;
103   } else if (const Scope * parent{GetDerivedTypeParent()}) {
104     return parent->FindComponent(name);
105   } else {
106     return nullptr;
107   }
108 }
109 
Contains(const Scope & that) const110 bool Scope::Contains(const Scope &that) const {
111   for (const Scope *scope{&that};; scope = &scope->parent()) {
112     if (*scope == *this) {
113       return true;
114     }
115     if (scope->IsGlobal()) {
116       return false;
117     }
118   }
119 }
120 
CopySymbol(const Symbol & symbol)121 Symbol *Scope::CopySymbol(const Symbol &symbol) {
122   auto pair{try_emplace(symbol.name(), symbol.attrs())};
123   if (!pair.second) {
124     return nullptr; // already exists
125   } else {
126     Symbol &result{*pair.first->second};
127     result.flags() = symbol.flags();
128     result.set_details(common::Clone(symbol.details()));
129     return &result;
130   }
131 }
132 
add_equivalenceSet(EquivalenceSet && set)133 void Scope::add_equivalenceSet(EquivalenceSet &&set) {
134   equivalenceSets_.emplace_back(std::move(set));
135 }
136 
add_crayPointer(const SourceName & name,Symbol & pointer)137 void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
138   CHECK(pointer.test(Symbol::Flag::CrayPointer));
139   crayPointers_.emplace(name, pointer);
140 }
141 
MakeCommonBlock(const SourceName & name)142 Symbol &Scope::MakeCommonBlock(const SourceName &name) {
143   const auto it{commonBlocks_.find(name)};
144   if (it != commonBlocks_.end()) {
145     return *it->second;
146   } else {
147     Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
148     commonBlocks_.emplace(name, symbol);
149     return symbol;
150   }
151 }
FindCommonBlock(const SourceName & name) const152 Symbol *Scope::FindCommonBlock(const SourceName &name) const {
153   const auto it{commonBlocks_.find(name)};
154   return it != commonBlocks_.end() ? &*it->second : nullptr;
155 }
156 
FindSubmodule(const SourceName & name) const157 Scope *Scope::FindSubmodule(const SourceName &name) const {
158   auto it{submodules_.find(name)};
159   if (it == submodules_.end()) {
160     return nullptr;
161   } else {
162     return &*it->second;
163   }
164 }
AddSubmodule(const SourceName & name,Scope & submodule)165 bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
166   return submodules_.emplace(name, submodule).second;
167 }
168 
FindType(const DeclTypeSpec & type) const169 const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {
170   auto it{std::find(declTypeSpecs_.begin(), declTypeSpecs_.end(), type)};
171   return it != declTypeSpecs_.end() ? &*it : nullptr;
172 }
173 
MakeNumericType(TypeCategory category,KindExpr && kind)174 const DeclTypeSpec &Scope::MakeNumericType(
175     TypeCategory category, KindExpr &&kind) {
176   return MakeLengthlessType(NumericTypeSpec{category, std::move(kind)});
177 }
MakeLogicalType(KindExpr && kind)178 const DeclTypeSpec &Scope::MakeLogicalType(KindExpr &&kind) {
179   return MakeLengthlessType(LogicalTypeSpec{std::move(kind)});
180 }
MakeTypeStarType()181 const DeclTypeSpec &Scope::MakeTypeStarType() {
182   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::TypeStar});
183 }
MakeClassStarType()184 const DeclTypeSpec &Scope::MakeClassStarType() {
185   return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar});
186 }
187 // Types that can't have length parameters can be reused without having to
188 // compare length expressions. They are stored in the global scope.
MakeLengthlessType(DeclTypeSpec && type)189 const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) {
190   const auto *found{FindType(type)};
191   return found ? *found : declTypeSpecs_.emplace_back(std::move(type));
192 }
193 
MakeCharacterType(ParamValue && length,KindExpr && kind)194 const DeclTypeSpec &Scope::MakeCharacterType(
195     ParamValue &&length, KindExpr &&kind) {
196   return declTypeSpecs_.emplace_back(
197       CharacterTypeSpec{std::move(length), std::move(kind)});
198 }
199 
MakeDerivedType(DeclTypeSpec::Category category,DerivedTypeSpec && spec)200 DeclTypeSpec &Scope::MakeDerivedType(
201     DeclTypeSpec::Category category, DerivedTypeSpec &&spec) {
202   return declTypeSpecs_.emplace_back(category, std::move(spec));
203 }
204 
GetType(const SomeExpr & expr)205 const DeclTypeSpec *Scope::GetType(const SomeExpr &expr) {
206   if (auto dyType{expr.GetType()}) {
207     if (dyType->IsAssumedType()) {
208       return &MakeTypeStarType();
209     } else if (dyType->IsUnlimitedPolymorphic()) {
210       return &MakeClassStarType();
211     } else {
212       switch (dyType->category()) {
213       case TypeCategory::Integer:
214       case TypeCategory::Real:
215       case TypeCategory::Complex:
216         return &MakeNumericType(dyType->category(), KindExpr{dyType->kind()});
217       case TypeCategory::Character:
218         if (const ParamValue * lenParam{dyType->charLengthParamValue()}) {
219           return &MakeCharacterType(
220               ParamValue{*lenParam}, KindExpr{dyType->kind()});
221         } else {
222           auto lenExpr{dyType->GetCharLength()};
223           if (!lenExpr) {
224             lenExpr =
225                 std::get<evaluate::Expr<evaluate::SomeCharacter>>(expr.u).LEN();
226           }
227           if (lenExpr) {
228             return &MakeCharacterType(
229                 ParamValue{SomeIntExpr{std::move(*lenExpr)},
230                     common::TypeParamAttr::Len},
231                 KindExpr{dyType->kind()});
232           }
233         }
234         break;
235       case TypeCategory::Logical:
236         return &MakeLogicalType(KindExpr{dyType->kind()});
237       case TypeCategory::Derived:
238         return &MakeDerivedType(dyType->IsPolymorphic()
239                 ? DeclTypeSpec::ClassDerived
240                 : DeclTypeSpec::TypeDerived,
241             DerivedTypeSpec{dyType->GetDerivedTypeSpec()});
242       }
243     }
244   }
245   return nullptr;
246 }
247 
GetImportKind() const248 Scope::ImportKind Scope::GetImportKind() const {
249   if (importKind_) {
250     return *importKind_;
251   }
252   if (symbol_ && !symbol_->attrs().test(Attr::MODULE)) {
253     if (auto *details{symbol_->detailsIf<SubprogramDetails>()}) {
254       if (details->isInterface()) {
255         return ImportKind::None; // default for non-mod-proc interface body
256       }
257     }
258   }
259   return ImportKind::Default;
260 }
261 
SetImportKind(ImportKind kind)262 std::optional<parser::MessageFixedText> Scope::SetImportKind(ImportKind kind) {
263   if (!importKind_) {
264     importKind_ = kind;
265     return std::nullopt;
266   }
267   bool hasNone{kind == ImportKind::None || *importKind_ == ImportKind::None};
268   bool hasAll{kind == ImportKind::All || *importKind_ == ImportKind::All};
269   // Check C8100 and C898: constraints on multiple IMPORT statements
270   if (hasNone || hasAll) {
271     return hasNone
272         ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
273         : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US;
274   } else if (kind != *importKind_ &&
275       (kind != ImportKind::Only || kind != ImportKind::Only)) {
276     return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US;
277   } else {
278     return std::nullopt;
279   }
280 }
281 
add_importName(const SourceName & name)282 void Scope::add_importName(const SourceName &name) {
283   importNames_.insert(name);
284 }
285 
286 // true if name can be imported or host-associated from parent scope.
CanImport(const SourceName & name) const287 bool Scope::CanImport(const SourceName &name) const {
288   if (IsTopLevel() || parent_.IsTopLevel()) {
289     return false;
290   }
291   switch (GetImportKind()) {
292     SWITCH_COVERS_ALL_CASES
293   case ImportKind::None:
294     return false;
295   case ImportKind::All:
296   case ImportKind::Default:
297     return true;
298   case ImportKind::Only:
299     return importNames_.count(name) > 0;
300   }
301 }
302 
FindScope(parser::CharBlock source) const303 const Scope *Scope::FindScope(parser::CharBlock source) const {
304   return const_cast<Scope *>(this)->FindScope(source);
305 }
306 
FindScope(parser::CharBlock source)307 Scope *Scope::FindScope(parser::CharBlock source) {
308   bool isContained{sourceRange_.Contains(source)};
309   if (!isContained && !IsTopLevel() && !IsModuleFile()) {
310     return nullptr;
311   }
312   for (auto &child : children_) {
313     if (auto *scope{child.FindScope(source)}) {
314       return scope;
315     }
316   }
317   return isContained && !IsTopLevel() ? this : nullptr;
318 }
319 
AddSourceRange(const parser::CharBlock & source)320 void Scope::AddSourceRange(const parser::CharBlock &source) {
321   for (auto *scope{this}; !scope->IsGlobal(); scope = &scope->parent()) {
322     scope->sourceRange_.ExtendToCover(source);
323   }
324 }
325 
operator <<(llvm::raw_ostream & os,const Scope & scope)326 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {
327   os << Scope::EnumToString(scope.kind()) << " scope: ";
328   if (auto *symbol{scope.symbol()}) {
329     os << *symbol << ' ';
330   }
331   if (scope.derivedTypeSpec_) {
332     os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';
333   }
334   os << scope.children_.size() << " children\n";
335   for (const auto &pair : scope.symbols_) {
336     const Symbol &symbol{*pair.second};
337     os << "  " << symbol << '\n';
338   }
339   if (!scope.equivalenceSets_.empty()) {
340     os << "  Equivalence Sets:\n";
341     for (const auto &set : scope.equivalenceSets_) {
342       os << "   ";
343       for (const auto &object : set) {
344         os << ' ' << object.AsFortran();
345       }
346       os << '\n';
347     }
348   }
349   for (const auto &pair : scope.commonBlocks_) {
350     const Symbol &symbol{*pair.second};
351     os << "  " << symbol << '\n';
352   }
353   return os;
354 }
355 
IsStmtFunction() const356 bool Scope::IsStmtFunction() const {
357   return symbol_ && symbol_->test(Symbol::Flag::StmtFunction);
358 }
359 
360 template <common::TypeParamAttr... ParamAttr> struct IsTypeParamHelper {
361   static_assert(sizeof...(ParamAttr) == 0, "must have one or zero template");
IsParamFortran::semantics::IsTypeParamHelper362   static bool IsParam(const Symbol &symbol) {
363     return symbol.has<TypeParamDetails>();
364   }
365 };
366 
367 template <common::TypeParamAttr ParamAttr> struct IsTypeParamHelper<ParamAttr> {
IsParamFortran::semantics::IsTypeParamHelper368   static bool IsParam(const Symbol &symbol) {
369     if (const auto *typeParam{symbol.detailsIf<TypeParamDetails>()}) {
370       return typeParam->attr() == ParamAttr;
371     }
372     return false;
373   }
374 };
375 
376 template <common::TypeParamAttr... ParamAttr>
IsParameterizedDerivedTypeHelper(const Scope & scope)377 static bool IsParameterizedDerivedTypeHelper(const Scope &scope) {
378   if (scope.IsDerivedType()) {
379     if (const Scope * parent{scope.GetDerivedTypeParent()}) {
380       if (IsParameterizedDerivedTypeHelper<ParamAttr...>(*parent)) {
381         return true;
382       }
383     }
384     for (const auto &nameAndSymbolPair : scope) {
385       if (IsTypeParamHelper<ParamAttr...>::IsParam(*nameAndSymbolPair.second)) {
386         return true;
387       }
388     }
389   }
390   return false;
391 }
392 
IsParameterizedDerivedType() const393 bool Scope::IsParameterizedDerivedType() const {
394   return IsParameterizedDerivedTypeHelper<>(*this);
395 }
IsDerivedTypeWithLengthParameter() const396 bool Scope::IsDerivedTypeWithLengthParameter() const {
397   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Len>(*this);
398 }
IsDerivedTypeWithKindParameter() const399 bool Scope::IsDerivedTypeWithKindParameter() const {
400   return IsParameterizedDerivedTypeHelper<common::TypeParamAttr::Kind>(*this);
401 }
402 
FindInstantiatedDerivedType(const DerivedTypeSpec & spec,DeclTypeSpec::Category category) const403 const DeclTypeSpec *Scope::FindInstantiatedDerivedType(
404     const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {
405   DeclTypeSpec type{category, spec};
406   if (const auto *result{FindType(type)}) {
407     return result;
408   } else if (IsGlobal()) {
409     return nullptr;
410   } else {
411     return parent().FindInstantiatedDerivedType(spec, category);
412   }
413 }
414 
GetDerivedTypeParent() const415 const Scope *Scope::GetDerivedTypeParent() const {
416   if (const Symbol * symbol{GetSymbol()}) {
417     if (const DerivedTypeSpec * parent{symbol->GetParentTypeSpec(this)}) {
418       return parent->scope();
419     }
420   }
421   return nullptr;
422 }
423 
GetDerivedTypeBase() const424 const Scope &Scope::GetDerivedTypeBase() const {
425   const Scope *child{this};
426   for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
427        parent = child->GetDerivedTypeParent()) {
428     child = parent;
429   }
430   return *child;
431 }
432 
InstantiateDerivedTypes()433 void Scope::InstantiateDerivedTypes() {
434   for (DeclTypeSpec &type : declTypeSpecs_) {
435     if (type.category() == DeclTypeSpec::TypeDerived ||
436         type.category() == DeclTypeSpec::ClassDerived) {
437       type.derivedTypeSpec().Instantiate(*this);
438     }
439   }
440 }
441 } // namespace Fortran::semantics
442