[flang] Remove GenericExpr, move operator overloads to tools.h
authorpeter klausler <pklausler@nvidia.com>
Mon, 20 Aug 2018 16:29:08 +0000 (09:29 -0700)
committerpeter klausler <pklausler@nvidia.com>
Wed, 12 Sep 2018 23:28:56 +0000 (16:28 -0700)
Original-commit: flang-compiler/f18@23e7a6c27c72c88f565bcd6e4cc02d46e082ec5a
Reviewed-on: https://github.com/flang-compiler/f18/pull/183
Tree-same-pre-rewrite: false

flang/lib/evaluate/expression.cc
flang/lib/evaluate/expression.h
flang/lib/evaluate/tools.cc
flang/lib/evaluate/tools.h
flang/lib/evaluate/variable.cc
flang/lib/semantics/expression.cc
flang/lib/semantics/expression.h
flang/test/evaluate/expression.cc

index 13186a59d9c104e74eceb5e9384b2cd494f7ad37..2e493ecc5eca14c122de9db0125769eac2e31607 100644 (file)
@@ -15,6 +15,7 @@
 #include "expression.h"
 #include "common.h"
 #include "int-power.h"
+#include "tools.h"
 #include "variable.h"
 #include "../common/idioms.h"
 #include "../parser/characters.h"
index 9d692a4c28f6d5e5f61a9957b172afbd4f343d2c..e00f5ff41ca8eeceb055a9ca394d341db92151a0 100644 (file)
@@ -42,6 +42,8 @@ using common::RelationalOperator;
 // wrap discriminated unions.
 template<typename A> class Expr;
 
+template<typename A> using ResultType = typename std::decay_t<A>::Result;
+
 template<typename DERIVED, typename RESULT, typename... OPERAND>
 class Operation {
 public:
@@ -597,92 +599,6 @@ public:
       u;
 };
 
-using GenericExpr = Expr<SomeType>;  // TODO: delete name?
-
-template<typename A> using ResultType = typename std::decay_t<A>::Result;
-
-// Convenience functions and operator overloadings for expression construction.
-
-template<TypeCategory C, int K>
-Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) {
-  return {Negate<Type<C, K>>{x}};
-}
-template<TypeCategory C>
-Expr<SomeKind<C>> operator-(const Expr<SomeKind<C>> &x) {
-  return std::visit(
-      [](const auto &y) -> Expr<SomeKind<C>> { return {-y}; }, x.u);
-}
-
-#define BINARY(op, CONSTR) \
-  template<TypeCategory C, int K> \
-  Expr<Type<C, K>> operator op( \
-      const Expr<Type<C, K>> &x, const Expr<Type<C, K>> &y) { \
-    return {CONSTR<Type<C, K>>{x, y}}; \
-  } \
-  template<TypeCategory C> \
-  Expr<SomeKind<C>> operator op( \
-      const Expr<SomeKind<C>> &x, const Expr<SomeKind<C>> &y) { \
-    return std::visit( \
-        [](const auto &xk, const auto &yk) -> Expr<SomeKind<C>> { \
-          return {xk op yk}; \
-        }, \
-        x.u, y.u); \
-  }
-
-BINARY(+, Add)
-BINARY(-, Subtract)
-BINARY(*, Multiply)
-BINARY(/, Divide)
-#undef BINARY
-
-#if 0
-#define OLDBINARY(FUNC, CONSTR) \
-  template<typename A> A FUNC(const A &x, const A &y) { \
-    return {CONSTR<typename A::Result>{x, y}}; \
-  } \
-  template<typename A> \
-  std::enable_if_t<!std::is_reference_v<A>, A> FUNC(const A &x, A &&y) { \
-    return {CONSTR<typename A::Result>{A{x}, std::move(y)}}; \
-  } \
-  template<typename A> \
-  std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, const A &y) { \
-    return {CONSTR<typename A::Result>{std::move(x), A{y}}}; \
-  } \
-  template<typename A> \
-  std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, A &&y) { \
-    return {CONSTR<typename A::Result>{std::move(x), std::move(y)}}; \
-  }
-#undef OLDBINARY
-#endif
-
-#define BINARY(FUNC, OP) \
-  template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \
-    return {Relational<ResultType<A>>{OP, x, y}}; \
-  } \
-  template<typename A> \
-  std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
-      const A &x, A &&y) { \
-    return {Relational<ResultType<A>>{OP, x, std::move(y)}}; \
-  } \
-  template<typename A> \
-  std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
-      A &&x, const A &y) { \
-    return {Relational<ResultType<A>>{OP, std::move(x), y}}; \
-  } \
-  template<typename A> \
-  std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
-      A &&x, A &&y) { \
-    return {Relational<ResultType<A>>{OP, std::move(x), std::move(y)}}; \
-  }
-
-BINARY(operator<, RelationalOperator::LT)
-BINARY(operator<=, RelationalOperator::LE)
-BINARY(operator==, RelationalOperator::EQ)
-BINARY(operator!=, RelationalOperator::NE)
-BINARY(operator>=, RelationalOperator::GE)
-BINARY(operator>, RelationalOperator::GT)
-#undef BINARY
-
 extern template class Expr<Type<TypeCategory::Character, 1>>;  // TODO others
 extern template struct Relational<Type<TypeCategory::Integer, 1>>;
 extern template struct Relational<Type<TypeCategory::Integer, 2>>;
