1 //===-- lib/Semantics/scope.cpp -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
18 namespace Fortran::semantics
{
20 Symbols
<1024> Scope::allSymbols
;
22 bool EquivalenceObject::operator==(const EquivalenceObject
&that
) const {
23 return symbol
== that
.symbol
&& subscripts
== that
.subscripts
&&
24 substringStart
== that
.substringStart
;
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
)));
35 std::string
EquivalenceObject::AsFortran() const {
37 llvm::raw_string_ostream ss
{buf
};
38 ss
<< symbol
.name().ToString();
39 if (!subscripts
.empty()) {
41 for (auto subscript
: subscripts
) {
42 ss
<< sep
<< subscript
;
48 ss
<< '(' << *substringStart
<< ":)";
53 Scope
&Scope::MakeScope(Kind kind
, Symbol
*symbol
) {
54 return children_
.emplace_back(*this, kind
, symbol
, context_
);
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
);
65 std::sort(result
.begin(), result
.end(), SymbolSourcePositionCompare
{});
69 MutableSymbolVector
Scope::GetSymbols() {
70 return GetSortedSymbols
<Symbol
>(symbols_
);
72 SymbolVector
Scope::GetSymbols() const {
73 return GetSortedSymbols
<const Symbol
>(symbols_
);
76 Scope::iterator
Scope::find(const SourceName
&name
) {
77 return symbols_
.find(name
);
79 Scope::size_type
Scope::erase(const SourceName
&name
) {
80 auto it
{symbols_
.find(name
)};
88 Symbol
*Scope::FindSymbol(const SourceName
&name
) const {
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
);
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
);
114 bool Scope::Contains(const Scope
&that
) const {
115 for (const Scope
*scope
{&that
};; scope
= &scope
->parent()) {
116 if (*scope
== *this) {
119 if (scope
->IsGlobal()) {
125 Symbol
*Scope::CopySymbol(const Symbol
&symbol
) {
126 auto pair
{try_emplace(symbol
.name(), symbol
.attrs())};
128 return nullptr; // already exists
130 Symbol
&result
{*pair
.first
->second
};
131 result
.flags() = symbol
.flags();
132 result
.set_details(common::Clone(symbol
.details()));
137 void Scope::add_equivalenceSet(EquivalenceSet
&&set
) {
138 equivalenceSets_
.emplace_back(std::move(set
));
141 void Scope::add_crayPointer(const SourceName
&name
, Symbol
&pointer
) {
142 CHECK(pointer
.test(Symbol::Flag::CrayPointer
));
143 crayPointers_
.emplace(name
, pointer
);
146 Symbol
&Scope::MakeCommonBlock(const SourceName
&name
) {
147 const auto it
{commonBlocks_
.find(name
)};
148 if (it
!= commonBlocks_
.end()) {
151 Symbol
&symbol
{MakeSymbol(name
, Attrs
{}, CommonBlockDetails
{})};
152 commonBlocks_
.emplace(name
, symbol
);
156 Symbol
*Scope::FindCommonBlock(const SourceName
&name
) const {
157 const auto it
{commonBlocks_
.find(name
)};
158 return it
!= commonBlocks_
.end() ? &*it
->second
: nullptr;
161 Scope
*Scope::FindSubmodule(const SourceName
&name
) const {
162 auto it
{submodules_
.find(name
)};
163 if (it
== submodules_
.end()) {
169 bool Scope::AddSubmodule(const SourceName
&name
, Scope
&submodule
) {
170 return submodules_
.emplace(name
, submodule
).second
;
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;
178 const DeclTypeSpec
&Scope::MakeNumericType(
179 TypeCategory category
, KindExpr
&&kind
) {
180 return MakeLengthlessType(NumericTypeSpec
{category
, std::move(kind
)});
182 const DeclTypeSpec
&Scope::MakeLogicalType(KindExpr
&&kind
) {
183 return MakeLengthlessType(LogicalTypeSpec
{std::move(kind
)});
185 const DeclTypeSpec
&Scope::MakeTypeStarType() {
186 return MakeLengthlessType(DeclTypeSpec
{DeclTypeSpec::TypeStar
});
188 const DeclTypeSpec
&Scope::MakeClassStarType() {
189 return MakeLengthlessType(DeclTypeSpec
{DeclTypeSpec::ClassStar
});
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
));
198 const DeclTypeSpec
&Scope::MakeCharacterType(
199 ParamValue
&&length
, KindExpr
&&kind
) {
200 return declTypeSpecs_
.emplace_back(
201 CharacterTypeSpec
{std::move(length
), std::move(kind
)});
204 DeclTypeSpec
&Scope::MakeDerivedType(
205 DeclTypeSpec::Category category
, DerivedTypeSpec
&&spec
) {
206 return declTypeSpecs_
.emplace_back(category
, std::move(spec
));
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();
216 switch (dyType
->category()) {
217 case TypeCategory::Integer
:
218 case TypeCategory::Real
:
219 case TypeCategory::Complex
:
220 return &MakeNumericType(dyType
->category(), KindExpr
{dyType
->kind()});
221 case TypeCategory::Character
:
222 if (const ParamValue
* lenParam
{dyType
->charLengthParamValue()}) {
223 return &MakeCharacterType(
224 ParamValue
{*lenParam
}, KindExpr
{dyType
->kind()});
226 auto lenExpr
{dyType
->GetCharLength()};
229 std::get
<evaluate::Expr
<evaluate::SomeCharacter
>>(expr
.u
).LEN();
232 return &MakeCharacterType(
233 ParamValue
{SomeIntExpr
{std::move(*lenExpr
)},
234 common::TypeParamAttr::Len
},
235 KindExpr
{dyType
->kind()});
239 case TypeCategory::Logical
:
240 return &MakeLogicalType(KindExpr
{dyType
->kind()});
241 case TypeCategory::Derived
:
242 return &MakeDerivedType(dyType
->IsPolymorphic()
243 ? DeclTypeSpec::ClassDerived
244 : DeclTypeSpec::TypeDerived
,
245 DerivedTypeSpec
{dyType
->GetDerivedTypeSpec()});
252 Scope::ImportKind
Scope::GetImportKind() const {
256 if (symbol_
&& !symbol_
->attrs().test(Attr::MODULE
)) {
257 if (auto *details
{symbol_
->detailsIf
<SubprogramDetails
>()}) {
258 if (details
->isInterface()) {
259 return ImportKind::None
; // default for non-mod-proc interface body
263 return ImportKind::Default
;
266 std::optional
<parser::MessageFixedText
> Scope::SetImportKind(ImportKind kind
) {
271 bool hasNone
{kind
== ImportKind::None
|| *importKind_
== ImportKind::None
};
272 bool hasAll
{kind
== ImportKind::All
|| *importKind_
== ImportKind::All
};
273 // Check C8100 and C898: constraints on multiple IMPORT statements
274 if (hasNone
|| hasAll
) {
276 ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
277 : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US
;
278 } else if (kind
!= *importKind_
&&
279 (kind
!= ImportKind::Only
&& *importKind_
!= ImportKind::Only
)) {
280 return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US
;
286 void Scope::add_importName(const SourceName
&name
) {
287 importNames_
.insert(name
);
290 // true if name can be imported or host-associated from parent scope.
291 bool Scope::CanImport(const SourceName
&name
) const {
292 if (IsTopLevel() || parent_
->IsTopLevel()) {
295 switch (GetImportKind()) {
296 SWITCH_COVERS_ALL_CASES
297 case ImportKind::None
:
299 case ImportKind::All
:
300 case ImportKind::Default
:
302 case ImportKind::Only
:
303 return importNames_
.count(name
) > 0;
307 void Scope::AddSourceRange(parser::CharBlock source
) {
308 if (source
.empty()) {
311 const parser::AllCookedSources
&allCookedSources
{context_
.allCookedSources()};
312 const parser::CookedSource
*cooked
{allCookedSources
.Find(source
)};
314 CHECK(context_
.IsTempName(source
.ToString()));
317 for (auto *scope
{this}; !scope
->IsTopLevel(); scope
= &scope
->parent()) {
318 CHECK(scope
->sourceRange_
.empty() == (scope
->cookedSource_
== nullptr));
319 if (!scope
->cookedSource_
) {
320 context_
.UpdateScopeIndex(*scope
, source
);
321 scope
->cookedSource_
= cooked
;
322 scope
->sourceRange_
= source
;
323 } else if (scope
->cookedSource_
== cooked
) {
324 auto combined
{scope
->sourceRange()};
325 combined
.ExtendToCover(source
);
326 context_
.UpdateScopeIndex(*scope
, combined
);
327 scope
->sourceRange_
= combined
;
329 // There's a bug that will be hard to fix; crash informatively
330 const parser::AllSources
&allSources
{allCookedSources
.allSources()};
331 const auto describe
{[&](parser::CharBlock src
) {
332 if (auto range
{allCookedSources
.GetProvenanceRange(src
)}) {
334 if (const parser::SourceFile
*
335 file
{allSources
.GetSourceFile(range
->start(), &offset
)}) {
336 return "'"s
+ file
->path() + "' at " + std::to_string(offset
) +
337 " for " + std::to_string(range
->size());
339 return "(GetSourceFile failed)"s
;
342 return "(GetProvenanceRange failed)"s
;
345 std::string scopeDesc
{describe(scope
->sourceRange_
)};
346 std::string newDesc
{describe(source
)};
347 common::die("AddSourceRange would have combined ranges from distinct "
348 "source files \"%s\" and \"%s\"",
349 scopeDesc
.c_str(), newDesc
.c_str());
351 // Note: If the "break;" here were unconditional (or, equivalently, if
352 // there were no loop at all) then the source ranges of parent scopes
353 // would not enclose the source ranges of their children. Timing
354 // shows that it's cheap to maintain this property, with the exceptions
355 // of top-level scopes and for (sub)modules and their descendant
357 if (scope
->IsSubmodule()) {
358 break; // Submodules are child scopes but not contained ranges
363 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&os
, const Scope
&scope
) {
364 os
<< Scope::EnumToString(scope
.kind()) << " scope: ";
365 if (auto *symbol
{scope
.symbol()}) {
366 os
<< *symbol
<< ' ';
368 if (scope
.derivedTypeSpec_
) {
369 os
<< "instantiation of " << *scope
.derivedTypeSpec_
<< ' ';
371 os
<< scope
.children_
.size() << " children\n";
372 for (const auto &pair
: scope
.symbols_
) {
373 const Symbol
&symbol
{*pair
.second
};
374 os
<< " " << symbol
<< '\n';
376 if (!scope
.equivalenceSets_
.empty()) {
377 os
<< " Equivalence Sets:\n";
378 for (const auto &set
: scope
.equivalenceSets_
) {
380 for (const auto &object
: set
) {
381 os
<< ' ' << object
.AsFortran();
386 for (const auto &pair
: scope
.commonBlocks_
) {
387 const Symbol
&symbol
{*pair
.second
};
388 os
<< " " << symbol
<< '\n';
393 bool Scope::IsStmtFunction() const {
394 return symbol_
&& symbol_
->test(Symbol::Flag::StmtFunction
);
397 template <common::TypeParamAttr
... ParamAttr
> struct IsTypeParamHelper
{
398 static_assert(sizeof...(ParamAttr
) == 0, "must have one or zero template");
399 static bool IsParam(const Symbol
&symbol
) {
400 return symbol
.has
<TypeParamDetails
>();
404 template <common::TypeParamAttr ParamAttr
> struct IsTypeParamHelper
<ParamAttr
> {
405 static bool IsParam(const Symbol
&symbol
) {
406 if (const auto *typeParam
{symbol
.detailsIf
<TypeParamDetails
>()}) {
407 return typeParam
->attr() == ParamAttr
;
413 template <common::TypeParamAttr
... ParamAttr
>
414 static bool IsParameterizedDerivedTypeHelper(const Scope
&scope
) {
415 if (scope
.IsDerivedType()) {
416 if (const Scope
* parent
{scope
.GetDerivedTypeParent()}) {
417 if (IsParameterizedDerivedTypeHelper
<ParamAttr
...>(*parent
)) {
421 for (const auto &nameAndSymbolPair
: scope
) {
422 if (IsTypeParamHelper
<ParamAttr
...>::IsParam(*nameAndSymbolPair
.second
)) {
430 bool Scope::IsParameterizedDerivedType() const {
431 return IsParameterizedDerivedTypeHelper
<>(*this);
433 bool Scope::IsDerivedTypeWithLengthParameter() const {
434 return IsParameterizedDerivedTypeHelper
<common::TypeParamAttr::Len
>(*this);
436 bool Scope::IsDerivedTypeWithKindParameter() const {
437 return IsParameterizedDerivedTypeHelper
<common::TypeParamAttr::Kind
>(*this);
440 const DeclTypeSpec
*Scope::FindInstantiatedDerivedType(
441 const DerivedTypeSpec
&spec
, DeclTypeSpec::Category category
) const {
442 DeclTypeSpec type
{category
, spec
};
443 if (const auto *result
{FindType(type
)}) {
445 } else if (IsGlobal()) {
448 return parent().FindInstantiatedDerivedType(spec
, category
);
452 const Scope
*Scope::GetDerivedTypeParent() const {
453 if (const Symbol
* symbol
{GetSymbol()}) {
454 if (const DerivedTypeSpec
* parent
{symbol
->GetParentTypeSpec(this)}) {
455 return parent
->scope();
461 const Scope
&Scope::GetDerivedTypeBase() const {
462 const Scope
*child
{this};
463 for (const Scope
*parent
{GetDerivedTypeParent()}; parent
!= nullptr;
464 parent
= child
->GetDerivedTypeParent()) {
470 void Scope::InstantiateDerivedTypes() {
471 for (DeclTypeSpec
&type
: declTypeSpecs_
) {
472 if (type
.category() == DeclTypeSpec::TypeDerived
||
473 type
.category() == DeclTypeSpec::ClassDerived
) {
474 type
.derivedTypeSpec().Instantiate(*this);
478 } // namespace Fortran::semantics