forked from OSchip/llvm-project
[flang] Refactor GenericKind
Change GenericKind from an enum class to a variant that includes the `NumericOperator`, `LogicalOperator`, and `RelationalOperator` from `common`. This allows for better tests like `IsIntrinsicOperator` (which used to check for being in a range of the `GenericKind` enumeration) and simplifies mapping the kind to a string representation. Original-commit: flang-compiler/f18@c74327c393 Reviewed-on: https://github.com/flang-compiler/f18/pull/841 Tree-same-pre-rewrite: false
This commit is contained in:
parent
4d7b6cf3c1
commit
701a9bd0e5
|
@ -358,8 +358,7 @@ void ModFileWriter::PutSubprogram(const Symbol &symbol) {
|
|||
|
||||
static bool IsIntrinsicOp(const Symbol &symbol) {
|
||||
if (const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()}) {
|
||||
GenericKind kind{details->kind()};
|
||||
return kind >= GenericKind::OpPower && kind <= GenericKind::OpNEQV;
|
||||
return details->kind().IsIntrinsicOperator();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace Fortran::semantics {
|
|||
|
||||
using common::LanguageFeature;
|
||||
using common::LogicalOperator;
|
||||
using common::NumericOperator;
|
||||
using common::RelationalOperator;
|
||||
using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator;
|
||||
|
||||
|
@ -96,20 +97,13 @@ std::forward_list<std::string> GenericSpecInfo::GetAllNames(
|
|||
}
|
||||
return result;
|
||||
}};
|
||||
switch (kind_) {
|
||||
case GenericKind::OpGE: return getNames(RelationalOperator::GE);
|
||||
case GenericKind::OpGT: return getNames(RelationalOperator::GT);
|
||||
case GenericKind::OpLE: return getNames(RelationalOperator::LE);
|
||||
case GenericKind::OpLT: return getNames(RelationalOperator::LT);
|
||||
case GenericKind::OpEQ: return getNames(RelationalOperator::EQ);
|
||||
case GenericKind::OpNE: return getNames(RelationalOperator::NE);
|
||||
case GenericKind::OpAND: return getNames(LogicalOperator::And);
|
||||
case GenericKind::OpOR: return getNames(LogicalOperator::Or);
|
||||
case GenericKind::OpEQV: return getNames(LogicalOperator::Eqv);
|
||||
case GenericKind::OpNEQV: return getNames(LogicalOperator::Neqv);
|
||||
case GenericKind::OpNOT: return getNames(LogicalOperator::Not);
|
||||
default: return {symbolName_.value().ToString()};
|
||||
}
|
||||
return std::visit(
|
||||
common::visitors{[&](const LogicalOperator &x) { return getNames(x); },
|
||||
[&](const RelationalOperator &x) { return getNames(x); },
|
||||
[&](const auto &) -> std::forward_list<std::string> {
|
||||
return {symbolName_.value().ToString()};
|
||||
}},
|
||||
kind_.u);
|
||||
}
|
||||
|
||||
Symbol *GenericSpecInfo::FindInScope(
|
||||
|
@ -136,7 +130,7 @@ void GenericSpecInfo::Resolve(Symbol *symbol) const {
|
|||
}
|
||||
|
||||
void GenericSpecInfo::Analyze(const parser::DefinedOpName &name) {
|
||||
kind_ = GenericKind::DefinedOp;
|
||||
kind_ = GenericKind::OtherKind::DefinedOp;
|
||||
parseName_ = &name.v;
|
||||
symbolName_ = name.v.source;
|
||||
}
|
||||
|
@ -145,17 +139,17 @@ void GenericSpecInfo::Analyze(const parser::GenericSpec &x) {
|
|||
symbolName_ = x.source;
|
||||
kind_ = std::visit(
|
||||
common::visitors{
|
||||
[&](const parser::Name &y) {
|
||||
[&](const parser::Name &y) -> GenericKind {
|
||||
parseName_ = &y;
|
||||
symbolName_ = y.source;
|
||||
return GenericKind::Name;
|
||||
return GenericKind::OtherKind::Name;
|
||||
},
|
||||
[&](const parser::DefinedOperator &y) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](const parser::DefinedOpName &z) {
|
||||
[&](const parser::DefinedOpName &z) -> GenericKind {
|
||||
Analyze(z);
|
||||
return GenericKind::DefinedOp;
|
||||
return GenericKind::OtherKind::DefinedOp;
|
||||
},
|
||||
[&](const IntrinsicOperator &z) {
|
||||
return MapIntrinsicOperator(z);
|
||||
|
@ -163,20 +157,20 @@ void GenericSpecInfo::Analyze(const parser::GenericSpec &x) {
|
|||
},
|
||||
y.u);
|
||||
},
|
||||
[&](const parser::GenericSpec::Assignment &) {
|
||||
return GenericKind::Assignment;
|
||||
[&](const parser::GenericSpec::Assignment &) -> GenericKind {
|
||||
return GenericKind::OtherKind::Assignment;
|
||||
},
|
||||
[&](const parser::GenericSpec::ReadFormatted &) {
|
||||
return GenericKind::ReadFormatted;
|
||||
[&](const parser::GenericSpec::ReadFormatted &) -> GenericKind {
|
||||
return GenericKind::DefinedIo::ReadFormatted;
|
||||
},
|
||||
[&](const parser::GenericSpec::ReadUnformatted &) {
|
||||
return GenericKind::ReadUnformatted;
|
||||
[&](const parser::GenericSpec::ReadUnformatted &) -> GenericKind {
|
||||
return GenericKind::DefinedIo::ReadUnformatted;
|
||||
},
|
||||
[&](const parser::GenericSpec::WriteFormatted &) {
|
||||
return GenericKind::WriteFormatted;
|
||||
[&](const parser::GenericSpec::WriteFormatted &) -> GenericKind {
|
||||
return GenericKind::DefinedIo::WriteFormatted;
|
||||
},
|
||||
[&](const parser::GenericSpec::WriteUnformatted &) {
|
||||
return GenericKind::WriteUnformatted;
|
||||
[&](const parser::GenericSpec::WriteUnformatted &) -> GenericKind {
|
||||
return GenericKind::DefinedIo::WriteUnformatted;
|
||||
},
|
||||
},
|
||||
x.u);
|
||||
|
@ -186,23 +180,23 @@ void GenericSpecInfo::Analyze(const parser::GenericSpec &x) {
|
|||
static GenericKind MapIntrinsicOperator(IntrinsicOperator op) {
|
||||
switch (op) {
|
||||
SWITCH_COVERS_ALL_CASES
|
||||
case IntrinsicOperator::Power: return GenericKind::OpPower;
|
||||
case IntrinsicOperator::Multiply: return GenericKind::OpMultiply;
|
||||
case IntrinsicOperator::Divide: return GenericKind::OpDivide;
|
||||
case IntrinsicOperator::Add: return GenericKind::OpAdd;
|
||||
case IntrinsicOperator::Subtract: return GenericKind::OpSubtract;
|
||||
case IntrinsicOperator::Concat: return GenericKind::OpConcat;
|
||||
case IntrinsicOperator::LT: return GenericKind::OpLT;
|
||||
case IntrinsicOperator::LE: return GenericKind::OpLE;
|
||||
case IntrinsicOperator::EQ: return GenericKind::OpEQ;
|
||||
case IntrinsicOperator::NE: return GenericKind::OpNE;
|
||||
case IntrinsicOperator::GE: return GenericKind::OpGE;
|
||||
case IntrinsicOperator::GT: return GenericKind::OpGT;
|
||||
case IntrinsicOperator::NOT: return GenericKind::OpNOT;
|
||||
case IntrinsicOperator::AND: return GenericKind::OpAND;
|
||||
case IntrinsicOperator::OR: return GenericKind::OpOR;
|
||||
case IntrinsicOperator::EQV: return GenericKind::OpEQV;
|
||||
case IntrinsicOperator::NEQV: return GenericKind::OpNEQV;
|
||||
case IntrinsicOperator::Concat: return GenericKind::OtherKind::Concat;
|
||||
case IntrinsicOperator::Power: return NumericOperator::Power;
|
||||
case IntrinsicOperator::Multiply: return NumericOperator::Multiply;
|
||||
case IntrinsicOperator::Divide: return NumericOperator::Divide;
|
||||
case IntrinsicOperator::Add: return NumericOperator::Add;
|
||||
case IntrinsicOperator::Subtract: return NumericOperator::Subtract;
|
||||
case IntrinsicOperator::AND: return LogicalOperator::And;
|
||||
case IntrinsicOperator::OR: return LogicalOperator::Or;
|
||||
case IntrinsicOperator::EQV: return LogicalOperator::Eqv;
|
||||
case IntrinsicOperator::NEQV: return LogicalOperator::Neqv;
|
||||
case IntrinsicOperator::NOT: return LogicalOperator::Not;
|
||||
case IntrinsicOperator::LT: return RelationalOperator::LT;
|
||||
case IntrinsicOperator::LE: return RelationalOperator::LE;
|
||||
case IntrinsicOperator::EQ: return RelationalOperator::EQ;
|
||||
case IntrinsicOperator::NE: return RelationalOperator::NE;
|
||||
case IntrinsicOperator::GE: return RelationalOperator::GE;
|
||||
case IntrinsicOperator::GT: return RelationalOperator::GT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2482,7 +2482,7 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
|
|||
}
|
||||
if (!namesSeen.insert(name->source).second) {
|
||||
Say(*name,
|
||||
IsDefinedOperator(generic.name())
|
||||
details.kind().IsDefinedOperator()
|
||||
? "Procedure '%s' is already specified in generic operator '%s'"_err_en_US
|
||||
: "Procedure '%s' is already specified in generic '%s'"_err_en_US,
|
||||
name->source, generic.name());
|
||||
|
@ -2567,12 +2567,6 @@ static GenericKind GetGenericKind(const Symbol &generic) {
|
|||
generic.details());
|
||||
}
|
||||
|
||||
static bool IsOperatorOrAssignment(const Symbol &generic) {
|
||||
auto kind{GetGenericKind(generic)};
|
||||
return kind == GenericKind::DefinedOp || kind == GenericKind::Assignment ||
|
||||
(kind >= GenericKind::OpPower && kind <= GenericKind::OpNEQV);
|
||||
}
|
||||
|
||||
// Check that the specifics of this generic are distinguishable from each other
|
||||
void InterfaceVisitor::CheckSpecificsAreDistinguishable(
|
||||
Symbol &generic, const SymbolVector &specifics) {
|
||||
|
@ -2580,7 +2574,8 @@ void InterfaceVisitor::CheckSpecificsAreDistinguishable(
|
|||
if (specifics.size() < 2) {
|
||||
return;
|
||||
}
|
||||
auto distinguishable{IsOperatorOrAssignment(generic)
|
||||
auto kind{GetGenericKind(generic)};
|
||||
auto distinguishable{kind.IsAssignment() || kind.IsOperator()
|
||||
? evaluate::characteristics::DistinguishableOpOrAssign
|
||||
: evaluate::characteristics::Distinguishable};
|
||||
using evaluate::characteristics::Procedure;
|
||||
|
@ -5621,7 +5616,7 @@ bool ModuleVisitor::Pre(const parser::AccessStmt &x) {
|
|||
const auto &symbolName{info.symbolName()};
|
||||
if (auto *symbol{info.FindInScope(context(), currScope())}) {
|
||||
info.Resolve(&SetAccess(symbolName, accessAttr, symbol));
|
||||
} else if (info.kind() == GenericKind::Name) {
|
||||
} else if (info.kind().IsName()) {
|
||||
info.Resolve(&SetAccess(symbolName, accessAttr));
|
||||
} else {
|
||||
Say(symbolName, "Generic spec '%s' not found"_err_en_US);
|
||||
|
|
|
@ -427,7 +427,7 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
|
|||
},
|
||||
[](const HostAssocDetails &) {},
|
||||
[&](const GenericDetails &x) {
|
||||
os << ' ' << EnumToString(x.kind());
|
||||
os << ' ' << x.kind().ToString();
|
||||
DumpBool(os, "(specific)", x.specific() != nullptr);
|
||||
DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
|
||||
os << " procs:";
|
||||
|
@ -586,4 +586,28 @@ void TypeParamDetails::set_type(const DeclTypeSpec &type) {
|
|||
type_ = &type;
|
||||
}
|
||||
|
||||
bool GenericKind::IsIntrinsicOperator() const {
|
||||
return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
|
||||
Has<common::NumericOperator>() || Has<common::RelationalOperator>();
|
||||
}
|
||||
|
||||
bool GenericKind::IsOperator() const {
|
||||
return IsDefinedOperator() || IsIntrinsicOperator();
|
||||
}
|
||||
|
||||
std::string GenericKind::ToString() const {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](const OtherKind &x) { return EnumToString(x); },
|
||||
[](const DefinedIo &x) { return EnumToString(x); },
|
||||
[](const auto &x) { return common::EnumToString(x); },
|
||||
},
|
||||
u);
|
||||
}
|
||||
|
||||
bool GenericKind::Is(GenericKind::OtherKind x) const {
|
||||
const OtherKind *y{std::get_if<OtherKind>(&u)};
|
||||
return y && *y == x;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -270,12 +270,28 @@ private:
|
|||
SymbolRef symbol_; // procedure bound to; may be forward
|
||||
};
|
||||
|
||||
ENUM_CLASS(GenericKind, // Kinds of generic-spec
|
||||
Name, DefinedOp, // these have a Name associated with them
|
||||
Assignment, // user-defined assignment
|
||||
OpPower, OpMultiply, OpDivide, OpAdd, OpSubtract, OpConcat, OpLT, OpLE,
|
||||
OpEQ, OpNE, OpGE, OpGT, OpNOT, OpAND, OpOR, OpEQV, OpNEQV, //
|
||||
ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
|
||||
// A GenericKind is one of: generic name, defined operator,
|
||||
// defined assignment, intrinsic operator, or defined I/O.
|
||||
struct GenericKind {
|
||||
ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
|
||||
ENUM_CLASS(DefinedIo, // defined io
|
||||
ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
|
||||
GenericKind() : u{OtherKind::Name} {}
|
||||
template<typename T> GenericKind(const T &x) { u = x; }
|
||||
bool IsName() const { return Is(OtherKind::Name); }
|
||||
bool IsAssignment() const { return Is(OtherKind::Assignment); }
|
||||
bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
|
||||
bool IsIntrinsicOperator() const;
|
||||
bool IsOperator() const;
|
||||
std::string ToString() const;
|
||||
std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
|
||||
common::RelationalOperator, DefinedIo>
|
||||
u;
|
||||
|
||||
private:
|
||||
template<typename T> bool Has() const { return std::holds_alternative<T>(u); }
|
||||
bool Is(OtherKind) const;
|
||||
};
|
||||
|
||||
class GenericBindingDetails {
|
||||
public:
|
||||
|
@ -286,7 +302,7 @@ public:
|
|||
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
|
||||
|
||||
private:
|
||||
GenericKind kind_{GenericKind::Name};
|
||||
GenericKind kind_;
|
||||
SymbolVector specificProcs_;
|
||||
};
|
||||
|
||||
|
@ -416,7 +432,7 @@ public:
|
|||
void set_useDetails(const UseDetails &details) { useDetails_ = details; }
|
||||
|
||||
private:
|
||||
GenericKind kind_{GenericKind::Name};
|
||||
GenericKind kind_;
|
||||
// all of the specific procedures for this generic
|
||||
SymbolVector specificProcs_;
|
||||
// a specific procedure with the same name as this generic, if any
|
||||
|
|
|
@ -84,7 +84,7 @@ const Scope *FindPureProcedureContaining(const Scope &start) {
|
|||
|
||||
bool IsGenericDefinedOp(const Symbol &symbol) {
|
||||
const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()};
|
||||
return details && details->kind() == GenericKind::DefinedOp;
|
||||
return details && details->kind().IsDefinedOperator();
|
||||
}
|
||||
|
||||
bool IsCommonBlockContaining(const Symbol &block, const Symbol &object) {
|
||||
|
|
Loading…
Reference in New Issue