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/symbol.h"
12 #include "flang/Semantics/type.h"
13 #include "llvm/Support/raw_ostream.h"
17 namespace Fortran::semantics
{
19 Symbols
<1024> Scope::allSymbols
;
21 bool EquivalenceObject::operator==(const EquivalenceObject
&that
) const {
22 return symbol
== that
.symbol
&& subscripts
== that
.subscripts
&&
23 substringStart
== that
.substringStart
;
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
)));
34 std::string
EquivalenceObject::AsFortran() const {
36 llvm::raw_string_ostream ss
{buf
};
37 ss
<< symbol
.name().ToString();
38 if (!subscripts
.empty()) {
40 for (auto subscript
: subscripts
) {
41 ss
<< sep
<< subscript
;
47 ss
<< '(' << *substringStart
<< ":)";
52 Scope
&Scope::MakeScope(Kind kind
, Symbol
*symbol
) {
53 return children_
.emplace_back(*this, kind
, symbol
, context_
);
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
);
64 std::sort(result
.begin(), result
.end(), SymbolSourcePositionCompare
{});
68 MutableSymbolVector
Scope::GetSymbols() {
69 return GetSortedSymbols
<Symbol
>(symbols_
);
71 SymbolVector
Scope::GetSymbols() const {
72 return GetSortedSymbols
<const Symbol
>(symbols_
);
75 Scope::iterator
Scope::find(const SourceName
&name
) {
76 return symbols_
.find(name
);
78 Scope::size_type
Scope::erase(const SourceName
&name
) {
79 auto it
{symbols_
.find(name
)};
87 Symbol
*Scope::FindSymbol(const SourceName
&name
) const {
91 } else if (IsSubmodule()) {
92 const Scope
*parent
{symbol_
->get
<ModuleDetails
>().parent()};
93 return parent
? parent
->FindSymbol(name
) : nullptr;
94 } else if (CanImport(name
)) {
95 return parent_
.FindSymbol(name
);
101 Symbol
*Scope::FindComponent(SourceName name
) const {
102 CHECK(IsDerivedType());
103 auto found
{find(name
)};
104 if (found
!= end()) {
105 return &*found
->second
;
106 } else if (const Scope
* parent
{GetDerivedTypeParent()}) {
107 return parent
->FindComponent(name
);
113 bool Scope::Contains(const Scope
&that
) const {
114 for (const Scope
*scope
{&that
};; scope
= &scope
->parent()) {
115 if (*scope
== *this) {
118 if (scope
->IsGlobal()) {
124 Symbol
*Scope::CopySymbol(const Symbol
&symbol
) {
125 auto pair
{try_emplace(symbol
.name(), symbol
.attrs())};
127 return nullptr; // already exists
129 Symbol
&result
{*pair
.first
->second
};
130 result
.flags() = symbol
.flags();
131 result
.set_details(common::Clone(symbol
.details()));
136 void Scope::add_equivalenceSet(EquivalenceSet
&&set
) {
137 equivalenceSets_
.emplace_back(std::move(set
));
140 void Scope::add_crayPointer(const SourceName
&name
, Symbol
&pointer
) {
141 CHECK(pointer
.test(Symbol::Flag::CrayPointer
));
142 crayPointers_
.emplace(name
, pointer
);
145 Symbol
&Scope::MakeCommonBlock(const SourceName
&name
) {
146 const auto it
{commonBlocks_
.find(name
)};
147 if (it
!= commonBlocks_
.end()) {
150 Symbol
&symbol
{MakeSymbol(name
, Attrs
{}, CommonBlockDetails
{})};
151 commonBlocks_
.emplace(name
, symbol
);
155 Symbol
*Scope::FindCommonBlock(const SourceName
&name
) const {
156 const auto it
{commonBlocks_
.find(name
)};
157 return it
!= commonBlocks_
.end() ? &*it
->second
: nullptr;
160 Scope
*Scope::FindSubmodule(const SourceName
&name
) const {
161 auto it
{submodules_
.find(name
)};
162 if (it
== submodules_
.end()) {
168 bool Scope::AddSubmodule(const SourceName
&name
, Scope
&submodule
) {
169 return submodules_
.emplace(name
, submodule
).second
;
172 const DeclTypeSpec
*Scope::FindType(const DeclTypeSpec
&type
) const {
173 auto it
{std::find(declTypeSpecs_
.begin(), declTypeSpecs_
.end(), type
)};
174 return it
!= declTypeSpecs_
.end() ? &*it
: nullptr;
177 const DeclTypeSpec
&Scope::MakeNumericType(
178 TypeCategory category
, KindExpr
&&kind
) {
179 return MakeLengthlessType(NumericTypeSpec
{category
, std::move(kind
)});
181 const DeclTypeSpec
&Scope::MakeLogicalType(KindExpr
&&kind
) {
182 return MakeLengthlessType(LogicalTypeSpec
{std::move(kind
)});
184 const DeclTypeSpec
&Scope::MakeTypeStarType() {
185 return MakeLengthlessType(DeclTypeSpec
{DeclTypeSpec::TypeStar
});
187 const DeclTypeSpec
&Scope::MakeClassStarType() {
188 return MakeLengthlessType(DeclTypeSpec
{DeclTypeSpec::ClassStar
});
190 // Types that can't have length parameters can be reused without having to
191 // compare length expressions. They are stored in the global scope.
192 const DeclTypeSpec
&Scope::MakeLengthlessType(DeclTypeSpec
&&type
) {
193 const auto *found
{FindType(type
)};
194 return found
? *found
: declTypeSpecs_
.emplace_back(std::move(type
));
197 const DeclTypeSpec
&Scope::MakeCharacterType(
198 ParamValue
&&length
, KindExpr
&&kind
) {
199 return declTypeSpecs_
.emplace_back(
200 CharacterTypeSpec
{std::move(length
), std::move(kind
)});
203 DeclTypeSpec
&Scope::MakeDerivedType(
204 DeclTypeSpec::Category category
, DerivedTypeSpec
&&spec
) {
205 return declTypeSpecs_
.emplace_back(category
, std::move(spec
));
208 const DeclTypeSpec
*Scope::GetType(const SomeExpr
&expr
) {
209 if (auto dyType
{expr
.GetType()}) {
210 if (dyType
->IsAssumedType()) {
211 return &MakeTypeStarType();
212 } else if (dyType
->IsUnlimitedPolymorphic()) {
213 return &MakeClassStarType();
215 switch (dyType
->category()) {
216 case TypeCategory::Integer
:
217 case TypeCategory::Real
:
218 case TypeCategory::Complex
:
219 return &MakeNumericType(dyType
->category(), KindExpr
{dyType
->kind()});
220 case TypeCategory::Character
:
221 if (const ParamValue
* lenParam
{dyType
->charLengthParamValue()}) {
222 return &MakeCharacterType(
223 ParamValue
{*lenParam
}, KindExpr
{dyType
->kind()});
225 auto lenExpr
{dyType
->GetCharLength()};
228 std::get
<evaluate::Expr
<evaluate::SomeCharacter
>>(expr
.u
).LEN();
231 return &MakeCharacterType(
232 ParamValue
{SomeIntExpr
{std::move(*lenExpr
)},
233 common::TypeParamAttr::Len
},
234 KindExpr
{dyType
->kind()});
238 case TypeCategory::Logical
:
239 return &MakeLogicalType(KindExpr
{dyType
->kind()});
240 case TypeCategory::Derived
:
241 return &MakeDerivedType(dyType
->IsPolymorphic()
242 ? DeclTypeSpec::ClassDerived
243 : DeclTypeSpec::TypeDerived
,
244 DerivedTypeSpec
{dyType
->GetDerivedTypeSpec()});
251 Scope::ImportKind
Scope::GetImportKind() const {
255 if (symbol_
&& !symbol_
->attrs().test(Attr::MODULE
)) {
256 if (auto *details
{symbol_
->detailsIf
<SubprogramDetails
>()}) {
257 if (details
->isInterface()) {
258 return ImportKind::None
; // default for non-mod-proc interface body
262 return ImportKind::Default
;
265 std::optional
<parser::MessageFixedText
> Scope::SetImportKind(ImportKind kind
) {
270 bool hasNone
{kind
== ImportKind::None
|| *importKind_
== ImportKind::None
};
271 bool hasAll
{kind
== ImportKind::All
|| *importKind_
== ImportKind::All
};
272 // Check C8100 and C898: constraints on multiple IMPORT statements
273 if (hasNone
|| hasAll
) {
275 ? "IMPORT,NONE must be the only IMPORT statement in a scope"_err_en_US
276 : "IMPORT,ALL must be the only IMPORT statement in a scope"_err_en_US
;
277 } else if (kind
!= *importKind_
&&
278 (kind
!= ImportKind::Only
&& *importKind_
!= ImportKind::Only
)) {
279 return "Every IMPORT must have ONLY specifier if one of them does"_err_en_US
;
285 void Scope::add_importName(const SourceName
&name
) {
286 importNames_
.insert(name
);
289 // true if name can be imported or host-associated from parent scope.
290 bool Scope::CanImport(const SourceName
&name
) const {
291 if (IsTopLevel() || parent_
.IsTopLevel()) {
294 switch (GetImportKind()) {
295 SWITCH_COVERS_ALL_CASES
296 case ImportKind::None
:
298 case ImportKind::All
:
299 case ImportKind::Default
:
301 case ImportKind::Only
:
302 return importNames_
.count(name
) > 0;
306 const Scope
*Scope::FindScope(parser::CharBlock source
) const {
307 return const_cast<Scope
*>(this)->FindScope(source
);
310 Scope
*Scope::FindScope(parser::CharBlock source
) {
311 bool isContained
{sourceRange_
.Contains(source
)};
312 if (!isContained
&& !IsTopLevel() && !IsModuleFile()) {
315 for (auto &child
: children_
) {
316 if (auto *scope
{child
.FindScope(source
)}) {
320 return isContained
&& !IsTopLevel() ? this : nullptr;
323 void Scope::AddSourceRange(const parser::CharBlock
&source
) {
324 for (auto *scope
{this}; !scope
->IsGlobal(); scope
= &scope
->parent()) {
325 scope
->sourceRange_
.ExtendToCover(source
);
329 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&os
, const Scope
&scope
) {
330 os
<< Scope::EnumToString(scope
.kind()) << " scope: ";
331 if (auto *symbol
{scope
.symbol()}) {
332 os
<< *symbol
<< ' ';
334 if (scope
.derivedTypeSpec_
) {
335 os
<< "instantiation of " << *scope
.derivedTypeSpec_
<< ' ';
337 os
<< scope
.children_
.size() << " children\n";
338 for (const auto &pair
: scope
.symbols_
) {
339 const Symbol
&symbol
{*pair
.second
};
340 os
<< " " << symbol
<< '\n';
342 if (!scope
.equivalenceSets_
.empty()) {
343 os
<< " Equivalence Sets:\n";
344 for (const auto &set
: scope
.equivalenceSets_
) {
346 for (const auto &object
: set
) {
347 os
<< ' ' << object
.AsFortran();
352 for (const auto &pair
: scope
.commonBlocks_
) {
353 const Symbol
&symbol
{*pair
.second
};
354 os
<< " " << symbol
<< '\n';
359 bool Scope::IsStmtFunction() const {
360 return symbol_
&& symbol_
->test(Symbol::Flag::StmtFunction
);
363 template <common::TypeParamAttr
... ParamAttr
> struct IsTypeParamHelper
{
364 static_assert(sizeof...(ParamAttr
) == 0, "must have one or zero template");
365 static bool IsParam(const Symbol
&symbol
) {
366 return symbol
.has
<TypeParamDetails
>();
370 template <common::TypeParamAttr ParamAttr
> struct IsTypeParamHelper
<ParamAttr
> {
371 static bool IsParam(const Symbol
&symbol
) {
372 if (const auto *typeParam
{symbol
.detailsIf
<TypeParamDetails
>()}) {
373 return typeParam
->attr() == ParamAttr
;
379 template <common::TypeParamAttr
... ParamAttr
>
380 static bool IsParameterizedDerivedTypeHelper(const Scope
&scope
) {
381 if (scope
.IsDerivedType()) {
382 if (const Scope
* parent
{scope
.GetDerivedTypeParent()}) {
383 if (IsParameterizedDerivedTypeHelper
<ParamAttr
...>(*parent
)) {
387 for (const auto &nameAndSymbolPair
: scope
) {
388 if (IsTypeParamHelper
<ParamAttr
...>::IsParam(*nameAndSymbolPair
.second
)) {
396 bool Scope::IsParameterizedDerivedType() const {
397 return IsParameterizedDerivedTypeHelper
<>(*this);
399 bool Scope::IsDerivedTypeWithLengthParameter() const {
400 return IsParameterizedDerivedTypeHelper
<common::TypeParamAttr::Len
>(*this);
402 bool Scope::IsDerivedTypeWithKindParameter() const {
403 return IsParameterizedDerivedTypeHelper
<common::TypeParamAttr::Kind
>(*this);
406 const DeclTypeSpec
*Scope::FindInstantiatedDerivedType(
407 const DerivedTypeSpec
&spec
, DeclTypeSpec::Category category
) const {
408 DeclTypeSpec type
{category
, spec
};
409 if (const auto *result
{FindType(type
)}) {
411 } else if (IsGlobal()) {
414 return parent().FindInstantiatedDerivedType(spec
, category
);
418 const Scope
*Scope::GetDerivedTypeParent() const {
419 if (const Symbol
* symbol
{GetSymbol()}) {
420 if (const DerivedTypeSpec
* parent
{symbol
->GetParentTypeSpec(this)}) {
421 return parent
->scope();
427 const Scope
&Scope::GetDerivedTypeBase() const {
428 const Scope
*child
{this};
429 for (const Scope
*parent
{GetDerivedTypeParent()}; parent
!= nullptr;
430 parent
= child
->GetDerivedTypeParent()) {
436 void Scope::InstantiateDerivedTypes() {
437 for (DeclTypeSpec
&type
: declTypeSpecs_
) {
438 if (type
.category() == DeclTypeSpec::TypeDerived
||
439 type
.category() == DeclTypeSpec::ClassDerived
) {
440 type
.derivedTypeSpec().Instantiate(*this);
444 } // namespace Fortran::semantics