return false;
}
}
-template<typename A> bool IsVariable(const Expr<A> &expr) {
+template<typename T> bool IsVariable(const Expr<T> &expr) {
return std::visit([](const auto &x) { return IsVariable(x); }, expr.u);
}
+template<typename A> bool IsVariable(const std::optional<A> &x) {
+ if (x.has_value()) {
+ return IsVariable(*x);
+ } else {
+ return false;
+ }
+}
// Predicate: true when an expression is assumed-rank
bool IsAssumedRank(const semantics::Symbol &);
return false;
}
}
-template<typename A> bool IsAssumedRank(const Expr<A> &expr) {
+template<typename T> bool IsAssumedRank(const Expr<T> &expr) {
return std::visit([](const auto &x) { return IsAssumedRank(x); }, expr.u);
}
+template<typename A> bool IsAssumedRank(const std::optional<A> &x) {
+ if (x.has_value()) {
+ return IsAssumedRank(*x);
+ } else {
+ return false;
+ }
+}
// Generalizing packagers: these take operations and expressions of more
// specific types and wrap them in Expr<> containers of more abstract types.
// Specializing extractor. If an Expr wraps some type of object, perhaps
// in several layers, return a pointer to it; otherwise null. Also works
-// with ActualArgument.
+// with expressions contained in ActualArgument.
template<typename A, typename B>
auto UnwrapExpr(B &x) -> common::Constify<A, B> * {
using Ty = std::decay_t<B>;
common::IfNoLvalue<std::optional<DataRef>, A> ExtractDataRef(const A &) {
return std::nullopt; // default base casec
}
-
template<typename T>
std::optional<DataRef> ExtractDataRef(const Designator<T> &d) {
return std::visit(
},
d.u);
}
-
template<typename T>
std::optional<DataRef> ExtractDataRef(const Expr<T> &expr) {
return std::visit([](const auto &x) { return ExtractDataRef(x); }, expr.u);
}
-
template<typename A>
std::optional<DataRef> ExtractDataRef(const std::optional<A> &x) {
if (x.has_value()) {
// If an expression is simply a whole symbol data designator,
// extract and return that symbol, else null.
-template<typename A> const Symbol *IsWholeSymbolDataRef(const A &x) {
+template<typename A> const Symbol *UnwrapWholeSymbolDataRef(const A &x) {
if (auto dataRef{ExtractDataRef(x)}) {
if (const Symbol **p{std::get_if<const Symbol *>(&dataRef->u)}) {
return *p;
VALUE value;
};
+// GetLastSymbol() returns the rightmost symbol in an object or procedure
+// designator (possibly wrapped in an Expr<>), or a null pointer if
+// none is found.
template<typename A> const semantics::Symbol *GetLastSymbol(const A &) {
return nullptr;
}
-
template<typename T>
const semantics::Symbol *GetLastSymbol(const Designator<T> &x) {
return x.GetLastSymbol();
}
-
inline const semantics::Symbol *GetLastSymbol(const ProcedureDesignator &x) {
return x.GetSymbol();
}
-
inline const semantics::Symbol *GetLastSymbol(const ProcedureRef &x) {
return GetLastSymbol(x.proc());
}
-
template<typename T> const semantics::Symbol *GetLastSymbol(const Expr<T> &x) {
return std::visit([](const auto &y) { return GetLastSymbol(y); }, x.u);
}
+template<typename A>
+const semantics::Symbol *GetLastSymbol(const std::optional<A> &x) {
+ if (x.has_value()) {
+ return GetLastSymbol(*x);
+ } else {
+ return nullptr;
+ }
+}
+// Convenience: If GetLastSymbol() succeeds on the argument, return its
+// set of attributes, otherwise the empty set.
template<typename A> semantics::Attrs GetAttrs(const A &x) {
if (const semantics::Symbol * symbol{GetLastSymbol(x)}) {
return symbol->attrs();
}
}
+// Predicate: IsAllocatableOrPointer()
template<typename A> bool IsAllocatableOrPointer(const A &x) {
return GetAttrs(x).HasAny(
semantics::Attrs{semantics::Attr::POINTER, semantics::Attr::ALLOCATABLE});
}
+// Predicate: IsProcedurePointer()
template<typename A> bool IsProcedurePointer(const A &) { return false; }
inline bool IsProcedurePointer(const ProcedureDesignator &) { return true; }
inline bool IsProcedurePointer(const ProcedureRef &) { return true; }
return std::visit(
[](const auto &x) { return IsProcedurePointer(x); }, expr.u);
}
+template<typename A> bool IsProcedurePointer(const std::optional<A> &x) {
+ if (x.has_value()) {
+ return IsProcedurePointer(*x);
+ } else {
+ return false;
+ }
+}
}
#endif // FORTRAN_EVALUATE_TOOLS_H_
// expr is set in either case unless there were errors
struct Selector {
Selector() {}
- Selector(const parser::CharBlock &source, MaybeExpr &&expr,
- const parser::Name *variable = nullptr)
- : source{source}, expr{std::move(expr)}, variable{variable} {}
+ Selector(const parser::CharBlock &source, MaybeExpr &&expr)
+ : source{source}, expr{std::move(expr)} {}
operator bool() const { return expr.has_value(); }
parser::CharBlock source;
MaybeExpr expr;
- const parser::Name *variable{nullptr};
};
// association -> [associate-name =>] selector
struct {
if (auto *symbol{FindInScope(currScope(), name)}) {
const auto &selector{std::get<parser::Selector>(x.t)};
if (auto sel{ResolveSelector(selector)}) {
- if (!sel.variable || sel.variable->symbol->Corank() == 0) {
+ const Symbol *whole{UnwrapWholeSymbolDataRef(sel.expr)};
+ if (!whole || whole->Corank() == 0) {
Say(sel.source, // C1116
"Selector in coarray association must name a coarray"_err_en_US);
} else if (auto dynType{sel.expr->GetType()}) {
MakePlaceholder(*name, MiscDetails::Kind::SelectTypeAssociateName);
association_.name = &*name;
} else {
- const auto *varName{association_.selector.variable};
- if (!varName || !varName->symbol->has<ObjectEntityDetails>()) {
+ const Symbol *whole{UnwrapWholeSymbolDataRef(association_.selector.expr)};
+ if (!whole || !whole->has<ObjectEntityDetails>()) {
Say(association_.selector.source, // C1157
"Selector is not a named variable: 'associate-name =>' is required"_err_en_US);
association_ = {};
return nullptr;
}
if (auto &expr{association_.selector.expr}) {
- symbol.set_details(AssocEntityDetails{std::move(*expr)});
- association_.selector.expr.reset();
+ symbol.set_details(AssocEntityDetails{common::Clone(*expr)});
} else {
symbol.set_details(AssocEntityDetails{});
}
return &symbol;
}
-// Set the type of symbol based on the current association variable or expr.
+// Set the type of symbol based on the current association selector.
void ConstructVisitor::SetTypeFromAssociation(Symbol &symbol) {
- if (association_.selector.variable) {
- const Symbol *varSymbol{association_.selector.variable->symbol};
- CHECK(varSymbol);
- if (const DeclTypeSpec * type{varSymbol->GetType()}) {
- symbol.SetType(*type);
- }
- } else {
- auto &details{symbol.get<AssocEntityDetails>()};
- if (const MaybeExpr & expr{details.expr()}) {
- if (std::optional<evaluate::DynamicType> type{expr->GetType()}) {
- if (const auto *charExpr{
- evaluate::UnwrapExpr<evaluate::Expr<evaluate::SomeCharacter>>(
- *expr)}) {
- symbol.SetType(ToDeclTypeSpec(std::move(*type),
- FoldExpr(std::visit(
- [](const auto &kindChar) { return kindChar.LEN(); },
- charExpr->u))));
- } else {
- symbol.SetType(ToDeclTypeSpec(std::move(*type)));
+ auto &details{symbol.get<AssocEntityDetails>()};
+ const MaybeExpr *pexpr{&details.expr()};
+ if (!pexpr->has_value()) {
+ pexpr = &association_.selector.expr;
+ }
+ if (pexpr->has_value()) {
+ const SomeExpr &expr{**pexpr};
+ if (evaluate::IsVariable(expr)) {
+ if (const Symbol * varSymbol{evaluate::GetLastSymbol(expr)}) {
+ if (const DeclTypeSpec * type{varSymbol->GetType()}) {
+ symbol.SetType(*type);
+ return;
}
+ }
+ }
+ if (std::optional<evaluate::DynamicType> type{expr.GetType()}) {
+ if (const auto *charExpr{
+ evaluate::UnwrapExpr<evaluate::Expr<evaluate::SomeCharacter>>(
+ expr)}) {
+ symbol.SetType(ToDeclTypeSpec(std::move(*type),
+ FoldExpr(
+ std::visit([](const auto &kindChar) { return kindChar.LEN(); },
+ charExpr->u))));
} else {
- // BOZ literal not acceptable
- Say(symbol.name(), "Associate name '%s' must have a type"_err_en_US);
+ symbol.SetType(ToDeclTypeSpec(std::move(*type)));
}
+ } else {
+ // BOZ literals, procedure designators, &c. are not acceptable
+ Say(symbol.name(), "Associate name '%s' must have a type"_err_en_US);
}
}
}
// If current selector is a variable, set some of its attributes on symbol.
void ConstructVisitor::SetAttrsFromAssociation(Symbol &symbol) {
- if (association_.selector.variable) {
- if (const auto *varSymbol{association_.selector.variable->symbol}) {
- symbol.attrs() |= varSymbol->attrs() &
- Attrs{Attr::TARGET, Attr::ASYNCHRONOUS, Attr::VOLATILE,
- Attr::CONTIGUOUS};
- if (varSymbol->attrs().test(Attr::POINTER)) {
- symbol.attrs().set(Attr::TARGET);
- }
- }
+ Attrs attrs{evaluate::GetAttrs(association_.selector.expr)};
+ symbol.attrs() |= attrs &
+ Attrs{Attr::TARGET, Attr::ASYNCHRONOUS, Attr::VOLATILE, Attr::CONTIGUOUS};
+ if (attrs.test(Attr::POINTER)) {
+ symbol.attrs().set(Attr::TARGET);
}
}
const parser::Selector &x) {
return std::visit(
common::visitors{
- [&](const parser::Expr &y) {
- return Selector{y.source, EvaluateExpr(y)};
+ [&](const parser::Expr &expr) {
+ return Selector{expr.source, EvaluateExpr(expr)};
},
- [&](const parser::Variable &y) {
- if (const auto *variable{ResolveVariable(y)}) {
- return Selector{variable->source, EvaluateExpr(y), variable};
- } else {
- return Selector{};
- }
+ [&](const parser::Variable &var) {
+ return Selector{var.GetSource(), EvaluateExpr(var)};
},
},
x.u);
case common::TypeCategory::Logical:
return context().MakeLogicalType(type.kind());
case common::TypeCategory::Derived:
- return currScope().MakeDerivedType(
- DeclTypeSpec::TypeDerived, DerivedTypeSpec{type.GetDerivedTypeSpec()});
+ return currScope().MakeDerivedType(type.isPolymorphic()
+ ? DeclTypeSpec::ClassDerived
+ : DeclTypeSpec::TypeDerived,
+ DerivedTypeSpec{type.GetDerivedTypeSpec()});
case common::TypeCategory::Character:
default: CRASH_NO_CASE;
}