[lldb] Add ability to hide the root name of a value
[llvm-project.git] / flang / lib / Semantics / scope.cpp
blobbcffbd331280cc1c77b55196c3eec9d230c7041a
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 //===----------------------------------------------------------------------===//
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>
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 {
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 = ',';
44 ss << ')';
46 if (substringStart) {
47 ss << '(' << *substringStart << ":)";
49 return ss.str();
52 Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
53 return children_.emplace_back(*this, kind, symbol, context_);
56 template <typename T>
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{});
65 return result;
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)};
80 if (it != end()) {
81 symbols_.erase(it);
82 return 1;
83 } else {
84 return 0;
87 Symbol *Scope::FindSymbol(const SourceName &name) const {
88 auto it{find(name)};
89 if (it != end()) {
90 return &*it->second;
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);
96 } else {
97 return nullptr;
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);
108 } else {
109 return nullptr;
113 bool Scope::Contains(const Scope &that) const {
114 for (const Scope *scope{&that};; scope = &scope->parent()) {
115 if (*scope == *this) {
116 return true;
118 if (scope->IsGlobal()) {
119 return false;
124 Symbol *Scope::CopySymbol(const Symbol &symbol) {
125 auto pair{try_emplace(symbol.name(), symbol.attrs())};
126 if (!pair.second) {
127 return nullptr; // already exists
128 } else {
129 Symbol &result{*pair.first->second};
130 result.flags() = symbol.flags();
131 result.set_details(common::Clone(symbol.details()));
132 return &result;
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()) {
148 return *it->second;
149 } else {
150 Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
151 commonBlocks_.emplace(name, symbol);
152 return 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()) {
163 return nullptr;
164 } else {
165 return &*it->second;
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();
214 } else {
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()});
224 } else {
225 auto lenExpr{dyType->GetCharLength()};
226 if (!lenExpr) {
227 lenExpr =
228 std::get<evaluate::Expr<evaluate::SomeCharacter>>(expr.u).LEN();
230 if (lenExpr) {
231 return &MakeCharacterType(
232 ParamValue{SomeIntExpr{std::move(*lenExpr)},
233 common::TypeParamAttr::Len},
234 KindExpr{dyType->kind()});
237 break;
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()});
248 return nullptr;
251 Scope::ImportKind Scope::GetImportKind() const {
252 if (importKind_) {
253 return *importKind_;
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) {
266 if (!importKind_) {
267 importKind_ = kind;
268 return std::nullopt;
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) {
274 return hasNone
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;
280 } else {
281 return std::nullopt;
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()) {
292 return false;
294 switch (GetImportKind()) {
295 SWITCH_COVERS_ALL_CASES
296 case ImportKind::None:
297 return false;
298 case ImportKind::All:
299 case ImportKind::Default:
300 return true;
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()) {
313 return nullptr;
315 for (auto &child : children_) {
316 if (auto *scope{child.FindScope(source)}) {
317 return scope;
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_) {
345 os << " ";
346 for (const auto &object : set) {
347 os << ' ' << object.AsFortran();
349 os << '\n';
352 for (const auto &pair : scope.commonBlocks_) {
353 const Symbol &symbol{*pair.second};
354 os << " " << symbol << '\n';
356 return os;
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;
375 return false;
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)) {
384 return true;
387 for (const auto &nameAndSymbolPair : scope) {
388 if (IsTypeParamHelper<ParamAttr...>::IsParam(*nameAndSymbolPair.second)) {
389 return true;
393 return false;
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)}) {
410 return result;
411 } else if (IsGlobal()) {
412 return nullptr;
413 } else {
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();
424 return nullptr;
427 const Scope &Scope::GetDerivedTypeBase() const {
428 const Scope *child{this};
429 for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
430 parent = child->GetDerivedTypeParent()) {
431 child = parent;
433 return *child;
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