index d22d71e57854324fe407eab05d9a4880c0598cf3..c49028983eaacc07a6e29653d86c89280b8ae544 100644 (file)
@@ -20,20 +20,9 @@ using namespace Fortran::parser::literals;
 
 namespace Fortran::evaluate {
 
-Expr<SomeReal> ConvertToTypeOf(
-    const Expr<SomeReal> &to, const Expr<SomeInteger> &from) {
-  return std::visit(
-      [&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
-}
-
-Expr<SomeReal> ConvertToTypeOf(
-    const Expr<SomeReal> &to, const Expr<SomeReal> &from) {
-  return std::visit(
-      [&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
-}
-
 std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
-    parser::ContextualMessages &messages, GenericExpr &&x, GenericExpr &&y) {
+    parser::ContextualMessages &messages, Expr<SomeType> &&x,
+    Expr<SomeType> &&y) {
   return std::visit(
       common::visitors{[&](Expr<SomeInteger> &&ix, Expr<SomeInteger> &&iy) {
                          // Can happen in a CMPLX() constructor.  Per F'2018,
@@ -43,11 +32,11 @@ std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
                              Expr<SomeReal>{Expr<DefaultReal>{std::move(iy)}})};
                        },
           [&](Expr<SomeInteger> &&ix, Expr<SomeReal> &&ry) {
-            auto rx{ConvertToTypeOf(ry, std::move(ix))};
+            auto rx{ConvertToTypeAndKindOf(ry, std::move(ix))};
             return std::optional{std::make_pair(std::move(rx), std::move(ry))};
           },
           [&](Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) {
-            auto ry{ConvertToTypeOf(rx, std::move(iy))};
+            auto ry{ConvertToTypeAndKindOf(rx, std::move(iy))};
             return std::optional{std::make_pair(std::move(rx), std::move(ry))};
           },
           [&](Expr<SomeReal> &&rx, Expr<SomeReal> &&ry) {
@@ -63,8 +52,8 @@ std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
 }
 
 std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
-    parser::ContextualMessages &messages, std::optional<GenericExpr> &&x,
-    std::optional<GenericExpr> &&y) {
+    parser::ContextualMessages &messages, std::optional<Expr<SomeType>> &&x,
+    std::optional<Expr<SomeType>> &&y) {
   if (x.has_value() && y.has_value()) {
     return ConvertRealOperands(messages, std::move(*x), std::move(*y));
   }
index 6b437cbd019be52b028cbb74200dd9f1f6f1f5c4..f1bc983b601e1d9346a07ac7cd642b94dcbe4181 100644 (file)
 
 namespace Fortran::evaluate {
 
-// Convert the second argument to the same type and kind of the first.
-Expr<SomeReal> ConvertToTypeOf(
-    const Expr<SomeReal> &to, const Expr<SomeInteger> &from);
-Expr<SomeReal> ConvertToTypeOf(
-    const Expr<SomeReal> &to, const Expr<SomeReal> &from);
+// Convenience functions and operator overloadings for expression construction.
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x) {
+  return {Negate<Type<C, K>>{std::move(x)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator+(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+  return {Add<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+  return {Subtract<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator*(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+  return {Multiply<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator/(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+  return {Divide<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C> Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x) {
+  return std::visit(
+      [](auto &xk) { return Expr<SomeKind<C>>{-std::move(xk)}; }, x.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator+(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+  return std::visit(
+      [](auto &xk, auto &yk) {
+        return Expr<SomeKind<C>>{std::move(xk) + std::move(yk)};
+      },
+      x.u, y.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+  return std::visit(
+      [](auto &xk, auto &yk) {
+        return Expr<SomeKind<C>>{std::move(xk) - std::move(yk)};
+      },
+      x.u, y.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator*(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+  return std::visit(
+      [](auto &xk, auto &yk) {
+        return Expr<SomeKind<C>>{std::move(xk) * std::move(yk)};
+      },
+      x.u, y.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator/(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+  return std::visit(
+      [](auto &xk, auto &yk) {
+        return Expr<SomeKind<C>>{std::move(xk) / std::move(yk)};
+      },
+      x.u, y.u);
+}
+
+// Convert the second argument expression to an expression of the same type
+// and kind as that of the first.
+template<TypeCategory TC, typename F>
+Expr<SomeKind<TC>> ConvertToTypeAndKindOf(
+    const Expr<SomeKind<TC>> &to, Expr<F> &&from) {
+  return std::visit(
+      [&](const auto &tk) -> Expr<SomeKind<TC>> {
+        using SpecificExpr = std::decay_t<decltype(tk)>;
+        return {SpecificExpr{std::move(from)}};
+      },
+      to.u);
+}
 
 // Ensure that both operands of an intrinsic REAL operation or CMPLX()
 // are INTEGER or REAL, and convert them as necessary to the same REAL type.
 using ConvertRealOperandsResult =
     std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>>;
 ConvertRealOperandsResult ConvertRealOperands(
-    parser::ContextualMessages &, GenericExpr &&, GenericExpr &&);
+    parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&);
 
 template<TypeCategory CAT>
 void ConvertToSameKind(Expr<SomeKind<CAT>> &x, Expr<SomeKind<CAT>> &y) {
index 7bca1a374d554bca32c32cba0240a87f74fa73aa..0dde964db7c7a233e1b807cb18a2d18bf7594ade 100644 (file)
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "variable.h"
+#include "tools.h"
 #include "../common/idioms.h"
 #include "../parser/char-block.h"
 #include "../parser/characters.h"
index 99f941f9948f40b2f50c53d73e571c130e57411b..722d4885cfd3c889d63e5d8127f61d3be0072068 100644 (file)
@@ -25,7 +25,7 @@ namespace Fortran::semantics {
 
 using common::TypeCategory;
 using evaluate::Expr;
-using evaluate::GenericExpr;
+using evaluate::SomeType;
 using evaluate::Type;
 
 using MaybeIntExpr = std::optional<Expr<evaluate::SomeInteger>>;
@@ -117,8 +117,8 @@ static std::optional<Expr<evaluate::SomeCharacter>> AnalyzeLiteral(
 }
 
 template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) {
-  std::function<GenericExpr(A &&)> f{
-      [](A &&y) { return GenericExpr{std::move(y)}; }};
+  std::function<Expr<SomeType>(A &&)> f{
+      [](A &&y) { return Expr<SomeType>{std::move(y)}; }};
   return common::MapOptional(f, std::move(x));
 }
 
@@ -153,7 +153,7 @@ MaybeExpr AnalyzeHelper(
   evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
   Expr<evaluate::DefaultCharacter> chExpr{std::move(ind)};
   chExpr.Fold(ea.context());
-  return {GenericExpr{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
+  return {Expr<SomeType>{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
 }
 
 // Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
@@ -269,7 +269,7 @@ static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral(
           AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) {
     if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
       if (sign == parser::Sign::Negative) {
-        return {-*result};
+        return {-std::move(*result)};
       }
     }
     return result;
@@ -577,12 +577,12 @@ ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
 std::optional<Expr<evaluate::SomeComplex>> ExpressionAnalyzer::ConstructComplex(
     MaybeExpr &&real, MaybeExpr &&imaginary) {
   // TODO: pmk abstract further, this will be a common pattern
-  auto partial{[&](GenericExpr &&x, GenericExpr &&y) {
+  auto partial{[&](Expr<SomeType> &&x, Expr<SomeType> &&y) {
     return evaluate::ConvertRealOperands(
         context_.messages, std::move(x), std::move(y));
   }};
   using fType =
-      evaluate::ConvertRealOperandsResult(GenericExpr &&, GenericExpr &&);
+      evaluate::ConvertRealOperandsResult(Expr<SomeType> &&, Expr<SomeType> &&);
   std::function<fType> f{partial};
   auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))};
   if (auto joined{common::JoinOptionals(std::move(converted))}) {
index 9faea6833807f4d46363789cb48570fe1b0106e9..43fc5f471d0694fea79c5698afeb9d4f79bc70b3 100644 (file)
@@ -23,7 +23,7 @@
 
 namespace Fortran::semantics {
 
-using MaybeExpr = std::optional<evaluate::GenericExpr>;
+using MaybeExpr = std::optional<evaluate::Expr<evaluate::SomeType>>;
 
 class ExpressionAnalyzer {
 public:
index 5c7ba2a8b75e27db5662e70b02016361d43e0bf7..c51dbc2637f62c22bb9446725fcc278b79c42aa2 100644 (file)
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "../../lib/evaluate/expression.h"
+#include "../../lib/evaluate/tools.h"
 #include "testing.h"
 #include "../../lib/parser/message.h"
 #include <cstdio>
@@ -41,11 +42,9 @@ int main() {
   FoldingContext context{messages};
   ex1.Fold(context);
   MATCH("-10_4", Dump(ex1));
-  MATCH("(6_4.LE.7_4)",
-      Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
+  MATCH("(1_4/2_4)", Dump(DefaultIntegerExpr{1} / DefaultIntegerExpr{2}));
   DefaultIntegerExpr a{1};
   DefaultIntegerExpr b{2};
-  MATCH("(1_4/2_4)", Dump(a / b));
   MATCH("1_4", Dump(a));
   a = b;
   MATCH("2_4", Dump(a));