[flang] Refactor GenericKind
authorTim Keith <tkeith@nvidia.com>
Fri, 22 Nov 2019 20:40:37 +0000 (12:40 -0800)
committerTim Keith <tkeith@nvidia.com>
Tue, 26 Nov 2019 19:18:47 +0000 (11:18 -0800)
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@c74327c393649ff95355f00333ffd2352b148f72
Reviewed-on: https://github.com/flang-compiler/f18/pull/841
Tree-same-pre-rewrite: false

flang/lib/semantics/mod-file.cc
flang/lib/semantics/resolve-names-utils.cc
flang/lib/semantics/resolve-names.cc
flang/lib/semantics/symbol.cc
flang/lib/semantics/symbol.h
flang/lib/semantics/tools.cc

index d50d1ba..115f06a 100644 (file)
@@ -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;
   }
index f63f509..58dfe98 100644 (file)
@@ -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;
   }
 }
 
index b337edc..1911274 100644 (file)
@@ -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);
index 1e29e38..b4d5d0c 100644 (file)
@@ -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;
+}
+
 }
index c02e9df..3c908b1 100644 (file)
@@ -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
index bc62f25..04ab228 100644 (file)
@@ -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) {