2019-01-07 15:42:36 -08:00
|
|
|
// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
2018-05-01 12:50:34 -07:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2018-03-22 17:08:20 -07:00
|
|
|
#include "symbol.h"
|
|
|
|
#include "scope.h"
|
2019-01-31 09:58:40 -08:00
|
|
|
#include "semantics.h"
|
2018-06-18 11:03:43 -07:00
|
|
|
#include "../common/idioms.h"
|
2019-01-07 15:05:53 -08:00
|
|
|
#include "../evaluate/fold.h"
|
2018-11-16 12:43:08 -08:00
|
|
|
#include <ostream>
|
|
|
|
#include <string>
|
2018-03-22 17:08:20 -07:00
|
|
|
|
2018-03-23 12:24:29 -07:00
|
|
|
namespace Fortran::semantics {
|
2018-03-22 17:08:20 -07:00
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const parser::CharBlock &name) {
|
|
|
|
return os << name.ToString();
|
|
|
|
}
|
|
|
|
|
2019-04-04 14:46:40 -07:00
|
|
|
template<typename T>
|
|
|
|
static void DumpOptional(
|
|
|
|
std::ostream &os, const char *label, const std::optional<T> &x) {
|
|
|
|
if (x) {
|
|
|
|
os << ' ' << label << ':' << *x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpBool(std::ostream &os, const char *label, bool x) {
|
|
|
|
if (x) {
|
|
|
|
os << ' ' << label;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpSymbolList(std::ostream &os, const SymbolList &list) {
|
|
|
|
char sep{' '};
|
|
|
|
for (const auto *elem : list) {
|
|
|
|
os << sep << elem->name();
|
|
|
|
sep = ',';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpType(std::ostream &os, const Symbol &symbol) {
|
|
|
|
if (const auto *type{symbol.GetType()}) {
|
|
|
|
os << *type << ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void DumpType(std::ostream &os, const DeclTypeSpec *type) {
|
|
|
|
if (type) {
|
|
|
|
os << ' ' << *type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
static void DumpList(
|
|
|
|
std::ostream &os, const char *label, const std::list<T> &list) {
|
|
|
|
if (!list.empty()) {
|
|
|
|
os << ' ' << label << ':';
|
|
|
|
char sep{' '};
|
|
|
|
for (const auto &elem : list) {
|
|
|
|
os << sep << elem;
|
|
|
|
sep = ',';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-02 16:21:27 -07:00
|
|
|
const Scope *ModuleDetails::parent() const {
|
2018-11-16 12:43:08 -08:00
|
|
|
return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
|
2018-08-02 16:21:27 -07:00
|
|
|
}
|
|
|
|
const Scope *ModuleDetails::ancestor() const {
|
2018-11-16 12:43:08 -08:00
|
|
|
if (!isSubmodule_ || !scope_) {
|
2018-08-02 16:21:27 -07:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
for (auto *scope{scope_};;) {
|
|
|
|
auto *parent{&scope->parent()};
|
|
|
|
if (parent->kind() != Scope::Kind::Module) {
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
scope = parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void ModuleDetails::set_scope(const Scope *scope) {
|
|
|
|
CHECK(!scope_);
|
|
|
|
bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
|
|
|
|
CHECK(isSubmodule_ == scopeIsSubmodule);
|
|
|
|
scope_ = scope;
|
|
|
|
}
|
|
|
|
|
2019-01-04 17:10:31 -08:00
|
|
|
std::ostream &operator<<(std::ostream &os, const SubprogramDetails &x) {
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpBool(os, "isInterface", x.isInterface_);
|
|
|
|
DumpOptional(os, "bindName", x.bindName_);
|
2019-01-04 17:10:31 -08:00
|
|
|
if (x.result_) {
|
2019-03-20 13:52:33 -07:00
|
|
|
os << " result:" << x.result_->name();
|
|
|
|
if (!x.result_->attrs().empty()) {
|
|
|
|
os << ", " << x.result_->attrs();
|
|
|
|
}
|
2019-01-04 17:10:31 -08:00
|
|
|
}
|
|
|
|
if (x.dummyArgs_.empty()) {
|
|
|
|
char sep{'('};
|
|
|
|
os << ' ';
|
|
|
|
for (const auto *arg : x.dummyArgs_) {
|
|
|
|
os << sep << arg->name();
|
|
|
|
sep = ',';
|
|
|
|
}
|
|
|
|
os << ')';
|
|
|
|
}
|
|
|
|
return os;
|
2018-04-12 12:59:42 -07:00
|
|
|
}
|
|
|
|
|
2019-01-04 17:10:31 -08:00
|
|
|
void EntityDetails::set_type(const DeclTypeSpec &type) {
|
2018-06-05 12:18:35 -07:00
|
|
|
CHECK(!type_);
|
2018-12-11 14:51:08 -08:00
|
|
|
type_ = &type;
|
2018-06-05 12:18:35 -07:00
|
|
|
}
|
|
|
|
|
2019-01-15 16:59:20 -08:00
|
|
|
void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
|
2019-01-07 15:05:53 -08:00
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
|
2018-04-12 12:59:42 -07:00
|
|
|
CHECK(shape_.empty());
|
|
|
|
for (const auto &shapeSpec : shape) {
|
2019-01-07 15:05:53 -08:00
|
|
|
shape_.push_back(shapeSpec);
|
2018-04-12 12:59:42 -07:00
|
|
|
}
|
|
|
|
}
|
2019-04-04 14:46:40 -07:00
|
|
|
void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
|
|
|
|
CHECK(coshape_.empty());
|
|
|
|
for (const auto &shapeSpec : coshape) {
|
|
|
|
coshape_.push_back(shapeSpec);
|
|
|
|
}
|
|
|
|
}
|
2018-04-12 12:59:42 -07:00
|
|
|
|
2019-01-04 17:10:31 -08:00
|
|
|
ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
|
|
|
|
if (type()) {
|
|
|
|
interface_.set_type(*type());
|
2018-06-05 12:18:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
const Symbol &UseDetails::module() const {
|
|
|
|
// owner is a module so it must have a symbol:
|
|
|
|
return *symbol_->owner().symbol();
|
|
|
|
}
|
|
|
|
|
2018-08-29 11:38:12 -07:00
|
|
|
UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
|
|
|
|
add_occurrence(useDetails.location(), *useDetails.module().scope());
|
|
|
|
}
|
|
|
|
UseErrorDetails &UseErrorDetails::add_occurrence(
|
|
|
|
const SourceName &location, const Scope &module) {
|
2018-11-16 12:43:08 -08:00
|
|
|
occurrences_.push_back(std::make_pair(location, &module));
|
2018-08-29 11:38:12 -07:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-12-26 13:31:13 -08:00
|
|
|
GenericDetails::GenericDetails(const SymbolList &specificProcs) {
|
2018-05-22 16:12:56 -07:00
|
|
|
for (const auto *proc : specificProcs) {
|
2018-12-26 13:31:13 -08:00
|
|
|
add_specificProc(*proc);
|
2018-05-22 16:12:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 08:21:19 -07:00
|
|
|
void GenericDetails::set_specific(Symbol &specific) {
|
2018-05-22 16:12:56 -07:00
|
|
|
CHECK(!specific_);
|
2018-06-22 08:21:19 -07:00
|
|
|
specific_ = &specific;
|
|
|
|
}
|
|
|
|
void GenericDetails::set_derivedType(Symbol &derivedType) {
|
|
|
|
CHECK(!derivedType_);
|
|
|
|
derivedType_ = &derivedType;
|
2018-05-22 16:12:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const Symbol *GenericDetails::CheckSpecific() const {
|
2019-04-25 13:18:33 -07:00
|
|
|
return const_cast<GenericDetails *>(this)->CheckSpecific();
|
|
|
|
}
|
|
|
|
Symbol *GenericDetails::CheckSpecific() {
|
2018-06-19 16:06:41 -07:00
|
|
|
if (specific_) {
|
2018-05-22 16:12:56 -07:00
|
|
|
for (const auto *proc : specificProcs_) {
|
2018-06-19 16:06:41 -07:00
|
|
|
if (proc == specific_) {
|
2018-05-22 16:12:56 -07:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
2018-06-19 16:06:41 -07:00
|
|
|
return specific_;
|
2018-05-22 16:12:56 -07:00
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-17 14:16:42 -07:00
|
|
|
// The name of the kind of details for this symbol.
|
|
|
|
// This is primarily for debugging.
|
2018-07-19 13:28:24 -07:00
|
|
|
std::string DetailsToString(const Details &details) {
|
2018-04-17 14:16:42 -07:00
|
|
|
return std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-05-22 16:12:56 -07:00
|
|
|
[](const UnknownDetails &) { return "Unknown"; },
|
|
|
|
[](const MainProgramDetails &) { return "MainProgram"; },
|
|
|
|
[](const ModuleDetails &) { return "Module"; },
|
|
|
|
[](const SubprogramDetails &) { return "Subprogram"; },
|
|
|
|
[](const SubprogramNameDetails &) { return "SubprogramName"; },
|
|
|
|
[](const EntityDetails &) { return "Entity"; },
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const ObjectEntityDetails &) { return "ObjectEntity"; },
|
|
|
|
[](const ProcEntityDetails &) { return "ProcEntity"; },
|
2018-06-22 08:21:19 -07:00
|
|
|
[](const DerivedTypeDetails &) { return "DerivedType"; },
|
2018-05-22 16:12:56 -07:00
|
|
|
[](const UseDetails &) { return "Use"; },
|
|
|
|
[](const UseErrorDetails &) { return "UseError"; },
|
2018-10-18 07:55:48 -07:00
|
|
|
[](const HostAssocDetails &) { return "HostAssoc"; },
|
2018-05-22 16:12:56 -07:00
|
|
|
[](const GenericDetails &) { return "Generic"; },
|
2018-08-31 16:20:00 -07:00
|
|
|
[](const ProcBindingDetails &) { return "ProcBinding"; },
|
|
|
|
[](const GenericBindingDetails &) { return "GenericBinding"; },
|
2019-02-05 14:43:00 -08:00
|
|
|
[](const NamelistDetails &) { return "Namelist"; },
|
2019-02-14 07:59:20 -08:00
|
|
|
[](const CommonBlockDetails &) { return "CommonBlockDetails"; },
|
2018-08-31 16:20:00 -07:00
|
|
|
[](const FinalProcDetails &) { return "FinalProc"; },
|
2018-09-04 10:28:27 -07:00
|
|
|
[](const TypeParamDetails &) { return "TypeParam"; },
|
2018-09-25 08:53:53 -07:00
|
|
|
[](const MiscDetails &) { return "Misc"; },
|
2019-01-15 16:59:20 -08:00
|
|
|
[](const AssocEntityDetails &) { return "AssocEntity"; },
|
2018-04-17 14:16:42 -07:00
|
|
|
},
|
2018-05-03 15:57:56 -07:00
|
|
|
details);
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string Symbol::GetDetailsName() const {
|
|
|
|
return DetailsToString(details_);
|
|
|
|
}
|
|
|
|
|
2018-11-05 14:36:11 -08:00
|
|
|
void Symbol::set_details(Details &&details) {
|
2018-05-14 13:51:13 -07:00
|
|
|
CHECK(CanReplaceDetails(details));
|
2018-11-05 14:36:11 -08:00
|
|
|
details_ = std::move(details);
|
2018-05-14 13:51:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Symbol::CanReplaceDetails(const Details &details) const {
|
|
|
|
if (has<UnknownDetails>()) {
|
|
|
|
return true; // can always replace UnknownDetails
|
|
|
|
} else {
|
2018-06-05 12:18:35 -07:00
|
|
|
return std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const UseErrorDetails &) { return true; },
|
|
|
|
[=](const ObjectEntityDetails &) { return has<EntityDetails>(); },
|
|
|
|
[=](const ProcEntityDetails &) { return has<EntityDetails>(); },
|
|
|
|
[=](const SubprogramDetails &) {
|
2019-06-14 15:04:13 -07:00
|
|
|
return has<SubprogramNameDetails>() || has<EntityDetails>();
|
2018-06-05 12:18:35 -07:00
|
|
|
},
|
|
|
|
[](const auto &) { return false; },
|
|
|
|
},
|
|
|
|
details);
|
2018-05-14 13:51:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 16:12:56 -07:00
|
|
|
Symbol &Symbol::GetUltimate() {
|
2019-01-18 15:53:11 -08:00
|
|
|
return const_cast<Symbol &>(const_cast<const Symbol *>(this)->GetUltimate());
|
2018-05-22 16:12:56 -07:00
|
|
|
}
|
2018-05-03 15:57:56 -07:00
|
|
|
const Symbol &Symbol::GetUltimate() const {
|
2018-07-17 07:02:30 -07:00
|
|
|
if (const auto *details{detailsIf<UseDetails>()}) {
|
2018-05-03 15:57:56 -07:00
|
|
|
return details->symbol().GetUltimate();
|
2018-10-18 07:55:48 -07:00
|
|
|
} else if (const auto *details{detailsIf<HostAssocDetails>()}) {
|
|
|
|
return details->symbol().GetUltimate();
|
2018-05-03 15:57:56 -07:00
|
|
|
} else {
|
|
|
|
return *this;
|
|
|
|
}
|
2018-04-17 14:16:42 -07:00
|
|
|
}
|
|
|
|
|
2018-06-26 15:01:42 -07:00
|
|
|
void Symbol::SetType(const DeclTypeSpec &type) {
|
|
|
|
std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](EntityDetails &x) { x.set_type(type); },
|
|
|
|
[&](ObjectEntityDetails &x) { x.set_type(type); },
|
2019-01-15 16:59:20 -08:00
|
|
|
[&](AssocEntityDetails &x) { x.set_type(type); },
|
2018-06-26 15:01:42 -07:00
|
|
|
[&](ProcEntityDetails &x) { x.interface().set_type(type); },
|
2018-09-04 10:28:27 -07:00
|
|
|
[&](TypeParamDetails &x) { x.set_type(type); },
|
2018-06-26 15:01:42 -07:00
|
|
|
[](auto &) {},
|
|
|
|
},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
2019-02-20 17:45:39 -08:00
|
|
|
bool Symbol::IsDummy() const {
|
|
|
|
return std::visit(
|
|
|
|
common::visitors{[](const EntityDetails &x) { return x.isDummy(); },
|
|
|
|
[](const ObjectEntityDetails &x) { return x.isDummy(); },
|
|
|
|
[](const ProcEntityDetails &x) { return x.isDummy(); },
|
|
|
|
[](const HostAssocDetails &x) { return x.symbol().IsDummy(); },
|
|
|
|
[](const auto &) { return false; }},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Symbol::IsFuncResult() const {
|
|
|
|
return std::visit(
|
|
|
|
common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
|
|
|
|
[](const ObjectEntityDetails &x) { return x.isFuncResult(); },
|
|
|
|
[](const ProcEntityDetails &x) { return x.isFuncResult(); },
|
|
|
|
[](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
|
|
|
|
[](const auto &) { return false; }},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
2019-02-07 12:25:59 -08:00
|
|
|
bool Symbol::IsObjectArray() const {
|
2019-02-06 10:28:31 -08:00
|
|
|
const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
|
|
|
|
return details && details->IsArray();
|
|
|
|
}
|
|
|
|
|
2018-10-26 11:57:08 -07:00
|
|
|
bool Symbol::IsSubprogram() const {
|
2018-05-14 13:51:13 -07:00
|
|
|
return std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const SubprogramDetails &) { return true; },
|
|
|
|
[](const SubprogramNameDetails &) { return true; },
|
|
|
|
[](const GenericDetails &) { return true; },
|
2018-10-26 11:57:08 -07:00
|
|
|
[](const UseDetails &x) { return x.symbol().IsSubprogram(); },
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const auto &) { return false; },
|
2018-05-14 13:51:13 -07:00
|
|
|
},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
2018-10-26 11:57:08 -07:00
|
|
|
bool Symbol::IsSeparateModuleProc() const {
|
2018-10-26 07:34:50 -07:00
|
|
|
if (attrs().test(Attr::MODULE)) {
|
|
|
|
if (auto *details{detailsIf<SubprogramDetails>()}) {
|
|
|
|
return details->isInterface();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-04 17:10:31 -08:00
|
|
|
ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
|
|
|
|
: EntityDetails(d) {}
|
2018-06-05 12:18:35 -07:00
|
|
|
|
2018-04-12 12:59:42 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const EntityDetails &x) {
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpBool(os, "dummy", x.isDummy());
|
|
|
|
DumpBool(os, "funcResult", x.isFuncResult());
|
2018-06-05 12:18:35 -07:00
|
|
|
if (x.type()) {
|
|
|
|
os << " type: " << *x.type();
|
|
|
|
}
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpOptional(os, "bindName", x.bindName_);
|
2018-06-05 12:18:35 -07:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &os, const ObjectEntityDetails &x) {
|
2019-01-04 17:10:31 -08:00
|
|
|
os << *static_cast<const EntityDetails *>(&x);
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpList(os, "shape", x.shape());
|
|
|
|
DumpList(os, "coshape", x.coshape());
|
|
|
|
DumpOptional(os, "init", x.init_);
|
2018-04-12 12:59:42 -07:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2019-01-15 16:59:20 -08:00
|
|
|
std::ostream &operator<<(std::ostream &os, const AssocEntityDetails &x) {
|
|
|
|
os << *static_cast<const EntityDetails *>(&x);
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpOptional(os, "expr", x.expr());
|
2019-01-15 16:59:20 -08:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const ProcEntityDetails &x) {
|
2018-07-17 07:02:30 -07:00
|
|
|
if (auto *symbol{x.interface_.symbol()}) {
|
2019-01-04 17:10:31 -08:00
|
|
|
os << ' ' << symbol->name();
|
2019-04-04 14:46:40 -07:00
|
|
|
} else {
|
|
|
|
DumpType(os, x.interface_.type());
|
2019-01-04 17:10:31 -08:00
|
|
|
}
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpOptional(os, "bindName", x.bindName());
|
|
|
|
DumpOptional(os, "passName", x.passName());
|
2018-06-05 12:18:35 -07:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-22 08:21:19 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const DerivedTypeDetails &x) {
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpBool(os, "sequence", x.sequence_);
|
|
|
|
DumpList(os, "components", x.componentNames_);
|
2018-04-17 14:16:42 -07:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const Details &details) {
|
|
|
|
os << DetailsToString(details);
|
2018-03-22 17:08:20 -07:00
|
|
|
std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-04-18 15:06:35 -07:00
|
|
|
[&](const UnknownDetails &x) {},
|
|
|
|
[&](const MainProgramDetails &x) {},
|
2018-08-02 16:21:27 -07:00
|
|
|
[&](const ModuleDetails &x) {
|
|
|
|
if (x.isSubmodule()) {
|
2018-11-16 12:43:08 -08:00
|
|
|
os << " (";
|
|
|
|
if (x.ancestor()) {
|
|
|
|
auto &ancestor{x.ancestor()->name()};
|
|
|
|
os << ancestor;
|
|
|
|
if (x.parent()) {
|
|
|
|
auto &parent{x.parent()->name()};
|
|
|
|
if (ancestor != parent) {
|
|
|
|
os << ':' << parent;
|
|
|
|
}
|
|
|
|
}
|
2018-08-02 16:21:27 -07:00
|
|
|
}
|
|
|
|
os << ")";
|
|
|
|
}
|
|
|
|
},
|
2018-03-22 17:08:20 -07:00
|
|
|
[&](const SubprogramDetails &x) {
|
2018-04-18 15:06:35 -07:00
|
|
|
os << " (";
|
2018-03-22 17:08:20 -07:00
|
|
|
int n = 0;
|
2018-04-17 14:16:42 -07:00
|
|
|
for (const auto &dummy : x.dummyArgs()) {
|
2018-03-22 17:08:20 -07:00
|
|
|
if (n++ > 0) os << ", ";
|
2018-04-17 14:16:42 -07:00
|
|
|
DumpType(os, *dummy);
|
2018-05-03 15:57:56 -07:00
|
|
|
os << dummy->name();
|
2018-03-22 17:08:20 -07:00
|
|
|
}
|
|
|
|
os << ')';
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpOptional(os, "bindName", x.bindName());
|
2018-04-17 14:16:42 -07:00
|
|
|
if (x.isFunction()) {
|
|
|
|
os << " result(";
|
|
|
|
DumpType(os, x.result());
|
2018-05-03 15:57:56 -07:00
|
|
|
os << x.result().name() << ')';
|
2018-03-22 17:08:20 -07:00
|
|
|
}
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpBool(os, "interface", x.isInterface());
|
2018-05-14 13:51:13 -07:00
|
|
|
},
|
|
|
|
[&](const SubprogramNameDetails &x) {
|
|
|
|
os << ' ' << EnumToString(x.kind());
|
2018-03-22 17:08:20 -07:00
|
|
|
},
|
2018-05-03 15:57:56 -07:00
|
|
|
[&](const UseDetails &x) {
|
|
|
|
os << " from " << x.symbol().name() << " in " << x.module().name();
|
|
|
|
},
|
|
|
|
[&](const UseErrorDetails &x) {
|
|
|
|
os << " uses:";
|
2018-11-16 12:43:08 -08:00
|
|
|
for (const auto &[location, module] : x.occurrences()) {
|
|
|
|
os << " from " << module->name() << " at " << location;
|
2018-05-03 15:57:56 -07:00
|
|
|
}
|
|
|
|
},
|
2018-10-18 07:55:48 -07:00
|
|
|
[](const HostAssocDetails &) {},
|
2018-05-14 13:51:13 -07:00
|
|
|
[&](const GenericDetails &x) {
|
2019-03-18 11:48:02 -07:00
|
|
|
os << ' ' << EnumToString(x.kind());
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpSymbolList(os, x.specificProcs());
|
2018-05-14 13:51:13 -07:00
|
|
|
},
|
2018-08-31 16:20:00 -07:00
|
|
|
[&](const ProcBindingDetails &x) {
|
|
|
|
os << " => " << x.symbol().name();
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpOptional(os, "passName", x.passName());
|
2018-08-31 16:20:00 -07:00
|
|
|
},
|
2018-12-26 13:31:13 -08:00
|
|
|
[&](const GenericBindingDetails &x) {
|
|
|
|
os << " =>";
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpSymbolList(os, x.specificProcs());
|
2018-12-26 13:31:13 -08:00
|
|
|
},
|
2019-02-05 14:43:00 -08:00
|
|
|
[&](const NamelistDetails &x) {
|
2019-02-18 11:39:46 -08:00
|
|
|
os << ':';
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpSymbolList(os, x.objects());
|
2019-02-14 07:59:20 -08:00
|
|
|
},
|
|
|
|
[&](const CommonBlockDetails &x) {
|
2019-02-18 11:39:46 -08:00
|
|
|
os << ':';
|
2019-02-14 07:59:20 -08:00
|
|
|
for (const auto *object : x.objects()) {
|
2019-02-05 14:43:00 -08:00
|
|
|
os << ' ' << object->name();
|
|
|
|
}
|
|
|
|
},
|
2018-08-31 16:20:00 -07:00
|
|
|
[&](const FinalProcDetails &) {},
|
2018-09-04 10:28:27 -07:00
|
|
|
[&](const TypeParamDetails &x) {
|
|
|
|
if (x.type()) {
|
|
|
|
os << ' ' << *x.type();
|
|
|
|
}
|
2018-09-05 16:02:41 -07:00
|
|
|
os << ' ' << common::EnumToString(x.attr());
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpOptional(os, "init", x.init());
|
2018-09-04 10:28:27 -07:00
|
|
|
},
|
2018-09-25 08:53:53 -07:00
|
|
|
[&](const MiscDetails &x) {
|
|
|
|
os << ' ' << MiscDetails::EnumToString(x.kind());
|
|
|
|
},
|
2019-01-15 16:59:20 -08:00
|
|
|
[&](const auto &x) { os << x; },
|
2018-03-22 17:08:20 -07:00
|
|
|
},
|
2018-05-03 15:57:56 -07:00
|
|
|
details);
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
std::ostream &operator<<(std::ostream &o, Symbol::Flag flag) {
|
|
|
|
return o << Symbol::EnumToString(flag);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &o, const Symbol::Flags &flags) {
|
|
|
|
std::size_t n{flags.count()};
|
|
|
|
std::size_t seen{0};
|
|
|
|
for (std::size_t j{0}; seen < n; ++j) {
|
|
|
|
Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
|
|
|
|
if (flags.test(flag)) {
|
|
|
|
if (seen++ > 0) {
|
|
|
|
o << ", ";
|
|
|
|
}
|
|
|
|
o << flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const Symbol &symbol) {
|
|
|
|
os << symbol.name();
|
|
|
|
if (!symbol.attrs().empty()) {
|
|
|
|
os << ", " << symbol.attrs();
|
|
|
|
}
|
2018-06-05 12:18:35 -07:00
|
|
|
if (!symbol.flags().empty()) {
|
|
|
|
os << " (" << symbol.flags() << ')';
|
|
|
|
}
|
2018-05-03 15:57:56 -07:00
|
|
|
os << ": " << symbol.details_;
|
2018-03-22 17:08:20 -07:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-26 15:01:42 -07:00
|
|
|
// Output a unique name for a scope by qualifying it with the names of
|
2018-08-27 11:48:49 -07:00
|
|
|
// parent scopes. For scopes without corresponding symbols, use the kind
|
|
|
|
// with an index (e.g. Block1, Block2, etc.).
|
2018-06-26 15:01:42 -07:00
|
|
|
static void DumpUniqueName(std::ostream &os, const Scope &scope) {
|
2018-08-22 16:05:06 -07:00
|
|
|
if (scope.kind() != Scope::Kind::Global) {
|
2018-06-26 15:01:42 -07:00
|
|
|
DumpUniqueName(os, scope.parent());
|
|
|
|
os << '/';
|
2019-05-06 07:26:43 -07:00
|
|
|
if (auto *scopeSymbol{scope.symbol()};
|
|
|
|
scopeSymbol && !scopeSymbol->name().empty()) {
|
2019-01-04 17:10:31 -08:00
|
|
|
os << scopeSymbol->name();
|
2018-06-26 15:01:42 -07:00
|
|
|
} else {
|
2018-08-27 11:48:49 -07:00
|
|
|
int index{1};
|
|
|
|
for (auto &child : scope.parent().children()) {
|
|
|
|
if (child == scope) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (child.kind() == scope.kind()) {
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
os << Scope::EnumToString(scope.kind()) << index;
|
2018-06-26 15:01:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dump a symbol for UnparseWithSymbols. This will be used for tests so the
|
|
|
|
// format should be reasonably stable.
|
|
|
|
std::ostream &DumpForUnparse(
|
|
|
|
std::ostream &os, const Symbol &symbol, bool isDef) {
|
|
|
|
DumpUniqueName(os, symbol.owner());
|
2019-01-04 17:10:31 -08:00
|
|
|
os << '/' << symbol.name();
|
2018-06-26 15:01:42 -07:00
|
|
|
if (isDef) {
|
|
|
|
if (!symbol.attrs().empty()) {
|
|
|
|
os << ' ' << symbol.attrs();
|
|
|
|
}
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpBool(os, "(implicit)", symbol.test(Symbol::Flag::Implicit));
|
|
|
|
DumpBool(os, "(local)", symbol.test(Symbol::Flag::LocalityLocal));
|
|
|
|
DumpBool(os, "(local_init)", symbol.test(Symbol::Flag::LocalityLocalInit));
|
|
|
|
DumpBool(os, "(shared)", symbol.test(Symbol::Flag::LocalityShared));
|
2018-06-26 15:01:42 -07:00
|
|
|
os << ' ' << symbol.GetDetailsName();
|
2019-04-04 14:46:40 -07:00
|
|
|
DumpType(os, symbol.GetType());
|
2018-06-26 15:01:42 -07:00
|
|
|
}
|
|
|
|
return os;
|
|
|
|
}
|
2019-01-07 15:05:53 -08:00
|
|
|
|
2018-12-04 10:55:32 -08:00
|
|
|
Symbol &Symbol::Instantiate(
|
2019-01-31 09:58:40 -08:00
|
|
|
Scope &scope, SemanticsContext &semanticsContext) const {
|
|
|
|
evaluate::FoldingContext foldingContext{semanticsContext.foldingContext()};
|
2019-01-31 16:04:17 -08:00
|
|
|
CHECK(foldingContext.pdtInstance() != nullptr);
|
|
|
|
const DerivedTypeSpec &instanceSpec{*foldingContext.pdtInstance()};
|
2019-01-07 15:05:53 -08:00
|
|
|
auto pair{scope.try_emplace(name_, attrs_)};
|
|
|
|
Symbol &symbol{*pair.first->second};
|
|
|
|
if (!pair.second) {
|
|
|
|
// Symbol was already present in the scope, which can only happen
|
2019-05-13 09:33:18 -07:00
|
|
|
// in the case of type parameters.
|
2019-01-31 11:44:13 -08:00
|
|
|
CHECK(has<TypeParamDetails>());
|
2019-01-07 15:05:53 -08:00
|
|
|
return symbol;
|
|
|
|
}
|
|
|
|
symbol.attrs_ = attrs_;
|
|
|
|
symbol.flags_ = flags_;
|
|
|
|
std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](const ObjectEntityDetails &that) {
|
|
|
|
symbol.details_ = that;
|
|
|
|
ObjectEntityDetails &details{symbol.get<ObjectEntityDetails>()};
|
2018-12-04 10:55:32 -08:00
|
|
|
if (DeclTypeSpec * origType{symbol.GetType()}) {
|
|
|
|
if (const DerivedTypeSpec * derived{origType->AsDerived()}) {
|
|
|
|
DerivedTypeSpec newSpec{*derived};
|
|
|
|
if (test(Flag::ParentComp)) {
|
2019-05-13 09:33:18 -07:00
|
|
|
// Forward any explicit type parameter values from the
|
|
|
|
// derived type spec under instantiation to its parent
|
|
|
|
// component derived type spec that define type parameters
|
|
|
|
// of the parent component.
|
2018-12-04 10:55:32 -08:00
|
|
|
for (const auto &pair : instanceSpec.parameters()) {
|
|
|
|
if (scope.find(pair.first) == scope.end()) {
|
|
|
|
newSpec.AddParamValue(
|
|
|
|
pair.first, ParamValue{pair.second});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-31 09:58:40 -08:00
|
|
|
details.ReplaceType(
|
|
|
|
scope.FindOrInstantiateDerivedType(std::move(newSpec),
|
2019-04-02 10:34:45 -07:00
|
|
|
semanticsContext, origType->category()));
|
2018-12-04 10:55:32 -08:00
|
|
|
} else if (origType->AsIntrinsic() != nullptr) {
|
2019-01-31 09:58:40 -08:00
|
|
|
const DeclTypeSpec &newType{scope.InstantiateIntrinsicType(
|
|
|
|
*origType, semanticsContext)};
|
2018-12-04 10:55:32 -08:00
|
|
|
details.ReplaceType(newType);
|
2019-06-03 12:18:52 -07:00
|
|
|
} else if (origType->category() != DeclTypeSpec::ClassStar) {
|
2018-12-04 10:55:32 -08:00
|
|
|
common::die("instantiated component has type that is "
|
2019-06-03 12:18:52 -07:00
|
|
|
"neither intrinsic, derived, nor CLASS(*)");
|
2018-12-04 10:55:32 -08:00
|
|
|
}
|
|
|
|
}
|
2019-01-07 15:05:53 -08:00
|
|
|
details.set_init(
|
|
|
|
evaluate::Fold(foldingContext, std::move(details.init())));
|
|
|
|
for (ShapeSpec &dim : details.shape()) {
|
|
|
|
if (dim.lbound().isExplicit()) {
|
|
|
|
dim.lbound().SetExplicit(Fold(
|
|
|
|
foldingContext, std::move(dim.lbound().GetExplicit())));
|
|
|
|
}
|
|
|
|
if (dim.ubound().isExplicit()) {
|
|
|
|
dim.ubound().SetExplicit(Fold(
|
|
|
|
foldingContext, std::move(dim.ubound().GetExplicit())));
|
|
|
|
}
|
|
|
|
}
|
2019-04-04 14:46:40 -07:00
|
|
|
for (ShapeSpec &dim : details.coshape()) {
|
|
|
|
if (dim.lbound().isExplicit()) {
|
|
|
|
dim.lbound().SetExplicit(Fold(
|
|
|
|
foldingContext, std::move(dim.lbound().GetExplicit())));
|
|
|
|
}
|
|
|
|
if (dim.ubound().isExplicit()) {
|
|
|
|
dim.ubound().SetExplicit(Fold(
|
|
|
|
foldingContext, std::move(dim.ubound().GetExplicit())));
|
|
|
|
}
|
|
|
|
}
|
2019-01-07 15:05:53 -08:00
|
|
|
},
|
2019-01-31 11:44:13 -08:00
|
|
|
[&](const ProcBindingDetails &that) { symbol.details_ = that; },
|
|
|
|
[&](const GenericBindingDetails &that) { symbol.details_ = that; },
|
2019-02-21 12:10:07 -08:00
|
|
|
[&](const ProcEntityDetails &that) { symbol.details_ = that; },
|
2019-06-03 12:28:20 -07:00
|
|
|
[&](const FinalProcDetails &that) { symbol.details_ = that; },
|
2019-01-07 15:05:53 -08:00
|
|
|
[&](const TypeParamDetails &that) {
|
2018-12-04 10:55:32 -08:00
|
|
|
// LEN type parameter, or error recovery on a KIND type parameter
|
|
|
|
// with no corresponding actual argument or default
|
2019-01-07 15:05:53 -08:00
|
|
|
symbol.details_ = that;
|
|
|
|
},
|
2018-12-04 10:55:32 -08:00
|
|
|
[&](const auto &that) {
|
|
|
|
common::die("unexpected details in Symbol::Instantiate");
|
2019-01-07 15:05:53 -08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
details_);
|
|
|
|
return symbol;
|
|
|
|
}
|
|
|
|
|
2018-12-04 10:55:32 -08:00
|
|
|
const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
|
|
|
|
if (const Symbol * parentComponent{GetParentComponent(scope)}) {
|
|
|
|
const auto &object{parentComponent->get<ObjectEntityDetails>()};
|
2019-02-18 13:47:34 -08:00
|
|
|
return &object.type()->derivedTypeSpec();
|
2018-12-04 10:55:32 -08:00
|
|
|
} else {
|
|
|
|
return nullptr;
|
2019-01-07 15:05:53 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-11 15:39:11 -07:00
|
|
|
const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
|
|
|
|
if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
|
|
|
|
if (scope == nullptr) {
|
|
|
|
CHECK(scope_ != nullptr);
|
|
|
|
scope = scope_;
|
|
|
|
}
|
|
|
|
return dtDetails->GetParentComponent(*scope);
|
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-05 10:48:26 -08:00
|
|
|
void DerivedTypeDetails::add_component(const Symbol &symbol) {
|
|
|
|
if (symbol.test(Symbol::Flag::ParentComp)) {
|
2019-02-18 13:47:34 -08:00
|
|
|
CHECK(componentNames_.empty());
|
2019-02-05 10:48:26 -08:00
|
|
|
}
|
2019-02-18 13:47:34 -08:00
|
|
|
componentNames_.push_back(symbol.name());
|
2019-02-05 10:48:26 -08:00
|
|
|
}
|
|
|
|
|
2019-01-07 15:05:53 -08:00
|
|
|
std::list<SourceName> DerivedTypeDetails::OrderParameterNames(
|
|
|
|
const Symbol &type) const {
|
|
|
|
std::list<SourceName> result;
|
2018-12-04 10:55:32 -08:00
|
|
|
if (const DerivedTypeSpec * spec{type.GetParentTypeSpec()}) {
|
|
|
|
const DerivedTypeDetails &details{
|
|
|
|
spec->typeSymbol().get<DerivedTypeDetails>()};
|
|
|
|
result = details.OrderParameterNames(spec->typeSymbol());
|
2019-01-07 15:05:53 -08:00
|
|
|
}
|
|
|
|
for (const auto &name : paramNames_) {
|
|
|
|
result.push_back(name);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-02-05 10:48:26 -08:00
|
|
|
SymbolList DerivedTypeDetails::OrderParameterDeclarations(
|
2019-01-07 15:05:53 -08:00
|
|
|
const Symbol &type) const {
|
2019-02-05 10:48:26 -08:00
|
|
|
SymbolList result;
|
2018-12-04 10:55:32 -08:00
|
|
|
if (const DerivedTypeSpec * spec{type.GetParentTypeSpec()}) {
|
|
|
|
const DerivedTypeDetails &details{
|
|
|
|
spec->typeSymbol().get<DerivedTypeDetails>()};
|
|
|
|
result = details.OrderParameterDeclarations(spec->typeSymbol());
|
2019-01-07 15:05:53 -08:00
|
|
|
}
|
2019-02-04 12:24:25 -08:00
|
|
|
for (const Symbol *symbol : paramDecls_) {
|
2019-01-07 15:05:53 -08:00
|
|
|
result.push_back(symbol);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-02-05 10:48:26 -08:00
|
|
|
SymbolList DerivedTypeDetails::OrderComponents(const Scope &scope) const {
|
|
|
|
SymbolList result;
|
2019-02-18 13:47:34 -08:00
|
|
|
for (SourceName name : componentNames_) {
|
2019-02-05 10:48:26 -08:00
|
|
|
auto iter{scope.find(name)};
|
|
|
|
if (iter != scope.cend()) {
|
|
|
|
const Symbol &symbol{*iter->second};
|
|
|
|
if (symbol.test(Symbol::Flag::ParentComp)) {
|
2019-03-11 15:39:11 -07:00
|
|
|
CHECK(result.empty()); // parent component must appear first
|
2019-02-12 17:24:43 -08:00
|
|
|
const DerivedTypeSpec &spec{
|
2019-02-18 13:47:34 -08:00
|
|
|
symbol.get<ObjectEntityDetails>().type()->derivedTypeSpec()};
|
2019-02-12 17:24:43 -08:00
|
|
|
result = spec.typeSymbol().get<DerivedTypeDetails>().OrderComponents(
|
|
|
|
*spec.scope());
|
2019-02-05 10:48:26 -08:00
|
|
|
}
|
|
|
|
result.push_back(&symbol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
|
2019-03-11 15:39:11 -07:00
|
|
|
if (auto extends{GetParentComponentName()}) {
|
|
|
|
if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
|
|
|
|
if (const Symbol & symbol{*iter->second};
|
|
|
|
symbol.test(Symbol::Flag::ParentComp)) {
|
2019-02-05 10:48:26 -08:00
|
|
|
return &symbol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-01-07 15:05:53 -08:00
|
|
|
void TypeParamDetails::set_type(const DeclTypeSpec &type) {
|
|
|
|
CHECK(type_ == nullptr);
|
|
|
|
type_ = &type;
|
|
|
|
}
|
2019-04-04 14:46:40 -07:00
|
|
|
|
2018-10-25 05:55:23 -07:00
|
|
|
}
|